Kafka Consumer如何实现exactly once/at least once

Kafka的Exactly-once语义与事务机制 Kafka 0.11.x版本(对应 Confluent Platform 3.3),该版本引入了exactly-once语义。精确一次确实很难实现(Exactly-once is a really hard problem)Mathias Verraes说,分布式系统中最难解决的两个问题是:消息顺序保证(Guaranteed order of messages)。消息的精确一次投递(Exactly... 阅读详情

消费端幂等性

  kafka具有两种提交offset(消费偏移量)方式,在Kafka每个分区具备一offset记录消费位置,如果消费者一直处于正常的运行转态,那么offset将没有什么用处,因为正常消费时,consumer记录了本次消费的offset和下一次将要进行poll数据的offset起始位置,但是如果消费者发生崩溃或者有新的消费者加入消费者组,就会触发再均衡Rebalance,Rebalance之后,每个消费者将会分配到新的分区,而消费者对于新的分区应该从哪里进行起始消费,这时候提交的offset信息就起作用了,提交的offset信息包括消费者组所有分区的消费进度,这时候消费者可以根据消费进度继续消费,offset自动提交是最不具确定性的,所以要使用手动提交来控制offset

消费时出现几种异常情况

自动提交

  • 重复消费:当数据已经被处理,然后自动提交offset时消费者出现故障或者有新消费者加入组导致再均衡,这时候offset提交失败,导致这批已经处理的数据的信息没有记录,后续会重复消费一次
  • 丢失数据:如果业务处理时间较长一点,这时候数据处理业务还未完成,offset信息已经提交了,但是在后续处理数据过程中程序发生了崩溃,导致这批数据未正常消费,这时候offset已经提交,消费者后续将不在消费这批数据,导致这批数据将会丢失

手动提交

  • 重复消费(最少一次消费语义实现):消费数据处理业务完成后进行offset提交,可以保证数据最少一次消费,因为在提交offset的过程中可能出现提交失败的情况,导致数据重复消费
  • 丢失数据(最多一次消费语义实现):在消费数据业务处理前进行offset提交,可以保证最多一次消费,在后续数据业务处理程序出现故障,将导致数据丢失

精确一次消费实现

offset手动提交,业务逻辑成功处理后,提交offset
解决方案:

  1. 对于流程中的消息,每条消息中包含唯一id,比如业务id,在数据库中将业务id作为Unique key,插入重复时会报duplicate key异常,不会导致数据库中出现脏数据
  2. Redis中使用set存储业务id,天然幂等性
  3. 如果不是上面两个场景,需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下消费过吗?如果没有消费过,就处理,然后这个 id 写 Redis。如果消费过了,那就别处理了,保证不重复处理相同的消息即可

自行控制offset的准确性,这里数据不具备状态,存储使用关系型数据库,比如MySQL。这里简单说明一下实现思路:
1)利用consumer api的seek方法可以指定offset进行消费,在启动消费者时查询数据库中记录的offset信息,如果是第一次启动,那么数据库中将没有offset信息,需要进行消费的元数据插入,然后从offset=0开始消费
2)关系型数据库具备事务的特性,当数据入库时,同时也将offset信息更新,借用关系型数据库事务的特性保证数据入库和修改offset记录这两个操作是在同一个事务中进行
3)使用ConsumerRebalanceListener来完成在分配分区时和Relalance时作出相应的处理逻辑

记录kafka信息表设计

create table kafka_info(
	topic_group_partition varchar(32) primary key, //主题+组名+分区号 这里冗余设计方便通过这个主键进行更新提升效率 
	topic_group varchar(30), //主题和组名
	partition_num tinyint,//分区号
	offsets bigint default 0 //offset信息
);

代码实现

