线程池如何监控,才能帮助开发者快速定位线上错误?(二)
04
如何定义公共监控?
抽象线程池存储
上面说到,线程池的采集历史运行数据在各个应用系统中,数据的存储、定期删除是否可以抽象出来,避免重复的工作
如果选择抽象数据存储,客户端节点与服务端之间的交互如下:
- 客户端定时采集线程池历史运行数据,将数据打包好发送服务端
- 服务端接收客户端上报的数据,进行数据入库持久化存储
- 服务端定期删除或存档客户端线程池历史运行数据
- 由服务端统一对外提供线程池运行图表的数据展示
这里有个小问题,客户端如何打包发送给服务端?定时采集数据后直接上报是不是可行呢
不推荐采集、上报两种行为放到一个流程中,好的设计应该是要 分离开职责;而且,如果在上报过程中网络出现阻塞等等问题,会耽误采集线程的下一次采集结果
我们可以使用多线程生产、消费模型来做,相信大家初学多线程一定都学过这个设计
// 缓冲队列
private BlockingQueue<Message> messageCollectVessel = new ArrayBlockingQueue(bufferSize);
// 生产者
Message message = collector.collectMessage();
boolean offer = messageCollectVessel.offer(message);
if (!offer) {
log.warn("Buffer data starts stacking data...");
}
// 消费者
while (true) {
try {
Message message = messageCollectVessel.take();
messageSender.send(message);
} catch (Throwable ex) {
log.error("Consumption buffer container task failed. Number of buffer container tasks :: {}", messageCollectVessel.size(), ex);
}
}
创建阻塞缓冲队列,由定时线程池采集历史运行数据,并放到缓冲队列中;然后起一个线程,循环消费即可
极端情况下缓冲队列元素会出现堆积,最新采集的线程池数据也就无法插入成功,为了不影响客户端的运行,仅做异常警告处理
使用最新抽象出来的客户端、服务端交互流程,有以下几个优点
- 数据的存储和查询展示由服务端提供功能,减轻客户端压力和重复工作量
- 历史运行数据的删除或备份操作由服务端统一执行
- 不同的项目不需要为线程池历史运行数据分别创建表结构存储
- 形成交互规范,避免业务发散单独开发,中心化的设计更利于技术的迭代和管理
监控图表展示
不同公司对于线程池的监控不尽相同,出于各种考虑,会将监控封装成最符合自己业务场景的流程
Hippo4J 从最基本的指标出发,封装出了最小代价的监控体系,并提供可视化页面的图标展示
有兴趣可以查看 Hippo4J 框架官网介绍
Site:https://www.hippox.cn
还有一个功能点,考虑到很多公司搭建了一套监控体系,其中以 Prometheus + Grafana 为主
后续 Hippo4J 会接入 Prometheus,应用内部存储线程池的运行数据,适配 Prometheus 采集存储,最终展示到 Grafana
05
总结回顾
线程池作为企业级应用广泛的技术,对它的监控是不可或缺的稳定性保障之一
文章从线程池的监控出发,讲解了如何监控、监控的指标以及监控数据的存储,相信读者们也各有收获
看了上面的线程池监控内容,大家有什么想要补充的,在下方评论区留言
各位读者所在的公司又是如何对线程池监控,可以互相交流下心得
文章转自公众号:龙台的技术笔记