摘要:本文讲述如何在保存Kafka特有能力的情况下给Kafka扩充一个具有能处理延时消息场景的能力。

本文分享自华为云社区《Kafka也能实现消息延时了?》,作者:HuaweiCloudDeveloper 。

1、背景

Kafka是一个拥有高吞吐、可持久化、可水平扩展,支持流式数据处理等多种特性的分布式消息流处理中间件,采用分布式消息发布与订阅机制,在日志收集、流式数据传输、在线/离线系统分析、实时监控等领域有广泛的应用,Kafka它虽有以上这么多的应用场景和优点,但也具备其缺陷,比如在延时消息场景下,Kafka就不具备这种能力,因此希望能在保存Kafka特有能力的情况下给Kafka扩充一个具有能处理延时消息场景的能力。

2、开发环境

3、云服务介绍

分布式消息服务Kafka版: 华为云分布式消息服务Kafka版是一款基于开源社区版Kafka提供的消息队列服务,向用户提供计算、存储和带宽资源独占式的Kafka专享实例。使用华为云分布式消息服务Kafka版,资源按需申请,按需配置Topic的分区与副本数量,即买即用,您将有更多精力专注于业务快速开发,不用考虑部署和运维。

4、方案设计

i、方案简述

此方案实现,需要借助两个Topic来进行实现,一个Topic用于及时接收生产者们所产生的消息,另一个Topic则用于消费者拉取消息进行消费。另外在这两个Topic之间加上一个队列用于做延时的逻辑判断,如果消息满足了延时的条件,则将队列中的消息生产至我们的消费者需要拉取的Topic中。

ii、方案架构图

Kafka消息延时方案架构图

Kafka消息延时实现思路

  1. 生产者将生产消息存入topic_delay主题中进行存储。
  2. 将topic_delay主题中的所有消息拉取至ConcurrentLinkedQueue队列中。
  3. 取值判断是否满足延时要求。
    a. 如果满足延时要求,则将消息生产至topic_out主题中,并将queue队列中的值移除。
    b. 如果不满足延时要求,则等待自定义时间后重试判断。
  4. 消费者最终从topic_out主题中拉取消息进行消费。

iii、方案时序图

Kafka消息延时方案时序图

5、代码参数指南

本项目中起到延时作用的类Delay.java其余类为官方提供用于测试生产和消费消息,如需使用官方测试的使用的生产消费代码相关配置介绍可以参考https://support.huaweicloud.com/devg-kafka/how-to-connect-kafka.html 。 如需使用自己配置的生产者消费者,只配置Delay.java中的参数即可。

Delay.java参数详情

  1. delay:自定义延时时间,单位ms。
  2. topic_delay变量:用于临时存储消息的topic名称。
  3. topic_out变量:用于消费者拉取消息消费的topic名称。
  4. 关于消费者和生产者配置可按需配置,可参考Kafka官方文档:https://kafka.apache.org/documentation/#producerconfigs

6、代码实现

实现代码可参考Kafka消息延时