import com.alibaba.fastjson.JSON;
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.PartitionInfo;
import org.apache.kafka.common.TopicPartition;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Duration;
import java.util.*;
public class AccurateConsumer {
    private static final Properties props = new Properties();
    private static final String GROUP_ID = "Test";
    static {
        props.put("bootstrap.servers", "192.168.142.139:9092");
        props.put("group.id", GROUP_ID);
        props.put("enable.auto.commit", false);//注意这里设置为手动提交方式
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    }
    final KafkaConsumer<String, String> consumer;
    //用于记录每次消费时每个partition的最新offset
    private Map<TopicPartition, Long> partitionOffsetMap;
    //用于缓存接受消息,然后进行批量入库
    private List<Message> list;
    private volatile boolean isRunning = true;
    private final String topicName;
    private final String topicNameAndGroupId;
    public AccurateConsumer(String topicName) {
        this.topicName = topicName;
        topicNameAndGroupId = topicName + "_" + GROUP_ID;
        consumer = new KafkaConsumer<>(props);
        consumer.subscribe(Arrays.asList(topicName), new HandleRebalance());
        list = new ArrayList<>(100);
        partitionOffsetMap = new HashMap<>();
    }
    //这里使用异步提交和同步提交的组合方式
    public void receiveMsg() {
        try {
            while (isRunning) {
                ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofSeconds(1));
                if (!consumerRecords.isEmpty()) {
                    for (TopicPartition topicPartition : consumerRecords.partitions()) {
                        List<ConsumerRecord<String, String>> records = consumerRecords.records(topicPartition);
                        for (ConsumerRecord<String, String> record : records) {
                            //使用fastjson将记录中的值转换为Message对象,并添加到list中
                            list.addAll(JSON.parseArray(record.value(), Message.class));
                        }
                        //将partition对应的offset信息添加到map中,入库时将offset-partition信息一起进行入库
                        partitionOffsetMap.put(topicPartition, records.get(records.size() - 1)
                                .offset() + 1);//记住这里一定要加1,因为下次消费的位置就是从+1的位置开始
                    }
                }
                //如果list中存在有数据,则进行入库操作
                if (list.size() > 0) {
                    boolean isSuccess = insertIntoDB(list, partitionOffsetMap);
                    if (isSuccess) {
                        //将缓存数据清空,并将offset信息清空
                        list.clear();
                        partitionOffsetMap.clear();
                    }
                }
            }
        } catch (Exception e) {
            //处理异常
        } finally {
            //offset信息由我们自己保存,提交offset其实没有什么必要
            //consumer.commitSync();
            close();
        }
    }
    private boolean insertIntoDB(List<Message> list, Map<TopicPartition, Long> partitionOffsetMap) {
        Connection connection = getConnection();//获取数据库连接 自行实现
        boolean flag = false;
        try {
            //设置手动提交,让插入数据和更新offset信息在一个事务中完成
            connection.setAutoCommit(false);
            insertMessage(list);//将数据进行入库 自行实现
            updateOffset(partitionOffsetMap);//更新offset信息 自行实现
            connection.commit();
            flag = true;
        } catch (SQLException e) {
            try {
                //出现异常则回滚事务
                connection.rollback();
            } catch (SQLException e1) {
                //处理异常
            }
        }
        return flag;
    }
    //获取数据库连接 自行实现
    private Connection getConnection() {
        return null;
    }
    public void close() {
        isRunning = false;
        if (consumer != null) {
            consumer.close();
        }
    }
    private class HandleRebalance implements ConsumerRebalanceListener {
        @Override
        public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
            //发生Rebalance时,只需要将list中数据和记录offset信息清空即可
            //这里为什么要清除数据,应为在Rebalance的时候有可能还有一批缓存数据在内存中没有进行入库,
            //并且offset信息也没有更新,如果不清除,那么下一次还会重新poll一次这些数据,将会导致数据重复
            list.clear();
            partitionOffsetMap.clear();
        }
        @Override
        public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
            //获取对应Topic的分区数
            List<PartitionInfo> partitionInfos = consumer.partitionsFor(topicName);
            Map<TopicPartition, Long> partitionOffsetMapFromDB = getPartitionOffsetMapFromDB
                    (partitionInfos.size());
            //在分配分区时指定消费位置
            for (TopicPartition partition : partitions) {
                //如果在数据库中有对应partition的信息则使用,否则将默认从offset=0开始消费
                if (partitionOffsetMapFromDB.get(partition) != null) {
                    consumer.seek(partition, partitionOffsetMapFromDB.get(partition));
                } else {
                    consumer.seek(partition, 0L);
                }
            }
        }
    }
    /**
     * 从数据库中查询分区和offset信息
     * @param size 分区数量
     * @return 分区号和offset信息
     */
    private Map<TopicPartition, Long> getPartitionOffsetMapFromDB(int size) {
        Map<TopicPartition, Long> partitionOffsetMapFromDB = new HashMap<>();
        //从数据库中查询出对应信息
        Connection connection = getConnection();//获取数据库连接 自行实现
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        String querySql = "SELECT partition_num,offsets from kafka_info WHERE topic_group = ?";
        try {
            preparedStatement = connection.prepareStatement(querySql);
            preparedStatement.setString(1, topicNameAndGroupId);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                partitionOffsetMapFromDB.put(new TopicPartition(topicName, resultSet.getInt(1)),
                        resultSet.getLong(2));
            }
            //判断数据库是否存在所有的分区的信息,如果没有,则需要进行初始化
            if (partitionOffsetMapFromDB.size() < size) {
                connection.setAutoCommit(false);
                StringBuilder sqlBuilder = new StringBuilder();
                //partition分区号是从0开始,如果有10个分区,那么分区号就是0-9
                /*这里拼接插入数据 格式 INSERT INTO kafka_info(topic_group_partition,topic_group,partition_num) VALUES
                (topicNameAndGroupId_0,topicNameAndGroupId,0),(topicNameAndGroupId_1, topicNameAndGroupId,1)....*/
                for (int i = 0; i < size; i++) {
                    sqlBuilder.append("(").append
                            (topicNameAndGroupId).append("_").append(i).append(",").append
                            (topicNameAndGroupId).append(",").append(i).append("),");
                }
                //将最后一个逗号去掉加上分号结束
                sqlBuilder.deleteCharAt(sqlBuilder.length() - 1).append(";");
                preparedStatement = connection.prepareStatement("INSERT INTO kafa_info" +
                        "(topic_group_partition,topic_group,partition_num) VALUES " + sqlBuilder.toString());
                preparedStatement.execute();
                connection.commit();
            }
        } catch (SQLException e) {
            //处理异常 回滚事务 这里应该结束程序 排查错误
            try {
                connection.rollback();
            } catch (SQLException e1) {
                //打印日志 排查错误信息
            }
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                //处理异常 打印日志即可 关闭资源失败
            }
        }
        return partitionOffsetMapFromDB;
    }
}

