记一次线上Curator使用过程JVM栈溢出解决

小说:华龙亲朋棋牌谁有群作者:王秉更新时间:2019-02-21字数:92002

没等武魂帝国大军出城,天刚蒙蒙亮,战鼓的轰鸣之声已经在天斗帝国大营中炸响。

即刻棋牌app器

不管外面吵得多厉害,刘皓四人却安静的进行修炼,足足半个多月的时间最先醒过来的当然是刘皓了,其次就是红衣,而阿蒂米斯和绿可儿两女估计还有一段时间。
韩非觉得事态严重了,唐长官已经撤退下去的可能性很大,于是他急忙对“狐狸”说道:“你立即带着‘老虎’他们赶去金陵女大,与陈少校会合,看看那边的情况怎么样?如果控制不了那些溃兵的事态,那就找潘团长,让他想办法找唐长官,只有找到唐长官,才能命令那些已经失去指挥的散兵游勇的,否则一旦事态扩大,那南京城内就要上演自己人打自己人的惨剧了!”

说完,他将一封鹰信交给了李抱真,李抱真也知道季胜率领一支斥候队活跃在河北境内,他又问送信兵道:“季将军现在在哪里?”

记一次线上Curator使用过程JVM栈溢出解决


    为了同学们看起来一目了,特按如下思路进行讲解。

      1.出现的场景

    2.分析及解决的过程

    3.总结

  最近公司要使用zookeeper做配置管理(后面简称ZK),然后自己就提前用虚拟机进行了ZK三台集群的搭建。之后开始选择使用zookeeper的java client工具,google了半天,发现了一个很名强大的Apache的Curator工具,很多底层的东西都已经给你封装好了,所以用起来很方便,因为我使用的场景是做配置管理,所以使用Curator的Framework就够了。Curator相对于zookeeper,就相当于Guava之于Java.

  因为每天的QPS上亿,所以考虑的因素还是很多,因此从网上找了一些demo,然后自己就开始写一些测试的类,下边的这个方法是用于获取客户端,并且加入了一些监听和输出:

private static CuratorFramework getClient(String namespace) throws Exception{

        ACLProvider aclProvider = new ACLProvider() {
            private List<ACL> acl ;
            @Override
            public List<ACL> getDefaultAcl() {
                if(acl ==null){
                    ArrayList<ACL> acl = ZooDefs.Ids.CREATOR_ALL_ACL;
                    acl.clear();
                    acl.add(new ACL(Perms.ALL, new Id("auth", "admin:admin") ));
                    this.acl = acl;
                }
                return acl;
            }
            @Override
            public List<ACL> getAclForPath(String path) {
                return acl;
            }
        };
        String scheme = "digest";
        byte[] auth = "admin:admin".getBytes();
        int connectionTimeoutMs = 1000;
        String connectString = "127.0.0.1:2181";        
        CuratorFramework client = CuratorFrameworkFactory.builder().
                aclProvider(aclProvider).
                authorization(scheme, auth).
                connectionTimeoutMs(1).
                connectString(connectString).sessionTimeoutMs(50).
                namespace(namespace).
                retryPolicy(new RetryOneTime(1)).build();
        client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
            @Override
            public void stateChanged(CuratorFramework client, ConnectionState newState) {
                System.out.println("** STATE CHANGED TO : " + newState);
            }
        });
        client.start();
        client.getZookeeperClient().internalBlockUntilConnectedOrTimedOut();

//        client.getZookeeperClient().blockUntilConnectedOrTimedOut();
        System.out.println(client.getZookeeperClient().isConnected());
        System.out.println(client.getState());
        return client;
    }

  获取客户端之后就可以启动(client.start())客户端并且创建相当的Node以及它的payload. 感觉写的已经可以了,而且经过简单的测试,觉得可以了,然后就上到测试环境上了,测试环境的访问量并不是很大,所以也没有什么特别异常,之后就放到线上了。

  当把程序放到线上去之后,系统的JVM监控系统就开始报警,线程数由几百迅速增加到了3、4千个,直接超过了我们设置的报警阈值,所以感觉使用jstack命令 jstack -l pid > threadDump,找一个 stack analyzer online的一个网站 fastthread.io, upload做好的threadDump文件,上边有很多汇总,然后基本上一目了然:

  1700多个TIMED_WATING,还有1700多个TIMED_WATING,这里边肯定有问题,然后继续往下拉,会按线程分组进行展示:

  会发现有大概有77%的线程和Curator有关系,这个应该就是它的问题了,那么点开里边的内容,就能看到线程的明细了,继续:

  里边有Curator Framework的代码了,找到相当的行907,发现只要Client一启动的话就会使得BlockingQueue会有一个take()的动作,这个take的含义是将head取到,如果没有的话就等待,这就是线程WAITING的状态,然后继续看是在什么地方调用的它。

    找到了,原来是客户端启动(client.start())的时候进行的调用,因为我在网上看到很多地方说build模式拿到的Client是线程安全的,所以我就每次拿一次client,然后调用其start()。这样每个不同的线程就会都等待在那个位置上。我没有在Finally调用 CloseableUtils.closeQuietly(client); 因为请求量太大,如果频繁的调用关闭客户端会造成性能下降,必须保持一个长连接。

  打开Curator的官网上,里边也进行了说明,创建采用build的方式是线程安全的,但是要保持单例。

  这样问题找到了,下边开始想着如果修复和优化,首先让它实现单例,同时还不能用完之后就直接关闭。同时要保持长连接,在特定情况下进行连接关闭,那就如果出现异常为

KeeperException.ConnectionLossException时需要捕获并且进行计数和关闭。同时也为了效率考虑,再获取Node的payload时将payload进行缓存,这样再次减少了对zk的大量访问。同时可以根据自己的实际情况去考虑缓存的时间。
if(client == null || client.getState().equals(CuratorFrameworkState.STOPPED) || !client.getNamespace().equals(namespace)) {
                synchronized (ZookeeperUtil.class) {
                    if(client == null || client.getState().equals(CuratorFrameworkState.STOPPED) || !client.getNamespace().equals(namespace)) {
                        client = getClient(namespace);
                    }
                }
            }

  同时在网上找到zookeeper集群上从3.4开始,从客户端连接数maxClientCnxns(配置在zoo.cfg)默认连接数为60,改为0时不限制。

  总结:

  1. 当遇到线程数增加或CPU过高时需要使用jstack将JVM的线程数据导出到文件,然后通过在线工具或自己下载的工具进行分析,我还是比较喜欢这个在线的分析工具,它能分析出总的线程数中按状态进行分析,还可以按线程类型进行分组,很强大。

  2. 遇到问题要冷静思考,然后多写几个小的demo进行测试。我其实在写这个问题的过程中我是写了测试类进行模拟的,然后通过本机的jvisualvm查看栈的情况,根我推断的一致的,所以就会找到解决的方法。

  3.有些技术知识还是从官方网站学习,而且如果看书的话,需要从头看到尾,这样的话基本上能了解事务的全部内容,否则只看到部分内容。

  如果有写的不对的地方,欢迎同学们来拍砖~

 

当前文章:http://www.0477auto.com/8j68a/40139.html

发布时间:2019-02-21 05:30:41

lol2019夏季赛赛程 2019qq赢钱棋牌 阜新52麻将下载 凯旋传奇怎么样 单机版水果老虎机2.0 万能神器授权码 千禧棋牌客户端 手机微信牛牛棋牌

编辑:乙辛

我要说两句: (0人参与)

发布