Golang ZeroMQ:REQ/REP 无意义的非阻塞
Golang ZeroMQ: REQ/REP senseless non-blocking
在Python上,ZeroMQ .recv()/.send()
操作是阻塞的,这对于REQ/REP
[=来说是完美的67=].
在 Golang 中,我必须将 zmq.DONTWAIT
传递给 .recv()
和 .send()
操作才能实现工作。
但问题是,流程需要锁步,所以:
server.recv()
client.send()
client.recv()
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 对零共享、零阻塞、(几乎)零复制等的热情。
在Python上,ZeroMQ .recv()/.send()
操作是阻塞的,这对于REQ/REP
[=来说是完美的67=].
在 Golang 中,我必须将 zmq.DONTWAIT
传递给 .recv()
和 .send()
操作才能实现工作。
但问题是,流程需要锁步,所以:
server.recv()
client.send()
client.recv()
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 对零共享、零阻塞、(几乎)零复制等的热情。