数据对象

public class Message {
    private String id;
    private String name;
    private Syring desc;
    private Date time;
    //get set toString 方法省略
}

这种实现方式对于以下故障场景测试通过,虽然不能说所有故障场景均可以保证精确一次消费,但目前基本覆盖大部分故障场景

  • 一个消费者组中的某个消费者频繁加入组或离开组
  • 直接kill消费应用程序
  • 故障kafka集群中某个节点
  • 故障客户端网络,使其不能连接kafka server端
  • 直接重启应用程序所在虚拟机

总结

这里主要使用自己管理offset的方式来确保数据和offset信息是同时变化的,通过数据库事务的特性来保证一致性和原子性。

至少消费一次

  Kafka中由Consumer维护消费状态,当Consumer消费消息时,支持2种模式commit消费状态,分别为立即commit和周期commit。前者会导致性能低下,做到消息投递恰好一次;后者性能高,通常用于实际应用,但极端条件下无法保证消息不丢失。

问题分析
在这里插入图片描述
Consumer Thread读取一条消息,更新缓存消费状态,传入消息执行业务逻辑,同时有另外一个调度线程异步周期执行,从缓存中读取消费状态信息,持久化消费状态。假设Consumer Thread更新了缓存消费状态,Scheduler Thread在“执行业务逻辑”完成前就持久化消费状态,正在此时,Consumer失效或宕机了,这条消息就丢失了。

解决思路
在这里插入图片描述
等待“执行业务逻辑”成功完成后更新缓存消费状态,就可以保证消息不会丢失。具体做法:新增一个消费机制策略开关,此开关启动执行图2策略,关闭启动执行图1策略

