本文主要研究一下nacos client的MetricsMonitor

MetricsMonitor

nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/monitor/MetricsMonitor.java

public class MetricsMonitor {
    private static Gauge nacosMonitor = Gauge.build()
        .name("nacos_monitor").labelNames("module", "name")
        .help("nacos_monitor").register();

    private static Histogram nacosClientRequestHistogram = Histogram.build().labelNames("module", "method", "url", "code")
        .name("nacos_client_request").help("nacos_client_request")
        .register();


    public static Gauge.Child getServiceInfoMapSizeMonitor() {
        return nacosMonitor.labels("naming", "serviceInfoMapSize");
    }

    public static Gauge.Child getDom2BeatSizeMonitor() {
        return nacosMonitor.labels("naming", "dom2BeatSize");
    }

    public static Gauge.Child getListenConfigCountMonitor() {
        return nacosMonitor.labels("naming", "listenConfigCount");
    }

    public static Histogram.Timer getConfigRequestMonitor(String method, String url, String code) {
        return nacosClientRequestHistogram.labels("config", method, url, code).startTimer();
    }

    public static Histogram.Child getNamingRequestMonitor(String method, String url, String code) {
        return nacosClientRequestHistogram.labels("naming", method, url, code);
    }
}
  • MetricsMonitor内置了nacosMonitor、nacosClientRequestHistogram;并提供了getServiceInfoMapSizeMonitor、getDom2BeatSizeMonitor、getListenConfigCountMonitor、getConfigRequestMonitor、getNamingRequestMonitor静态方法

MetricsHttpAgent

nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/config/http/MetricsHttpAgent.java

public class MetricsHttpAgent implements HttpAgent {
    private HttpAgent httpAgent;

    public MetricsHttpAgent(HttpAgent httpAgent) {
        this.httpAgent = httpAgent;
    }

    @Override
    public void start() throws NacosException {
        httpAgent.start();
    }

    @Override
    public HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException {
        Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor("GET", path, "NA");
        HttpResult result = null;
        try {
            result = httpAgent.httpGet(path, headers, paramValues, encoding, readTimeoutMs);
        } catch (IOException e) {
            throw e;
        } finally {
            timer.observeDuration();
            timer.close();
        }

        return result;
    }

    @Override
    public HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException {
        Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor("POST", path, "NA");
        HttpResult result = null;
        try {
            result = httpAgent.httpPost(path, headers, paramValues, encoding, readTimeoutMs);
        } catch (IOException e) {
            throw e;
        } finally {
            timer.observeDuration();
            timer.close();
        }

        return result;
    }

    @Override
    public HttpResult httpDelete(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException {
        Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor("DELETE", path, "NA");
        HttpResult result = null;
        try {
            result = httpAgent.httpDelete(path, headers, paramValues, encoding, readTimeoutMs);
        } catch (IOException e) {

            throw e;
        } finally {
            timer.observeDuration();
            timer.close();
        }

        return result;
    }

    @Override
    public String getName() {
        return httpAgent.getName();
    }

    @Override
    public String getNamespace() {
        return httpAgent.getNamespace();
    }

    @Override
    public String getTenant() {
        return httpAgent.getTenant();
    }

    @Override
    public String getEncode() {
        return httpAgent.getEncode();
    }
}
  • MetricsHttpAgent代理了httpAgent,它在httpGet、httpPost、httpDelete方法执行前后通过MetricsMonitor.getConfigRequestMonitor获取Histogram.Timer,记录了响应耗时

NamingProxy

nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/naming/net/NamingProxy.java

public class NamingProxy {

    private static final int DEFAULT_SERVER_PORT = 8848;

    private int serverPort = DEFAULT_SERVER_PORT;

    private String namespaceId;

    private String endpoint;

    private String nacosDomain;

    private List<String> serverList;

    private List<String> serversFromEndpoint = new ArrayList<String>();

    private long lastSrvRefTime = 0L;

    private long vipSrvRefInterMillis = TimeUnit.SECONDS.toMillis(30);

    private Properties properties;

    public NamingProxy(String namespaceId, String endpoint, String serverList) {

        this.namespaceId = namespaceId;
        this.endpoint = endpoint;
        if (StringUtils.isNotEmpty(serverList)) {
            this.serverList = Arrays.asList(serverList.split(","));
            if (this.serverList.size() == 1) {
                this.nacosDomain = serverList;
            }
        }

        initRefreshSrvIfNeed();
    }

    //......

    public String callServer(String api, Map<String, String> params, String curServer, String method)
        throws NacosException {
        long start = System.currentTimeMillis();
        long end = 0;
        checkSignature(params);
        List<String> headers = builderHeaders();

        String url;
        if (curServer.startsWith(UtilAndComs.HTTPS) || curServer.startsWith(UtilAndComs.HTTP)) {
            url = curServer + api;
        } else {
            if (!curServer.contains(UtilAndComs.SERVER_ADDR_IP_SPLITER)) {
                curServer = curServer + UtilAndComs.SERVER_ADDR_IP_SPLITER + serverPort;
            }
            url = HttpClient.getPrefix() + curServer + api;
        }

        HttpClient.HttpResult result = HttpClient.request(url, headers, params, UtilAndComs.ENCODING, method);
        end = System.currentTimeMillis();

        MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(result.code))
            .observe(end - start);

        if (HttpURLConnection.HTTP_OK == result.code) {
            return result.content;
        }

        if (HttpURLConnection.HTTP_NOT_MODIFIED == result.code) {
            return StringUtils.EMPTY;
        }

        throw new NacosException(NacosException.SERVER_ERROR, "failed to req API:"
            + curServer + api + ". code:"
            + result.code + " msg: " + result.content);
    }

    //......
}
  • NamingProxy的callServer方法会在执行完http请求之后通过MetricsMonitor.getNamingRequestMonitor来记录请求耗时

小结

MetricsMonitor内置了nacosMonitor、nacosClientRequestHistogram;并提供了getServiceInfoMapSizeMonitor、getDom2BeatSizeMonitor、getListenConfigCountMonitor、getConfigRequestMonitor、getNamingRequestMonitor静态方法

doc

03-05 17:59