系统间通知要求是要保证消息不丢失,那么作为生产者怎样保证消息能安全的发送到kafka集群上。
一、kafka消息确认机制
侧重于消息到达kafka集群的情况。
kafka有一个参数:“request.required.acks”。这个参数觉得了kafka消息确认机制。
properties.put(“request.required.acks”, “1”);
acks=0,Kafka Producer只要把消息发送出去,不管那条数据有没有是否落到Partition Leader磁盘上,只要消息发出去就认为这个消息发送成功了。
acks=1,只要Partition Leader接收到消息而且写入本地磁盘了,就认为成功了,不管他其他的Follower有没有同步过去这条消息了。
acks=all/-1,意思就是说Partition Leader接收到消息之后,还必须要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步过去,才能认为这条消息是写入成功了。
二、kafka发送方式
上面的消息确认机制是确定消息发送到某种程度,对于一些特定场景,需要producer生产者考虑发送失败等异常下,如何去处理?
主要有三种发送方式:
2.1、发送即忘记
不关心消息是否正常到达,对返回结果不做任何判断处理。这种方式虽然吞吐量高,但无法保证消息的可靠性。
public synchronized void send(Object obj) {
try {
// 发送对象转JSON
String message = JSON.toJSONString(obj);
// 随机发送到各个节点分区
String key = getNumPartitions();
// 发送消息到消息中介,kafka_topic指定要接受消息的主题
KeyedMessage<String, String> data = new KeyedMessage<String, String>(getTopic(), key, message);
//执行发送
getProducer().send(data);
} catch (Exception e) {
}
}
2.2、同步发送
通过get方式等待kafka响应,判断消息是否成功。
-------以同步方式发送消息,每条消息发送的返回结果进行判断,是同步阻塞方式,只有返回了才能继续下一条消息发送。
public synchronized void sendV2(Object obj) {
String message = JSON.toJSONString(obj); // 发送对象转JSON
String key = getNumPartitions();// 随机发送到各个节点分区
//执行发送
ProducerRecord<String,String> data = new ProducerRecord<String,String>(getTopic(),
key,message);
RecordMetadata metadata =null;
try {
metadata = getKafkaProducer().send(data).get();
} catch (Exception e) {
}
if(null!=metadata){
System.out.println("同步发送后获得分区为 :" + metadata.partition() + " ,同步发送后获得offset为 :" + metadata.offset());
}
}
2.3、异步发送+回调函数
消息以异步方式发送,通过回调函数返回消息来确定发送成功或失败。
--------在调用send方式发送消息时,指定一个回调函数,服务器在返回响应时会调用回调函数,通过回调能够对异常情况进行处理,只有回调函数执行完毕,生产者才会结束,否则一直阻塞。
public synchronized void sendV3(Object obj) {
try {
String message = JSON.toJSONString(obj); // 发送对象转JSON
String key = getNumPartitions();// 随机发送到各个节点分区
//执行发送
ProducerRecord<String,String> data = new ProducerRecord<String,String>(getTopic(),
key,message);
getKafkaProducer().send(data, new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (recordMetadata != null) {
//异步发送,record真正发送成功后才会执行该方法,所以可以在该方法里面获取到metadata
System.out.println("异步发送后获得分区为 :" + recordMetadata.partition() + " ,同步发送后获得offset为 :" + recordMetadata.offset());
}
}
});
} catch (Exception e) {
}
}
三、kafka发送方式场景
如果业务要求消息必须是按顺序发送的,那么可以使用同步发送方式,并且只能在一个partation上,结合参数设置retries的值让发送失败时重试,设置max_in_flight_requests_per_connection=1,可以控制生产者在收到服务器晌应之前只能发送1个消息,从而控制消息顺序发送。
如果业务只关心消息的吞吐量,容许少量消息发送失败,也不关注消息的发送顺序,那么可以使用发送并忘记方式,并配合参数acks=0,这样生产者不需要等待服务器的响应,以网络能支持的最大速度发送消息。
如果业务需要知道消息发送是否成功,并且对消息的顺序不关心,那么可以异步发送+回调函数方式来发送消息,并将发送失败的消息记录到日志文件中。