import kafka.utils.{IteratorTemplate, Logging, Utils}
import java.util.concurrent.{TimeUnit, BlockingQueue}
import kafka.serializer.Decoder
import java.util.concurrent.atomic.AtomicReference
import kafka.message.{MessageAndOffset, MessageAndMetadata}
import kafka.common.{KafkaException, MessageSizeTooLargeException}
class ConsumerIterator[K, V](private val channel: BlockingQueue[FetchedDataChunk],
                             consumerTimeoutMs: Int,
                             private val keyDecoder: Decoder[K],
                             private val valueDecoder: Decoder[V],
                             val clientId: String, val consumerAtLeastOnceMessageEnabled: Boolean)
  extends IteratorTemplate[MessageAndMetadata[K, V]] with Logging {
  private var current: AtomicReference[Iterator[MessageAndOffset]] = new AtomicReference(null)
  private var currentTopicInfo: PartitionTopicInfo = null
  private var consumedOffset: Long = -1L
  private val consumerTopicStats = ConsumerTopicStatsRegistry.getConsumerTopicStat(clientId)
  override def next(): MessageAndMetadata[K, V] = {
    val item = super.next()
    if(consumedOffset < 0)
      throw new KafkaException("Offset returned by the message set is invalid %d".format(consumedOffset))
    if (consumerAtLeastOnceMessageEnabled)
      currentTopicInfo.resetConsumeOffset(consumedOffset)
    val topic = currentTopicInfo.topic
    trace("Setting %s consumed offset to %d".format(topic, consumedOffset))
    consumerTopicStats.getConsumerTopicStats(topic).messageRate.mark()
    consumerTopicStats.getConsumerAllTopicStats().messageRate.mark()
    item
  }
  protected def makeNext(): MessageAndMetadata[K, V] = {
    var currentDataChunk: FetchedDataChunk = null
    // if we don't have an iterator, get one
    var localCurrent = current.get()
    if(localCurrent == null || !localCurrent.hasNext) {
      if (consumerTimeoutMs < 0)
        currentDataChunk = channel.take
      else {
        currentDataChunk = channel.poll(consumerTimeoutMs, TimeUnit.MILLISECONDS)
        if (currentDataChunk == null) {
          // reset state to make the iterator re-iterable
          resetState()
          throw new ConsumerTimeoutException
        }
      }
      if(currentDataChunk eq ZookeeperConsumerConnector.shutdownCommand) {
        debug("Received the shutdown command")
        return allDone
      } else {
        currentTopicInfo = currentDataChunk.topicInfo
        val cdcFetchOffset = currentDataChunk.fetchOffset
        val ctiConsumeOffset = currentTopicInfo.getConsumeOffset
        if (ctiConsumeOffset < cdcFetchOffset) {
          error("consumed offset: %d doesn't match fetch offset: %d for %s;\n Consumer may lose data"
            .format(ctiConsumeOffset, cdcFetchOffset, currentTopicInfo))
          currentTopicInfo.resetConsumeOffset(cdcFetchOffset)
        }
        localCurrent = currentDataChunk.messages.iterator
        current.set(localCurrent)
      }
      // if we just updated the current chunk and it is empty that means the fetch size is too small!
      if(currentDataChunk.messages.validBytes == 0)
        throw new MessageSizeTooLargeException("Found a message larger than the maximum fetch size of this consumer on topic " +
                                               "%s partition %d at fetch offset %d. Increase the fetch size, or decrease the maximum message size the broker will allow."
                                               .format(currentDataChunk.topicInfo.topic, currentDataChunk.topicInfo.partitionId, currentDataChunk.fetchOffset))
    }
    var item = localCurrent.next()
    // reject the messages that have already been consumed
    while (item.offset < currentTopicInfo.getConsumeOffset && localCurrent.hasNext) {
      item = localCurrent.next()
    }
    consumedOffset = item.nextOffset
    item.message.ensureValid() // validate checksum of message to ensure it is valid
    new MessageAndMetadata(currentTopicInfo.topic, currentTopicInfo.partitionId, item.message, item.offset, keyDecoder, valueDecoder)
  }
  def clearCurrentChunk() {
    try {
      debug("Clearing the current data chunk for this consumer iterator")
      current.set(null)
    }
  }
  def resetConsumeOffset() {
    if (!consumerAtLeastOnceMessageEnabled)
      currentTopicInfo.resetConsumeOffset(consumedOffset)
  }
}
class ConsumerTimeoutException() extends RuntimeException()

