Golang ZeroMQ:REQ/REP 无意义的非阻塞

Golang ZeroMQ: REQ/REP senseless non-blocking

在Python上,ZeroMQ .recv()/.send()操作是阻塞的,这对于REQ/REP[=来说是完美的67=].
在 Golang 中,我必须将 zmq.DONTWAIT 传递给 .recv().send() 操作才能实现工作。

但问题是,流程需要锁步,所以:

  1. server.recv()
  2. client.send()
  3. client.recv()
  4. server.send()

在 3 和 4 之间开始出现怪异,因为它们是异步的。

当客户端发送了一条消息,而服务器还没有收到消息,但客户端试图接收响应时,锁步就不再是锁步了。

zmq.DONTWAIT相比,是否存在某种zmq.DOBLOCK

还是我哪里搞错了?


EDIT:

我在 C 中为 zeromq 使用这个 go 绑定:https://godoc.org/github.com/pebbe/zmq4#Type

如您所见,.recv() 需要输入 flag,这是第二个参考中的两者之一:

接收:https://godoc.org/github.com/pebbe/zmq4#Socket.Recv

要传递的标志:https://github.com/pebbe/zmq4/blob/master/zmq4.go#L403

这是我用来解决问题的当前代码,感觉有点难看:

package connection

import (
  "zmq4"
  "fmt"
  "time"
)


const ERRTMPUNAV="resource temporarily unavailable"


func checkError(e error){
  if e != nil {
    panic(e)
  }
}


func CreateRepNode(address string,onMessage chan<- string,send <-chan string,closeConn <-chan bool){
  stop:=false
  socket,err:=zmq4.NewSocket(zmq4.REP)
  checkError(err)
  err=socket.Bind(address)
  checkError(err)
  go func(socket *zmq4.Socket){
    for {
      msg,err:=socket.Recv(zmq4.DONTWAIT)
      fmt.Println("server message"+msg)
      if stop==true {
        return
      }
      if err != nil {
        rateLimit := time.Tick(100 * time.Millisecond)
    <-rateLimit
    continue
      }
      checkError(err)
      onMessage<-msg
      rep:=<-send
      _,err=socket.Send(rep,zmq4.DONTWAIT)
    }
  }(socket)
  <-closeConn
  stop=true
}


func CreateReqNode(address string,onMessage chan<- string,send <-chan string,closeConn <-chan bool){
  stop:=false
  socket,err:=zmq4.NewSocket(zmq4.REQ)
  checkError(err)
  err=socket.Connect(address)
  checkError(err)
  go func(){
    for {
      msg:=<-send
      if stop==true {
        return
      }
      _,err:=socket.Send(msg,zmq4.DONTWAIT)
      for {
        msg,err=socket.Recv(zmq4.DONTWAIT)
        fmt.Println("client got message "+msg)
        if err!=nil {
          if err.Error()==ERRTMPUNAV {
            w:=time.Tick(100*time.Millisecond)
            <-w
            continue
          }
        }
        break
      }
      onMessage<-msg
    }
  }()

  <-closeConn
  stop=true
}

ZeroMQ 琐碎的基本原型更像是一组构建块,而不是满足任何需求的生产级解决方案。

Go-lang 是一种非常强大的现代语言,带有协程和其他用于控制并发的智能工具,所以请原谅我列出以下建议:

  • 尽可能避免阻塞式设计(非阻塞式设计让人们可以完全控制所有事情... 在任何 infinite/uncontrollable 等待循环中都没有"hanging",在已经形成的死锁中更糟)

  • 避免依赖 SLOC 示例 具有单一的基本类型的正式通信模式,人们应该开发 强大的生存能力-handler strategy 适用于所有可能出错的情况(传输网络中的信号丢失、消息丢失、DDoS 级别的资源过载,...)


重新设计提示 - 根本不要使用 REQ/REP。是的,从来没有...

ZeroMQ 可扩展正式通信模式 REQ/REP 适合学习 ZeroMQ,但在实际生产级部署中是致命的。 .

接下来考虑内部无条件模式,例如 PAIR(虽然标记为 experimental,但对于某些用例它有效太棒了), XREQ/XREP, PUSH/PULL 或一些复合 signalling/transport 多插座定制设计自己的模式.

最好的下一步是什么?

What I can do for your further questions right now is to direct you to see a bigger picture on this subject 有更多论据,一个简单的信号平面/消息平面插图和直接 link 到 Pieter HINTJENS 的必读书籍。

这本书值得花时间和精力。如果一个人对分布式系统设计很认真,你会爱上它以及 Pieter 对零共享、零阻塞、(几乎)零复制等的热情。