后端服务通常是多个进程各自提供部分功能联合起来作为整体对外提供服务,经常会有不同后端进程间互相通信的需求,有时还有进程间相互保活维持连接状态的需求。如果进程数比较少,相互建立网络连接也能简单解决,但如果服务扩展,进程数变多了,网络拓扑结构连接错综复杂,难以部署和动态扩容。

源代码在此

relay的设计目的

relay server解耦原来需要互相连接进行通信的进程,所有relay client进程只连接relay server,relay server路由转发relay client之间的通信消息。client本身可以带有基于每次连接会话的状态,旧的连接会话中的消息不能影响新的连接会话。relay client能及时获取到彼此的存活状态,断开连接会话重连尝试建立新会话。

设计方案

使用ZMQ作为底层网络连接和消息通信机制,简化实现,跨平台,高效。

  1. 客户端,服务端分别使用DELEAR socket type 和 ROUTER socket type;

  2. 上层使用心跳检测网络连接状态,超时则触发重连;

  3. 维护客户端两两之间的连接状态,每条连接是一个连接会话,用递增的会话id标识,消息带上会话id发送,过期的会话消息会被丢弃;

  4. 客户端使用独立线程收发网络消息,应用层异步收发消息,不阻塞主线程,使用起来更灵活;

使用ZMQ

  1. 使用CZMQ的actor提供客户端多线程异步处理消息支持;

  2. 最初是计划监测网络断开和连接来维护连接状态,但是ZMQ并没有暴露给上层这样的事件回调接口,唯一可用的 zmq_socket_monitor并不好用,比如事件的参数都是原始的fd,并不能很好的关联到对应的peer;

  3. 不使用默认的连接断开重连机制,因为relay的连接是有状态的,一次连接会话成功不仅在于网络连接建立成功,还需要发送注册协议,需要等待收到注册协议回包,并且relay server会广播给其他客户端;

  4. router socket type每次调用zmsg_recv收到的msg第一个frame是peer的identity数据,标识客户端身份。客户端则需要调用zmq_setsockopt设置自己的identity(如不设置,则会被分配唯一id),参考文档:id的第一个字节不能是0。同样发送msg时,第一个frame也得是目标客户端得id数据;

Reference

  1. The Guide

  2. ZMQ API

  3. CZMQ API