一、背景
很久以前寫了DAO框架和MVC框架,前段時間又重寫了DAO框架-GDAO(手寫DAO框架(一)-從“1”開始,源碼:https://github.com/shuimutong/gdao.git)和MVC框架-GMVC(手寫MVC框架(一)-再出發,源碼:https://gitee.com/simpleha/gmvc.git)。
之前也嘗試過寫RPC框架(源碼:https://github.com/shuimutong/grpc_beta.git),客戶端、服務端的方法調用寫完了,但是網絡傳輸沒有寫。
其實寫框架也好,寫博客也好,主要是為了學習。所以現在再開始的時候,我就在思考寫什么好?
我的想法很簡單:把目前用到的框架,能自己實現的盡量都實現一遍。站在這個時間點,寫哪個框架有兩個選擇:繼續寫RPC;寫MQ。這兩個框架個人認為有很多相似的地方:MQ雖然是異步的,其實也是有“長連接”在連着的。比如訂閱方,會有長連接連着MQ的服務端。RPC框架不分訂閱、發送,而是客戶端、服務端,當客戶端找到服務端之后,客戶端會盡量和服務端保持連接。
相比MQ,RPC框架不需要持久化的動作,而MQ不僅需要考慮持久化,還需要考慮如何進行高效的持久化。
通過一番對比,我最終選擇實現MQ框架,以學習序列化、網絡傳輸、高效持久化方面的知識。選擇的參照框架是kafka。
二、如何下手
既然選擇了實現MQ,那從何下手呢?
先了解一下kafka吧。
1、mq框架大致流程
生產方和服務端建立連接,將消息發送到服務端。
訂閱方和服務端建立連接,服務端將訂閱方訂閱的消息推送給訂閱方,或者訂閱方自己拉取指定的消息。
2、了解一下kafka
1)為什么kafka有如此高的qps
kafka服務可以部署在機械硬盤上,接收到的每條消息都會存盤,但是qps可以輕松過萬,甚至達到百萬級別(數據來源於網上,本人暫未親測)。怎么做到的?
通過官網可以了解到,我記錄的有3點。
首先,采用磁盤順序讀寫。其次,基於java,使用堆外內存,避免gc的干擾。再次,所有數據寫兩份,防止丟失。此外,還有零拷貝技術等。
以上各個方面結合起來,最終成就了kafka的英名!
2)是推消息還是拉消息
推消息的話,如果消息驟增,可能導致訂閱方崩掉,所以kafka采用的是拉的方式。以什么頻率拉,由訂閱方自己決定。
其實采用拉消息的方式也有缺點,比如訂閱方為了拉消息,就會一直在哪里循環請求。如果沒有新消息,訂閱方就會頻繁的請求,白白浪費資源。
針對這個循環空請求的問題,kafka增加了一個特性。當拉消息的時候,可以設置:如果沒有消息,就先夯住請求,等到消息來了,再返回結果。這樣,就能夠避免這類問題了。
3、寫框架計划
在稍微看了kafka之后,感覺這個技術含量還是很高的。雖然上面只列了幾點,其實還有很多很重要的點沒有提及。但是,我就是要學寫。如果等我先把kafka看透之后再寫,那可能得等很長時間。(其實我已經磨蹭了很長時間)
所以我決定,先把架子搭起來。萬丈高樓也得平地起!
1)大致方案
寫服務端,網絡傳輸使用http,序列化使用json(傳輸字符串,其實無所謂json),數據持久化使用DB。
雖然使用http傳輸,但是需要封裝成具體的工具,避免客戶端自己寫請求工具,方便后期升級。
2)生產方發消息
消息包括:主題、消息內容
3)訂閱方拉消息
主題、消息內容、offset(拉多少條)
4)服務端處理
消息來了之后,將消息存在DB,編offset。
拉消息動作,根據offset,返回取的多少條。
offset的提交應在客戶端里進行封裝,可先實現為自動提交。
5)框架組成
a、服務端
b、生產消息客戶端(服務配置)
c、消費消息客戶端(服務配置)
6)配置項
a、服務地址
b、主題號
大致計划已定,那就開始實現吧
三、服務端功能梳理
1、注冊主題號
校驗主題號是否存在,不存在則新增
2、接收消息
參數:主題號、消息體
先校驗主題號是否存在,存在則保存消息到DB,然后返回結果
3、拉消息
參數:主題號、offset、希望取的消息數量
校驗主題號是否存在,校驗offset是否正常,正常則返回希望的消息數量(如果有消息)。
4、更改offset
參數:主題號、offset
校驗主題號是否存在,校驗offset。
重復消費功能后期做。
四、結語
關於手寫MQ,暫時想的就這么多,后面想到其他的再加上。
先實現一個簡易的服務端,接下來就是代碼實現了。
寫代碼中……
第一個版本在上周寫完了,歡迎指教->手寫MQ框架(二)-服務端實現