【Springboot系列】监控kafka topic,钉钉报警

1、需求的诞生

前几天公司我们部门需要演示一个应用,应用依赖kafka的数据,但是kafka的数据来自其他部门的投递。

一些原因导致数据无法给到,导致我们部门的演示也很有问题,所以想做一个简单的kafka topic的监控,在没有数据的时候及时发现并找兄弟部门沟通

这里记录下原因,因为机房的带宽只有500M,其他部门在做一些视频录制的工作,导致带宽满了,往kafka生产数据的producer无法发送到。

2、kafka监测

kafka的检测有很多方案,但是因为我们在测试环境使用,讲究一个轻量级,所以直接写一个小程序监控就得了。

kafka的监控没搞过,但是用过Offset Explorer,Offset中可以看到总的消息数量,延续这个思路,只要这个数值有变化,证明又在投递。这是思路

2.1 加入依赖

创建一个Springboot的项目,这个没难度,也不说了

这里把所有的依赖都放这了,主要是kafka和等会要用的钉钉的sdk

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>alibaba-dingtalk-service-sdk</artifactId>
    <version>2.0.0</version>
</dependency>

2.2 看下配置文件

application.yml

yaml 复制代码
spring:
  kafka:
    bootstrap-servers: kafka地址
    consumer:
      auto-offset-reset: earliest
      group-id: test-xiangcai
dingding:
  webHook: https://oapi.dingtalk.com/robot/send?access_token=xxx
  topics: topic1,topic2
  sign: sign

2.3 写一个类获取topic的数据

ini 复制代码
@Component
public class KafkaTools {
    private static KafkaTools _this;
    @Autowired
    private ConsumerFactory<Long, String> consumerFactory;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    Consumer<Long, String> consumer;
    @PostConstruct
    public void init() {
        _this = this;
        _this.consumer = consumerFactory.createConsumer();
    }
    public static Long getTopicCount(String topic) {
        List<PartitionInfo> partitionInfos = _this.kafkaTemplate.partitionsFor(topic);
        long count = 0L;
        for (PartitionInfo str : partitionInfos) {
            TopicPartition topicPartition = new TopicPartition(topic, str.partition());
            long logEndOffset = _this.consumer.endOffsets(List.of(topicPartition)).get(topicPartition);
            _this.consumer.assign(List.of(topicPartition));
            long currentOffset = _this.consumer.position(topicPartition);
            count += (logEndOffset - currentOffset);
            System.err.println( "  topic  " + topic + "  最后的offset is  " + logEndOffset + "    currentOffset  " + currentOffset + "  totalCount  " + (logEndOffset - currentOffset));
        }
        return count;
    }
}

解释下重点代码

LOG-END-OFFSET :每个分区当前最新生产的消息的位移值

CURRENT-OFFSET :该消费者组当前最新消费消息的位移值

注:因为内部是使用的单机的kafka,并且也只有一个partition

3、发送到钉钉

想做一个提醒,最初的方案是发送的邮箱,没有养成看邮件的习惯,所以想要发送到微信或者钉钉,看了下方案,钉钉是最容易实现的,所以这里选择使用钉钉

3.1 钉钉webhook

创建一个钉钉群,点击右上角群设置,机器人,进入到机器人的设置界面,然后点击添加机器人,选择自定义机器人,进入界面就好

这里可以设置机器人的头像,机器人的名字,同时也展示webhook的地址,可以通过这个url 发送消息到群里。

这里选择的安全设置加签的方式,可以参考说明文档,等会代码展示

3.2 钉钉发送消息到群里

看下代码,这里设置的消息为文本,并且使用了at全体人

ini 复制代码
/**
 * 发送消息到钉钉
 *
 * @param topic
 */
