dotnet core使用IO合并技巧轻松实现千万级消息推送
之前讲述过多路复用实现单服百万级别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[] { , , , , , , };
private static double[] mPrice = new double[] { 2.3, 1.6, 3.2, 4.6, , };
public static Order CreateOrder()
{
Order order = new Order();
order.ID = System.Threading.Interlocked.Increment(ref mId);
order.Product = mProducts[order.ID % mPrice.Length];
order.Quantity = mQuantity[order.ID % mQuantity.Length];
order.Price = mPrice[order.ID % mPrice.Length];
order.Total = order.Quantity * order.Price;
return order;
}
基于测试资源有限,这次的测试并没像之前跑PRS那样采用Protobuf,因为这量的对象处理量实在太大,测试的硬件环境不变所以采了自定义的序列化方式,具体可以参考源代码。
接收端代码
public override void SessionPacketDecodeCompleted(IServer server, PacketDecodeCompletedEventArgs e)
{
PushMessages.Order order = (PushMessages.Order)e.Message;
if (order.ID > MaxOrerID)
MaxOrerID = order.ID;
System.Threading.Interlocked.Increment(ref Count);
}
由于是接收推送的消息,服务端接收消息后统计相关数量即可完成,对于之前的RPS测试所需处理的东西就少很多了。
推送端压测代码
public void Run()
{
foreach (var item in mClients)
System.Threading.ThreadPool.QueueUserWorkItem(OnRun, item);
}
private void OnRun(object state)
{
AsyncTcpClient item = (AsyncTcpClient)state;
while (true)
{
Order order = OrderFactory.CreateOrder();
item.Send(order);
if (order.ID > MaxOrerID)
MaxOrerID = order.ID;
System.Threading.Interlocked.Increment(ref Count);
if (item.Count > )
System.Threading.Thread.Sleep();
}
}
为了防止压爆连接内部的消息队列,压测端当连接队列超过2000个消息的时候停止一下。由于采用了消息合并机制所以并不需要太多连接,在整个测试过程中开启了三个压测实例,每个实例使用5个连接,换句话说BeetleX通过15个连接,实现千万级消息的推送能力。
测试服务器资源
这次测试使用了两家云服务器,第一家名字就不说了,开启了V16核的虚拟服务器,内部带宽6G和100万pps,结果实际压测2G带宽就压不上去了,刚开始以为是linux系统要配置问题,换了windows系统试一下还是不行……,最终还是换回了阿里云测,在v12核的虚拟服务器上顺利完成了这一次测试。
服务端: v12核,24G内存,操作系统ubuntu16.04 一台,内网最大带宽4Gb.
压测端: v12核,24G内存,操作系统ubuntu16.04,内网最大带宽4Gb, 两台(主要测试方式有些暴力一台无法达到压测目标)
测试结果
二台压测机共开启了3个实例,每个实例5个连接,每个连接应用层处理的buffer 32k;整个测结果消息推送量达到了1000万个/秒。服务端记录接收IO每秒15000次,平均每次receive得到的消息大概在600个左右。以下是测试情况的截图:
服务程序统计情况

服务端CPU情况

网络使用情况


