詳解redis在微服務領域的貢獻
前言
說到redis,可能大傢的腦海中蹦出的關鍵詞是:NoSQL、KV、高性能、緩存等。但今天的文章從另一個角度——微服務來展開。
這篇文章的起因也是源自一次面試經歷,在面試一位來自陌陌的候選人(就是那個交友的陌陌)時,他提到一點讓我覺得很有意思,他說redis在陌陌被使用的非常廣泛,除瞭常規的緩存外,某些場景下也當NoSQL數據庫來使用,還用redis作為微服務的註冊中心,甚至連RPC的調用協議都用瞭redis協議。
註冊中心
最早瞭解到redis可以作為註冊中心是從dubbo的源碼中看到,但一直也沒有過多的瞭解,因為從沒聽說哪傢公司使用redis來做服務發現。
在dubbo中使用redis來做服務發現還是挺簡單的,引入jedis依賴,將註冊中心地址改為redis地址即可:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
dubbo.registry.address=redis://127.0.0.1:6379
註冊上來的數據是這樣,類型是hash
/dubbo/${service}/${category}
如
/dubbo/com.newboo.sample.api.DemoService/consumers /dubbo/com.newboo.sample.api.DemoService/providers
hash數據結構下保存的key是註冊上來的url,value是過期時間
127.0.0.1:6379> hgetall /dubbo/com.newboo.sample.api.DemoService/providers
1) “dubbo://172.23.233.142:20881/com.newboo.sample.api.DemoService?anyhost=true&application=boot-samples-dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.newboo.sample.api.DemoService&metadata-type=remote&methods=sayHello&pid=19807&release=2.7.8&side=provider×tamp=1621857955355”
2) “1621858734778”
從理論上來說,註冊中心隻要符合數據存儲、監聽推送變更、心跳檢測這幾個基本的功能即可。
以dubbo為例看下redis是如何利用自身特性來完成註冊中心的功能( 以dubbo 2.7.8版本為例):
服務註冊
- provider在服務註冊時,將服務提供方的url寫入
/dubbo/${service}/providers
下,數據類型為hash,key為提供方url,value為key的過期時間,默認為60s,可配置 - 寫入完成後以
/dubbo/${service}/providers
為key調用publish
命令發佈一個register事件provider在初始化時起一個單獨的線程每隔1/2過期時間
(默認30s)時對 - provider進行重新重新註冊並發佈register事件
服務發現
- 獲取匹配
/dubbo/${service}/*
的key(此處用到瞭keys
命令),拿到的有這幾種:/dubbo/${service}/providers
、/dubbo/${service}/routers
、/dubbo/${service}/configuators
- 對
/dubbo/${service}/*
拿到的key進行hgetall
,拿到真實的provider列表以及配置等數據,進行組裝、匹配 - 同時對每個subscribe的服務單獨開一個線程,對
/dubbo/${service}
執行psubscribe
命令阻塞等待有事件發生
從源碼和測試來看,dubbo的redis註冊中心不能直接用於生產環境,原因有如下兩點:
- 使用瞭
keys
命令,會阻塞單線程的redis,keys執行期間,其他命令都得排隊 - 沒有心跳檢測這個功能,我測試瞭provider被
kill -9
殺死後,consumer是無法感知的。但從實現上來看是想通過存儲的過期時間來判斷服務是否可用,即需要對比url對應的value與當前的時間,如果過期應被剔除,但這部分貌似沒有實現完整
雖然dubbo的redis註冊中心生產不可用,但這並不影響他可以構建一個生產可用的註冊中心,陌陌就是個很好的例子。
RPC調用協議
redis協議作為RPC調用協議也是陌陌同學告訴我的,當時我問瞭他兩個問題:
- 為什麼選擇redis協議作為RPC調用協議
- redis協議如何透傳類似header的
隱式參數
第一個問題的答案也比較出乎意料,他說是為瞭跨語言調用,當時覺得隻有http、gRPC等協議做到瞭跨語言,redis協議跨語言也是第一次聽說。但仔細一想,確實沒毛病,現在哪個後端語言沒有實現redis的客戶端呢?
之所以redis協議能夠做到跨語言,這也全仰仗它的設計非常簡潔,易於實現,詳細協議內容可以參考這個鏈接:
http://redisdoc.com/topic/protocol.html
我就舉一個例子來證明redis協議簡潔到瞭什麼程度,這是我很久之前就關註的一個項目
https://github.com/jdp/redisent
它是一個php實現的redis客戶端,隻有一個php文件,共196行
,這196行包含瞭註釋,變量定義,鏈接建立等,真正解析協議的代碼非常少,請求的編碼和發送隻用瞭17行代碼
,解析返回的代碼隻有58行
!正如項目的介紹那樣:simple, no-nonsense
第二個問題回答的和我的預期一致,從redis協議的層面暫時無法支持類似header的隱式參數,但陌陌的RPC框架是自研的,所以他們在框架層解決瞭這個問題,序列化他們選擇瞭json
,如果要透傳header參數,框架將參數組裝到傳輸體中去。
遺憾的是dubbo中的redis協議實現並不完整,無法暴露redis協議,隻能調用,所以測試也隻能測試client連接到redis服務器進行get、set調用,意義不大。
總結
redis目前是個用途非常廣泛的存儲組件,雖然在微服務領域它不是主流,但這也給我們提供瞭一種思路,至少這條路是可以走通的。
到此這篇關於redis在微服務領域的貢獻的文章就介紹到這瞭,更多相關redis微服務內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java中dubbo+zookeeper微服務架構簡介
- 升級dubbo2.7.4.1版本平滑遷移到註冊中心nacos
- Python模塊對Redis數據庫的連接與使用講解
- Java Dubbo框架知識點梳理
- Redis憑啥可以這麼快