构建SatelliteRpc:基于Kestrel的RPC框架(整体设计篇)
内容提要
本文介绍了.NET Core时代的性能最强Web服务框架之一Kestrel的设计方案、项目信息和演示,以及性能优化工作。作者还开设了.NET性能优化交流群,欢迎加入讨论。
延伸解读
Kestrel作为通用网络框架的潜力
文章指出Kestrel不仅是ASP.NET Core的网络框架,更是一个高性能的通用网络框架,适用于消息服务器、游戏服务器和物联网网关。这为开发者提供了DotNetty之外的替代选择,尤其适合需要高性能和现代.NET特性的场景。
SatelliteRpc的设计亮点:多路复用与中间件
SatelliteRpc通过ulong类型的请求Id实现多路复用,确保请求与响应的匹配。同时,其客户端和服务端均支持类似ASP.NET Core的中间件扩展,允许开发者灵活处理请求和响应,增强了框架的扩展性和可定制性。
性能优化策略与待办事项
项目采用了Pipelines、表达式树、代码生成和内存复用等技术优化性能,但仍有许多待办事项,如服务端代码生成、请求取消传递、Context池化等。这些优化方向为后续性能提升提供了明确路径。
项目定位与使用建议
作者强调SatelliteRpc仅作为学习、演示使用,未经过生产环境检验。因此,读者在参考其设计时,需注意潜在的设计不合理或BUG,并建议在生产环境中进行充分测试和优化。
Q&A
Kestrel 只能用于 ASP.NET Core 吗?它还能用来做什么?
Kestrel 不仅是 ASP.NET Core 的网络框架,还是一个通用的高性能网络框架,适用于创建消息服务器、游戏服务器或物联网网关。
SatelliteRpc 的传输协议是如何设计的?
请求协议格式为:[请求总长度][请求Id][请求的路径(字符串)]['\0'分隔符][请求数据序列化类型][请求体];响应协议格式为:[响应总长度][请求Id][响应状态][响应数据序列化类型][响应体]。请求Id 是 ulong 类型,链接内唯一自增,用于匹配请求和响应。
SatelliteRpc 如何实现多路复用?
客户端通过 ulong 类型的请求Id 匹配请求和响应,在 RpcConnection 中使用 TaskCompletionSource 字典存储请求Id 与 TaskCompletionSource 的对应关系,收到响应时根据请求Id 找到对应的 TaskCompletionSource 完成匹配。并发请求通过 Channel<AppRequest> 排队,由后台线程单线程取出并发送,避免字节流混乱。服务端在读取完整请求后使用 Task.Run 并发执行逻辑,响应通过 Channel<HttpRawContext> 由后台线程单线程发送。
SatelliteRpc 做了哪些性能优化?
主要优化包括:使用 Pipelines 减少内存拷贝;使用表达式树减少反射损耗;客户端使用代码生成简化调用并自动注入;使用 PooledArray 和 PooledList 实现内存复用;通过 PayloadWriter 和 ReadOnlySequence<byte> 减少内存拷贝。
SatelliteRpc 的扩展性如何?支持自定义中间件和序列化吗?
扩展性类似 ASP.NET Core,支持自定义中间件(Delegate 或类形式),可通过 CallContext 处理请求和响应,支持阻断操作。序列化通过 IPayloadConverter 接口扩展,内置 Protobuf 和 Json,用户可自定义序列化器并注册到 DI 容器。其他接口如 IRpcClientMiddlewareBuilder、IRpcConnection 等也可通过 DI 替换默认实现。
SatelliteRpc 项目还有哪些待办事项?
待办包括:服务端代码生成、客户端取消请求传递到服务端、Context 和 AppRequest/AppResponse 池化、堆外内存和 FOH 管理、AsyncTask 内存优化、客户端连接池化、异常场景处理(重试、熔断等)。