package com.dms.delay;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord; import java.time.Duration;
import java.util.Arrays;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.ConcurrentLinkedQueue; /**
* Hello world!
*
*/
public class Delay { //缓存队列
public static ConcurrentLinkedQueue<ConsumerRecord<String, String>> link = new ConcurrentLinkedQueue();
//延迟时间(20秒),可根据需要设置延迟大小
public static long delay = 20000L; /**
*入口
* @param args
*/
public static void main( String[] args )
{
//延时主题(用于控制延时缓冲)
String topic_delay = "topic_delay";
//输出主题(直接供消费者消费)
String topic_out = "topic_out";
/*
消费线程
*/
new Thread(new Runnable() {
@Override
public void run() {
//消费者配置。请根据需要自行设置Kafka配置
Properties props = new Properties();
props.setProperty("bootstrap.servers", "192.168.0.59:9092,192.168.0.185:9092,192.168.0.4:9092");
props.setProperty("group.id", "test");
props.setProperty("enable.auto.commit", "true");
props.setProperty("auto.commit.interval.ms", "1000");
props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
//创建消费者
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
//指定消费主题
consumer.subscribe(Arrays.asList(topic_delay));
while (true) {
//轮询消费
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(10));
//遍历当前轮询批次拉取到的消息
for (ConsumerRecord<String, String> record : records){
System.out.println(record);
//将消息添加到缓存队列
link.add(record);
}
}
}
}).start();
/*
生产线程
*/
new Thread(new Runnable() {
@Override
public void run() {
//生产者配置(请根据需求自行配置)
Properties props = new Properties();
props.put("bootstrap.servers", "192.168.0.59:9092,192.168.0.185:9092,192.168.0.4:9092");
props.put("linger.ms", 1);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
//创建生产者
Producer<String, String> producer = new KafkaProducer<>(props);
//持续从缓存队列中获取消息
while(true){
//如果缓存队列为空则放缓取值速度
if(link.isEmpty()){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
//获取缓存队列栈顶消息
ConsumerRecord<String, String> record = link.peek();
//获取该消息时间戳
long timestamp = record.timestamp();
Date now = new Date();
long nowTime = now.getTime();
if(timestamp+ Delay.delay <nowTime){
//获取消息值
String value = record.value();
//生产者发送消息到输出主题
producer.send(new ProducerRecord<String, String>(topic_out, "",value));
//从缓存队列中移除该消息
link.poll();
}else {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
}

7、结果反馈

点击关注,第一时间了解华为云新鲜技术~

OUT了吧,Kafka能实现消息延时了的更多相关文章

  1. ActiveMQ笔记(6):消息延时投递

    在开发业务系统时,某些业务场景需要消息定时发送或延时发送(类似:飞信的短信定时发送需求),这时候就需要用到activemq的消息延时投递,详细的文档可参考官网说明,本文只介绍二种常用的用法: 注:本文 ...

  2. Kafka介绍与消息队列

    消息队列的好处: 消息队列(Message Queue) 消息: 网络中的两台计算机或者两个通讯设备之间传递的数据.例如说:文本.音乐.视频等内容. 队列:一种特殊的线性表(数据元素首尾相接),特殊之 ...

  3. Kafka与常见消息队列的对比

    Kafka与常见消息队列的对比 RabbitMQ Erlang编写 支持很多的协议:AMQP,XMPP, SMTP, STOMP 非常重量级,更适合于企业级的开发 发送给客户端时先在中心队列排队.对路 ...

  4. Kafka设计解析(十六)Kafka 0.11消息设计

    转载自 huxihx,原文链接 [原创]Kafka 0.11消息设计 目录 一.Kafka消息层次设计 1. v1格式 2. v2格式 二.v1消息格式 三.v2消息格式 四.测试对比 Kafka 0 ...

  5. Kafka中的消息是否会丢失和重复消费(转)

    在之前的基础上,基本搞清楚了Kafka的机制及如何运用.这里思考一下:Kafka中的消息会不会丢失或重复消费呢?为什么呢? 要确定Kafka的消息是否丢失或重复,从两个方面分析入手:消息发送和消息消费 ...

  6. RabbitMq(7)消息延时推送

    应用场景 目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如: 淘宝七天自动确认收货.在我们签收商品后,物流系统会在七天后延时发送一个消息给支付系统,通知支付系统将款打给商家,这个过程持 ...

  7. Kafka作为分布式消息系统的系统解析

    Kafka概述 Apache Kafka由Scala和Java编写,基于生产者和消费者模型作为开源的分布式发布订阅消息系统.它提供了类似于JMS的特性,但设计上又有很大区别,它不是JMS规范的实现,如 ...

  8. RabbitMQ,RocketMQ,Kafka 几种消息队列的对比

    常用的几款消息队列的对比 前言 RabbitMQ 优点 缺点 RocketMQ 优点 缺点 Kafka 优点 缺点 如何选择合适的消息队列 参考 常用的几款消息队列的对比 前言 消息队列的作用: 1. ...

  9. RabbitMQ,RocketMQ,Kafka 事务性,消息丢失和消息重复发送的处理策略

    消息队列常见问题处理 分布式事务 什么是分布式事务 常见的分布式事务解决方案 基于 MQ 实现的分布式事务 本地消息表-最终一致性 MQ事务-最终一致性 RocketMQ中如何处理事务 Kafka中如 ...

  10. Kafka笔记--指定消息的partition规则

    参数的设定:参考资料 不错的资料:http://blog.csdn.net/honglei915/article/details/37697655 http://developer.51cto.com ...

随机推荐

  1. 【虹科干货】Redis Enterprise vs ElastiCache——如何选择缓存解决方案?

    使用Redis 或 Amazon ElastiCache 来作为缓存加速已经是业界主流的解决方案,二者各有什么优势?又有哪些区别呢? 为了提高 Web 应用程序和数据驱动服务的性能与效率,使用 Red ...

  2. 浅谈Python异步编程

    1. 异步编程概述 异步编程是一种编程范式,用于处理那些需要等待I/O操作完成或者耗时任务的情况.在传统的同步编程中,代码会按照顺序逐行执行,直到遇到一个耗时操作,它会阻塞程序的执行直到操作完成.这种 ...

  3. Atcoder Regular Contest 167

    卡 B 下大分了. A. Toasts for Breakfast Party 发现题意是让方差尽可能小,就是让 \(A\) 里的值尽可能接近. 所以从小到大排个序,把 \(A_{N,\dots,N- ...

  4. JavaScript(ES6):变量的解构赋值

    解构赋值定义: 允许按照一定模式从数组或对象中提取值,然后对变量进行赋值. 数组的解构赋值 注:数组的元素要一次排序的,变量的值由他的位置决定. 基本用法 // ES6 解构赋值 let [a, b, ...

  5. Git入门笔记--版本控制系统的使用

    首先记录下使用命令行工具git与github交互的 "Hello,World!" ."Hello,World!"是任何程序设计语言入门第一课,不管原理,先跑起来 ...

  6. MongoDB 位置查询报错 planner returned error: unable to find index for $geoNear query

    执行查询语句,使用 $nearSphere /** * 1千米 = 0.6213712英里 15千米 = 9.3205679英里 查询通过除以地球的大约赤道半径(3963.2英里)将距离转换为弧度. ...

  7. 巅峰对决:英伟达 V100、A100/800、H100/800 GPU 对比

    近期,不论是国外的 ChatGPT,还是国内诸多的大模型,让 AIGC 的市场一片爆火.而在 AIGC 的种种智能表现背后,均来自于堪称天文数字的算力支持.以 ChatGPT 为例,据微软高管透露,为 ...

  8. go基础-函数

    概述 在任何语言中函数都是极其重要的内容,业务功能都是由一个或多个函数组合完成.go语言是函数式编程语言,函数是一等公民,可以被传递.有函数类型,go语言有三种类型的函数,普通函数.匿名函数(Lamb ...

  9. 数据结构与算法 | 图(Graph)

    在这之前已经写了数组.链表.二叉树.栈.队列等数据结构,本篇一起探究一个新的数据结构:图(Graphs ).在二叉树里面有着节点(node)的概念,每个节点里面包含左.右两个子节点指针:比对于图来说同 ...

  10. Element的安装与基本使用

    一.什么是Element? Element是饿了么团队研发的一套为开发者与设计师等准备的基于Vue2.0的桌面端组件库,使开发人员可以快速拼凑出一套页面 组件:组成网页的部件,例如:超链接,按钮,图片 ...