開篇
近兩個星期參與了一個比較完整的項目,項目背景在這里就不做過多介紹了,這里只是想簡單總結(jié)下項目過程中涉及的一些技術(shù)方案,權(quán)當(dāng)給自己之前糾結(jié)的技術(shù)和業(yè)務(wù)的方向做一個階段性的總結(jié)。
在這個總結(jié)中對我個人而言既有已經(jīng)技術(shù)點的回顧,又有新技術(shù)點的使用,這也是我為什么會寫這篇總結(jié)的原因。
在這個項目中我們使用了一些中間件的技術(shù),包括RabbimtMq、Redis、HttpClient等,這些都是日常比較常用的。
RabbitMq重試
這是一個大家都會遇到的問題,在一套測試環(huán)境中存在多個消費者消費同一個主題的消息,但是我們的最新消費邏輯的代碼只會在其中一個消費者中部署,這就導(dǎo)致測試過程中無法保證消息都會被最新的代碼邏輯消費到。
為了解決指定機器消費消息,研究了下RabbitMq的重試機制后發(fā)現(xiàn)可以利用重試機制來解決這個問題。通過在消費側(cè)增加代碼用來判斷當(dāng)前機器是否在配置中心指定消費的機器ip地址,如果不是指定機器的消費我們就直接拋出異常來讓RabbitMq進行重試直到指定機器的消費。
整個解決方案的核心在于了解RabbitMq的重試機制并知道如何進行利用,至于增加判斷代碼我們使用了Interceptor,只是為了讓代碼顯得有些逼格。
Redis的lua腳本
- 關(guān)于Redis,大家熟知內(nèi)容包括Redis從3.0版本開始引入集群模式,Redis是讀寫處理是單線程的并且線程安全的。
- 在項目中我們用Redis來實現(xiàn)一個固長的隊列并支持批量消費。整體解決方案是基于Redis的List數(shù)據(jù)結(jié)構(gòu)和Lua腳本。
- Redis的固長隊列我們使用Lua腳本,在Lua腳本中判斷List的長度并且在達到長度后丟棄最早的數(shù)據(jù)并插入最新的數(shù)據(jù),使用是LPOP和RPUSH的組合命令。
- Redis的批量消費我們使用Lua腳本,在Lua腳本中使用LRANGE和LTRIM組合命令來實現(xiàn)的。
- Redis 3.0是支持集群模式的,所以在一個Lua腳本當(dāng)中只能針對單個key進行操作,否則會出現(xiàn)多個key不在一個redis槽的問題。
- Redis 3.x 和 4.x版本針對Lua腳本中對nil類型的數(shù)據(jù)處理是一致的,這部分建議查看Redis的官網(wǎng)的語法,Lua腳本對nil的處理是當(dāng)作false。
Jedis的集群模式
- 項目中訪問Redis使用的是Jedis的客戶端,之前對Jedis的源碼就有閱讀的經(jīng)驗,這次剛好借項目之便又重新看了一次。
- Jedis針對Redis的集群模式的訪問是通過cluster slots命令進行發(fā)現(xiàn)并給予發(fā)現(xiàn)的master節(jié)點進行連接處理的,這部分邏輯已經(jīng)完成整理并準(zhǔn)備公司內(nèi)部技術(shù)投稿。
- Jedis的集群模式下的連接管理是通過apache common pools進行管理的,DBCP應(yīng)該也是使用它來實現(xiàn)對象復(fù)用管理的,有興趣的可以研究研究。
HttpClient的多線程問題
- 項目中通過HttpClient訪問外部網(wǎng)站,借項目之便順帶研究了下多線程訪問HttpClient的邏輯,可以減少頻繁重新連接的開銷。
- 整體的思路可以參考之前我寫的文章HttpClient介紹和使用,針對HttpClient的連接池管理抽空再寫篇文章進行分析。