定义高性能,这里指的是高流量、低延时。在服务器端,大量的消息蜂拥而至,每个消息都需要“马上”应答,需要服务器能够提供足够的处理能力。
其实也考虑过其他的方案,broker化的如ActiveMQ以及自己写Socket。ActiveMQ的确方便,但是消息一大Latency马上就飙升,功能太多也感觉累赘。不过有朋友要做性能不是太敏感的服务我还是会推荐这个,开发快学习周期短。自己写Socket写出来简单,写好太难,没办法保证高流量的可靠性和稳定性(也许有同学可以,我水平还差了点)。
ZMQ相对而言不能说它是最快的,但目前来说它是大流量下延时变长相对不明显的,基本能保证大流量下速度的稳定性。
简单介绍一下,ZMQ(www.zeromq.org)是一个开源的网络中间件,个人感觉用来代替原生的Socket非常好用。ZMQ的主要元素包括Context、Socket(zmq socket)、Message(zmq message)。Z是Zero、零拷贝的意思。ZMQ封装了底层的连接/重连/封包等。ZMQ支持inter-thread/ipc/tcp传输等。
由于零拷贝,ZMQ的表现相当不错。在Linux下每个消息大小为几个kb时,每个ipc点对点的消息传输延时大约40us,机器对机器的tcp消息传输延时大约200us。ZMQ自带测试用的代码,有兴趣的同学可以详细测试一下。
与Poll和timerfd结合起来,可以构建无等待的消息处理循环。这里的无等待是指没有额外的等待,消息的传入还是需要poll的。
1 int main()
2 {
3 int tfd, rc ;
5 tfd = timerfd_init();
6
7 context_t *cxt = new context_t(1);
8 socket_t *socket = new socket_t(*cxt,ZMQ_SUB);
9 socket->connect("tcp://127.0.0.1:5000");
10 socket->setsockopt(ZMQ_IDENTITY, "Hello", 5);
11 socket->setsockopt(ZMQ_SUBSCRIBE, "", 0);
12
13 pollitem_t *items = new pollitem_t[2];
14
15 items[0] = pollitem_t{NULL, tfd, ZMQ_POLLIN, 0};
16 items[1] = pollitem_t{*socket, 0, ZMQ_POLLIN, 0};
17
18 while(1)
19 {
20 rc = zmq::poll (items, 2, _interval);
22 if (items [0].revents & ZMQ_POLLIN)
23 {
24 readtimerfd(tfd);
27 }
28 if(items[1].revents & ZMQ_POLLIN)
29 {
30 message_t msg(0);
31 socket->recv(&msg,0);
32 … …
33 }
34 }
35 }
36
使用这样的处理过程构造的典型的双机热备服务器应用,基本能达到流量20~30万/s、典型延时700~800us的程度。当然,这个数字是空转的数字,加上应用的话流量应该有所降低。