前提auto.offset.reset=smallest,这样能保证每条消息都at least once,至少一次。否则offset取最大时,会导致有些消息因为offset已经跳过而取不到。
zookeeper中没有初始化的offset时,如果offset是以下值的回应:
smallest:自动复位offset为smallest的offset
largest:自动复位offset为largest的offset
anything else:向consumer抛出异常
目前定时提交offset的开关是打开的,每分钟提交一次。
有两种异常情况
1、offset提交时挂掉,会引起重复取消息
2、消息fetch后,消息处理的过程中,offset已经被定时提交,而此时消息处理时有异常(或者交易系统挂掉),这条消息就会丢失掉。
auto.commit.enable=false时,
1、手动提交也会有异常的时候,消息还是会重复;但是不会有消息丢失的情况。
蒋为处理方法:
1、防止丢消息:取消息时把topic、partition、offset信息落地到一张表中。消息处理完成后,删除表中的信息。
如果有没有处理完的消息,则利用低版本的consumer去消费指定offset的消息。
缺点:数据库异常的话,没有办法处理。
(但调用的是异步接口,直接发到支付平台kafka,所以支付平台保存不了请求消息)
2、重复消费消息:接口中做幂等处理。
Pascore处理方法
1、防止丢消息(有些消息取不到):(可能有问题)
public synchronizedOrderMessageDTO fetchMessage()throws NoMessageException{
OrderMessageDTOmsgDTO=null;
if(recoveryOrders.size()==0){
//-------------获取消息
byte[]message = getMessage();
//------------解释消息
msgDTO=parseMssage(message);
if(msgDTO==null){
returnnull;
}
msgDTO.setOffset(offset);
msgDTO.setTopic(topic);
msgDTO.setPartition(partition);
//取出消息后应该马上更新消息状态
orderRecord.updateMsgStatus(msgDTO.getId(),OrderMsgStatus.FETCH_FROM_MQ,msgDTO.getOffset());
recoveryOrders.add(msgDTO);
}
//恢复数据处理
Stringkey=topic+"-"+partition;
LongprocOffset=topicPartitionMap.get(key);
topicPartitionMap.put(key,offset);
if(procOffset==null){
logger.info("First processmessage:"+key+"-"+offset+" and need recovery data for avoidlose message!");
Calendar cal=Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.MINUTE,(-1)*config.getRecoveryMinutes());
List<OrderMessageDTO> recoveryList =orderRecord.getRecoveryOrder(topic, partition, offset,recoveryStatus,cal.getTime(), new Date());
if(recoveryList!=null&&recoveryList.size()>0){
logger.info("recovery datasize:"+recoveryList.size());
recoveryOrders.addAll(0, recoveryList);
}
}
returnrecoveryOrders.remove(0);
}
2、重复消费消息:取消息后先检查mongodb中消息的状态,如果已经是处理过状态,则不重复消费;
Kafka 对比 ActiveMQ
Kafka是LinkedIn开发的一个高性能、分布式的消息系统,广泛用于日志收集、流式数据处理、在线和离线消息分发等场景。虽然不是作为传统的MQ来设计,在大部分情况,Kafaka也可以代替原先ActiveMQ 等传统的消息系统。
Kafka 将消息流按Topic组织,保存消息的服务器称为Broker,消费者可以订阅一个或者多个Topic。为了均衡负载,一个Topic的消息又可以划分到多个分区(Partition),分区越多,Kafka并行能力和吞吐量越高。
Kafka集群需要zookeeper 支持来实现集群,最新的kafka 发行包中已经包含了zookeeper,部署的时候可以在一台服务器上同时启动一个zookeeperServer 和 一个Kafka Server,也可以使用已有的其他zookeeper集群。
和传统的MQ不同,消费者需要自己保留一个offset,从kafka获取消息时,只拉去当前offset 以后的消息。Kafka 的scala/java 版的client 已经实现了这部分的逻辑,将offset保存到zookeeper 上。每个消费者可以选择一个id,同样id 的消费者对于同一条消息只会收到一次。一个Topic的消费者如果都使用相同的id,就是传统的 Queue;如果每个消费者都使用不同的id, 就是传统的pub-sub.
如果在MQ的场景下,将Kafka和 ActiveMQ 相比:
Kafka 的优点
分布式可高可扩展。Kafka集群可以透明的扩展,增加新的服务器进集群。
高性能。Kafka的性能大大超过传统的ActiveMQ、RabbitMQ等MQ 实现,尤其是Kafka 还支持batch 操作。下图是linkedin 的消费者性能压测结果:
容错。Kafka每个Partition的数据都会复制到几台服务器上。当某个Broker故障失效时,ZooKeeper服务将通知生产者和消费者,生产者和消费者转而使用其它Broker。
Kafka 的不利
重复消息。Kafka只保证每个消息至少会送达一次,虽然几率很小,但一条消息有可能会被送达多次。
消息乱序。虽然一个Partition内部的消息是保证有序的,但是如果一个Topic 有多个Partition,Partition 之间的消息送达不保证有序。
复杂性。Kafka需要zookeeper集群的支持,Topic通常需要人工来创建,部署和维护较一般消息队列成本更高
查看topic的命令:。
./kafka-topics.sh-z 109 2181 -describe > /tmp/test20160320
6、./kafka-consumer-offset-checker.sh--zookeeper 102181 --group Order --topic -rder-topic