蔡建坤
本文针对空管系统间信息交互的困难,研究分析ZeroMQ 的运作原理、支持的工作模式,并描述了使用ZeroMQ 作为空管系统信息交换的通信模型,为空管应用系统间信息交互提供基础研究。
ZeroMQ 专为可扩展的分布式或并发应用程序而设计,是一个高性能的异步消息库[1]。按TCP/IP 协议,ZeroMQ 可作为新的网络通信层,位于应用层和传输层之间,是一个可以并行工作并在分布式系统之间传播的可扩展层。与消息中间件不同的地方,ZeroMQ 不需要启动任何专用的消息代理。ZeroMQ 可视为是一个套接字Socket 库,看起来像一个框架,使套接字编程更高效,更简单,更清晰。
当使用ZeroMQ,数据流的操作如图1 所示,通信中几乎一切IO 操作都为异步的,主线程不会被阻塞。ZeroMQ 根据调用zmk_init 函数时传输的形参创建相同数量的IO 线程。每个IO Thread 都有与之绑定的“ Poller”,依据操作系统的不同的平台,“Poller”应用不同的网络IO 模型(Kequeue、Select、Epoll 、Poll、Devpoll 等)。主 线 程和IO 线程通过邮箱(Mail Box)进行通信。当服务器开始听或客户端发起连接时它会创建zmk_connecter 或zmk_listener 在主要线程,通过邮箱(Mail Box)与IO 线程连接,以及IO 线程增加zmk_connecter 或zmk_listener 用于听读/写事件。当服务器首次与客户端通信时,它会创建zmk_init 以发送身份验证。检查完成后,双方将为此连接创建会话,然后双方将通过会话进行通信。每个会话都连接到管道,主线程仅通过从管道读取/写入数据来发送和接收消息。会话实际上并不与内核共享IO 数据,相反,IO 数据在会话中通过“plugin”到“Session”中的“Engine”与内核交换。
图1 ZeroMQ内部数据架构图
ZeroMQ 提供四种通信协议,格式为ipc://,inproc://,tcp://,pgm://,分别对应进程间,进程内,机器间和广播。通信协议非常易于配置,通过类似于URL 的字符串指定,ZeroMQ 自动解释协议,地址,端口号和其他信息[1]。
ZeroMQ 将消息通信分成推拉模型、一对一结对模型、发布订阅模型、请求回应模型4 种模型。这四个模型基本满足了空管系统的网络通信模型,在实践中,您可以组合两个或更多模型进行使用。
1)一对一结对模型。消息一对一通信模型的最简单通信模型,可以被视为TCP 连接,但TCP 服务器只能接受一个连接。与请求回应模型不同,数据可以在两个方向上运行。
2)请求回应模型。请求端提出请求,等待回应端答复,请求与回应对应。对应请求端来说,它是一个发—收配对,对于回应端来说,它是一个收—发配对。相对于与一对一结对模型,其区别在于可以是N 个(N 大于等于1)的请求。这个模型主要用于任务分配和远程调用[2]。
3)发布订阅模式。发布者单向传播数据,不管数据是否被客户订阅到。如果发布者在开始输出时没有连接,发布者将立即丢弃信息。没有连接和信息的丢失问题可以通过在组合请求响应模型来解决。订阅者只负责接收,但不负责提供反馈。如果订阅速度快或与发布者相同,数据可以及时使用,如果处理速度慢,数据会堆积到订阅者身上。该模型主要用于数据分发[3]。
4)推拉模式。服务器用作推送端,客户使用作为拉取端,如果多个客户端同时连接到服务器,该服务将在内部执行负载平衡发布到客户端上。与发布订阅者模型相比,此模型不丢弃信息,如消费者能力不足,模型为消费者提供了并行处理选项[3]。该模型用于平行多任务处理场景。
ZeroMQ 具有以下特征:
1)异步,支持高并发,比TCP 更快,适用于大型集群和分布式计算;
2)提供异步I/O 模式,支持超过 30 种的编程语言,包括所有主流编程语言;
3)提供多种消息传递机制和内置丰富的组合模式可用于简化大型分步式计算架构;
4)良好的跨平台性,支持多种操作系统;
5)拥有iMatik 在商业层面的支持,它是完全免费的,且开发者社区活跃,发展迅速。
本文介绍的四种ZeroMQ 模型总结了空管系统网络通信的通用模型,在实践中,可根据空管系统应用需求组合两种或更多模型来构建解决方案。如代理模式,此模式主要用于按需扩展请求响应模式。如果需要扩展多响应服务器,可以使用代理模式。ROUTER 对应于一个请求,它等同于响应服务器,它执行先收后发,接收和发送循环。当它在内部从前端接收请求,然后发送DEALER 请求,该请求接收ROUTER 消息并将消息发送给响应者,但DEALER 面临N 个响应者。通过代理模式的转变,请求响应模式将自动扩展容量。如果将此机制集成到操作中,则代理模式是异步的。与异步的接线员类似,将N个请求与M 个响应连接起来。并确保它们是平衡的。
因此,可以说ZeroMQ 几乎可以满足现有的通信要求,无论是单机还是分布式。
以下通过模拟客户端和服务端的通信,说明采用ZeroMQ 进行系统间信息交换时的通信模型。
采用ZeroMQ 进行空管系统通信时,客户端或服务端的程序都设计为由主线程和IO 线程组成。主线程主要负责创建或销毁IO 线程通信的上下文和作为消息的生产者或消费者;IO 线程则负责利用ZeroMQ 进行通信。下面各自对客户端和服务端的主线程和IO 线程的工作流程进行说明。
采用ZeroMQ 通信时,客户端或服务器程序设计为由主线程和IO 线程组成。主线程主要负责创建或销毁IO 通信的上下文,既不是制造消息也不是消息的消费者,IO 线程负责与ZeroMQ 通信。下面是主线程和和IO 线程的工作流程。
2.5.1 客户端的主线程的工作流程
1)调用zmq_init 创建context 指针;
2)创建IO 线程对象;
3)创建mail box;
4)启动IO 线程;
5)调用zmq_socket 根据指定模式创建socket指针;
6)调用zmq_connect 根据指定通信方式连接服务端;
7)创建session_t 指针;
8)添加会话指针到IO 线程;
9)创建zmq_connector_t 指针;
10)连接到connector,由IO 现场与服务端建立连接;
11)调用zmq_send 将消息写入与会话相关联的通道;
12)调用zmq_close 关闭套接字;
13)调用zmq_term 销毁上下文。
2.5.2 客户端的IO 线程的工作流程
1)IO 线程调用start_connting 函数连接服务端;
2)在连接成功后,发送peer_identity;
3)通过会话读取管道中的消息;
4)通过engine 向服务器发送消息。
2.5.3 服务端主线程的工作流程
1)调用zmq_init 创建context 指针;
2)创建IO 线程对象;
3)创建mail box;
4)启动IO 线程;
5)调用zmq_socket 根据指定的模式创建socket 指针;
6)调用zmq_bind 根据指定的通信方式监听客户端的连接请求;
7)创建监听者指针;
8)Attach 到监听者;
9)调用zmq_recv 从session 关联管道读取消息;
10)通信结束时,调用zmq_close 关闭socket;
11)调用zmq_term 销毁context。
2.5.4 服务端IO 线程的工作流程
1)接受客户端连接请求,创建zmq_init_t 指针;
2)创建sesstion_t 指针;
3)通过engine 从客户端接收消息;
4)通过sesstion 将消息写入管道。
ZeroMQ 使用组合多模式在空管系统网络中完成通信任务和扩展任务,同时,它隐藏了复杂的网络编程细节,如协议桥接、重连、补发等等。除了为不同的操作系统提供完整的编程接口外,还可以减少移植问题。本文通过研究ZeroMQ 的运作原理、支持的工作模式,描述了使用ZeroMQ 作为空管系统信息交换的通信模型,为空管应用系统间信息交互提供基础研究成果。