1,、前言surging內(nèi)部使用的是高性能RPC遠(yuǎn)程服務(wù)調(diào)用,,如果用json.net序列化肯定性能上達(dá)不到最優(yōu),,所以后面擴(kuò)展了protobuf,messagepack序列化組件,以支持RPC二進(jìn)制傳輸. 在這里需要感謝白紙無字Zonciu,,新增了messagepack序列化,,讓surging 性能上跨了一大步,。此篇文章我們來談?wù)刴essagepack、protobuffer,、json.net ,,并且性能做下對(duì)比 開源地址:https://github.com/dotnetcore/surging 2、序列化組件 2.1 surging 使用的是以下序列化組件: json.net:surging 使用的是Newtonsoft.Json,, 它是基于json格式的序列化和反序列化的組件.官方網(wǎng)站: http://json./ protobuf:surging 使用的是protobuf-net,, 它是基于二進(jìn)制格式的序列化和反序列化的組件.官方網(wǎng)站: https://github.com/mgravell/protobuf-net messagepack:surging 使用的是MessagePack-CSharp, 它是基于二進(jìn)制格式的序列化和反序列化的組件.官方網(wǎng)站: https://github.com/neuecc/MessagePack-CSharp 2.2 各個(gè)組件的優(yōu)點(diǎn) json.net 有以下優(yōu)點(diǎn): 侵入性:可以不添加attribute,就能進(jìn)行序列化操作 靈活性:可以靈活性配置,,比如允許被序列化的成員自定義名字,,屏蔽的非序列化屬性成員 可讀性: 數(shù)據(jù)格式比較簡(jiǎn)單, 易于讀寫 依賴性:可以序列化成JObject,無需依賴對(duì)象進(jìn)行序列化和泛型化,。 protobuf 有以下優(yōu)點(diǎn): 性能高 序列化后體積相比Json和XML很小,,適合RPC二進(jìn)制傳輸 跨語言:支持跨平臺(tái)多語言 兼容性:消息格式升級(jí)和兼容性還不錯(cuò) 速度快 :序列化反序列化速度很快,快于Json的處理速速 messagepack有以下優(yōu)點(diǎn): 性能高 序列化后體積相比Json和XML很小,,適合RPC二進(jìn)制傳輸 跨語言:支持跨平臺(tái)多語言 兼容性:消息格式升級(jí)和兼容性還不錯(cuò) 速度快 :序列化反序列化速度很快,,快于Json的處理速度 針對(duì)于protobuf和messagepack都是基于二進(jìn)制格式的序列化和反序列化,優(yōu)點(diǎn)都一樣,,但是基于messagepack的MessagePack-CSharp組件侵入性更小,,可以不需要加attribute,而且性能上更優(yōu).下一節(jié)來看看組件在surging 中的表現(xiàn) 3. 性能比較服務(wù)端: (注:如果不加UseProtoBufferCodec和UseMessagePackCodec就是json.net序列化) var host = new ServiceHostBuilder() .RegisterServices(option=> { option.Initialize(); //初始化服務(wù) option.RegisterServices();//依賴注入領(lǐng)域服務(wù) option.RegisterRepositories();//依賴注入倉(cāng)儲(chǔ) option.RegisterModules();//依賴注入第三方模塊 option.RegisterServiceBus();//依賴注入ServiceBus }) .RegisterServices(builder => { builder.AddMicroService(option => { option.AddServiceRuntime();// // option.UseZooKeeperManager(new ConfigInfo('127.0.0.1:2181')); //使用Zookeeper管理 option.UseConsulManager(new ConfigInfo('127.0.0.1:8500'));//使用Consul管理 option.UseDotNettyTransport();//使用Netty傳輸 option.UseRabbitMQTransport();//使用rabbitmq 傳輸 option.AddRabbitMQAdapt();//基于rabbitmq的消費(fèi)的服務(wù)適配 // option.UseProtoBufferCodec();//基于protobuf序列化傳輸 option.UseMessagePackCodec();//基于MessagePack序列化傳輸 builder.Register(p => new CPlatformContainer(ServiceLocator.Current));//初始化注入容器 }); }) .SubscribeAt() //消息訂閱 .UseServer('127.0.0.1', 98) //.UseServer('127.0.0.1', 98,“true”) //自動(dòng)生成Token //.UseServer('127.0.0.1', 98,,“123456789”) //固定密碼Token .UseStartup<Startup>() .Build(); using (host.Run()) { Console.WriteLine($'服務(wù)端啟動(dòng)成功,,{DateTime.Now}。'); }
客戶端: var host = new ServiceHostBuilder() .RegisterServices(option => { option.Initialize(); option.RegisterServices(); option.RegisterRepositories(); option.RegisterModules(); }) .RegisterServices(builder => { builder.AddMicroService(option => { option.AddClient(); option.AddClientIntercepted(typeof(CacheProviderInterceptor)); //option.UseZooKeeperManager(new ConfigInfo('127.0.0.1:2181')); option.UseConsulManager(new ConfigInfo('127.0.0.1:8500')); option.UseDotNettyTransport(); option.UseRabbitMQTransport(); option.UseProtoBufferCodec(); //option.UseMessagePackCodec(); builder.Register(p => new CPlatformContainer(ServiceLocator.Current)); }); }) .UseClient() .UseStartup<Startup>() .Build(); using (host.Run()) { Startup.Test(ServiceLocator.GetService<IServiceProxyFactory>()); Startup.TestRabbitMq(); }
測(cè)試 0 object(注:測(cè)試無參數(shù)) /// <summary> /// 測(cè)試 /// </summary> /// <param name='serviceProxyFactory'></param> public static void Test(IServiceProxyFactory serviceProxyFactory) { Task.Run(async () => { var userProxy = serviceProxyFactory.CreateProxy<IUserService>('User'); await userProxy.GetUserId('user'); do { Console.WriteLine('正在循環(huán) 1w次調(diào)用 GetUser.....'); //1w次調(diào)用 var watch = Stopwatch.StartNew(); for (var i = 0; i < 10000; i ) { var a =userProxy.GetDictionary().Result; } watch.Stop(); Console.WriteLine($'1w次調(diào)用結(jié)束,,執(zhí)行時(shí)間:{watch.ElapsedMilliseconds}ms'); Console.ReadLine(); } while (true); }).Wait(); }
測(cè)試 1 object(注:測(cè)試參數(shù)傳對(duì)象) /// <summary> /// 測(cè)試 /// </summary> /// <param name='serviceProxyFactory'></param> public static void Test(IServiceProxyFactory serviceProxyFactory) { Task.Run(async () => { var userProxy = serviceProxyFactory.CreateProxy<IUserService>('User'); await userProxy.GetUserId('user'); do { Console.WriteLine('正在循環(huán) 1w次調(diào)用 GetUser.....'); //1w次調(diào)用 var watch = Stopwatch.StartNew(); for (var i = 0; i < 10000; i ) { var a =userProxy.GetUser(new UserModel { UserId = 1 }).Result; } watch.Stop(); Console.WriteLine($'1w次調(diào)用結(jié)束,,執(zhí)行時(shí)間:{watch.ElapsedMilliseconds}ms'); Console.ReadLine(); } while (true); }).Wait(); }
測(cè)試 10 object(注:測(cè)試參數(shù)傳List 集合對(duì)象) /// <summary> /// 測(cè)試 /// </summary> /// <param name='serviceProxyFactory'></param> public static void Test(IServiceProxyFactory serviceProxyFactory) { Task.Run(async () => { var userProxy = serviceProxyFactory.CreateProxy<IUserService>('User'); await userProxy.GetUserId('user'); var list = new List<UserModel>(); for(int i=0;i<10;i ) { list.Add(new UserModel { UserId = 1, Age = 18, Name = 'fanly' }); } do { Console.WriteLine('正在循環(huán) 1w次調(diào)用 GetUser.....'); //1w次調(diào)用 var watch = Stopwatch.StartNew(); for (var i = 0; i < 10000; i ) { var a =userProxy.Get(list).Result; } watch.Stop(); Console.WriteLine($'1w次調(diào)用結(jié)束,執(zhí)行時(shí)間:{watch.ElapsedMilliseconds}ms'); Console.ReadLine(); } while (true); }).Wait(); }
測(cè)試100 object(注:測(cè)試參數(shù)傳List 集合對(duì)象) /// <summary> /// 測(cè)試 /// </summary> /// <param name='serviceProxyFactory'></param> public static void Test(IServiceProxyFactory serviceProxyFactory) { Task.Run(async () => { var userProxy = serviceProxyFactory.CreateProxy<IUserService>('User'); await userProxy.GetUserId('user'); var list = new List<UserModel>(); ;i<;i ) { list.Add(, Age = , Name = 'fanly' }); } do { Console.WriteLine('正在循環(huán) 1w次調(diào)用 GetUser.....'); //1w次調(diào)用 var watch = Stopwatch.StartNew(); ; i < ; i ) { var a =userProxy.Get(list).Result; } watch.Stop(); Console.WriteLine($'1w次調(diào)用結(jié)束,,執(zhí)行時(shí)間:{watch.ElapsedMilliseconds}ms'); Console.ReadLine(); } while (true); }).Wait(); }
通過以上測(cè)試代碼,,我們得到了如下的測(cè)試結(jié)果 通過上圖,可以發(fā)現(xiàn)messagepack不管是小數(shù)據(jù)量還是大數(shù)據(jù)量都保持比較穩(wěn)定的性能,,而json.net 在100object平均已經(jīng)達(dá)到了1.1ms,,和messagepack,、protobuffer比差太多,,而 protobuffer在此次測(cè)試中表現(xiàn)的極其不穩(wěn)定只有在1 object 和100 object 性能比較不錯(cuò),但是與messagepack比還是相差比較大,。所以我建議還是使用messagepack,,性能上更優(yōu),侵入性也非常低 我們來看看性能最優(yōu)的messagepack 詳細(xì)測(cè)試數(shù)據(jù) o object: 1 object: 10 object: 100 object 測(cè)試環(huán)境 CPU:Intel Core i7-4710MQ 內(nèi)存:16G 硬盤:1T SSD 512G HDD 網(wǎng)絡(luò):局域網(wǎng)
|