golang nats request reply 模式

來源:互聯網
上載者:User

請求響應模式

無論是發布訂閱模式還是queue模式,nats都不能保證訊息一定發送到訂閱者,除非訂閱者發送一個響應給發行者。
所以訂閱者發送一個回執給發行者,就是請求響應模式。

這種模式有什麼用?

nats要求訂閱者一定要先完成訂閱,發布訊息後,訂閱者才能收到訊息,類似離線訊息的模式nats不支援。就算先完成訂閱,後發送訊息,訊息發送方也不知道是否有訂閱者收到了訊息,請求響應模式就是應對這種情況。

基本流程

A發送訊息,B收到訊息,發送回執給A。這就是request reply的基本流程。

基本實現原理

  • A啟用request模式發送訊息(訊息中包含了回執資訊,replya主題),同步等待回執(有逾時時間)。
  • B收到訊息,在訊息中取出回執資訊=replay主題,對replay主題,主動發送普通訊息(訊息內容可自訂,比如server A上的service1收到msgid=xxxx的訊息。)。
  • A在逾時內收到訊息,確認結束。
  • A在逾時內未收到訊息,逾時結束。

注意

  • 因為A發送的訊息中封裝了回執測相關資訊,訂閱者B收到訊息後,也要主動發送回執,所以請求響應模式,對雙方都有影響。
  • A發送訊息後,等待B的回執,需要給A設定逾時時間,逾時後,不在等待回執,直接結束,效果和不需要回執的訊息發送一樣,不在關心是否有訂閱者收到訊息。

兩種模式

request reply有兩種模式:

  • one to one 預設模式

1條訊息,N個訂閱者,訊息發送方,僅會收到一條回執記錄(因為訊息發送方收到回執訊息後,就自動斷開了對回執訊息的訂閱。),即使N個訂閱都都收到了訊息。注意:pub/sub和queue模式的不同

  • one to many 非預設模式,需要自己實現

1條訊息,N個訂閱者,訊息發送方,可以自己設定一個數量限制N,接受到N個回執訊息後,斷開對回執訊息的訂閱。

Server