【kafka系列】At Least Once语义 通过合理配置和业务设计,At-Least-Once可平衡可靠性与性能,是大多数场景的推荐选择。若Broker写入成功但网络超时,生产者重试会导致消息重复发送到Topic。失败(如消费者崩溃),下次启动时会重新拉取并处理同一消息,导致积分重复增加。复杂(需生产者、Broker、消费者协同)允许重复的业务(如日志采集)高(事务与协调开销) 阅读详情

相关推荐

流处理平台Kafka--消息队列

1 Kafka是什么 Kafka是一个基于ZooKeeper协调的流处理平台,它由Scala和Java开发,可以实时处理大量数据,并且可以方便的扩展。Kafka由LinkedIn开发,并由LinkedIn在2010年贡献给Apache基金会,成为顶级开源项目。这篇文章主要是一些关于其核心组件消息队列的内容。 2 Kafka的特性 持久化:Kafka的消息实时持久化,允许数据在不同的broker上做备份,提高了安全性,并且不会因为消息已消费而被删除。 高吞吐量:Kafka每秒可以处理数十万条消息。 可扩展:

m0_50753725的博客 661

Kafka核心原理之精准一次性投递

在Kafka中,精准一次性投递(Exactly Once)=至少投递一次(At Least Once)+幂等性。至少投递一次(At Least Once):将生产端参数acks设置为-1(all),可以保证生产端发送到Broker的消息不会丢失,即:至少投递一次(At Least Once)。

南秋同学的博客 2352

Kafka 消息 Deliver guarantee

Kafka 消息有以下三种delivery guarantee: At most once 消息可能会丢,但绝不会重复传输 At least one 消息绝不会丢,但可能会重复传输 Exactly once 每条消息肯定会被传输一次且仅传输一次,很多时候这是用户所想要的。       Producer到Broker的delivery guarantee semantic非常直接。当producer向

Kuzury 1093

Kafka之精确一次处理语义

文章目录精确一次处理语义幂等性实现原理 精确一次处理语义 消息处理语义 最多一次(at most once):消息可能丢失也可能被处理,但最多只会处理一次 至少一次(at least once):消息不会丢失,但可能被处理多次 精确一次(exactly once):消息被处理且只会被处理一次 producer: 在0.11.0.0之前,kafka producer默认提供至少一次...

jannal专栏 1407

flink实战--flink整合kafka (kafka source 与 kafka sink)

简介 Flink提供的Kafka连接器,用于向Kafka主题读取或写入数据。Flink Kafka Consumer集成了Flink的检查点机制,可提供一次性处理语义。为实现这一目标,Flink并不完全依赖kafka的消费者群体偏移跟踪,而是在内部跟踪和检查这些偏移。 Maven 依赖 支持到的版本 生产者和消费者类的名成 Kafka version ...

阿华田的博客 1万+

基于立创EDA的8口全千兆POE交换机设计详解:RTL8370N芯片与90W大功率供电方案

本文详细解析了基于立创EDA设计的8口全千兆POE交换机方案,核心采用RTL8370N交换芯片与支持90W大功率供电的IEEE 802.3bt标准PD芯片。文章深入探讨了PSE/PD供电管理、电源架构设计、电路细节及关键散热方案,为DIY或学习POE交换机硬件设计提供了完整的开源实践指南。

weixin_29050829的博客 1万+

Kafka Consumer位移提交机制详解:从原理到实战,避免重复消费与消息丢失

在分布式消息系统中,消费语义是保障数据一致性的核心概念,它定义了消息被处理的次数边界。其实现原理依赖于消费者位移管理机制,即通过记录消费进度来控制消息的投递与确认。这一机制的技术价值在于平衡系统吞吐量与数据可靠性,确保在故障场景下仍能维持预期的数据处理行为。常见的应用场景包括订单处理、实时监控和金融交易等对数据准确性要求较高的领域。本文聚焦于Kafka Consumer的位移提交策略,深入剖析自动提交的潜在风险与手动提交的精细控制,并结合重复消费和消息丢失等典型问题,提供实战解决方案与参数调优指南,帮助开发

weixin_34292402的博客 287

使用再生龙还原镜像文件到硬盘

