Go 語言被設(shè)計成一門應(yīng)用于搭載 Web 服務(wù)器,存儲集群或類似用途的巨型中央服務(wù)器的系統(tǒng)編程語言。對于高性能分布式系統(tǒng)領(lǐng)域而言,Go 語言無疑比大多數(shù)其它語言有著更高的開發(fā)效率。學習Go語言,可以說是很簡單的,入門快,想學習Go語言,可以到黑馬程序員看看,有新出的教程。
創(chuàng)新互聯(lián)公司專注于奎屯網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供奎屯營銷型網(wǎng)站建設(shè),奎屯網(wǎng)站制作、奎屯網(wǎng)頁設(shè)計、奎屯網(wǎng)站官網(wǎng)定制、小程序開發(fā)服務(wù),打造奎屯網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供奎屯網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
重點提示:
這樣我們就啟動了一個 nsqd 的實例
編寫一個消息生產(chǎn)者
nsq_single_product.go
編寫一個消息消費者
nsq_single_consumer.go
添加第一個實例
添加第二個實例
消息生產(chǎn)者
nsq_cluster_product.go
消息消費者
nsq_cluster_consumer.go
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 編寫出的應(yīng)用運行時通常由成千上萬個輕量級“進程”(并非傳統(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 對應(yīng) 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)品丨運營丨個人深度思考。
很多朋友可能知道Go語言的優(yōu)勢在哪,卻不知道Go語言適合用于哪些地方。
1、 Go語言作為服務(wù)器編程語言,很適合處理日志、數(shù)據(jù)打包、虛擬機處理、文件系統(tǒng)、分布式系統(tǒng)、數(shù)據(jù)庫代理等;網(wǎng)絡(luò)編程方面。Go語言廣泛應(yīng)用于Web應(yīng)用、API應(yīng)用、下載應(yīng)用等;除此之外,Go語言還可用于內(nèi)存數(shù)據(jù)庫和云平臺領(lǐng)域,目前國外很多云平臺都是采用Go開發(fā)。
2、 其實Go語言主要用作服務(wù)器端開發(fā)。其定位是用來開發(fā)"大型軟件"的,適合于很多程序員一起開發(fā)大型軟件,并且開發(fā)周期長,支持云計算的網(wǎng)絡(luò)服務(wù)。Go語言能夠讓程序員快速開發(fā),并且在軟件不斷的增長過程中,它能讓程序員更容易地進行維護和修改。它融合了傳統(tǒng)編譯型語言的高效性和腳本語言的易用性和富于表達性。
3、 Go語言成功案例。Nsq:Nsq是由Go語言開發(fā)的高性能、高可用消息隊列系統(tǒng),性能非常高,每天能處理數(shù)十億條的消息;
4、 Docker:基于lxc的一個虛擬打包工具,能夠?qū)崿F(xiàn)PAAS平臺的組建。
5、 Packer:用來生成不同平臺的鏡像文件,例如VM、vbox、AWS等,作者是vagrant的作者
6、 Skynet:分布式調(diào)度框架。
7、 Doozer:分布式同步工具,類似ZooKeeper。
8、 Heka:mazila開源的日志處理系統(tǒng)。
9、 Cbfs:couchbase開源的分布式文件系統(tǒng)。
10、 Tsuru:開源的PAAS平臺,和SAE實現(xiàn)的功能一模一樣。
11、 Groupcache:memcahe作者寫的用于Google下載系統(tǒng)的緩存系統(tǒng)。
12、 God:類似redis的緩存系統(tǒng),但是支持分布式和擴展性。
13、 Gor:網(wǎng)絡(luò)流量抓包和重放工具。
以上的就是關(guān)于go語言能做什么的內(nèi)容介紹了。