1、前言
surging內部使用的是高效能RPC遠端服務呼叫,如果用json.net序列化肯定效能上達不到最優,所以後面擴充套件了protobuf,messagepack序列化元件,以支援RPC二進位制傳輸.
在這裡需要感謝白紙無字Zonciu,新增了messagepack序列化,讓surging 效能上跨了一大步。此篇文章我們來談談messagepack、protobuffer、json.net ,並且效能做下對比
開源地址:https://github.com/dotnetcore/surging
2、序列化元件
2.1 surging 使用的是以下序列化元件:
json.net:surging 使用的是Newtonsoft.Json, 它是基於json格式的序列化和反序列化的元件.官方網站: http://json.codeplex.com/
protobuf:surging 使用的是protobuf-net, 它是基於二進位制格式的序列化和反序列化的元件.官方網站: https://github.com/mgravell/protobuf-net
messagepack:surging 使用的是MessagePack-CSharp, 它是基於二進位制格式的序列化和反序列化的元件.官方網站: https://github.com/neuecc/MessagePack-CSharp
2.2 各個元件的優點
json.net 有以下優點:
侵入性:可以不新增attribute,就能進行序列化操作
靈活性:可以靈活性配置,比如允許被序列化的成員自定義名字,遮蔽的非序列化屬性成員
可讀性: 資料格式比較簡單, 易於讀寫
依賴性:可以序列化成JObject,無需依賴物件進行序列化和泛型化。
protobuf 有以下優點:
效能高 序列化後體積相比Json和XML很小,適合RPC二進位制傳輸
跨語言:支援跨平臺多語言
相容性:訊息格式升級和相容性還不錯
速度快 :序列化反序列化速度很快,快於Json的處理速速
messagepack有以下優點:
效能高 序列化後體積相比Json和XML很小,適合RPC二進位制傳輸
跨語言:支援跨平臺多語言
相容性:訊息格式升級和相容性還不錯
速度快 :序列化反序列化速度很快,快於Json的處理速度
針對於protobuf和messagepack都是基於二進位制格式的序列化和反序列化,優點都一樣,但是基於messagepack的MessagePack-CSharp元件侵入性更小,可以不需要加attribute,而且效能上更優.下一節來看看元件在surging 中的表現
3. 效能比較
服務端:
(注:如果不加UseProtoBufferCodec和UseMessagePackCodec就是json.net序列化)
var host = new ServiceHostBuilder() .RegisterServices(option=> { option.Initialize(); //初始化服務 option.RegisterServices();//依賴注入領域服務 option.RegisterRepositories();//依賴注入倉儲 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的消費的服務適配 // 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”) //自動生成Token //.UseServer("127.0.0.1", 98,“123456789”) //固定密碼Token .UseStartup<Startup>() .Build(); using (host.Run()) { Console.WriteLine($"服務端啟動成功,{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(); }
測試 0 object(注:測試無引數)
/// <summary> /// 測試 /// </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("正在迴圈 1w次呼叫 GetUser....."); //1w次呼叫 var watch = Stopwatch.StartNew(); for (var i = 0; i < 10000; i++) { var a =userProxy.GetDictionary().Result; } watch.Stop(); Console.WriteLine($"1w次呼叫結束,執行時間:{watch.ElapsedMilliseconds}ms"); Console.ReadLine(); } while (true); }).Wait(); }
測試 1 object(注:測試引數傳物件)
/// <summary> /// 測試 /// </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("正在迴圈 1w次呼叫 GetUser....."); //1w次呼叫 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次呼叫結束,執行時間:{watch.ElapsedMilliseconds}ms"); Console.ReadLine(); } while (true); }).Wait(); }
測試 10 object(注:測試引數傳List 集合物件)
/// <summary> /// 測試 /// </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("正在迴圈 1w次呼叫 GetUser....."); //1w次呼叫 var watch = Stopwatch.StartNew(); for (var i = 0; i < 10000; i++) { var a =userProxy.Get(list).Result; } watch.Stop(); Console.WriteLine($"1w次呼叫結束,執行時間:{watch.ElapsedMilliseconds}ms"); Console.ReadLine(); } while (true); }).Wait(); }
測試100 object(注:測試引數傳List 集合物件)
/// <summary> /// 測試 /// </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<100;i++) { list.Add(new UserModel { UserId = 1, Age = 18, Name = "fanly" }); } do { Console.WriteLine("正在迴圈 1w次呼叫 GetUser....."); //1w次呼叫 var watch = Stopwatch.StartNew(); for (var i = 0; i < 10000; i++) { var a =userProxy.Get(list).Result; } watch.Stop(); Console.WriteLine($"1w次呼叫結束,執行時間:{watch.ElapsedMilliseconds}ms"); Console.ReadLine(); } while (true); }).Wait(); }
通過以上測試程式碼,我們得到了如下的測試結果
通過上圖,可以發現messagepack不管是小資料量還是大資料量都保持比較穩定的效能,而json.net 在100object平均已經達到了1.1ms,和messagepack、protobuffer比差太多,而 protobuffer在此次測試中表現的極其不穩定只有在1 object 和100 object 效能比較不錯,但是與messagepack比還是相差比較大。所以我建議還是使用messagepack,效能上更優,侵入性也非常低
我們來看看效能最優的messagepack 詳細測試資料
o object:
1 object:
10 object:
100 object
測試環境
CPU:Intel Core i7-4710MQ
記憶體:16G
硬碟:1T SSD+512G HDD
網路:區域網
6、總結
surging 已經完成JWT驗證和AppSecret驗證,下篇文章會詳細介紹surging 身份認證,如感興趣請多關注或者加入QQ群:542283494