1. 把制作好的再生龙光盘插入需要的电脑,开机按F4使用再生龙启动2. 选择默认的:Clonezailla live(Default settings,VGA 800*600),然后等待几分钟 3. 选择语言:简体中文 4. 选择不修改键盘映射 5. 选择使用再生龙          6. 选择硬盘/分区(存到/来自)镜像文件,此选项既可以制作镜像,也可以恢复镜像。 7. 使用本机的分区     ...

weixin_42168893的博客 1万+

kafka--基础知识点--16--最多一次、至少一次、精确一次

个人理解,仅供参考。一个消息的传递可以分两个过程,a) producer发送消息到 broker,b) consumer从broker读消息并发送。

Chasing__Dreams的博客 1360

【数据库】SQL Server 2008 R2 安装全流程详解与常见问题避坑指南

本文详细解析了SQL Server 2008 R2的完整安装流程与核心配置。从安装前的系统兼容性检查、.NET Framework依赖准备,到图文详解实例配置、混合身份验证模式设置等关键步骤,并提供了安装失败、服务无法启动等高频问题的排查与避坑指南,帮助用户顺利完成部署。

java5的博客 1242

音频质量评估指标全解析:从主观到客观的全面指南

本文全面解析了音频质量评估的核心指标,涵盖主观评价(如MOS、DMOS)与客观评价(如PESQ、STOI、SDR)。重点介绍了DNSMOS等AI驱动的无参考评估方法,并提供了根据语音通信、噪声抑制、语音分离等不同场景选择指标组合的实战指南,帮助开发者和研究者科学量化音频质量。

rum55的博客 644

简单理解 Kafka 的消息可靠性策略

如果要回答如何在 broker 之间保证存储的消息和状态不会丢失,就要回答 broker 之间的各个 replica 的消息状态一致性如何解决,包括 producer 已经提交了哪些消息,哪些消息已经落地,哪些消息在节点故障后不会丢失。Follower 带着自己的 HW(0)&LEO(1) 去请求 leader .此时 leader 的 HW 更新为 1,leader 保存的 follower 的 LEO 更新为 1,带着 leader 的 HW(1)&LEO(1)返回自身,更新自己的 HW&LEO。

qq_40875747的博客 312

DeepSeek Harness 工程实践与高级特性:从测试到安全的完整指南

AI Agent 能执行命令、读写文件、自主决策,能力越强风险越大——删文件、泄密钥、死循环、竞态条件随时可能发生。本文是 DeepSeek Harness 系列第三篇,深入剖析其工程实践与高级特性:从单元测试到真实 API 冒烟测试的分层策略,拒绝 Mock 依赖、坚持"验证世界而非自我报告";从正交结果、规范化契约到 Dispose 静止的防御式编程铁律;以及跨平台多层进程沙箱、文件系统版本守卫、fail-closed 审批机制、模型编写的工作流引擎与上下文压缩等高级能力。

program哲学 207

Kafka全套学习知识手册

Apache Kafka是一款分布式实时流式事件平台,兼具消息收发、数据流传输、事件存储和流式计算调度能力,适用于日志采集、用户行为埋点、数据库同步等高吞吐场景。其核心优势包括超高吞吐(依托顺序写、零拷贝等技术)、高可用(多副本机制)、数据可回溯和强大生态兼容性。 文档系统梳理了Kafka知识体系: 基础认知:核心概念(Topic/Partition/ISR等)、应用场景、优缺点分析 架构原理:生产者发送流程、消费者Rebalance机制、副本同步与HW水位线 高阶特性:幂等生产者、事务实现、延迟队列解决方

专注 Java 后端开发,分享基础语法、JVM、并发、Spring 全家桶、微服务、分布式、性能优化等实战干货。坚持输出高质量技术笔记,用简单语言讲清复杂原理,助力每一位 Java 开发者稳步进阶。 646

故障诊断 | 小波变换机械设备外圈振动信号故障诊断

故障诊断 | 小波变换机械设备外圈振动信号故障诊断

天天酷科研的博客 506

【保姆级教程】YOLOv8_OBB旋转目标检测:训练自己的数据集

【保姆级教程】YOLOv8_OBB旋转目标检测:训练自己的数据集

m0_51579041的博客 1万+

Kafka - 消息投递语义:At-Least-Once、At-Most-Once、Exactly-Once实现

