一、消息发送方式
发送消息主要有三种模式:发后即忘、同步、异步。
发后即忘: 它只管往Kafka中发送消息而并不关心消息是否正确到达。大多是情况下,这种方式没有问题,但是有些时候出现异常,会造成消息丢失。这种发送方式,性能很高,但是可靠性最差。
同步发送:
同步发送的方式,可靠性高。要么消息发送成功,要么发生异常,如果发生异常,则可以捕获异常并进行相应的处理,不会造成消息丢失。不过同步发送方式,性能会差很多,需要阻塞等待一条消息发送完之后才能发送下一条。
异步发送:
一般是在send()方法里指定一个Callback的回调函数。Kafka在返回响应时调用该函数来实现异步的发送确认。有人疑问,send()方法返回的本来就是Future类型,而Future本身就可以用作异步的逻辑处理,这样做不是不行,只不过Future里的get()方法在何时调用,以及怎么调用都是需要面对的问题,消息不停地发送,那么诸多消息对应的Future对象的处理难免会引起代码处理逻辑的混乱,使用Callback的回调函数,就比较简单明了。
二、序列化
生产者需要使用序列化器把对象转换成字节数组才能通过网络发送给Kafka。而在对侧,消费者需要使用反序列化器,把从Kafka中收到的字节数组转换成相应的对象。生产者和消费者使用的序列化器需要一一对应。
三、分区器
消息在通过send方法发送到broker的过程中,有可能需要经过拦截器、序列化器、还有分区器的一系列作用之后才能被真正的发送到broker。拦截器一般不是必须得,但是序列化器是必须得。 如果发送之前,指定了partition字段,那么就不需要分区器的作用,因为partition字段代表的就是所要发往的分区号。如果没有指定partition字段,那么就需要依赖分区器,根据key这个字段来计算partition的值。分区器的作用就是为消息分配分区。
在默认分区器中,如果key字段不为null,那么默认的分区器会对key进行哈希(采用MurmurHash2算法,具备高运算性能以及低碰撞率),最终根据得到的哈希值来计算分区号,拥有相同key的消息会被写入同一个分区,最终可以达到同一个topic,相同业务字段的有序性。如果key为null,那么消息将会以轮训的方式发送主题内的各个可用分区。
四、重要的生产者参数
acks=1:默认值即为1。生产者只要发送消息后,只要分区的leader副本成功消息,那么它就会收到来自服务端的成功响应。如果消息在写入leader副本并返回成功给生产者,且在被其他follower副本拉取之前,leader副本崩溃,那么此时消息还是会丢失,因为新选举的leader副本中并没有这条对应的消息。
acks=0:生产者发送消息之后不需要等待任何的服务端的响应,
acks=-1或acks=null:生产者发送消息之后,需要等待ISR中的所有副本都成功写入消息之后才能收到来自于服务器的成功响应。可以达到最强的可靠性,但是不是消息一定可靠,因为ISR中可能只有leader副本,这样就退化成了acks=1的情况。要活得更好的可靠性,需要配合min.insync.replicas等参数的联动。