.NET Core通过多路复用实现单服务百万级别RPS吞吐

2018-10-2718:58:04后端程序开发Comments2,976 views字数 2928阅读模式

多路复用其实并不是什么新技术,它的作用是在一个通讯连接的基础上可以同时进行多个请求响应处理。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

对于网络通讯来其实不存在这一说法,因为网络层面只负责数据传输;由于上层应用协议的制订问题,导致了很多传统服务并不能支持多路复用;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

如:http1.1,sqlserver和redis等等,虽然有些服务提供批量处理,但这些处理都基于一个RPS下。下面通过图解来了解释单路和多路复用的区别。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

.NET Core通过多路复用实现单服务百万级别RPS吞吐文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

单路存在的问题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

每个请求响应独占一个连接,并独占连接网络读写;这样导致连接在有大量时间被闲置无法更好地利用网络资源。由于是独占读写IO,这样导致RPS处理量由必须由IO承担,IO操作起来比较损耗性能,这样在高RPS处理就出现性能问题。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

由于不能有效的合并IO也会导致在通讯中的带宽存在浪费情况,特别对于比较小的请求数据包。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

通讯上的延时当要持大量的RPS那就必须要有更多连接支撑,连接数增加也对资源的开销有所增加。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

多路复用的优点文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

多路复用可以在一个连接上同时处理多个请求响应,这样可以大大的减少连接的数量,并提高了网络的处理能力。由于是共享连接不同请求响应数据包可以合并到一个IO上处理,这样可以大大降低IO的处理量,让性能表现得更出色。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

通过多路复用实现百万级RPS文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

多路复用是不是真的如此出色呢,以下在.net core上使用多路复用实现单服务百万RPS吞吐,并能达到比较低的延时性。以下是测试流程:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

.NET Core通过多路复用实现单服务百万级别RPS吞吐文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

测试消息结构文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

本测试使用了Protobuf作为基础交互消息,毕竟Protobuf已经是一个二进制序列化标准了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

请求消息文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(1)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public int ID {  get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(2)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public Double RequestTime { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

响应消息文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

 [ProtoMember(1)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public int EmployeeID { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(2)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public string LastName { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(3)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public string FirstName { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(4)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public string Address { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(5)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public string City { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(6)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public string Region { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(7)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public string Country { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

[ProtoMember(8)]文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public Double RequestTime { get; set; }文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

** 服务端处理代码**文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public static void Response(Tuple<IServer, ISession, SearchEmployee> value)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

Employee emp = Employee.GetEmployee();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

emp.RequestTime = value.Item3.RequestTime;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

value.Item1.Send(emp, value.Item2);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

System.Threading.Interlocked.Increment(ref Count);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

public override void SessionPacketDecodeCompleted(IServer server, PacketDecodeCompletedEventArgs e)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

SearchEmployee emp = (SearchEmployee)e.Message;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

multiThreadDispatcher.Enqueue(new Tuple<IServer, ISession, SearchEmployee>(server, e.Session, emp));文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

服务响应对象内容文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

Employee result = new Employee();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

result.EmployeeID = 1;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

result.LastName = "Davolio";文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

result.FirstName = "Nancy";文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

result.Address = "ja";文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

result.City = "Seattle";文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

result.Region = "WA";文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

result.Country = "USA";文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

接收消息后放入队列,然后由队列处理响应,设置请求相应请求时间并记录总处理消息计数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

客户端请求代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

private static void Response(Tuple<AsyncTcpClient, Employee> data)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

System.Threading.Interlocked.Increment(ref mCount);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

if (mCount > 100)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

if (data.Item2.RequestTime > 0)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

double tick = mWatch.Elapsed.TotalMilliseconds - data.Item2.RequestTime;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

AddToLevel(tick);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

var s = new SearchEmployee();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

s.RequestTime = mWatch.Elapsed.TotalMilliseconds;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

data.Item1.Send(s);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

客户端测试发起代码文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

 for (int i = 0; i < mConnections; i++)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

var client = SocketFactory.CreateClient<BeetleX.Clients.AsyncTcpClient, TestMessages.ProtobufClientPacket>(mIPAddress, 9090);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

client.ReceivePacket = (o, e) =>文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

Employee emp = (Employee)e;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

multiThreadDispatcher.Enqueue(new Tuple<AsyncTcpClient, Employee>((AsyncTcpClient)o, emp));文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

};文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

client.ClientError = (o, e) =>文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

Console.WriteLine(e.Message);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

};文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

mClients.Add(client);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

for (int i = 0; i < 200; i++)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

foreach (var item in mClients)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

{文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

SearchEmployee search = new SearchEmployee();文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

Task.Run(() => { item.Send(search); });文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

}文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

整个测试开启了10个连接,在这10个连接的基础上进行请求响应复用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

测试配置文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

测试环境是两台服务器,配置是阿里云上的12核服务器(对应的物理机应该是6核12线程)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

服务和客户端的系统都是:Ubuntu 16.04文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

Dotnet core版本是:2.14文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

测试结果文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

客户端统计结果文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

.NET Core通过多路复用实现单服务百万级别RPS吞吐文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

服务端统计信息文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

.NET Core通过多路复用实现单服务百万级别RPS吞吐文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

带宽统计文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

.NET Core通过多路复用实现单服务百万级别RPS吞吐文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

测试使用了10个连接进行多路复用,每秒接收响应量在100W,大部分响应延时在1-3毫秒之间文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

测试代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

https://github.com/IKende/BeetleX/blob/master/samples/MultiplexingConnectionTest.zip文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/7337.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/bc/7337.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定