Flink 消费RabbitMQ 和 Kafka
1 2 | 在消息RabbitMQ时,我们关心的一个问题是手动ack还是自动ack,如果是自动ack就怕出现丢消息的情况 Flink以RabbitMQ作为Source,是怎么保证消息唯一性的呢,是怎么保证ack的. |
1 2 3 4 5 6 | 首先引入依赖包 <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-connector-kafka- 0 .10_${scala.version}</artifactId> <version>${flink.version}</version> </dependency> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | RMQSource类,可以看到如果设置了checkpointing,则默认autoAck是 false ,是手动控制提交的<br>那什么时候提交呢,flink checkpointing有个时间间隔,每次checkpointing触发时,才能ack,也就是说,不是一条消息ack一下,而是定时ack<br>这个跟kafka,update offset一样,都是在checkpoint的时候处理 @Override public void open(Configuration config) throws Exception { super .open(config); ConnectionFactory factory = setupConnectionFactory(); try { connection = factory.newConnection(); channel = connection.createChannel(); if (channel == null ) { throw new RuntimeException( "None of RabbitMQ channels are available" ); } setupQueue(); consumer = new QueueingConsumer(channel); RuntimeContext runtimeContext = getRuntimeContext(); if (runtimeContext instanceof StreamingRuntimeContext && ((StreamingRuntimeContext) runtimeContext).isCheckpointingEnabled()) { autoAck = false ; // enables transaction mode channel.txSelect(); } else { autoAck = true ; } LOG.debug( "Starting RabbitMQ source with autoAck status: " + autoAck); channel.basicConsume(queueName, autoAck, consumer); } catch (IOException e) { throw new RuntimeException( "Cannot create RMQ connection with " + queueName + " at " + rmqConnectionConfig.getHost(), e); } running = true ; } |
RMQSource @Override public void run(SourceContext<OUT> ctx) throws Exception { while (running) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); synchronized (ctx.getCheckpointLock()) { OUT result = schema.deserialize(delivery.getBody()); if (schema.isEndOfStream(result)) { break ; } if (!autoAck) { final long deliveryTag = delivery.getEnvelope().getDeliveryTag(); if (usesCorrelationId) { final String correlationId = delivery.getProperties().getCorrelationId(); Preconditions.checkNotNull(correlationId, "RabbitMQ source was instantiated " + "with usesCorrelationId set to true but a message was received with " + "correlation id set to null!" ); if (!addId(correlationId)) { // we have already processed this message continue ; } } sessionIds.add(deliveryTag); } ctx.collect(result); } } } |
@Override protected void acknowledgeSessionIDs(List<Long> sessionIds) { try { for ( long id : sessionIds) { channel.basicAck(id, false ); } channel.txCommit(); } catch (IOException e) { throw new RuntimeException( "Messages could not be acknowledged during checkpoint creation." , e); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理