一、前言
为什么要设计kafka告警方案?现成的监控项目百度一下一大堆,KafkaOffsetMonitor、KafkaManager、 Burrow等,具体参考:kafka的消息挤压监控。由于本小组的项目使用的kafka集群并没有被公司的kafka-manager管理,所以只能自己简单做一个告警。
二、告警方案
首先需要两个定时任务,之间的通信依靠延迟队列。
左边的定时任务按周期扫面配置Topic-Consumer列表,通过kafka api获取消费详情并判断消息积压量是否已经大于阈值,如果阈值校验失败则放入延迟队里。
右边的定时任务按照周期从延迟队列对应的真实队列中取出一个Topic-Consumer关系,再次进行一下阈值的校验,如果检验失败才发送告警短信。
三、准备工作
1、依赖配置中心
配置中心是实现告警方案的一个关键点,通过配置中心可以动态获取告警相关的属性配置,并刷新对应的 java bean。如下是告警对应的配置bean。
@ConfigCenterBean @ConfigurationProperties(prefix = "wmhcontrol.alarm") @Component public class AlarmConstants extends BaseConfigCenterBean { private static Logger LOGGER = LoggerFactory.getLogger(AlarmConstants.class); //告警电话号码 @ConfigField private String[] phones; //短信模板ID @ConfigField private String templateId; //延迟时间 @ConfigField private Integer delay = 600; //轮训时间 @ConfigField private Integer period = 60; //获取topic-consumer消费详情地址 @ConfigField private String tcsr; //查看topic-consumer消费详情地址 @ConfigField private String tclr; //全局统一阈值 @ConfigField private Integer threshold = 1000; //topic和consumer关系列表 @ConfigField private List<TCR> tcrs; @ToInitial private void refreshProperties() { try { super.doBind(); LOGGER.info(String.format("%s 刷新成功..., 当前配置=%s...", this.getModuleName(), this)); } catch (Exception e) { LOGGER.error("AlarmConstants 对象属性绑定失败...", e); } } private void toRefresh() { try { if (isCfgCenterEffect()) { ZookeeperPropertySource propertySource = ConfigHelper.getZookeeperPropertySource(); if (ConfigCenterUtils.propertySourceShouldRefresh(this.getModuleName(), propertySource)) { this.refreshProperties(); } } } catch (Exception e) { LOGGER.error("AlarmConstants 对象属性刷新失败", e); } } @ToRefresh public Integer getThreshold() { return threshold; } public void setThreshold(Integer threshold) { this.threshold = threshold; } @ToRefresh public List<TCR> getTcrs() { return tcrs; } public void setTcrs(List<TCR> tcrs) { this.tcrs = tcrs; } @ToRefresh public String getTcsr() { return tcsr; } public void setTcsr(String tcsr) { this.tcsr = tcsr; } @ToRefresh public Integer getPeriod() { return period; } public void setPeriod(Integer period) { this.period = period; } @ToRefresh public Integer getDelay() { return delay; } public void setDelay(Integer delay) { this.delay = delay; } @ToRefresh public String[] getPhones() { return phones; } public void setPhones(String[] phones) { this.phones = phones; } @ToRefresh public String getTemplateId() { return templateId; } public void setTemplateId(String templateId) { this.templateId = templateId; } @ToRefresh public String getTclr() { return tclr; } public void setTclr(String tclr) { this.tclr = tclr; } @Override public String toString() { return ReflectionToStringBuilder.toString(this , ToStringStyle.JSON_STYLE , false , false , AlarmConstants.class); } @Override public String getDefaultResourcePath() { return "config/alarm.properties"; } @Override public String getConfigPrefix() { return "wmhcontrol.alarm"; } @Override public String getModuleName() { return "告警配置"; } @Override public void refreshForEvent() { this.refreshProperties(); } /** * topic 和 consumer之间的关系实体 */ public static class TCR { private String topic; private String consumer; private String channel; private Integer threshold; public String getTopic() { return topic; } public void setTopic(String topic) { this.topic = topic; } public String getConsumer() { return consumer; } public void setConsumer(String consumer) { this.consumer = consumer; }