美文网首页
打印日志时,如何实现监控日志按秒聚合

打印日志时,如何实现监控日志按秒聚合

作者: 周群力 | 来源:发表于2021-01-18 00:29 被阅读0次

之前写自己的rpc框架时候遇到这个问题,记录下

一、问题

假设代码会打印日志“key111 count=1”,每秒有1000qps请求调用这行代码,那么一秒打印1000条。
如何实现监控日志按秒聚合,每秒只打印一条“key111 count=1000”?

二、线程模型

a. 生产消费者模式,消费者做聚合、打日志

image.png

日志全打印到queue里,一个消费者负责聚合、落盘;
如果queue满了,那么生产者直接打印。

优点:好写
缺点:

  1. 占内存
  2. queue满了(比如写吞吐太快来不及消费/log线程异常/log线程饥饿)有退化问题

b. 生产消费者模式,生产者写入时聚合

image.png

我的框架就是这么实现的,见https://github.com/seeflood/PUA-RPC/blob/master/src/main/java/pua/rpc/framework/common/utils/LogUtils.java

缺点如上图,包括:

  1. jdk提供的DelayQueue是无界的,需要自己手动封装一个有界DelayQueue
    https://stackoverflow.com/questions/29832664/how-to-set-capacity-for-java-delayqueue

Q: schedulerExecutorService是有界还是无界的?
A: schedulerExecutorService也是无界的。https://stackoverflow.com/questions/7403764/what-is-best-way-to-have-bounded-queue-with-scheduledthreadpoolexecutor

Q: 能否用schedulerExecutorService避免这个问题?
能。用schedulerExecutorService的话,queue就用普通的blockingQueue就行,即:


image.png
  1. 退化问题
  2. 有点复杂

c. 生产消费者模式,生产者写入时聚合,一个单独的scheduler负责投递任务

image.png

log遍历map里所有元素,打完之后不用删,让map等着被自动gc

Q: 为啥不是scheduler把map换下来后,自己把日志打印了,干嘛丢给另一个线程打日志?
A: scheduler刚把map换下来,自己打日志可能遍历map时有并发写,导致打印不精确,想通过等一会再遍历map打日志来避免这种并发问题。

优点:
相比于b,结构清晰些

缺点:

  1. jdk提供的DelayQueue是无界的
  2. 退化问题

c2. 简单一点,scheduler先sleep再自己打日志

image.png

优点:省了queue,就没有queue无界、queue满时退化问题
缺点:sleep(200)解并发问题可能不准,也可能导致再次唤醒时太晚

  • Q: 等待下一秒时,是用await()还是Thread.sleep()

c3. 不换map也不删元素,遍历map、把每个counter通过cas减到0

image.png

d. 生产消费者模式,基于环+Timer

image.png

其实就是时间轮

Q: 写环太麻烦了,能否直接用Map代替环?
A: 不能,有可能内存泄漏

三、使用开源库来实现?

a. Dubbo Metrics?

https://developer.aliyun.com/article/693569
文档太少,只能靠看ut、源码来猜怎么用;
看着没有按秒统计、按秒打日志的功能;

结论:不选择

  • Q: 看统计吞吐用到EWMA,这啥算法?

b. Dropwizard Metrics?

https://metrics.dropwizard.io/4.1.2/getting-started.html
https://www.baeldung.com/dropwizard-metrics
看着没有按秒统计、按秒打日志的功能;

结论:不选择

相关文章

网友评论

      本文标题:打印日志时,如何实现监控日志按秒聚合

      本文链接:https://www.haomeiwen.com/subject/bjlzaktx.html