基于.NET CORE框架Surging

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有以下优点:

  • 性能高 序列化后体积相比JsonXML很小,适合RPC二进制传输
  • 跨语言:支持跨平台多语言
  • 兼容性:消息格式升级和兼容性还不错
  • 速度快 :序列化反序列化速度很快,快于Json的处理速度

针对于protobufmessagepack都是基于二进制格式的序列化和反序列化,优点都一样,但是基于messagepackMessagePack-CSharp组件侵入性更小,可以不需要加attribute,而且性能上更优.下一节来看看组件在surging 中的表现

3. 性能比较

服务端:

(注:如果不加UseProtoBufferCodecUseMessagePackCodec就是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}。');
        }

客户端:

  /// <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();

        }

测试 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(, Age = , 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.net100object平均已经达到了1.1ms,和messagepack、protobuffer比差太多,而 protobuffer在此次测试中表现的极其不稳定只有在1 object100 object 性能比较不错,但是与messagepack比还是相差比较大。所以我建议还是使用messagepack,性能上更优,侵入性也非常低

我们来看看性能最优的messagepack 详细测试数据

o object:
在这里插入图片描述
1 object:
在这里插入图片描述
10 object:
在这里插入图片描述
100 object
在这里插入图片描述
测试环境

CPU:Intel Core i7-4710MQ

内存:16G

硬盘:1T SSD 512G HDD

网络:局域网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值