dotnet core使用IO合并技巧轻松实现千万级消息推送

原文地址:https://www.cnblogs.com/smark/p/9869384.html
之前讲述过多路复用实现单服百万级别RPS吞吐,但在文中有一点是没有说的就是消息IO合并,如果缺少了消息IO合并即使怎样多路复用也很难达到百万级别的请求响毕竟所有应用层面的网络IO读写都是非常损耗性能的(需要硬件配置很高的服务器)。这一章主要讲述的是IO合并的应用,并通过这个特性实现普通单服务千万级别的消息推送测试。

什么是消息IO合并

所谓的消息IO合并即是由原来一个消息对应一个网络读写设计成多个消息共享一个网络读写。那这样的设计到底会带来多大的性能提升,最简单的对比场就是每次执行1条SQL执行1万次和直接批执行1万条SQL的差别,相信做过的朋友一定非常清楚其性能提升的幅度。那在网络通讯中如何设计才能让多个消息进行IO合并呢?作者在实际实践中的方式有两种:1)通过定时器把队列中的所有消息定期合并发送,2)通过一个状态机归递消息队列,一旦队列存在消息一次过合并发送。定时器这种比较损耗性能,在连接量大的情况存在延时间相互影响;对于后者则比较好控制很多也不存在延时性,原理发送消息进队列后和网络发送完成再回到状态机检测消息队列状态即可。
image

消息推送相对于请求响应来说相还是简单很多的,毕竟消息推送是单向并不需要有高效的响应机制。不过对于普通服务器间实现千万级的消息推送还是需要做些规划,毕竟是需要在有限的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 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 > 2000)
                    System.Threading.Thread.Sleep(1);
            }
        }

为了防止压爆连接内部的消息队列,压测端当连接队列超过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个左右。以下是测试情况的截图:

服务程序统计情况

image

服务端CPU情况

image

网络使用情况

image
image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,361评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,680评论 2 59
  • 今天姐姐说她的小狗雪花记性越来越不好了,经常在外面转几圈才想起回家,视力不济,听力也不好,还胡乱小便。。。好像患上...
    悠然的桥阅读 454评论 0 7
  • 今天是在五台山徒步的第二天 总有人质疑 每次出行都这么辛苦值得吗? 腼腆一笑:还好 是真的还好 因为 可以不断认识...
    Abel刘阅读 248评论 0 1