.NET C# RPC产品性能测试、性能对比报告

448 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

文章目录 一、说明 二、待测试产品、环境 2.1 RPC产品 2.2 测试物理机 三、测试 3.1 服务器测试项目配置 3.2 RPC服务器测试参数配置 3.3 测试 测试结果 四、测试总结 五、综合功能及特性 六、最后结语 一、说明 本测试结果仅供参考,可能由于设置、侧重的不同,导致测试结果有偏颇的,请联系若汝棋茗本人。QQ:505554090。测试的本意是进步学习,绝不是恶意诋毁,因为每个产品都有自己的侧重,每个用户都有自己选择的权力。所以本测试仅仅是将同类产品的最真实的成绩呈现给大家,让大家在选择的时候,心里也有个底。

二、待测试产品、环境 2.1 RPC产品 有其他建议请联系我

Grpc BeetleXRPC NewLifeRPC RRQMRPC-TCP 项目 Grpc BeetleXRPC NewLifeRPC RRQMRPC-TCP Github Github Github Github Github Gitee 2.2 测试物理机 个人笔记本,戴尔G5,CPU:i7-10750H,六核12线程。RAM:8G。

三、测试 3.1 服务器测试项目配置 控制台netcoreapp3.1项目。

3.2 RPC服务器测试参数配置 【Grpc】

版本:Grpc.Core 2.43.0

Server server = new Server { Services = { TestGrpcService.BindService(new TestService()) }, Ports = { new ServerPort("localhost", 5555, ServerCredentials.Insecure) } }; server.Start(); Console.WriteLine("Grpc启动"); 1 2 3 4 5 6 7 syntax = "proto3";

option csharp_namespace = "GrpcServer.Web.Protos";

message GrpcGetAddRequest { int32 A=1; int32 B=2; }

message GrpcGetAddResponse { int32 Result=1; }

