先說些題外話~自上次確診為鼻竇炎+過敏性鼻炎到現在已經一個月了,最初那會,從下午到晚上頭疼難忍。大概是積勞成疾,以前流鼻涕、打噴嚏的時候從來沒有注意過,結果病根一下爆發。
關鍵在於鎖定問題,開始治療一兩天之后就不會頭疼了。當然,習慣也很重要,再也不敢用力擤鼻子了。
挺過那一陣就好受很多,之后就是鼻塞稍微煩人一些。鼻子的問題很容易串到其他面部器官中去,一旦發展嚴重必然大幅度影響生活質量。
治療方法推薦洗鼻(前兩周先消炎,吃地紅霉素),但注意不要讓醫院賺的太狠,葯包到葯店或者網上買都可以;如果是過敏引發流涕也要吃抗過敏葯。
以上,為同樣深受困擾的小伙伴提供一些經驗。。
【問題】使用jediscluster連接redis集群,使用jedis執行redis命令,一些時候報Could not get a resource from the pool ,底層是連接超時異常,另一些時候則正常。
【復現】時好時壞,有時失敗后馬上第二次請求相同命令即成功,進一步測試發現竟然與請求的key有關,極難定位問題原因。
【方案】1、考慮為服務端與客戶端版本不匹配問題,而
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
jedis版本已為最新,另有3.X-m1版本,換用之后也無效。此處麻煩大家告知一下“m1”的意思。
換用spring的包裝客戶端,spring-data-redis,亦無效。
從時好時壞這一點來看,版本不是主因。事實上,redis對於版本匹配並不如kafka那般嚴格。
2、考慮為客戶端連接參數問題,結合網上各種經驗調整JedisPoolConfig與JedisCluster構造方法參數,均無效。這里時間浪費最多,網上信息龐雜而大部分無用。
3、考慮為服務端單個redis節點配置問題,bind不到外網ip,這點很疑惑。
4、考慮為服務端密碼問題,從slot槽的設計入手,假設在目前的客戶端中,如果請求的key需要轉發到其他節點,則因為沒有驗證密碼而被其他節點拒絕。(實際上這是對部署腳本或者jedis集群客戶端不信任)
服務端取消密碼構建集群后問題依舊,但已經接近問題答案。
【解決】定位問題在於集群節點。
原因排查依據:
(1)命令執行時好時壞,同一命令請求不同key,一些一直成功,其他一直不成功。
(2)查詢所有節點的keys命令從未成功。
(3)debug之下發現不成功的命令請求的節點是內網ip,成功的命令是另一節點的外網ip。
原來,為了測試方便,我使用了外網ip構建集群。但是,官方提供的redis-trib.rb腳本帶有極大的迷惑性,在構建時返回屏幕的信息正確,而自動生成的每個節點的nodes.conf中,表述自身的一行與預期均有出入,如下所示:
圖中139為外網ip,而172則是內網ip。導致客戶端經對key哈希后得到的槽,所對應的請求節點有可能拿到內網ip,導致無法連接。超時后報錯。
為解決問題,我假設只要該配置存在,節點之間即可相互感知,節點重啟后也不會影響集群狀態。故而手工將內網ip修改為外網ip,重啟每個redis節點,問題解決。
【目前最佳實踐】
目前認為官方提供用於構建和管理集群的redis-trib.rb腳本,對外網ip的支持並不完善。因此,
1、在開發測試階段,通過外網ip構建集群,通過密碼保證安全性。
2、單個redis配置:bind注釋掉,打開保護模式,設置密碼和集群master密碼,ruby client.rb中對應修改密碼。
我的路徑/usr/local/rvm/gems/ruby-2.4.1/gems/redis-4.0.2/lib/redis/client.rb 密碼用就替換,不用就填nil,不是空字串!
3、清除每一個節點的持久化記錄和之前的nodes.conf之后,用外網ip正常構建集群。
4、手工修改生成的每一個nodes.conf,然后重啟對應的redis節點。
如有理解偏差或更好方案,希望可以告知,大家一起討論。