Kafka消息投递语义解析 本文深入探讨Kafka的三种消息投递语义:At-Most-Once(至多一次)、At-Least-Once(至少一次)和Exactly-Once(恰好一次)。通过对比分析三种语义的特点、实现原理及适用场景,帮助开发者构建可靠的数据管道。 核心要点 At-Most-Once:速度优先,可能丢失消息但不会重复 实现方式:Producer设置acks=0,Consumer预提交偏移量 适用场景:可容忍丢失的日志收集和监控数据 At-Least-Once:可靠性优先,保证不丢失但可能重复

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

深度学习-176-知识图谱技术之langchain与neo4j的嵌入向量Neo4jVector

使用Neo4jVector将输入的文档向量化,并创建向量索引,然后进行语义检索。

qq_20466211的博客 440

Kafka Consumer

Consumer消费数据时的可靠性是很容易保证的,因为数据在Kafka中是持久化的,故不用担心数据丢失问题。 由于consumer在消费过程中可能会出现断电宕机等故障,consumer恢复后,需要从故障前的位置的继续消费,所以consumer需要实时记录自己消费到了哪个offset,以便故障恢复后继续消费。 所以offset的维护是Consumer消费数据是必须考虑的问题 <dependency> <groupId>org.apache.kafka</groupId> &

1345

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

kafka保证消息不丢失 / exactly once / rocketmq事务消息

kafka保证消息不丢失

JaweG 867

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Kafka中的消息传递保证语义

http://cxy7.com/articles/2018/06/12/1528812656788.html 目录 Kafka提供的消息传递保证语义 Producer的消息传递语义 at-least-once传递语义 exactly-once传递语义 request.required.acks持久性级别 Consumer的offset记录方式 记录offset的位置 提交o...

z69183787的专栏 1582

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Kafka

Kafka 分布式流处理平台摘要 Kafka 是一个高性能的分布式流处理平台,核心架构由 Producer、Broker、Consumer 组成,通过分区(Partition)和副本(Replica)机制实现高吞吐和高可用。Producer 按 Topic 分区发送消息,Broker 集群采用去中心化设计,Consumer Group 实现并行消费。Kafka 通过顺序写磁盘、零拷贝和批量发送等技术保证高性能,并采用多副本、ACK 确认和 ISR 机制确保消息可靠性。对于数据倾斜问题,Kafka 主要通过分

qq_41893505的博客 1726

kafka发送消息服务器宕机,Kafka之消息传输

问题研究:研究Kafka consumer和broker之间的数据传输方式?Kafka是如何保证可靠性?消费机制是consumer pull还是broker push?, 如果是push的话,kafka是否知道数据传输成功0.写在前面昨天整理完Kafka之数据存储之后,今天决定再把笔记中kafka消息传输部分整理一下,逐步去完善kafka系列的博文。本文中讲述的kafka是0.8.1版,目前最新版...

weixin_28678517的博客 972

Kafka史上最详细原理总结

本文深入解析了Apache Kafka的核心架构与设计思想。作为分布式消息系统,Kafka具有高吞吐、低延迟、可扩展等特性,其核心设计包括:1)基于Partition的消息分区机制,支持水平扩展;2)多副本机制保障数据可靠性;3)高效的文件存储设计,通过顺序读写和稀疏索引实现高性能;4)灵活的生产者-消费者模型,支持多种消息传递语义。文章详细阐述了Topic与Partition的组织方式、消息查找机制、副本同步策略等关键技术点,并分析了Kafka在可靠性、负载均衡等方面的设计考量。

ywl470812087的博客 12万+

Kafka学习笔记 - 03: 消息与同步机制

Producer 根据指定的 partition 方法(默认round-robin、hash等),将消息发布到指定 topic 的 partition 里面;kafka 集群接收到Producer 发过来的消息后,将其持久化到硬盘,并保留消息指定时长(可配置),而不关注消息是否被消费;Consumer 从 Kafka集群 pull 数据,并控制获取消息的 offset。 下面讨论以下 Kafka ...

u011682283的博客 410
上一篇: BIO和NIO | Reactor
下一篇: 单线程Redis高性能原因
K. Bob
博客等级 码龄8年 82粉丝 294原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值