1、producer使用同步发送方式发送消息。
同步发送方式再消息发送失败时支持自动重试,相关参数可以再
//如果消息发送失败,最大重试次数,该参数只对同步发送模式起作用,默认为2
producer.setRetryTimesWhenSendAsyncFailed(2);
//发送消息超时时间,单位毫秒,模式10秒中
producer.setSendMsgTimeout(10000);
//同步发送消息
SendResult sendResult = producer.send(msg);
以上策略也是在一定程度上保证了消息可以发送成功。如遇到rocket宕机、断网等原因消息还是会丢失的。
当超过消息超时时间还未发送成功时,send方法会抛出异常。此时则尝试将消息存储到db,然后由后台线程定时重试,确保消息一定到达Broker。
try {
SendResult sendResult = producer.send(msg);
}catch (Exception e){
//持久化到DB
}
2、Broker的flushDiskType设置为SYNC_FLUSH
producer.send(msg);执行成功说明消息发送成功
borker将消息写入磁盘分为同步和异步两种方式
同步刷盘:直接写入commitLog文件
异步刷盘:先写入内存,一定时间间隔统一写入commitLog,如果服务器宕机会导致内存中的数据丢失
broker默认为异步刷盘,所以要保证消息不丢失,要讲Broker的刷盘设置为同步刷盘
修改FlushDiskType参数
flushDiskType=SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH 异步刷盘
3、master_broker的brokerRole设置为SYNC_MASTER
broker主从间的数据同步也分为同步和异步两种
异步方式,当消息写入主broker,但是还未同步给从broker,此时主broker宕机了,那么消息也会丢失
brokerRole=SYNC_MASTER 同步
brokerRole=AYNC_MASTER 异步
4、同步发送返回SendResult说明
send消息方法只要不抛异常,就代表发送成功。发送成功会有多个状态,在sendResult里定义。以下对每个状态进行说明:
SEND_OK
消息发送成功。要注意的是消息发送成功也不意味着它是可靠的。要确保不会丢失任何消息,还应启用同步Master服务器或同步刷盘,即SYNC_MASTER或SYNC_FLUSH。
FLUSH_DISK_TIMEOUT
消息发送成功但是服务器刷盘超时。此时消息已经进入服务器队列(内存),只有服务器宕机,消息才会丢失。消息存储配置参数中可以设置刷盘方式和同步刷盘时间长度,如果Broker服务器设置了刷盘方式为同步刷盘,即FlushDiskType=SYNC_FLUSH(默认为异步刷盘方式),当Broker服务器未在同步刷盘时间内(默认为5s)完成刷盘,则将返回该状态——刷盘超时。
FLUSH_SLAVE_TIMEOUT
消息发送成功,但是服务器同步到Slave时超时。此时消息已经进入服务器队列,只有服务器宕机,消息才会丢失。如果Broker服务器的角色是同步Master,即SYNC_MASTER(默认是异步Master即ASYNC_MASTER),并且从Broker服务器未在同步刷盘时间(默认为5秒)内完成与主服务器的同步,则将返回该状态——数据同步到Slave服务器超时。
SLAVE_NOT_AVAILABLE
消息发送成功,但是此时Slave不可用。如果Broker服务器的角色是同步Master,即SYNC_MASTER(默认是异步Master服务器即ASYNC_MASTER),但没有配置slave Broker服务器,则将返回该状态——无Slave服务器可用。
5、消费者consumer手动offset + 自动故障转移
消费者代码
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
try {
//业务处理,省略。。。
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}catch (Exception e){
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
}
});
只有本地业务正确处理完毕后才返回CONSUME_SUCCESS,否则返回RECONSUME_LATER
如果未返回CONSUME_SUCCESS也未返回RECONSUME_LATER时,Broker会将消息发送给其他consumer处理
注意不要再代码中对消息进行异步处理,返回CONSUME_SUCCESS后broker就认为消息被处理成功了 此时线程中处理方法报错或consumer宕机了,就会造成消息丢失。例如
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
new Thread(new Runnable() {
@Override
public void run() {
//业务逻辑
}
});
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});