Based on the. net core microservice framework and the. netcore framework
1Preface
Surging uses high-performance RPC remote service calling. If json.net is used for serialization, the performance will not reach the optimal level. Therefore, protobuf and messagepack serialization components are extended to support RPC binary transmission.
Thanks to the White Paper and wordless Zonciu, messagepack serialization is added, which makes the surging performance a huge step. In this article, we will talk about messagepack, protobuffer, and json.net, and compare their performance.
Open Source Address: https://github.com/dotnetcore/surging
2
Serialization component
2.1 The following serialization components are used for surging:
Json.net: surging uses Newtonsoft. Json, which is a json-format-based serialization and deserialization component. Official Website: http://json.codeplex.com/
Protobuf: surging uses protobuf-net, which is a component of serialization and deserialization based on binary formats. Official Website: https://github.com/mgravell/protobuf-net
Messagepack: surging uses MessagePack-CSharp, a component based on binary format serialization and deserialization. Official Site: https://github.com/neuecc/MessagePack-CSharp
2.2 advantages of each component
Json.net has the following advantages:
Invasive: serialization can be performed without adding attribute.
Flexibility: flexible configuration, such as allowing serialized members to customize names and blocked non-serialized attribute members
Readability: the data format is simple and easy to read/write.
Dependency: It can be serialized into JObject without the need to serialize and generics the dependent objects.
Protobuf has the following advantages:
High-performance post-serialization is smaller than Json and XML, and is suitable for RPC binary transmission.
Cross-language: supports cross-platform and multi-language
Compatibility: Message format upgrade and compatibility are good
Fast: serialization and deserialization are fast and faster than Json processing.
Messagepack has the following advantages:
High-performance post-serialization is smaller than Json and XML, and is suitable for RPC binary transmission.
Cross-language: supports cross-platform and multi-language
Compatibility: Message format upgrade and compatibility are good
Fast: serialization and deserialization are fast and faster than Json processing.
Protobuf and messagepack are both based on binary format serialization and deserialization, with the same advantages. However, messagepack-CSharp components based on MessagePack are less invasive, and attribute is not required, and the performance is better. next, let's take a look at the performance of Components in surging.
3. Performance Comparison
Server:
(Note: If UseProtoBufferCodec and UseMessagePackCodec are not added, json.net will be serialized)
Var host = new ServiceHostBuilder (). registerServices (option => {option. initialize (); // Initialize the service option. registerServices (); // dependency injection domain service option. registerRepositories (); // dependency injection warehousing option. registerModules (); // dependency injection third-party module option. registerServiceBus (); // dependency injection ServiceBus }). registerServices (builder => {builder. addMicroService (option => {option. addServiceRuntime (); // option. useZooKeeperManager (new ConfigInfo ("127". 0.0.1: 2181 "); // use Zookeeper to manage the option. useConsulManager (new ConfigInfo ("127.0.0.1: 8500"); // use Consul to manage option. useDotNettyTransport (); // use Netty to transmit option. useRabbitMQTransport (); // use rabbitmq to transmit option. addRabbitMQAdapt (); // service adaptation based on rabbitmq consumption // option. useProtoBufferCodec (); // serialized transmission option based on protobuf. useMessagePackCodec (); // serialized transmission builder Based on MessagePack. register (p => new CPlatformContainer (ServiceLocator. cu Rrent); // initialize the injection container });}). subscribeAt () // message subscription. useServer ("127.0.0.1", 98 )//. useServer ("127.0.0.1", 98, "true") // automatically generate Token //. useServer ("127.0.0.1", 98, "123456789") // fixed password Token. useStartup <Startup> (). build (); using (host. run () {Console. writeLine ($ "server started successfully, {DateTime. now }. ");}
Client:
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(); }
Test 0 object (Note: The test has no parameters)
/// <Summary> /// Test //</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 ("calling GetUser for 1 million times ..... "); // call var watch = Stopwatch. startNew (); for (var I = 0; I <10000; I ++) {var a = userProxy. getDictionary (). result;} watch. stop (); Console. writeLine ($ "Call ended, execution time: {watch. elapsedMilliseconds} ms "); Console. readLine () ;}while (true );}). wait ();}
Test 1 object (Note: passing objects to test parameters)
/// <Summary> /// Test //</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 ("calling GetUser for 1 million times ..... "); // call var watch = Stopwatch. startNew (); for (var I = 0; I <10000; I ++) {var a = userProxy. getUser (new UserModel {UserId = 1 }). result;} watch. stop (); Console. writeLine ($ "Call ended, execution time: {watch. elapsedMilliseconds} ms "); Console. readLine () ;}while (true );}). wait ();}
Test 10 objects (Note: objects in the List set for passing test parameters)
/// <Summary> /// Test //</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 ("calling GetUser for 1 million times ..... "); // call var watch = Stopwatch. startNew (); for (var I = 0; I <10000; I ++) {var a = userProxy. get (list ). result;} watch. stop (); Console. writeLine ($ "Call ended, execution time: {watch. elapsedMilliseconds} ms "); Console. readLine () ;}while (true );}). wait ();}
Test object 100(Note: Upload List set objects to test parameters)
/// <Summary> /// Test //</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 ("calling GetUser for 1 million times ..... "); // call var watch = Stopwatch. startNew (); for (var I = 0; I <10000; I ++) {var a = userProxy. get (list ). result;} watch. stop (); Console. writeLine ($ "Call ended, execution time: {watch. elapsedMilliseconds} ms "); Console. readLine () ;}while (true );}). wait ();}
Through the above test code, we get the following test results:
It can be found that messagepack maintains stable performance in both small data volumes and large data volumes, while json.net has reached an average of 1.1 ms in objects, which is much worse than messagepack and protobuffer, protobuffer is extremely unstable in this test. Only 1 object and 100 object have good performance, but it is still quite different from messagepack. Therefore, I suggest using messagepack, which provides better performance and low intrusion.
Let's take a look at the detailed test data of messagepack with the best performance.
O object:
1 object:
10 object:
100 object
Test Environment
CPU: Intel Core i7-4710MQ
Memory: 16 GB
Hard Disk: 1 tb ssd + 512 GB HDD
Network: Lan
6. Summary
Surging has completed JWT verification and AppSecret verification. The next article will detail surging identity authentication. If you are interested, please pay attention to it or join the QQ group: 615562965