Golang是一種靜態(tài)類型的編程語言,具有高效性、安全性和可擴展性。它特別適合用于構(gòu)建中間件,因為它可以更快地生成和處理數(shù)據(jù),而且它可以構(gòu)建可靠的、可維護的系統(tǒng)。 Golang還具有跨平臺的能力,可以在各種操作系統(tǒng)中使用,而且可以使用內(nèi)置的庫和框架來編寫大量的代碼,從而大大簡化了中間件的開發(fā)過程。此外,Golang的性能也更好,能夠更快地處理大量的數(shù)據(jù)。因此,Golang對于構(gòu)建中間件來說是一個非常理想的選擇。
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了金安免費建站歡迎大家使用!
1. 介紹
最近在研究一些消息中間件,常用的MQ如RabbitMQ,ActiveMQ,Kafka等。NSQ是一個基于Go語言的分布式實時消息平臺,它基于MIT開源協(xié)議發(fā)布,由bitly公司開源出來的一款簡單易用的消息中間件。
官方和第三方還為NSQ開發(fā)了眾多客戶端功能庫,如官方提供的基于HTTP的nsqd、Go客戶端go-nsq、Python客戶端pynsq、基于Node.js的JavaScript客戶端nsqjs、異步C客戶端libnsq、Java客戶端nsq-java以及基于各種語言的眾多第三方客戶端功能庫。
1.1 Features
1). Distributed
NSQ提供了分布式的,去中心化,且沒有單點故障的拓撲結(jié)構(gòu),穩(wěn)定的消息傳輸發(fā)布保障,能夠具有高容錯和HA(高可用)特性。
2). Scalable易于擴展
NSQ支持水平擴展,沒有中心化的brokers。內(nèi)置的發(fā)現(xiàn)服務(wù)簡化了在集群中增加節(jié)點。同時支持pub-sub和load-balanced 的消息分發(fā)。
3). Ops Friendly
NSQ非常容易配置和部署,生來就綁定了一個管理界面。二進制包沒有運行時依賴。官方有Docker image。
4.Integrated高度集成
官方的 Go 和 Python庫都有提供。而且為大多數(shù)語言提供了庫。
1.2 組件
1.3 拓撲結(jié)構(gòu)
NSQ推薦通過他們相應的nsqd實例使用協(xié)同定位發(fā)布者,這意味著即使面對網(wǎng)絡(luò)分區(qū),消息也會被保存在本地,直到它們被一個消費者讀取。更重要的是,發(fā)布者不必去發(fā)現(xiàn)其他的nsqd節(jié)點,他們總是可以向本地實例發(fā)布消息。
NSQ
首先,一個發(fā)布者向它的本地nsqd發(fā)送消息,要做到這點,首先要先打開一個連接,然后發(fā)送一個包含topic和消息主體的發(fā)布命令,在這種情況下,我們將消息發(fā)布到事件topic上以分散到我們不同的worker中。
事件topic會復制這些消息并且在每一個連接topic的channel上進行排隊,在我們的案例中,有三個channel,它們其中之一作為檔案channel。消費者會獲取這些消息并且上傳到S3。
nsqd
每個channel的消息都會進行排隊,直到一個worker把他們消費,如果此隊列超出了內(nèi)存限制,消息將會被寫入到磁盤中。Nsqd節(jié)點首先會向nsqlookup廣播他們的位置信息,一旦它們注冊成功,worker將會從nsqlookup服務(wù)器節(jié)點上發(fā)現(xiàn)所有包含事件topic的nsqd節(jié)點。
nsqlookupd
2. Internals
2.1 消息傳遞擔保
1)客戶表示已經(jīng)準備好接收消息
2)NSQ 發(fā)送一條消息,并暫時將數(shù)據(jù)存儲在本地(在 re-queue 或 timeout)
3)客戶端回復 FIN(結(jié)束)或 REQ(重新排隊)分別指示成功或失敗。如果客戶端沒有回復, NSQ 會在設(shè)定的時間超時,自動重新排隊消息
這確保了消息丟失唯一可能的情況是不正常結(jié)束 nsqd 進程。在這種情況下,這是在內(nèi)存中的任何信息(或任何緩沖未刷新到磁盤)都將丟失。
如何防止消息丟失是最重要的,即使是這個意外情況可以得到緩解。一種解決方案是構(gòu)成冗余 nsqd對(在不同的主機上)接收消息的相同部分的副本。因為你實現(xiàn)的消費者是冪等的,以兩倍時間處理這些消息不會對下游造成影響,并使得系統(tǒng)能夠承受任何單一節(jié)點故障而不會丟失信息。
2.2 簡化配置和管理
單個 nsqd 實例被設(shè)計成可以同時處理多個數(shù)據(jù)流。流被稱為“話題”和話題有 1 個或多個“通道”。每個通道都接收到一個話題中所有消息的拷貝。在實踐中,一個通道映射到下行服務(wù)消費一個話題。
在更底的層面,每個 nsqd 有一個與 nsqlookupd 的長期 TCP 連接,定期推動其狀態(tài)。這個數(shù)據(jù)被 nsqlookupd 用于給消費者通知 nsqd 地址。對于消費者來說,一個暴露的 HTTP /lookup 接口用于輪詢。為話題引入一個新的消費者,只需啟動一個配置了 nsqlookup 實例地址的 NSQ 客戶端。無需為添加任何新的消費者或生產(chǎn)者更改配置,大大降低了開銷和復雜性。
2.3 消除單點故障
NSQ被設(shè)計以分布的方式被使用。nsqd 客戶端(通過 TCP )連接到指定話題的所有生產(chǎn)者實例。沒有中間人,沒有消息代理,也沒有單點故障。
這種拓撲結(jié)構(gòu)消除單鏈,聚合,反饋。相反,你的消費者直接訪問所有生產(chǎn)者。從技術(shù)上講,哪個客戶端連接到哪個 NSQ 不重要,只要有足夠的消費者連接到所有生產(chǎn)者,以滿足大量的消息,保證所有東西最終將被處理。對于 nsqlookupd,高可用性是通過運行多個實例來實現(xiàn)。他們不直接相互通信和數(shù)據(jù)被認為是最終一致。消費者輪詢所有的配置的 nsqlookupd 實例和合并 response。失敗的,無法訪問的,或以其他方式故障的節(jié)點不會讓系統(tǒng)陷于停頓。
2.4 效率
對于數(shù)據(jù)的協(xié)議,通過推送數(shù)據(jù)到客戶端最大限度地提高性能和吞吐量的,而不是等待客戶端拉數(shù)據(jù)。這個概念,稱之為 RDY 狀態(tài),基本上是客戶端流量控制的一種形式。
efficiency
2.5 心跳和超時
組合應用級別的心跳和 RDY 狀態(tài),避免頭阻塞現(xiàn)象,也可能使心跳無用(即,如果消費者是在后面的處理消息流的接收緩沖區(qū)中,操作系統(tǒng)將被填滿,堵心跳)為了保證進度,所有的網(wǎng)絡(luò) IO 時間上限勢必與配置的心跳間隔相關(guān)聯(lián)。這意味著,你可以從字面上拔掉之間的網(wǎng)絡(luò)連接 nsqd 和消費者,它會檢測并正確處理錯誤。當檢測到一個致命錯誤,客戶端連接被強制關(guān)閉。在傳輸中的消息會超時而重新排隊等待傳遞到另一個消費者。最后,錯誤會被記錄并累計到各種內(nèi)部指標。
2.6 分布式
因為NSQ沒有在守護程序之間共享信息,所以它從一開始就是為了分布式操作而生。個別的機器可以隨便宕機隨便啟動而不會影響到系統(tǒng)的其余部分,消息發(fā)布者可以在本地發(fā)布,即使面對網(wǎng)絡(luò)分區(qū)。
這種“分布式優(yōu)先”的設(shè)計理念意味著NSQ基本上可以永遠不斷地擴展,需要更高的吞吐量?那就添加更多的nsqd吧。唯一的共享狀態(tài)就是保存在lookup節(jié)點上,甚至它們不需要全局視圖,配置某些nsqd注冊到某些lookup節(jié)點上這是很簡單的配置,唯一關(guān)鍵的地方就是消費者可以通過lookup節(jié)點獲取所有完整的節(jié)點集。清晰的故障事件——NSQ在組件內(nèi)建立了一套明確關(guān)于可能導致故障的的故障權(quán)衡機制,這對消息傳遞和恢復都有意義。雖然它們可能不像Kafka系統(tǒng)那樣提供嚴格的保證級別,但NSQ簡單的操作使故障情況非常明顯。
2.7 no replication
不像其他的隊列組件,NSQ并沒有提供任何形式的復制和集群,也正是這點讓它能夠如此簡單地運行,但它確實對于一些高保證性高可靠性的消息發(fā)布沒有足夠的保證。我們可以通過降低文件同步的時間來部分避免,只需通過一個標志配置,通過EBS支持我們的隊列。但是這樣仍然存在一個消息被發(fā)布后馬上死亡,丟失了有效的寫入的情況。
2.8 沒有嚴格的順序
雖然Kafka由一個有序的日志構(gòu)成,但NSQ不是。消息可以在任何時間以任何順序進入隊列。在我們使用的案例中,這通常沒有關(guān)系,因為所有的數(shù)據(jù)都被加上了時間戳,但它并不適合需要嚴格順序的情況。
2.9 無數(shù)據(jù)重復刪除功能
NSQ對于超時系統(tǒng),它使用了心跳檢測機制去測試消費者是否存活還是死亡。很多原因會導致我們的consumer無法完成心跳檢測,所以在consumer中必須有一個單獨的步驟確保冪等性。
3. 實踐安裝過程
本文將nsq集群具體的安裝過程略去,大家可以自行參考官網(wǎng),比較簡單。這部分介紹下筆者實驗的拓撲,以及nsqadmin的相關(guān)信息。
3.1 拓撲結(jié)構(gòu)
topology
實驗采用3臺NSQD服務(wù),2臺LOOKUPD服務(wù)。
采用官方推薦的拓撲,消息發(fā)布的服務(wù)和NSQD在一臺主機。一共5臺機器。
NSQ基本沒有配置文件,配置通過命令行指定參數(shù)。
主要命令如下:
LOOKUPD命令
NSQD命令
工具類,消費后存儲到本地文件。
發(fā)布一條消息
3.2 nsqadmin
對Streams的詳細信息進行查看,包括NSQD節(jié)點,具體的channel,隊列中的消息數(shù),連接數(shù)等信息。
nsqadmin
channel
列出所有的NSQD節(jié)點:
nodes
消息的統(tǒng)計:
msgs
lookup主機的列表:
hosts
4. 總結(jié)
NSQ基本核心就是簡單性,是一個簡單的隊列,這意味著它很容易進行故障推理和很容易發(fā)現(xiàn)bug。消費者可以自行處理故障事件而不會影響系統(tǒng)剩下的其余部分。
事實上,簡單性是我們決定使用NSQ的首要因素,這方便與我們的許多其他軟件一起維護,通過引入隊列使我們得到了堪稱完美的表現(xiàn),通過隊列甚至讓我們增加了幾個數(shù)量級的吞吐量。越來越多的consumer需要一套嚴格可靠性和順序性保障,這已經(jīng)超過了NSQ提供的簡單功能。
結(jié)合我們的業(yè)務(wù)系統(tǒng)來看,對于我們所需要傳輸?shù)陌l(fā)票消息,相對比較敏感,無法容忍某個nsqd宕機,或者磁盤無法使用的情況,該節(jié)點堆積的消息無法找回。這是我們沒有選擇該消息中間件的主要原因。簡單性和可靠性似乎并不能完全滿足。相比Kafka,ops肩負起更多負責的運營。另一方面,它擁有一個可復制的、有序的日志可以提供給我們更好的服務(wù)。但對于其他適合NSQ的consumer,它為我們服務(wù)的相當好,我們期待著繼續(xù)鞏固它的堅實的基礎(chǔ)。
golangchannel和mq的區(qū)別
我是一個著迷于產(chǎn)品和運營的技術(shù)人,樂于跨界的終身學習者。歡迎關(guān)注我喲~
每周五12點 按時送達~
我的第「218」篇原創(chuàng)敬上
大家好,我是Z哥。
最近在項目中遇到了一個使用 RabbitMQ 時的問題,這個問題我覺得還是有一定普適性的,和大家分享一下,避免大家后續(xù)在同一個問題上犯錯。
消息隊列(MQ)是在軟件開發(fā)中很常用的中間件,如果一個程序需要協(xié)調(diào)另一個程序進行數(shù)據(jù)的“write”操作,并且不關(guān)心“write”的結(jié)果,則便會選擇它。它是一個保存消息(數(shù)據(jù))的容器,由它來確保消息一定被送達到目標程序。
打個比喻來說,消息隊列就是一個郵差,它負責將信件(消息)從源頭送往目的地,并且根據(jù)信件重要性的不同,提供當面簽收確認或者直接投放兩種服務(wù)。
RabbitMQ 就是一個典型的消息隊列,以 AMQP 為標準。歷史也比較悠久,大概是從 2007年研發(fā)出來的,用的編程語言Erlang也同樣具有年代感。
需要簡單介紹一下 Erlang 的特點,它對我們理解 RabbitMQ 有很大的幫助。
Erlang 是一種運行于“虛擬機”(類似 JVM)的解釋性語言。是一個結(jié)構(gòu)化,動態(tài)類型編程語言,內(nèi)建并行計算支持。使用 Erlang 編寫出的應用運行時通常由成千上萬個輕量級“進程”(并非傳統(tǒng)意義上的進程)組成,并通過消息傳遞相互通訊。進程間上下文切換對于 Erlang 來說僅僅 只是一兩個環(huán)節(jié),比起 C 程序的線程切換要高效得多得多了。
——整理于百度百科的資料
不管是什么 MQ 中間件,作為消息的生產(chǎn)方和消費方都需要和 MQ 的服務(wù)端建立連接進行通訊。
?
一般這個連接都會使用 TCP 協(xié)議,在 RabbitMQ 里也不例外。大多數(shù) RabbitMQ 的 SDK 都會將連接封裝為一個「Connection」對象。
還沒完,大多數(shù)的 MQ 中間件還會在「Connection」的基礎(chǔ)上增加一個「Channel」的概念,以通過復用的方式提高 TCP 連接的利用率,因為建立和銷毀 TCP 連接是非常昂貴的開銷。在 RabbitMQ 中的復用 TCP 連接方式是「Non-blocking I/O」的模式。
關(guān)于NIO,「Non-blocking I/O」的概念,有感興趣的話可以跳轉(zhuǎn)去看之前寫的這篇文章。(用最通俗的話講明白阻塞/非阻塞/異步/同步,到底啥區(qū)別?)
?
多說一句,任何方案都不是“銀彈”。當每個 Channel 的流量不是很大時,復用單一的 Connection 可以在產(chǎn)生性能瓶頸的情況下有效地節(jié)省 TCP 連接資源。但是 Channel 本身的流量很大時,這時候多個 Channel 復用一個 Connection 就會產(chǎn)生性能瓶頸,進而使整體的流量被限制了。此時就需要開辟多個 Connection,將這些 Channel 均攤到這些 Connection 中,至于哪些 Channel 使用那個 Connection 以及Connection 與 Channel 之間的數(shù)量關(guān)系是多少,需要根據(jù)業(yè)務(wù)自身的實際情況進行調(diào)節(jié)。
Channel 在 AMQP 中是一個很重要的概念,大多數(shù)操作都是在信道這個層面展開的。比如, channel.exchangeDeclare、channel.queueDeclare、channel.basicPublish、channel.basicConsume 等方法。RabbitMQ 相關(guān)的 API 與 AMQP 緊密相連,比如 channel.basicPublish 對應 AMQP 的 Basic.Publish 命令。
可能你要問了,Channel 是不是也能像 Connection 一樣被復用?這是個好問題,也是我們這次遇到問題的關(guān)鍵點。
結(jié)論是:可以,但是需要自己保證客戶端對 Channel 訪問的線程安全問題,因為在 Channel 的另一端,在 RabbitMQ 的服務(wù)端,每個 Channel 由一個單獨的“進程”所管理,如果由于多線程復用Channel 導致數(shù)據(jù)幀亂序了,RabbitMQ 的服務(wù)端會主動關(guān)閉整個 Connection 。
因此,我們這次犯的錯誤就是多線程復用了同一個 Channel 導致的問題。所以,如果你也用到 streadway/amqp 這個庫的話,需要特別注意這點。
不過,不同語言的SDK內(nèi)部實現(xiàn)不同,我們分別使用 Golang 的 AMQP 庫 streadway/amqp,和 RabbitMQ 官方提供的 C# 版本的庫分別模擬過同樣的場景,前者出現(xiàn)問題,后者卻沒有問題。
受限于時間原因,沒有具體去核實 C# 庫的源碼,主觀猜測是 C# 庫內(nèi)部多做了一些對于單個 Channel 的線程安全處理。
最后,我整理了三點使用 streadway/amqp 庫的最佳實踐,你可以看看:
01
golang 中使用 streadway/amqp 時,需要保證每一個線程單獨一個 Channel。
streadway/amqp 庫中的獲取一個 Channel 的方法「Connection.channel()」是線程安全的。但是內(nèi)部有一個 defaultChannelMax 的參數(shù)對 Channel 的數(shù)量進行了限制,默認是 (2 10) - 1,2047。這個需要注意:
?
02
我們可以通過調(diào)用 amqp.DialConfig(url string, config Config) 來調(diào)整個限制。
?
但是,并不是你調(diào)整了多少就是多少,還需要和 RabbitMQ 服務(wù)端的配置進行 min() 函數(shù)的處理,最終為兩者的最小值。
Tips:特別是用云廠商的 MQ 產(chǎn)品,因為階梯收費的原因會對很多性能參數(shù)做限制,需要格外關(guān)注這點,比如某版本的阿里云 RabbitMQ 實例限制是單個 Connection 最多 64 個 Channel)
03
正如前面對 Erlang 的簡單介紹,Erlang 是一個天然支持多“進程”設(shè)計的語言,所以在 RabbitMQ 的服務(wù)端設(shè)計中,每一個 Queue,每一個 Connection 都是單獨的一個“進程”。因此如果你想盡可能地壓榨 RabbitMQ 性能,可以通過建立更多的 Connection 或者創(chuàng)建更多的 Queue 來實現(xiàn),當然需要注意到 Connection 的創(chuàng)建和銷毀的性能開銷問題。
推薦閱讀:
減少聯(lián)調(diào)、高效集成,試試這個工具
golang使用3周總結(jié)
也可以「關(guān)注」我,帶你以技術(shù)思維看世界~
想更進一步和我一起玩耍,歡迎「搜索微信公號:跨界架構(gòu)師」。
內(nèi)容包括:架構(gòu)設(shè)計丨分布式系統(tǒng)丨產(chǎn)品丨運營丨個人深度思考。
網(wǎng)站題目:go語言消息中間件 go gin 中間件
網(wǎng)站路徑:http://vcdvsql.cn/article38/ddsicpp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊、小程序開發(fā)、網(wǎng)站設(shè)計、營銷型網(wǎng)站建設(shè)、、品牌網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)