記一次線上Curator使用過程JVM棧溢出解決

    爲了同窗們看起來一目了,特按以下思路進行講解。java

      1.出現的場景緩存

    2.分析及解決的過程安全

    3.總結session

  最近公司要使用zookeeper作配置管理(後面簡稱ZK),而後本身就提早用虛擬機進行了ZK三臺集羣的搭建。以後開始選擇使用zookeeper的java client工具,google了半天,發現了一個很名強大的Apache的Curator工具,不少底層的東西都已經給你封裝好了,因此用起來很方便,由於我使用的場景是作配置管理,因此使用Curator的Framework就夠了。Curator相對於zookeeper,就至關於Guava之於Java.ide

  由於天天的訪問量上億級的,因此考慮的因素仍是不少,所以從網上找了一些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監控系統就開始報警,線程數由幾百迅速增長到了三、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)) {
               CloseableUtils.closeQuietly(client);   client
= getClient(namespace); } } }

  同時在網上找到zookeeper集羣上從3.4開始,從客戶端鏈接數maxClientCnxns(配置在zoo.cfg)默認鏈接數爲60,改成0時不限制。

  總結:

  1. 當遇到線程數增長或CPU太高時須要使用jstack將JVM的線程數據導出到文件,而後經過在線工具或本身下載的工具進行分析,我仍是比較喜歡這個在線的分析工具,它能分析出總的線程數中按狀態進行分析,還能夠按線程類型進行分組,很強大。

  2. 遇到問題要冷靜思考,而後多寫幾個小的demo進行測試。我其實在寫這個問題的過程當中我是寫了測試類進行模擬的,而後經過本機的jvisualvm查看棧的狀況,根我推斷的一致的,因此就會找到解決的方法。

  3.有些技術知識仍是從官方網站學習,並且若是看書的話,須要從頭看到尾,這樣的話基本上能瞭解事務的所有內容,不然只看到部份內容。

  若是有寫的不對的地方,歡迎同窗們來拍磚~

相關文章
相關標籤/搜索