RPC性能指标的收集——Prometheus

对于RPC的性能收集,以微博的motan和阿里的dubbo为例,也是通过intercept去做的。

motan的性能指标收集:使用的是motan中的扩展机制

//此处的spi使用的是weibo.com中的扩展
@SpiMeta(name = "pepperProfiler")
@Activation(sequence = 2)
public class MotanProfilerFilter implements Filter {
    //进来的请求指标
    private static final Stats PROFILER_STAT_IN = Profiler.Builder
            .builder()
            .type("motan")
            .subType("in")
            .build();
    //对外请求的指标
    private static final Stats PROFILER_STAT_OUT = Profiler.Builder
            .builder()
            .type("motan")
            .subType("out")
            .build();

    @Override
    public Response filter(Caller<?> caller, Request request) {
        if (!System.getProperty("motanProfileEnable", "true").equalsIgnoreCase("true")) {
            return caller.call(request);
        }

        final String category = MotanUtils.getShortName(request.getInterfaceName());
        final String metrics = category + "." + request.getMethodName() + "(" + MotanUtils.getShortName(request.getParamtersDesc()) + ")";
        String[] tags = new String[]{"method", metrics, "service", category};

        if (StringUtils.isEmpty(metrics) || StringUtils.isEmpty(category)) {
            return caller.call(request);
        }
        long begin = System.nanoTime();
        boolean specialException = true;
        boolean isError = false;
        beforeCall(tags, caller instanceof Provider);
        try {
            final Response response = caller.call(request);
            if (response == null) {
                isError = true;
            } else {
                if (response.getException() != null) {
                    isError = true;
                }
            }
            specialException = false;
            return response;
        } finally {
            if (specialException) {
                isError = true;
            }
            postCall(tags, caller instanceof Provider, begin, isError);
        }
    }

    private void postCall(String[] tags, boolean isIncoming, long begin, boolean isError) {
        if (isIncoming) {
            PROFILER_STAT_IN.observe(System.nanoTime() - begin, TimeUnit.NANOSECONDS, tags);
            PROFILER_STAT_IN.decConc(tags);
            if (isError) {
                PROFILER_STAT_IN.error(tags);
            }
        } else {
            PROFILER_STAT_OUT.observe(System.nanoTime() - begin, TimeUnit.NANOSECONDS, tags);
            PROFILER_STAT_OUT.decConc(tags);
            if (isError) {
                PROFILER_STAT_OUT.error(tags);
            }
        }
    }

    private void beforeCall(String[] tags, boolean isIncoming) {
        if (isIncoming) {
            PROFILER_STAT_IN.incConc(tags);
        } else {
            PROFILER_STAT_OUT.incConc(tags);
        }
    }
}

扩展类文件:因为使用的是motan自带的扩展过滤器,所以这里的文件名要是motan的文件路径。

          

 

 

dubbo的性能指标收集:

定义的指标收集模板类:

public abstract class DubboProfilerFilterTemplate implements Filter {

    static final Stats PROFILER_STAT_IN = Profiler.Builder
            .builder()
            .type("dubbo")
            .subType("in")
            .build();
    static final Stats PROFILER_STAT_OUT = Profiler.Builder
            .builder()
            .type("dubbo")
            .subType("out")
            .build();

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        final String category = invoker.getInterface().getSimpleName(); // 接口名
        StringBuilder params = new StringBuilder();
        Class[] clazzs = invocation.getParameterTypes();
        for (int index = 0; index < clazzs.length; index++) {
            params.append(index == clazzs.length - 1 ? clazzs[index].getSimpleName() : clazzs[index].getSimpleName() + ", ");
        }

        final String metrics = invocation.getMethodName() + "(" + params.toString() + ")"; // method(参数类型...)

        String[] tags = new String[]{"method", metrics, "service", category};

        if (StringUtils.isEmpty(category) || StringUtils.isEmpty(metrics)) {
            return invoker.invoke(invocation);
        }

        long begin = System.nanoTime();
        boolean specialException = true;
        boolean isError = false;

        // before trace...
        beforeInvoke(tags);
        try {
            Result result = invoker.invoke(invocation);
            if (result == null || result.hasException()) {
                isError = true;
            }

            specialException = false;

            return result;
        } finally {
            if (specialException) {
                isError = true;
            }
            // after trace...
            afterInvoke(tags, begin, isError);
        }
    }

    abstract void afterInvoke(String[] tags, long begin, boolean isError);

    abstract void beforeInvoke(String[] tags);
}

服务提供方收集类:

@Activate(group = {PROVIDER})
public class DubboProviderProfilerFilter extends DubboProfilerFilterTemplate {
    @Override
    void afterInvoke(String[] tags, long begin, boolean isError) {
        PROFILER_STAT_IN.observe(System.nanoTime() - begin, TimeUnit.NANOSECONDS, tags);
        PROFILER_STAT_IN.decConc(tags);
        if (isError) {
            PROFILER_STAT_IN.error(tags);
        }
    }

    @Override
    void beforeInvoke(String[] tags) {
        PROFILER_STAT_IN.incConc(tags);
    }
}

服务调用方收集类:

@Activate(group = {CONSUMER})
public class DubboConsumerProfilerFilter extends DubboProfilerFilterTemplate {
    @Override
    void afterInvoke(String[] tags, long begin, boolean isError) {
        PROFILER_STAT_OUT.observe(System.nanoTime() - begin, TimeUnit.NANOSECONDS, tags);
        PROFILER_STAT_OUT.decConc(tags);
        if (isError) {
            PROFILER_STAT_OUT.error(tags);
        }
    }

    @Override
    void beforeInvoke(String[] tags) {
        PROFILER_STAT_OUT.incConc(tags);
    }
}

扩展类文件:

   

 

总结:到这里,一些列关于Prometheus介绍,端点暴露,健康指标健康,常用的业务级别性能指标(http、mybatis、rpc)的性能指标收集就全都分享完了。最后再推荐一下同事的开源项目:https://github.com/zrbcool/pepper-metrics

 

posted @ 2021-02-09 11:33  jingyi_up  阅读(478)  评论(0编辑  收藏  举报