golang使用Nsq

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

為什麼要使用Nsq

最近一直在尋找一個高效能,高可用的訊息佇列做內部服務之間的通訊。一開始想到用zeromq,但在尋找資料的過程中,意外的發現了Nsq這個由golang開發的訊息佇列,畢竟是golang原汁原味的東西,功能齊全,關鍵是效能還不錯。其中支援動態拓展,消除單點故障等特性,  都可以很好的滿足我的需求

下面上一張Nsq與其他mq的對比圖,看上去的確強大。下面簡單記錄一下Nsq的使用方法

圖片來自golang2017開發人員大會

Nsq服務端

Nsq服務端簡介

在使用Nsq服務之前,還是有必要瞭解一下Nsq的幾個核心組件
整個Nsq服務包含三個主要部分

nsqlookupd

先看看官方的原話是怎麼說:
nsqlookupd是守護進程負責管理拓撲資訊。用戶端通過查詢 nsqlookupd 來發現指定話題(topic)的生產者,並且 nsqd 節點廣播話題(topic)和通道(channel)資訊

簡單的說nsqlookupd就是中心管理服務,它使用tcp(預設連接埠4160)管理nsqd服務,使用http(預設連接埠4161)管理nsqadmin服務。同時為用戶端提供查詢功能

總的來說,nsqlookupd具有以下功能或特性

  •  唯一性,在一個Nsq服務中只有一個nsqlookupd服務。當然也可以在叢集中部署多個nsqlookupd,但它們之間是沒有關聯的

  • 去中心化,即使nsqlookupd崩潰,也會不影響正在啟動並執行nsqd服務

  • 充當nsqd和naqadmin資訊互動的中介軟體

  • 提供一個http查詢服務,給用戶端定時更新nsqd的地址目錄 

nsqadmin

官方原話:是一套 WEB UI,用來彙集叢集的即時統計,並執行不同的管理工作

總的來說,nsqadmin具有以下功能或特性

  • 提供一個對topic和channel統一管理的操作介面以及各種即時監控資料的展示,介面設計的很簡潔,操作也很簡單

  • 展示所有message的數量,恩....裝X利器

  • 能夠在後台建立topic和channel,這個應該不常用到

  • nsqadmin的所有功能都必須依賴於nsqlookupd,nsqadmin只是向nsqlookupd傳遞使用者操作並展示來自nsqlookupd的資料

nsqadmin預設的訪問地址是http://127.0.0.1:4171/ 

nsqd

官方原話:nsqd 是一個守護進程,負責接收,排隊,投遞訊息給用戶端

簡單的說,真正幹活的就是這個服務,它主要負責message的收發,隊列的維護。nsqd會預設監聽一個tcp連接埠(4150)和一個http連接埠(4151)以及一個可選的https連接埠

總的來說,nsqd 具有以下功能或特性

  • 對訂閱了同一個topic,同一個channel的消費者使用負載平衡策略(不是輪詢)

  • 只要channel存在,即使沒有該channel的消費者,也會將生產者的message緩衝到隊列中(注意訊息的到期處理)

  • 保證隊列中的message至少會被消費一次,即使nsqd退出,也會將隊列中的訊息暫存磁碟上(結束進程等意外情況除外)

  • 限定記憶體佔用,能夠配置nsqd中每個channel隊列在記憶體中緩衝的message數量,一旦超出,message將被緩衝到磁碟中

  • topic,channel一旦建立,將會一直存在,要及時在管理台或者用代碼清除無效的topic和channel,避免資源的浪費

這是官方的圖,第一個channel(meteics)因為有多個消費者,所以觸發了負載平衡機制。後面兩個channel由於沒有消費者,所有的message均會被緩衝在相應的隊列裡,直到消費者出現

這裡想到一個問題是,如果一個channel只有生產者不停的在投遞message,會不會導致伺服器資源被耗盡?也許nsqd內部做了相應處理,但還是要避免這種情況的出現

Nsq服務端與用戶端的關係

瞭解nsqlookupd,nsqd與用戶端中消費者和生產者的關係

消費者

消費者有兩種方式與nsqd建立串連

  • 消費者直連nsqd,這是最簡單的方式,缺點是nsqd服務無法實現動態伸縮了(當然,自己去實現一個也是可以的)  

  • 消費者通過http查詢nsqlookupd擷取該nsqlookupd上所有nsqd的串連地址,然後再分別和這些nsqd建立串連(官方推薦的做法),但是用戶端會不停的向nsqlookupd查詢最新的nsqd地址目錄(不喜歡用http輪詢這種方式...)
    還是看圖更直接些 ,官方的消費者模型:

生產者

生產者必須直連nsqd去投遞message(網上說,可以串連到nsqlookupd,讓nsqlookupd自動選擇一個nsqd去完成投遞,但是我用Producer的tcp是連不上nsqlookupd的,不知道http可不可以...),

這裡有一個問題就是如果生產者所串連的nsqd炸了,那麼message就會投遞失敗,所以在用戶端必須自己實現相應的備用方案

安裝Nsq

方法一

  • 首先搭建golang開發環境,這裡就不詳細講了

    • 注意一下,搭建golang環境時最好將bin目錄添加到系統內容(path)裡,省去了每次都要去bin目錄裡執行的麻煩

  • 安裝包管理器godep