private void sendMsgToDingDing(String topic) {
 
    try {
        String url = makeUrl(dingDingConfig.getWebHook(), dingDingConfig.getSign());
        DingTalkClient client = new DefaultDingTalkClient(url);
        OapiRobotSendRequest request = new OapiRobotSendRequest();
        request.setMsgtype("text");
        OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
        text.setContent("192.168.2.8 kafka  " + topic + "超过2分钟没有数据,检查下");
 
        OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
        // isAtAll类型如果不为Boolean,请升级至最新SDK
        at.setIsAtAll(true);
        request.setAt(at);
        request.setText(text);
 
        client.execute(request);
    } catch (Exception e) {
    }
}
 
/**
 * 组装url
 *
 * @param url
 * @param secret
 * @return
 * @throws Exception
 */
public static String makeUrl(String url, String secret) throws Exception {
    Long timestamp = System.currentTimeMillis();
 
    String stringToSign = timestamp + "\n" + secret;
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
    byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
    String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
 
    return url + String.format("&timestamp=%d&sign=%s", timestamp, sign);
}

看下效果

4、定时器功能

定时器直接使用springboot 的 schedule,在application上添加 直接 @EnableScheduling

创建定时job,并且设置2分钟执行一次,两分钟发现没有数据更新就会发送消息到钉钉提醒

ini 复制代码
public static Map<String, Long> countMap = new HashMap<>();
 
//    @Scheduled(cron = "0/5 * *  * * ? ")   //每5秒执行一次
@Scheduled(cron = "0 0/2 * * * ?") //  2分钟执行一次
public void execute() {
    for (String topic : dingDingConfig.getTopics().split(",")) {
        Long topicCount = KafkaTools.getTopicCount(topic);
        Long orDefault = countMap.getOrDefault(topic, 0L);
        if (orDefault.equals(topicCount)) {
            if (System.currentTimeMillis() - preDingTime > 60 * 60 * 1000L) {
                sendMsgToDingDing(topic);
                preDingTime = System.currentTimeMillis();
            }
        } else {
            countMap.put(topic, topicCount);
        }
    }
    System.err.println("job 执行时间  " + new Date());
}

这里做了一些处理

第一个点就是 在内存中保存数量,没有使用数据库,主要考虑到轻量级,在测试环境

第二个就是钉钉消息的发送,防止出现消息喷涌,这里限制了1小时才可以发送一次

5、打包部署

看下dockerfile

bash 复制代码
#项目所依赖的jdk镜像
FROM openjdk:11-jdk
RUN mkdir -p /app
WORKDIR /app
#设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#将maven构建好的jar添加到镜像中,第二个为别名
COPY start.sh start.sh
ADD target/kafkaMonitor.jar kafkaMonitor.jar
#镜像所执行的命令
ENTRYPOINT ["sh","start.sh"]

看下启动脚本

bash 复制代码
echo "192.168.2.8 kafka.tyjt.com" >> /etc/hosts
java -jar kafkaMonitor.jar
echo 'finish start!!'

很简单直接启动,这个程序主打就是一个轻便

5、总结

这只是一个小的需求,没有使用一些重量级的组件,尽可能的快速的解决问题。

这里手动操作kafka,可以在每次订阅之后直接跳到最新的进行消费

kafkaTools中的很多操作可以在其他地方使用,比如获取partition,获取最新的offset

切换到最新拉取

相关推荐
Estar.Lee13 分钟前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书1 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放1 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang1 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net
Rverdoser3 小时前
RabbitMQ的基本概念和入门
开发语言·后端·ruby
Tech Synapse3 小时前
Java根据前端返回的字段名进行查询数据的方法
java·开发语言·后端
.生产的驴3 小时前
SpringCloud OpenFeign用户转发在请求头中添加用户信息 微服务内部调用
spring boot·后端·spring·spring cloud·微服务·架构
微信-since811924 小时前
[ruby on rails] 安装docker
后端·docker·ruby on rails
代码吐槽菌6 小时前
基于SSM的毕业论文管理系统【附源码】
java·开发语言·数据库·后端·ssm
豌豆花下猫6 小时前
Python 潮流周刊#78:async/await 是糟糕的设计(摘要)
后端·python·ai