You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在.NET6中使用Grpc.Core获取消息包大小实现流量统计

gRPC消息流量统计:拦截字节数的合适环节

不要依赖解析日志来统计流量——日志属于输出层,格式可能变动、日志级别可能被调整,可靠性和性能都不如直接在gRPC的核心处理流程中拦截。针对Grpc.Core 2.46.6 + .NET6的场景,推荐使用gRPC拦截器(Interceptor)结合Marshaller包装的方式,在消息序列化/反序列化环节直接统计字节数,这是官方设计的扩展点,准确性和可维护性都更高。

具体实现思路

  1. 自定义统计Marshaller:包装gRPC默认的Marshaller,在序列化(发送消息)和反序列化(接收消息)时,记录字节数并累加:
public class CountingMarshaller<T> : Marshaller<T>
{
    private readonly Marshaller<T> _innerMarshaller;
    private readonly IByteCounter _counter;

    public CountingMarshaller(Marshaller<T> innerMarshaller, IByteCounter counter)
    {
        _innerMarshaller = innerMarshaller;
        _counter = counter;
    }

    public override byte[] Serialize(T value)
    {
        var bytes = _innerMarshaller.Serialize(value);
        _counter.AddOutboundBytes(bytes.Length);
        return bytes;
    }

    public override T Deserialize(byte[] bytes)
    {
        _counter.AddInboundBytes(bytes.Length);
        return _innerMarshaller.Deserialize(bytes);
    }
}
  1. 实现拦截器:在客户端/服务端拦截器中,替换默认的Marshaller为上述统计Marshaller,让所有消息处理都经过统计逻辑:
public class CountingClientInterceptor : ClientInterceptor
{
    private readonly IByteCounter _counter;

    public CountingClientInterceptor(IByteCounter counter)
    {
        _counter = counter;
    }

    public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
        TRequest request,
        ClientInterceptorContext<TRequest, TResponse> context,
        AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
    {
        var countingRequestMarshaller = new CountingMarshaller<TRequest>(context.RequestMarshaller, _counter);
        var countingResponseMarshaller = new CountingMarshaller<TResponse>(context.ResponseMarshaller, _counter);
        
        var newContext = new ClientInterceptorContext<TRequest, TResponse>(
            context.Method,
            context.Host,
            context.Options.WithMarshallers(countingRequestMarshaller, countingResponseMarshaller));

        return continuation(request, newContext);
    }

    // 按需重写其他调用类型的方法,如AsyncServerStreamingCall、AsyncClientStreamingCall等
}
  1. 注册拦截器:创建gRPC客户端时,将统计拦截器传入:
var byteCounter = new ByteCounter(); // 自定义的计数器实现,保存累加的字节数
var channel = new Channel("your-service-address", ChannelCredentials.Insecure);
var client = new MyService.MyServiceClient(channel, new Interceptor[] { new CountingClientInterceptor(byteCounter) });

为什么这比解析日志好

  • 准确性:直接获取序列化/反序列化的原始字节数,和gRPC内部日志输出的数值完全一致,不会因日志格式变动失效。
  • 性能:避免了日志解析的字符串处理开销,属于轻量级的核心流程扩展。
  • 灵活性:可以同时统计入站(接收)和出站(发送)流量,还能按服务、方法维度拆分统计。

内容的提问来源于stack exchange,提问作者monty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:59:55