go get github.com/tools/godep

執行完後檢查godep是否已經安裝在bin目錄下,一般都會自動安裝,如果沒有,用go install手動安裝下

  • 安裝依賴包assert

go get github.com/bmizerany/assert
  • 安裝Nsq

godep get github.com/bitly/nsq/...

如果安裝成功,bin目錄裡就會出現一大堆nsq_...開頭的可執行檔

  • PS:如果安裝失敗

    • 像我一樣出現了一大堆"use of internal package not allowed"錯誤,找了半天,才在一個角落裡發現了這句話
      注意:NSQ 保持了 go get 相容,但是不推薦,因為之後不能保證仍然能穩定編譯。

    這時採用方法二安裝

方法二

  • 直接去https://github.com/nsqio/nsq/releases下載編譯好的執行檔案,將裡面的可執行檔複製到bin目錄下就可以使用了

運行Nsq

運行單機nsqd服務

nsqd是一個獨立的服務,啟動一個nsqd就可以完成message的收發,啟動一個單機的nsqd,很簡單

nsqd

用戶端可以使用http,也可以使用tcp,這裡我使用是官方的go-nsq包做用戶端,使用tcp進行message的收發

  • 發送

  • 接收

運行Nsq服務叢集

  • 首先啟動nsqlookud

nsqlookupd
  • 啟動nsqd,並接入剛剛啟動的nsqlookud。這裡為了方便接下來的測試,啟動了兩個nsqd

nsqd --lookupd-tcp-address=127.0.0.1:4160
nsqd --lookupd-tcp-address=127.0.0.1:4160 -tcp-address=0.0.0.0:4152 -http-address=0.0.0.0:4153
  • 啟動nqsadmin

nsqd --lookupd-http-address=127.0.0.1:4161

基於go-nsq的用戶端實現

幾個值得注意的地方

  • Producer斷線後不會重連,需要自己手動重連,Consumer斷線後會自動重連

  • Consumer的重連時間配置項有兩個功能(這個設計必須吐槽一下,分開配置更好一點)

    • Consumer檢測到與nsqd的串連斷開後,每隔x秒向nsqd請求重連

    • Consumer每隔x秒,向nsqlookud進行http輪詢,用來更新自己的nsqd地址目錄

    • Consumer的重連時間預設是60s(...菜都涼了),我改成了1s

  • Consumer可以同時接收不同nsqd node的同名topic資料,為了避免混淆,就必須在用戶端進行處理

  • 在AddConurrentHandlers和 AddHandler中設定的介面回調是在另外的goroutine中執行的

  • Producer不能發布(Publish)空message,否則會導致panic

go_nsq-send.go

//Nsq發送測試package mainimport ( "bufio" "fmt" "github.com/nsqio/go-nsq" "os")var producer *nsq.Producer// 主函數func main() { strIP1 := "127.0.0.1:4150" strIP2 := "127.0.0.1:4152" InitProducer(strIP1) running := true //讀取控制台輸入 reader := bufio.NewReader(os.Stdin) for running { data, _, _ := reader.ReadLine() command := string(data) if command == "stop" { running = false } for err := Publish("test", command); err != nil; err = Publish("test", command) { //切換IP重連 strIP1, strIP2 = strIP2, strIP1 InitProducer(strIP1) } }}// 初始化生產者func InitProducer(str string) { var err error fmt.Println("address: ", str) producer, err = nsq.NewProducer(str, nsq.NewConfig()) if err != nil { panic(err) }}//發布訊息func Publish(topic string, message string) error { var err error if producer != nil { if message == "" { //不能發布空串,否則會導致error return nil } err = producer.Publish(topic, []byte(message)) // 發布訊息 return err } return fmt.Errorf("producer is nil", err)}

go_nsq-receive.go

//Nsq接收測試package mainimport ( "fmt" "time" "github.com/nsqio/go-nsq")// 消費者type ConsumerT struct{}// 主函數func main() { InitConsumer("test", "test-channel", "127.0.0.1:4161") for { time.Sleep(time.Second * 10) }}//處理訊息func (*ConsumerT) HandleMessage(msg *nsq.Message) error { fmt.Println("receive", msg.NSQDAddress, "message:", string(msg.Body)) return nil}//初始化消費者func InitConsumer(topic string, channel string, address string) { cfg := nsq.NewConfig() cfg.LookupdPollInterval = time.Second          //設定重連時間 c, err := nsq.NewConsumer(topic, channel, cfg) // 建立一個消費者 if err != nil { panic(err) } c.SetLogger(nil, 0)        //屏蔽系統日誌 c.AddHandler(&ConsumerT{}) // 添加消費者介面 //建立NSQLookupd串連 if err := c.ConnectToNSQLookupd(address); err != nil { panic(err) } //建立多個nsqd串連 // if err := c.ConnectToNSQDs([]string{"127.0.0.1:4150", "127.0.0.1:4152"}); err != nil { //  panic(err) // } // 建立一個nsqd串連 // if err := c.ConnectToNSQD("127.0.0.1:4150"); err != nil { //  panic(err) // }}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.