NewLife.Net——网络压测单机1.88亿tps
NewLife.Net压力测试,峰值4.2Gbps,50万pps,消息大小24字节,消息处理速度1.88亿tps!
共集合20台高配ECS参与测试,主服务器带宽6Gbps、100万pps,16核心64G内存。另外19台共模拟400个用户连接,13*16+6*32=400,每用户发送2000万个消息,服务端收到后原样返回。
有些同学比较着急,觉得前面两篇有点小儿科,群友就说,上数字吧!
我们在2017.4.1做了一个极限并发测试,奔着单机100万并发,实际上只得到了84.5万,这次补一个吞吐量的压力测试好了。
老规矩,先上代码:https://github.com/nnhy/NewLife.Net.Tests
一、测试结果
二、服务端修改
我们对前一篇文章的例程稍微调整一下:
class MyNetSession : NetSession<MyNetServer>
{
/// <summary>客户端连接</summary>
public override void Start()
{
base.Start();
// 欢迎语
var str = String.Format("Welcome to visit {1}! [{0}]rn", Remote, Environment.MachineName);
Send(str);
}
/// <summary>收到客户端数据</summary>
/// <param name="e"></param>
protected override void OnReceive(ReceivedEventArgs e)
{
//WriteLog("收到:{0}", e.Packet.ToStr());
// 把收到的数据发回去
Send(e.Packet);
}
}
把显示收到数据的那一行给注册了,否则这一行就能玩死千万级测试,更别说亿万级了。
服务主函数的线程数也要从2改为1,关闭第二个向所有客户端定时群发时间的任务。
public MyService()
{
ServiceName = "EchoAgent";
DisplayName = "回声服务";
Description = "这是NewLife.Net的一个回声服务示例!";
// 准备两个工作线程,分别负责输出日志和向客户端发送时间
//ThreadCount = 2;
ThreadCount = 1;
Intervals = new[] { 1, 5 };
}
三、增加客户端压测项目
新建控制台项目Benchmark,并从nuget引用NewLife.Core
入口函数需要分析参数:
static void Main(String[] args)
{
XTrace.UseConsole();
try
{
var cfg = new Config();
// 分解参数
if (args != null && args.Length > 0) cfg.Parse(args);
// 显示帮助菜单或执行
if (cfg.Address.IsNullOrEmpty())
ShowHelp();
else
Work(cfg);
}
catch (Exception ex)
{
XTrace.WriteException(ex.GetTrue());
}
//Console.WriteLine("OK!");
//Console.ReadKey();
}
主函数就是开一定数量的LongTask,然后等待
static void Work(Config cfg)
{
var uri = new NetUri(cfg.Address);
if (cfg.Content.IsNullOrEmpty()) cfg.Content = "学无先后达者为师";
var pk = new Packet(cfg.Content.GetBytes());
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("NewLife.NC v{0}", AssemblyX.Entry.Version);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("目标:{0}", uri);
Console.WriteLine("请求:{0:n0}", cfg.Times);
Console.WriteLine("并发:{0:n0}", cfg.Thread);
Console.WriteLine("并发:[{0:n0}] {1}", pk.Count, cfg.Content);
Console.ResetColor();
Console.WriteLine();
var sw = Stopwatch.StartNew();
// 多线程
var ts = new List<Task>();
var total = 0;
for (var i = 0; i < cfg.Thread; i++)
{
var tsk = Task.Factory.StartNew(() =>
{
try
{
var client = uri.CreateRemote();
client.Open();
for (var k = 0; k < cfg.Times; k++)
{
client.Send(pk);
Interlocked.Increment(ref total);
}
}
catch { }
}, TaskCreationOptions.LongRunning);
ts.Add(tsk);
}
Task.WaitAll(ts.ToArray());
sw.Stop();
Console.WriteLine("完成:{0:n0}", total);
var ms = sw.Elapsed.TotalMilliseconds;
Console.WriteLine("速度:{0:n0}tps", total * 1000L / ms);
}
四、上线测试
从阿里云分批租用最高配置的竞价实例20台。统一选择华东2(上海)的D区,因为代码压测只能使用内网,公网达不到这个速度。
整个华东2D最高配就是大数据网络增强型,仅剩的7台都拿下,其中一台作为服务端跑EchoAgent,另外再补13台8核的机器,共19台跑nc(Benchmark)。
在8核心机器上(13台),测试命令:
nc -n 20000000 -c 16 tcp://172.19.227.198:1234
在16核心机器上(6台),测试命令
nc -n 20000000 -c 32 tcp://172.19.227.198:1234
五、结论
人有多大胆,地有多大产!
虽然这次的EchoTest只是简单把数据包发回来,没有挂载复杂业务,但是说明了网络库不是瓶颈,只要硬件性能跟得上,它要多强有多强!
e.Packet的设计,实际上实现了ZeroCopy,同时大大减轻了GC附带,后面会有专门文章提到。
网络库NewLife.Net支持.Net Core 2.0,但XAgent不支持,毕竟它是Windows服务。
这次测试在 .Net Framework v4.6.1 上进行。
网络系列文章,是为了一步步介绍X组件网络库 NewLife.Net的设计理念,从2005年开始,活了13年,不管是成功还是失败,都积累了很多的经验。
我是大石头,打1999年起,19年老码农。目前在物流行业从事数据分析架构工作,日常工作都是亿万数据的读写使用。欢迎大家一起C#大数据!
- 如何使用Sentry管理Hive外部表(补充)
- WebLogic XMLDecoder反序列化漏洞(CVE-2017-10271)漏洞复现&修复方案
- 如何在CDSW中使用R绘制直方图
- CTF学习交流群 第一期入群题writeup大放送
- 如何使用Hue创建Spark1和Spark2的Oozie工作流
- 【译】深入研究 Laravel 的依赖注入容器
- 一次XSS突破的探险
- 如何使用Hue创建Spark2的Oozie工作流(补充)
- 如何基于CDSW基础镜像定制Docker
- OVSDB介绍及在OpenDaylight中的调用
- 如何在CDH集群的非元数据库节点安装MySQL5.7.12
- PySpark数据类型转换异常分析
- SQLI-LABS 更新帖(二)
- 如何重置Hue用户密码
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Spark中的聚类算法
- 【Linux_Shell 脚本编程学习笔记六、shell的数值运算】
- Java自动化测试(adb常用命令 32)
- 前端学习计算机理论知识的好处
- 【Vue 学习笔记 一、Vue开发环境搭建】
- Vue 图片上传组件(base64 版):vue-upload-imgs
- 三、运行时的动态常量(学习笔记)
- Vue Cli 3 打包配置--自动忽略 console.log 语句
- git 常用命令介绍
- PAT (Basic Level) Practice (中文)1043 输出PATest (20 分)
- PAT (Basic Level) Practice (中文)1047 编程团体赛 (20 分)
- Vue中computed分析
- 半小时搞懂 HTTP、HTTPS和HTTP2
- RestPack Java实现Html转PDF文件
- 六、垃圾回收_判断对象是否存活算法_引用计数法详解