package mainimport (    "github.com/nats-io/go-nats"    "log"    "flag")const (    //url   = "nats://192.168.3.125:4222"    url = nats.DefaultURL)var (    nc *nats.Conn    encodeConn *nats.EncodedConn    err        error)func init() {    if nc, err = nats.Connect(url); checkErr(err) {        //        if encodeConn, err = nats.NewEncodedConn(nc, nats.JSON_ENCODER);            checkErr(err) {        }    }}func main() {    var (        servername = flag.String("servername", "Y", "name for server")        queueGroup = flag.String("group", "", "group name for Subscribe")        subj       = flag.String("subj", "yasenagat", "subject name")    )    flag.Parse()    mode := "queue"    if *queueGroup == "" {        mode = "pub/sub"    }    log.Printf("Server[%v] Subscribe Subject[%v] in [%v]Mode", *servername, *subj, mode)    startService(*subj, *servername+" worker1", *queueGroup)    startService(*subj, *servername+" worker2", *queueGroup)    startService(*subj, *servername+" worker3", *queueGroup)    nc.Flush()    select {}}//receive messagefunc startService(subj, name, queue string) {    go async(nc, subj, name, queue)}func async(nc *nats.Conn, subj, name, queue string) {    replyMsg := name + " Received a msg"    if queue == "" {        nc.Subscribe(subj, func(msg *nats.Msg) {            nc.Publish(msg.Reply, []byte(replyMsg))            log.Println(name, "Received a message From Async : ", string(msg.Data))        })    } else {        nc.QueueSubscribe(subj, queue, func(msg *nats.Msg) {            nc.Publish(msg.Reply, []byte(replyMsg))            log.Println(name, "Received a message From Async : ", string(msg.Data))        })    }}func checkErr(err error) bool {    if err != nil {        log.Println(err)        return false    }    return true}

Client

package mainimport (    "github.com/nats-io/go-nats"    "log"    "github.com/pborman/uuid"    "flag"    "time")const (    //url   = "nats://192.168.3.125:4222"    url = nats.DefaultURL)var (    nc         *nats.Conn    encodeConn *nats.EncodedConn    err        error)func init() {    if nc, err = nats.Connect(url); checkErr(err, func() {    }) {        //        if encodeConn, err = nats.NewEncodedConn(nc, nats.JSON_ENCODER);            checkErr(err, func() {            }) {        }    }}func main() {    var (        subj = flag.String("subj", "yasenagat", "subject name")    )    flag.Parse()    log.Println(*subj)    startClient(*subj)    time.Sleep(time.Second)}//send message to serverfunc startClient(subj string) {    for i := 0; i < 3; i++ {        id := uuid.New()        log.Println(id)        if msg, err := nc.Request(subj, []byte(id+" hello"), time.Second); checkErr(err, func() {            // handle err        }) {            log.Println(string(msg.Data))        }    }}func checkErr(err error, errFun func()) bool {    if err != nil {        log.Println(err)        errFun()        return false    }    return true}

pub/sub模式啟動

$ ./main2018/08/18 18:54:10 Server[Y] Subscribe Subject[yasenagat] in [pub/sub]Mode2018/08/18 18:54:26 Y worker2 Received a message From Async :  b035d7c2-e7e9-4337-bb8a-a23ec85fc31a hello2018/08/18 18:54:26 Y worker1 Received a message From Async :  b035d7c2-e7e9-4337-bb8a-a23ec85fc31a hello2018/08/18 18:54:26 Y worker3 Received a message From Async :  b035d7c2-e7e9-4337-bb8a-a23ec85fc31a hello2018/08/18 18:54:26 Y worker2 Received a message From Async :  2d8dfe75-8fee-4b4c-8599-1824638dfa8c hello2018/08/18 18:54:26 Y worker1 Received a message From Async :  2d8dfe75-8fee-4b4c-8599-1824638dfa8c hello2018/08/18 18:54:26 Y worker3 Received a message From Async :  2d8dfe75-8fee-4b4c-8599-1824638dfa8c hello2018/08/18 18:54:26 Y worker2 Received a message From Async :  fe9f773a-129b-4919-9bc4-c8a4571fef6e hello2018/08/18 18:54:26 Y worker1 Received a message From Async :  fe9f773a-129b-4919-9bc4-c8a4571fef6e hello2018/08/18 18:54:26 Y worker3 Received a message From Async :  fe9f773a-129b-4919-9bc4-c8a4571fef6e hello

發送訊息

$ ./main2018/08/18 18:54:26 yasenagat2018/08/18 18:54:26 b035d7c2-e7e9-4337-bb8a-a23ec85fc31a2018/08/18 18:54:26 Y worker3 Received a msg2018/08/18 18:54:26 2d8dfe75-8fee-4b4c-8599-1824638dfa8c2018/08/18 18:54:26 Y worker2 Received a msg2018/08/18 18:54:26 fe9f773a-129b-4919-9bc4-c8a4571fef6e2018/08/18 18:54:26 Y worker2 Received a msg

queue模式啟動

$ ./main -group=test2018/08/18 19:14:31 Server[Y] Subscribe Subject[yasenagat] in [queue]Mode2018/08/18 19:14:33 Y worker2 Received a message From Async :  4ecf2728-b3a7-4181-893a-aefde3bc8d2e hello Y worker2 Received a msg2018/08/18 19:14:33 Y worker3 Received a message From Async :  4e7f1363-9a47-4705-b87a-4aaeb80164f0 hello Y worker3 Received a msg2018/08/18 19:14:33 Y worker2 Received a message From Async :  38b1f74b-8a3b-46ba-a10e-62e50efbc127 hello Y worker2 Received a msg

發送訊息

$ ./main2018/08/18 19:14:33 yasenagat2018/08/18 19:14:33 4ecf2728-b3a7-4181-893a-aefde3bc8d2e2018/08/18 19:14:33 Y worker2 Received a msg2018/08/18 19:14:33 4e7f1363-9a47-4705-b87a-4aaeb80164f02018/08/18 19:14:33 Y worker3 Received a msg2018/08/18 19:14:33 38b1f74b-8a3b-46ba-a10e-62e50efbc1272018/08/18 19:14:33 Y worker2 Received a msg

queue模式下,發送3條訊息,3個訂閱者有相同的queue,每條訊息只有一個訂閱者收到。

pub/sub模式下,發送3條訊息,3個訂閱者都收到3條訊息,一共9條。

總結:

回執主要解決:訂閱者是否收到訊息的問題、有多少個訂閱者收到訊息的問題。(不是具體業務是否執行完成的回執!)
基於事件的架構模式可以構建於訊息機制之上,依賴訊息機制。非同步呼叫的其中一種實現方式,就是基於事件模式。非同步呼叫又是分布式系統中常見的任務處理方式。

業務模式

  • 業務A發送eventA給事件中心,等待回執
  • 事件中心告知A收到了訊息,開始對外發送廣播
  • 訂閱者B訂閱了eventA主題
  • 事件中心對eventA主題發送廣播,等待回執
  • B收到訊息,告知事件中心,收到eventA,開始執行任務taskA
  • B非同步執行完taskA,通知事件中心taskAComplete,等待回執
  • 事件中心發送回執給B,對外發送廣播,taskAComplete
  • ........

如果逾時,未能收到回執,需要回執資訊的確認方可以主動調用相關介面,查詢任務執行狀態,根據任務狀態做後續的處理。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.