service TestGrpcService { rpc GetAdd(GrpcGetAddRequest) returns(GrpcGetAddResponse) ; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 【BeetleXRPC】

版本:BeetleX.XRPC 1.1.0,BeetleX.XRPC.Hosting 1.0.6

var builder = new HostBuilder() .ConfigureServices((hostContext, services) => { services.UseXRPC(s => { s.ServerOptions.LogLevel = BeetleX.EventArgs.LogType.Error; s.ServerOptions.DefaultListen.Port = 9090; s.RPCOptions.ParameterFormater = new JsonPacket();//default messagepack }, typeof(Program).Assembly); }); builder.Build().Run();

1 2 3 4 5 6 7 8 9 10 11 12 13 【NewLifeRPC】

版本:NewLife.Core 9.0.2022.101

XTrace.UseConsole(); var netUri = new NetUri(NetType.Tcp, IPAddress.Any, 5001); var server = new ApiServer(netUri) { //Log = XTrace.Log, //EncoderLog = XTrace.Log, //ShowError = true

//不输出调用日志

}; server.Register(); server.Start(); Console.WriteLine("NewLifeRPC启动成功"); 1 2 3 4 5 6 7 8 9 10 11 12 13 【RRQMSocket.RPC】

版本:RRQMSocket.RPC 6.5.0

RPCService rpcService = new RPCService();

TcpRpcParser tcpRPCParser = new TcpRpcParser(); //声明配置 var config = new TcpRpcParserConfig();

//继承TcpService配置 config.ListenIPHosts = new IPHost[] { new IPHost("127.0.0.1:7789") };

//继承TokenService配置 config.VerifyToken = "123RPC";//连接验证令箭,可实现多租户模式 config.VerifyTimeout = 3 * 1000;//验证3秒超时

//继承TcpRpcParser配置,以实现RPC交互 config.ProxyToken = "RPC";//代理令箭,当客户端获取代理文件,或服务时需验证令箭 tcpRPCParser.Setup(config); tcpRPCParser.Start();

rpcService.AddRPCParser("TcpParser", tcpRPCParser); Console.WriteLine("TCP解析器添加完成");

rpcService.RegisterServer(); Console.WriteLine("RPC服务已启动");

rpcService.ShareProxy(new IPHost(8848)); Console.WriteLine($"通过8848端口分享代理。");

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 3.3 测试 调用10w次极简调用。

【Grpc 客户端】

public static void Start(int count) { Console.WriteLine("1.测试Sum"); Console.WriteLine("2.测试GetBytes"); Console.WriteLine("3.测试BigString");

        Channel channel = new Channel("127.0.0.1:5555", ChannelCredentials.Insecure);
        var client = new TestGrpcService.TestGrpcServiceClient(channel);

        switch (Console.ReadLine())
        {
            case "1":
                {
                    var rs = client.GetAdd(new GrpcGetAddRequest() {A=10,B=20 });//试调一次,保持在线

                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = client.GetAdd(new GrpcGetAddRequest() { A = i, B = i });
                            if (rs.Result != i + i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }

                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            default:
                break;
        }
        channel.ShutdownAsync().Wait();
    }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 【BeetleXRPC 客户端】

public static void Start(int count) { Console.WriteLine("1.测试Sum"); Console.WriteLine("2.测试GetAdd"); Console.WriteLine("3.测试GetBytes"); Console.WriteLine("4.测试BigString");

        XRPCClient client = new XRPCClient("localhost", 9090);
        client.Options.ParameterFormater = new JsonPacket();//default messagepack
        ITestTaskController testController = client.Create<ITestTaskController>();

        switch (Console.ReadLine())
        {
            case "1":
                {
                    var rs = testController.Sum(10,20);//试调一次,保持在线
                    rs.Wait();

                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs  =testController.Sum(i,i);
                            rs.Wait();
                            if (rs.Result!=i+i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }

                            if (i%1000==0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            case "2":
                {
                    var rs = testController.GetBytes(10);//试调一次,保持在线
                    rs.Wait();

                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = testController.GetAdd(new GetAddRequest() { A=i,B=i});
                            rs.Wait();
                            if (rs.Result.Result!=i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }

                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            case "3":
                {
                    var rs = testController.GetBytes(10);//试调一次,保持在线
                    rs.Wait();

                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = testController.GetBytes(i);//测试10k数据
                            rs.Wait();
                            if (rs.Result.Length != i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }

                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            case "4":
                {
                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = testController.GetBigString();

                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            default:
                break;
        }
    }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 【NewLifeRPC 客户端】

public static void Start(int count) { Console.WriteLine("1.测试Sum"); Console.WriteLine("2.测试GetBytes"); Console.WriteLine("3.测试BigString"); Console.WriteLine("选择数字,测试1w次调用用时。"); var client = new ApiClient("tcp://127.0.0.1:5001") { Log = XTrace.Log, EncoderLog = XTrace.Log };

        switch (Console.ReadLine())
        {
            case "1":
                {
                    var rs = client.Invoke<int>("Test/Sum", new { a=10,b=20});//先试调一下,保证已经建立了完整的连接

                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = client.Invoke<int>("Test/Sum", new { a = i, b = i });
                            if (rs!= i + i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }
                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            case "2":
                {
                    var rs = client.Invoke<byte[]>("Test/GetBytes", new { a = 10 });//先试调一下,保证已经建立了完整的连接

                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = client.Invoke<byte[]>("Test/GetBytes", new { a = i });//测试10k数据
                            if (rs.Length != i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }
                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            case "3":
                {
                    var rs = client.Invoke<string>("Test/GetBigString");//先试调一下,保证已经建立了完整的连接
                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = client.Invoke<string>("Test/GetBigString");
                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            default:
                break;
        }
    }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 【RRQMRPC 客户端】

public static void Start(int count) { Console.WriteLine("1.测试Sum"); Console.WriteLine("2.测试GetAdd"); Console.WriteLine("3.测试GetBytes"); Console.WriteLine("4.测试BigString");

        TcpRpcClient client = new TcpRpcClient();
        var config = new TcpRpcClientConfig();
        config.RemoteIPHost = new IPHost("127.0.0.1:7789");
        client.Setup(config);
        client.Connect("123RPC");
        client.DiscoveryService("RPC");

        switch (Console.ReadLine())
        {
            case "1":
                {
                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = client.Invoke<int>("Sum", InvokeOption.WaitInvoke, i,i);
                            if (rs!= i + i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }
                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            case "2":
                {
                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = client.Invoke<GetAddResponse>("GetAdd", InvokeOption.WaitInvoke,new GetAddRequest() { A=i,B=i });
                            if (rs.Result != i + i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }
                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            case "3":
                {
                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = client.Invoke<byte[]>("GetBytes", InvokeOption.WaitInvoke,i);//测试10k数据
                            if (rs.Length != i)
                            {
                                Console.WriteLine("调用结果不一致");
                            }
                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            case "4":
                {
                    TimeSpan timeSpan = RRQMCore.Diagnostics.TimeMeasurer.Run(() =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            var rs = client.Invoke<string>("GetBigString", InvokeOption.WaitInvoke);
                            if (i % 1000 == 0)
                            {
                                Console.WriteLine(i);
                            }
                        }
                    });
                    Console.WriteLine(timeSpan);
                    break;
                }
            default:
                break;
        }
    }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 测试结果 【Grpc】

【BeetleXRPC】

【NewLifeRPC】

【RRQMRPC】

四、测试总结 在10w次极简调用中,Grpc用时29.47s,也是用时最久的。BeetleXRPC用时19.34s,NewLifeRPC用时26.88s,RRQMRPC用时6.06秒。基本上,RRQMRPC是Grpc的五倍,是BeetleXRPC的三倍,是NewLifeRPC的四倍有余。

但是值得注意的是,Grpc使用的是在ssl加密模式下HTTP数据格式,且数据参数也经过了message封装类,所以本次测试对于Grpc不是很公平,但是基本上也能给大家一些参考性意见。

五、综合功能及特性 功能 Grpc BeetleXRPC NewLifeRPC RRQMRPC 开源 是 是 是 是 免费商业 是 是 是 是 .Net跨平台性 依托.Net Core跨平台 依托.Net Core跨平台 依托.Net Core跨平台 依托.Net Core跨平台 完全跨平台性 支持 不确定 不确定 RRQMRPC不支持,但JsonRpc、XmlRpc扩展组件能辅助调用,实现Web,TCP直接调用 支持自定义参数类 支持 本测试不支持 本测试不支持 支持 支持out、ref 不支持 本测试不支持 本测试不支持 支持 自定义序列化 支持 不确定 不确定 支持 客户端显式RPC接口 支持 需要自己创建接口 本测试不支持 支持 获取调用上下文 支持 不确定 不确定 支持 回调RPC 支持双向流,但不确定是否支持反向RPC 不确定 不确定 支持 大数据传递 支持,单向流、双向流,可以传递大数据 不确定 不确定 支持单项流,双向流 支持类似EventBus功能 支持 不确定 不确定 支持 二次开发容易程度 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