現象:一個dubbo服務偶發性的出現個別機器甚至整個集羣大量報線程池耗盡的問題。一開始對問題的處理比較粗暴,直接增長了10倍的線程數。可是問題依然偶爾出現,重啓服務就能夠暫時解決。後來,發現問題出現頻率有點高,不得不花點時間認真分析了。java
實際緣由:jedis參數設置不當。實際仔細分析問題後發現每次出現異常最開始都是出現了大量的jedis鏈接池獲取鏈接異常:redis
redis.clients.jedis.exceptions.JedisConnection: Could not get a resource from the pool ...省略其餘堆棧信息 Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect time out ...省略其餘堆棧信息
而這些time out實際是redis節點故障或者網絡抖動引發的。而後看看jedis配置,timeout設置爲1000,maxRedirect爲2,因此一旦出現redis鏈接問題,將會致使請求阻塞3s左右。而此服務的qps分攤到單機約爲200,阻塞致使了dubbo請求的堆積,進而致使雪崩。處理方法:縮短timeout;去除redirect;根據業務請求考慮增長熔斷組件。網絡
另外經過jstack分析,發現一旦出dubbo線程池耗盡的問題,大量的dubbo處理線程都是處於WAITING(parking)狀態,卡頓在獲取redis鏈接。分析jedis鏈接管理相關代碼,jedis鏈接池使用ReentrantReadWriteLock管理,獲取鏈接涉及鎖資源的爭奪,而redis server節點沒法鏈接將致使鏈接池須要嘗試建立新的鏈接,這個過程會拿走寫鎖,致使其餘須要經過讀鎖獲取鏈接的線程進入等待。因此 也須要根據qps設置maxTotal(這個出現問題的jedis竟然設置的鏈接數爲10!)。spa
咱們所使用的redis cluster集羣是個比較大集羣,具備數十個節點,集羣的讀寫壓力都至關大。其中一部分讀寫操做來自其餘同事維護的spark服務,使用jedis訪問。.net
現象:發現redis的響應時間出現有規律的毛刺。 DBA排查發現redis集羣的一個節點的負載相對於其餘節點比較高,並且出現大量的cluster slots命令。線程
分析:分析jedis源碼,jedis每次初始化建立鏈接都是從第一個節點開始嘗試並執行cluster slots命令來獲取整個redis cluster集羣的拓撲信息;若是jedis鏈接池獲取的鏈接失效,也會執行renewSlotCache,renewClotCache也是會執行cluster slots命令的。 通過推斷及分析,問題出在spark使用jedis的模式上,spark每一個批次任務都會建立新的jedis鏈接,批次處理完成即銷燬掉,因此spark任務執行過程當中會反覆執行jedis鏈接池的初始化進而執行cluster slots命令,而從DBA瞭解到cluster slots命令是比較耗資源的,因此致使了第一個節點負載比較高(jedis鏈接串固定的,因此第一個節點老是被執行cluster slots命令)。code
處理:經過打散jedis鏈接串上節點的順序來避免老是固定的第一個節點被用來執行cluster slots。此方法實施後,毛刺確實消失了。server
疑問:上述方法能夠說只是緩解了redis節點負載不均衡的問題,可是因爲對spark使用不太瞭解,因此暫時不知道是否有辦法在多個批次任務間共享jedis鏈接。資源