NewLife.Net壓力測試,峰值4.2Gbps,50萬pps,消息大小24字節,消息處理速度2266萬tps!
共集合20台高配ECS參與測試,主服務器帶寬6Gbps、100萬pps,16核心64G內存。另外19台共模擬400個用戶連接,13*16+6*32=400,每用戶發送2000萬個消息,服務端收到后原樣返回。
tps意義非常重大,就是告訴所有人,.Net下普普通通的Socket封裝,甚至沒有使用MSDN的Pool,就能得到非常不錯的性能!
*感謝樓下提醒,錯誤計算了速度,算法如下:
每秒流量 = 4.2G / 8 = 537.6M (進出都是4.2Gbps)
包頭消耗 = 50萬 * 40 = 19M (50萬包,ip+tcp頭40字節)
處理速度 = (537.6M - 19M) / 24 = 22,657,979 = 2266萬
另外每個nc客戶端均有速度計算,102萬~200萬tps之間,共19客戶端,與上吻合
由於我的疏忽,只是簡單拿4.2G除以24得到1.88億,也沒有匯總各客戶端數據,給出了錯誤數據,非常抱歉!
(有考慮tcp包頭,因報文很短必然粘包,按MTU=1500算誤差2.7%,所以直接沒有算進去)
有些同學比較着急,覺得前面兩篇有點小兒科,群友就說,上數字吧!
我們在2017.4.1做了一個極限並發測試,奔着單機100萬並發,實際上只得到了84.5萬,這次補一個吞吐量的壓力測試好了。
老規矩,先上代碼:https://github.com/NewLifeX/NewLife.Net
一、測試結果
二、服務端修改
我們對前一篇文章的例程稍微調整一下:
class MyNetSession : NetSession<MyNetServer> { /// <summary>客戶端連接</summary> public override void Start() { base.Start(); // 歡迎語 var str = String.Format("Welcome to visit {1}! [{0}]\r\n", 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#大數據!