下功测试代码
dotnet core使用IO合并技巧轻松实现千万级消息推送的更多相关文章
- Socket.io+Notification实现浏览器消息推送
前言 socket.io: 包含对websocket的封装,可实现服务端和客户端之前的通信.详情见官网(虽然是英文文档,但还是通俗易懂).Notification: Html5新特性,用于浏览器的桌面 ...
- ZH奶酪:基于ionic.io平台的ionic消息推送功能实现
Hybrid App越来越火,Ionic的框架也逐渐被更多的人熟知. 在mobile app中,消息推送是很必要的一个功能. 国内很多ionic应用的推送都是用的极光推送,最近研究了一下Ionic自己 ...
- 基于socket.io的实时消息推送
用户访问Web站点的过程是基于HTTP协议的,而HTTP协议的工作模式是:请求-响应,客户端发出访问请求,服务器端以资源数据响应请求. 也就是说,服务器端始终是被动的,即使服务器端的资源数据发生变化, ...
- HMS Core地理围栏能力助你实现指定范围人群的精准消息推送
精准推送是移动端产品留存阶段的主要运营手段,精准推送常常会与用户画像紧密结合,针对用户的喜好.画像,采用不同策略,但基于用户所属区域推送消息却很难实现.目前市面上大多数第三方消息推送服务商,在系统未深 ...
- socket.io简单入门(一.实现简单的图表推送)
引子:随着nodejs蓬勃发展,虽然主要业务系统因为架构健壮性不会选择nodejs座位应用服务器.但是大量的内部系统却可以使用nodejs试水,大量的前端开发人员转入全堆开发也是一个因素. 研究本例主 ...
- node.js中使用socket.io + express进行实时消息推送
socket.io是一个websocket库,包含客户端的js和服务端的node.js,可以在不同浏览器和移动设备上构建实时应用. 一.安装 socket.io npm install socket. ...
- RabbitMQ消息队列(七)-通过fanout模式将消息推送到多个Queue中(.Net Core版)
前面第六章我们使用的是direct直连模式来进行消息投递和分发.本章将介绍如何使用fanout模式将消息推送到多个队列. 有时我们会遇到这样的情况,多个功能模块都希望得到完整的消息数据.例如一个log ...
- DingTalk钉钉消息推送(.net core 3 WebApi尝鲜记)
我发了个朋友圈,Swagger真他妈的牛B,解放了开发API的码农,麻麻再也不用担心我们写API文档耽误回家吃饭了. /// <summary> /// 发送钉钉消息 /// </s ...
- .NET Core 企业微信消息推送
接口定义 应用支持推送文本.图片.视频.文件.图文等类型.请求方式:POST(HTTPS)请求地址: https://qyapi.weixin.qq.com/cgi-bin/message/send? ...
随机推荐
- I - Infinite Improbability Drive
I - Infinite Improbability Drivehttp://codeforces.com/gym/241750/problem/I不断构造,先填n-1个0,然后能放1就放1,最后这个 ...
- 【转】Apache与Tomcat有什么关系和区别
[原文链接:https://www.cnblogs.com/zangdalei/p/8057325.html] Apache 和 Tomcat 都是web网络服务器,两者既有联系又有区别,在进行HTM ...
- [Tips]vim设置
临时设置 在vim中输入 :set nu! 若显示行号时,它的功能时取消行号:若不显示行号时,它的功能是显示行号. 固定设置 在~/.vimrc中进行设置. 添加注释: 双引号是注释 ” this i ...
- pip install
pip install <包名> 或 pip install -r requirements.txt 通过使用 == >= <= > < 来指定版本,不写则安装最新 ...
- [CF1138B]Circus
Description: 给你2个长度为n的01串 从中选出\(n/2\)个,使得选出的数中第一排1的个数等于未选出数中第二排1的个数 输出一种方案即可,没有输出-1 Hint: \(n \le 50 ...
- 使用anaconda创建tensorflow环境后如何在jupyter notebook中使用
在以下目录中 C:\Users\UserName\AppData\Roaming\jupyter\kernels\python3 打开kernel.json文件,将python.exe文件的路径修改至 ...
- 无法运行 vue-manage-system@3.1.0 dev: `webpack-dev-server --inline --progress --
一个项目的变大好多人开发,难免会有很多的冲突.每次跟新代码都要一个坑一个坑的解决的.这次遇到这个坑好大.急死了.... 百度了好多说占用端口,试了好几遍不行.最终还是要去查原因的....经过了几个小时 ...
- Linux进阶命令用法
1.tr命令 可以对来自标准输入的字符进行替换.压缩和删除.它可以将一组字符变成另一组字符 选项 -c或——complerment:取代所有不属于第一字符集的字符: -d或——delete:删除所有属 ...
- Spring源码Gradle
Microsoft Windows [版本 10.0.17134.590](c) 2018 Microsoft Corporation.保留所有权利. D:\Workspaces\idea\sprin ...
- sketch2code 有的叫screenshot to code什么的
先mark一下项目,回头再深究 https://github.com/mzbac/sketch2code https://www.floydhub.com/emilwallner/datasets/h ...