golang實時訊息平臺NSQ的使用

changjixiong發表於2017-02-13

#NSQ 是什麼 (本文作者 changjixiong,以下是正文)

NSQ 是一個實時訊息平臺,引用一段 InfoQ 上的介紹:

“NSQ是一個基於Go語言的分散式實時訊息平臺,它基於MIT開源協議釋出,程式碼託管在GitHub。NSQ可用於大規模系統中的實時訊息服務,並且每天能夠處理數億級別的訊息,其設計目標是為在分散式環境下執行的去中心化服務提供一個強大的基礎架構。NSQ具有分散式、去中心化的拓撲結構,該結構具有無單點故障、故障容錯、高可用性以及能夠保證訊息的可靠傳遞的特徵。NSQ非常容易配置和部署,且具有最大的靈活性,支援眾多訊息協議。”

# 如何開始使用 這裡有一個例子用來說明如何安裝、啟動以及傳送與接收訊息: An Example of Using NSQ From Go(地址:http://tleyden.github.io/blog/2014/11/12/an-example-of-using-nsq-from-go/)

# 構建訊息的響應函式 如果單是用一個匿名函式來處理收到的訊息顯然是不夠的,下面用程式碼來演示一下如果根據收到的訊息來使用相應的處理函式。

## 生產者 首先我們來建立生產者

config := nsq.NewConfig()
w, _ := nsq.NewProducer("127.0.0.1:4150", config)

jsonData := []string{}
jsonData = append(jsonData, `
            {
                "func_name":"BarFuncAdd",
                "params":[0.5,0.51]
            }`)
jsonData = append(jsonData, `
            {
                "func_name":"FooFuncSwap",
                "params":["a","b"]
            }`)

for _, j := range jsonData {
        w.Publish("Topic_json", []byte(j))
}

上面的程式碼向 NSQ 傳送了 2 個 json 格式的訊息,從字面上不難看出其目的是呼叫 2 個函式,分別是 BarFuncAdd 和 FooFuncSwap。

## 消費者 現在我們來建立消費者

config := nsq.NewConfig()
config.DefaultRequeueDelay = 0
config.MaxBackoffDuration = 20 * time.Millisecond
config.LookupdPollInterval = 1000 * time.Millisecond
config.RDYRedistributeInterval = 1000 * time.Millisecond
config.MaxInFlight = 2500

MakeConsumer("Topic_json", "ch", config, HandleJsonMessage)

MakeConsumer 的定義如下:

func MakeConsumer(topic, channel string, config *nsq.Config,
    handle func(message *nsq.Message) error) {
    consumer, _ := nsq.NewConsumer(topic, channel, config)
    consumer.AddHandler(nsq.HandlerFunc(handle))
    err := consumer.ConnectToNSQD("127.0.0.1:4150")
    if err != nil {
        log.Panic("Could not connect")
    }
}

### 處理器函式 NSQ 訊息的處理器函式定義如下:

func HandleJsonMessage(message *nsq.Message) error {

    resultJson := reflectinvoke.InvokeByJson([]byte(message.Body))
    result := reflectinvoke.Response{}
    err := json.Unmarshal(resultJson, &result)
    if err != nil {
        return err
    }
    info := "HandleJsonMessage get a result\n"
    info += "raw:\n" + string(resultJson) + "\n"
    info += "function: " + result.FuncName + " \n"
    info += fmt.Sprintf("result: %v\n", result.Data)
    info += fmt.Sprintf("error: %d,%s\n\n", result.ErrorCode,
        reflectinvoke.ErrorMsg(result.ErrorCode))

    fmt.Println(info)

    return nil
}

### 功能函式 處理器函式根據收到的 json 資料通過反射最終呼叫了 Foo 的 FooFuncSwap 方法及 Bar 的 BarFuncAdd 方法。

type Foo struct {
}

type Bar struct {
}

func (b *Bar) BarFuncAdd(argOne, argTwo float64) float64 {

    return argOne + argTwo
}

func (f *Foo) FooFuncSwap(argOne, argTwo string) (string, string) {

    return argTwo, argOne
}

### 怎麼呼叫的 reflectinvoke.InvokeByJson 是如何根據形如:

{
    "func_name":"BarFuncAdd",
    "params":[0.5,0.51]
}

的 json 資料呼叫 Bar.BarFuncAdd 的? 請參考《golang 通過反射使用 json 字串呼叫 struct 的指定方法及返回 json 結果》(如果前面這段沒有連線地址,那肯定是文章被爬蟲幹掉了連線,請找本文的原文閱讀)

文中程式碼的完整內容在https://github.com/changjixiong/goNotes/tree/master/nsqNotes以及https://github.com/changjixiong/goNotes/tree/master/reflectinvoke中。 ### 注意事項 同一個訊息 channel 如果有多個消費者則消費者收到的訊息是不確定的。例如,如果將文中的生產者執行一個例項,將消費者執行兩個例項 (命名為 A,B),則會出現 A 收到 2 個訊息或者 B 收到 2 個訊息或者 AB 各收到一個訊息。

更多原創文章乾貨分享,請關注公眾號
  • golang實時訊息平臺NSQ的使用
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章