ZeroMQ
套接字通信
传统Socket编程:所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口
- 1.流套接字(SOCK_STREAM):用于提供面向连接、可靠的数据传输服务。使用TCP协议。
- 2.数据报套接字(SOCK_DGRAM):提供一种无连接的服务。使用UDP协议。
- 3.原始套接字(SOCK_RAW):原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送的数据必须使用原始套接。
ZMQ
ZMQ与Socket的区别是:普通的socket是端到端的(1:1的关系),而ZMQ却是可以N:M 的关系,人们对BSD套接字的了解较多的是点对点的连接,点对点连接需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等,而ZMQ屏蔽了这些细节,让你的网络编程更为简单。ZMQ用于node与node间的通信,node可以是主机或者是进程。
ZMQ优点:轻量级,跨语言性能好,时延低。
ZMQ缺点:只是一个网络库,不支持持久化。
三种模式
应答模式
将一组服务端和一组客户端相连,用于远程过程调用或任务分发。
这里使用请求-应答模式实现一个简单的hello world程序。
和普通的socket通信一样,需要一个客户端和一个服务器。客户端发送hello,服务器收到hello后回应world
使用REQ-REP套接字发送和接受消息是需要遵循一定规律的。客户端首先使用zmq_send()发送消息,再用zmq_recv()接收,如此循环。如果打乱了这个顺序(如连续发送两次)则会报错。类似地,服务端必须先进行接收,后进行发送。
发布订阅模式
将一组发布者和一组订阅者相连,用于数据分发。
发布/订阅模式实现了单向数据分发,服务端将事件发送给一组客户端。
PUB-SUB套接字组合是异步的。客户端在一个循环体中使用recv ()接收消息,如果向SUB套接字发送消息则会报错;类似地,服务端可以不断地使用send ()发送消息,但不能再PUB套接字上使用recv ()。
关于PUB-SUB套接字,还有一点需要注意:你无法得知SUB是何时开始接收消息的。就算你先打开了SUB套接字,后打开PUB发送消息,这时SUB还是会丢失一些消息的,因为建立连接是需要一些时间的。很少,但并不是零。解决此问题需要在PUB端加入sleep。
- 订阅者可以连接多个发布者,轮流接收消息;
- 如果发布者没有订阅者与之相连,那它发送的消息将直接被丢弃;
- 如果你使用TCP协议,那当订阅者处理速度过慢时,消息会在发布者处堆积。可以使用阈值(HWM)来保护发布者。
- 从ZeroMQ v3.x开始,当使用(tcp:// or ipc://)连接协议时,消息的过滤在发布端,使用epgm://时,在订阅端过滤。在ZeroMQ v2.x中,所有消息的过滤是在订阅者处进行的。也就是说,发布者会向订阅者发送所有的消息,订阅者会将未订阅的消息丢弃。
基于分布式处理(平行管道模式、推拉模式)
- worker上游和任务分发器相连,下游和结果收集器相连,这就意味着你可以开启任意多个worker。但若worker是绑定至端点的,而非连接至端点,那我们就需要准备更多的端点,并配置任务分发器和结果收集器。所以说,任务分发器和结果收集器是这个网络结构中较为稳定的部分,因此应该由它们绑定至端点,而非worker,因为它们较为动态。
- 我们需要做一些同步的工作,等待worker全部启动之后再分发任务。这点在ZMQ中很重要,且不易解决。连接套接字的动作会耗费一定的时间,因此当一组worker连接到端点,第一个worker连接成功时,它会一下收到很多任务。所以说,如果我们不进行同步,那这些任务根本就不会被并行地执行。
- 任务分发器使用PUSH套接字向worker均匀地分发任务(假设所有的worker都已经连接上了),数据在所有连接的节点之间进行轮询,这种机制称为负载均衡。
- 结果收集器的PULL套接字会均匀地从worker处收集消息,这种机制称为公平队列。