在系列文章前面幾篇中,介紹了NSQ改造的過程和幾個基礎特性,本文中我們繼續介紹幾個高階特性及其使用場景,這些都是結合有贊業務場景總結提煉出來的重要功能。
NSQ擴充訊息格式的設計
有贊中介軟體在NSQ中引入了支援擴充內容的訊息格式,通過支援擴充的訊息格式。業務方能夠在訊息體外定義額外的資料,擴充了應用功能,支援更多的場景。
相比較於Kafka等訊息中介軟體,NSQ的訊息格式在內容和數量上較為簡單。一條訊息除了基本的後設資料之外,其餘內容為訊息體。訊息的後設資料主要包括了訊息在服務端產生時的時間戳,服務端對於該訊息的下發次數,訊息ID。Kafka訊息格式(record batch,control record,record)中出現的部
分後設資料例如壓縮格式(snappy),nsq在客戶端建連的過程中通過IDENTIFY確認,而部分後設資料,如CRC,事務屬性等,在NSQ中則沒有對應實現。
訊息格式的相對簡單,使得nsq傳輸訊息內容上有更高的效率,同時使得編寫NSQ客戶端時更為容易。而簡單格式所帶來的缺點就是NSQ訊息除了訊息體本身之外,無法攜帶更多的額外資訊。在傳輸一些可以和業務流程解耦的資料時,依然需要修改已有訊息格式,並且由於缺少重用性,每個需要傳輸擴充資料的業務方都需要重新改造自己的業務訊息格式。
###擴充內容的訊息格式
為了使NSQ支援更多的場景,有贊中介軟體在原有NSQ訊息格式的基礎上進行了改進,設計並實現了一種支援擴充的訊息格式。
[x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x][x]...[x][x][x][x]... | (int64) || || (binary string ) || || || || (binary) | 8-byte || || 16-byte || || || || N-byte ---------------------------------------------------------------------------------------------------------------------------------... nanosecond timestamp ^^ message ID ^ ^ message body (uint16) , 2-byte , attempts ,
可以看到新訊息格式在已有訊息格式上增加了3個部分(綠色字型):
- 擴充內容的版本(version of extension content):
長度為1個位元組,用於區分擴充內容的類別和格式。例如,0x01為json擴充; - 擴充內容的長度(length of extension content):
長度為2個位元組,表示擴充內容的位元組長度; - 擴充內容的二進位制字串:可變長度,為擴充內容的二進位制位元組陣列;
通過在訊息格式中引入以上附加資訊,NSQ在訊息傳輸過程中能夠在不修改原有訊息格式的前提下附帶額外的資訊,業務方或者應用框架能夠通過擴充訊息格式支援新的場景和新的功能。在此我們以有贊業務中使用的幾個典型場景為例, 詳細描述下擴充套件訊息的使用。
###擴充訊息使用場景之鏈路壓測
鏈路壓測是生產環境中的典型場景。壓測器在短時間內生產大量線上壓測資料,用以檢測線上鏈路的效能以及可用性。針對壓測鏈路上使用訊息中介軟體的應用,通過擴充訊息設計,在鏈路壓測場景中,訊息中介軟體可以提供如下功能。
fig1. 訊息使用場景之鏈路壓測
生產者應用在處理壓測訊息時,在擴充訊息頭中標記該訊息為壓測訊息。NSQ將線上訊息以及壓測訊息統一下發至下游消費者(線上Consumer),下游消費者通過檢查擴充訊息中的壓測欄位來判斷該訊息是否為壓測流量,由應用框架根據擴充訊息頭內容決定是否下發至應用,或者對壓測訊息進行攔截。
該方案的優勢在於,應用方無需對已有NSQ的Topic生產/消費配置進行變更,新版NSQ通過對已有topic進行升級,使topic支援擴充訊息格式。業務方僅需要關注壓測訊息的處理。該方案的缺點在於,線上訊息和壓測訊息共用一個topic,未進行隔離。一旦生產者對於壓測訊息的處理出現錯誤,或者下游消費應用超過負載時,此時隔離壓測資料的操作較為複雜,需要業務方修改程式碼,新版NSQ通過回溯消費功能來“洗掉”壓測訊息。
###擴充訊息使用場景之鏈路隔離
擴充訊息的另外一種場景為應用鏈路隔離。場景如下:QA環境總存在兩類應用,第一類是QA環境中應用的穩定版本,另外一類是應用在QA上進行新功能開發/驗證的版本。QA環境中應用通過NSQ進行解耦。新功能版本中增加了新的訊息處理邏輯來消費穩定QA環境中不支援的訊息,在NSQ不支援鏈路隔離前,開發需要:
- 停止QA穩定消費,啟動新功能驗證的消費;
- 在NSQ上驗證新功能;
- 停止新功能驗證消費,恢復穩定QA消費;
- 以上步驟往復,直至原有QA被替換;
fig2. QA環境中應用使用NSQ場景
通過在NSQ服務端實現基於擴充訊息頭內容的投遞優先順序,新版NSQ支援業務上鍊路隔離的需求。
fig3. 新版NSQ支援鏈路隔離應用場景
供新功能驗證的訊息將通過在擴充訊息頭上的附帶資訊進行標記,NSQ服務端在投遞訊息時根據訊息頭中的投遞資訊(Tag)按照以下規則進行路由:
- 消費者中不存在帶有相同投遞資訊的消費者時,訊息統一投遞給QA穩定環境的消費者;
- 消費者中存在和訊息頭中相同的投遞資訊時,訊息投遞給該消費者;
- 訊息投中不包含投遞資訊時,訊息統一投遞給QA穩定環境的消費者;
通過實現該規則,新版NSQ支援業務方實現環境鏈路隔離。
###擴充訊息使用場景之訊息過濾
NSQ訊息的消費模式為,訊息在channel之間為組播,channel內的客戶端(Consumer)競爭一條訊息。
fig4.NSQ訊息投遞機制
與鏈路隔離的思路類似,通過對訊息擴充頭的指定值進行過濾,新版NSQ可以支援channel內的訊息過濾。
訂閱到相同channel上的消費者附帶相同的擴充訊息關鍵字,當NSQ投遞訊息時:
- 訊息內容沒有標識資訊或者標識資訊空, 則只會投遞沒有filter_key或者filter_key為空的channel;
- 訊息有過濾標識資訊, 投遞到匹配的filter_key的消費channel, 未指定filter的channel也要投遞;
- 對於某個channel不匹配的訊息, 服務端視為已消費,現象為該channel不投遞;
fig5. NSQ基於channel的訊息過濾
該功能的實現基於訊息擴充頭,可以在服務端,客戶端單獨實現,或由服務端和客戶端共同實現。
###NSQ migrate proxy-nsq遷移工具
對於正在使用開源版本NSQ的使用者,NSQ migrate proxy提供將開源版本NSQ遷移到有贊自研版本NSQ的能力。藉助於該遷移工具,可在使用者無感知的情況下對topic進行遷移。NSQ migrate proxy在遷移過程中作為開源NSQ和自研NSQ的代理,根據遷移階段的變化將lookup請求代理至開源NSQ和自研NSQ,整合nsqlookupd的結果後返回給客戶端。使用遷移代理需要連線客戶端實現讀寫策略,遷移代理需要根據讀(r)寫(w)引數對對生產者和消費者進行區分。
fig6. nsq遷移結構圖
####遷移步驟
結合自研版NSQ的讀寫策略(r/w),NSQ migrate proxy定義了3個遷移階段,到達最後階段後,topic的生產消費便遷移到自研版本
1.第1階段中,代理將在返回給客戶端的lookup結果中包含兩個NSQ叢集的節點資訊。消費者將在兩個叢集間建立消費連線。生產繼續向開源nsq進行生產。
fig7.遷移階段1
2.第2階段中,代理對於生產者的lookup請求,只返回遷移目標叢集的lookup結果。此時訊息生產將指向目標NSQ叢集。消費者繼續維持雙叢集消費。
fig8.遷移階段2
3.當確認開源NSQ叢集中的訊息已經消費完後,遷移進入最後階段。代理對於消費者的lookup請求只返回目標NSQ節點資訊。消費和開源NSQ的連線將斷開。此時訊息的生產和消費都遷移到自研NSQ叢集。遷移完成。
fig9.遷移階段3
###Connectors
除了圍繞NSQ本身的的改造,我們針對spark和flume嘗試了通過擴充與nsq進行整合。
####spark connectors
spark consumer作為NSQ的消費者,從NSQ消費訊息後通過spark streaming API進行處理。
####flume connectors
flume nsq sink作為apache flume sink擴充,用於連線flume和NSQ,並通過本地檔案序列化儲存傳送失敗的event body並重試。通過外掛的方式,使用者在flume中的配置檔案中指定NSQ作為flume的下游。
未來計劃
為了支撐更多樣的業務需求,有贊NSQ還在繼續完善和豐富更多新特性, 這些特性包括NSQ本身的特性開發,也包括基於NSQ做的外部擴充套件系統的開發。未來的一段時間,我們計劃增加如下值得期待的重要特性。
流控
目前有贊有大量的topic都部署在一個大的叢集,受益於golang的goroutine模型,每個topic基本都是獨立的處理,互相直接影響不大, 但是碰到一些資料量大的情況, 還是會對其他topic造成一定的影響,特別是一些網路流量非常大的 topic,為了降低這種topic流量影響,我們需要限制一些topic的流量上限, 對整個叢集的穩定性提供保障。 設計方案上, 我們計劃使用業界常用的令牌桶方案。
批量訂閱
目前的NSQ還是沿用每條訊息ack的模式, 保持相容特性。 效能上雖然滿足目前以及未來一段時間的業務需求,但是還有改進的空間。特別是在某些網路延遲較高的場景下,批量訂閱可以大大提高吞吐量。批量訂閱將會支援一次消費一組訊息並且可以一次性ack一組訊息,從而減少一定的網路開銷。
更豐富安全審計功能
原版的NSQ已經支援一部分的安全審計功能, 包括使用安全連結以及使用驗證伺服器,我們後面將會針對topic的生產和channel的一些操作提供獨立的安全驗證服務,並做好審計日誌,防範一些安全問題。另外針對nsqadmin也會打通內部的統一登入驗證,針對性的限制業務的一些危險操作。
分散式事務協調器
微服務拆分的痛點就是多個系統之間的一致性保證問題,因此急需一個統一的框架能解決此類問題。分散式事務協調器將會是構建在NSQ基礎之上的一個重要產品, 該產品將會充分利用NSQ的一些特性去解決業務的痛點。
基於訊息內容的消費過濾
雖然目前已經有支援基於訊息擴充套件頭進行初步過濾的功能,但是也有些業務需求非常定製化,需要更加複雜的過濾規則,這種情況為了避免給NSQ核心程式碼帶來影響,我們也計劃在NSQ之上構建一個更加複雜的過濾系統去做和業務耦合的事情,避免給NSQ注入過多的業務耦合功能.
##總結
本文中,先展示了有贊中介軟體在NSQ中引入的支援擴充的訊息格式,並通過3個業務場景來展示新的訊息格式的玩法。之後的部分介紹了圍繞自研版本NSQ開發的擴充工具,包括了用於遷移的代理,以及可以將NSQ與spark和flume進行整合的擴充。最後對於未來計劃進行了介紹,展望了部分計劃中的新特性。
##參考資料
- [1]NSQ spark consumer: https://github.com/youzan/spark-nsq-consumer
- [2]NSQ flume sink: https://github.com/DoraALin/flume-nsq-sink
點選連結,可直達《How we redesigned the NSQ》系列所有文章:
https://tech.youzan.com/tag/paas/