之前讲述过多路复用实现单服百万级别RPS吞吐,但在文中有一点是没有说的就是消息IO合并,如果缺少了消息IO合并即使怎样多路复用也很难达到百万级别的请求响毕竟所有应用层面的网络IO读写都是非常损耗性能的(需要硬件配置很高的服务器)。这一章主要讲述的是IO合并的应用,并通过这个特性实现普通单服务千万级别的消息推送测试。
什么是消息IO合并
所谓的消息IO合并即是由原来一个消息对应一个网络读写设计成多个消息共享一个网络读写。那这样的设计到底会带来多大的性能提升,最简单的对比场就是每次执行1条SQL执行1万次和直接批执行1万条SQL的差别,相信做过的朋友一定非常清楚其性能提升的幅度。那在网络通讯中如何设计才能让多个消息进行IO合并呢?作者在实际实践中的方式有两种:1)通过定时器把队列中的所有消息定期合并发送,2)通过一个状态机归递消息队列,一旦队列存在消息一次过合并发送。定时器这种比较损耗性能,在连接量大的情况存在延时间相互影响;对于后者则比较好控制很多也不存在延时性,原理发送消息进队列后和网络发送完成再回到状态机检测消息队列状态即可。 
消息推送相对于请求响应来说相还是简单很多的,毕竟消息推送是单向并不需要有高效的响应机制。不过对于普通服务器间实现千万级的消息推送还是需要做些规划,毕竟是需要在有限的IO读写量的情况来达到这么大规模的消息处理。还有这么大量的消息序列化和反序列化也是一非常损耗性能的事情,所以这次实践并没有使用Protobuf,而是采用自定义序列化。测试的通讯组件选择Beetlex因为它具备了自动消息合并能力,并配合高效的多复路用机制在服务之间进行千万级别的消息推变得简单。
测试简述
这一次测试主要是向服务端推着一个简单的订单信息,由客户每次生成不同的订单信息推送给服务端,服务器接收订单消息后进行统计,并计算每秒接收的订单数量。
消息结构
public class Order { public long ID; public string Product; public int Quantity; public double Price; public double Total; }
创建订单
private static long mId; private static string[] mProducts = new string[] { "Apple", "Orange", "Banana", "Citrus", "Mango" }; private static int[] mQuantity = new int[] { 3, 10, 20, 23, 6, 9, 21 }; private static double[] mPrice = new double[] { 2.3, 1.6, 3.2, 4.6, 20, 4 }; public static

