kafka

kafka架构

消息不丢、 不重复、顺序

重复发送,数据落地,确认信号

不丢消息
1 生产者
2 服务器
3 消费者
生产者的正确的消息发送方式
Kafka为生产者生产消息提供了一个 send(msg) 方法,
另有一个重载的方法send(msg, callback),

send(msg)

该方法可以将一条消息发送出去,
但是对发送出去的消息没有掌控能力,
无法得知其最后是不是到达了Kafka,
所以这是一种不可靠的发送方式,
但是也因为客户端只需要负责发送,
所以具有较好的性能。

Future<RecordMetadata> future = producer.send(record)

上面的示例代码也可以看到,send返回的是一个 Future,
也就是说其实你是可以 Future.get()获取返回值的,
但这种同步的方式,基本上可以说是不会用到。

send(msg, callback)

该方法可以将一条消息发送出去,
并且可以从callback回调中得到该条消息的发送结果,
并且callback是异步回调,
所以在兼具性能的情况下,
也对消息具有比较好的掌控。

 ProducerRecord<byte[],byte[]> record = new ProducerRecord<byte[],byte[]>("the-topic", key, value);
 producer.send(myRecord,
           new Callback() {
               public void onCompletion(RecordMetadata metadata, Exception e) {
                   if(e != null) {
                      e.printStackTrace();
                   } else {
                      System.out.println("The offset of the record we just sent is: " + metadata.offset());
                   }
               }
           });

综上,如果要使数据不丢失,
首先你就的使用 send(msg, callback)来发送消息,
绝大多数情况下,我也建议你这么做。

生产者的配置
当我们通过 send(msg, callback) 是不是就意味着消息一定不丢失了呢?
答案明显是:不是的
我们接着上面,
send(msg, callback)里面 callback返回的成功,
到底是不是真的确保消息万无一失了?
其实这个返回的成功也是可以在生产者配置的:

 Properties props = new Properties();
 props.put("bootstrap.servers", "localhost:9092");
//*******重点*****************
 props.put("acks", "all");
 props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
 props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

 Producer<String, String> producer = new KafkaProducer<>(props);
 for (int i = 0; i < 100; i++)
     producer.send(new ProducerRecord<String, String>("my-topic", Integer.toString(i), Integer.toString(i)));
 producer.close();

这段代码是生产者发送消息的一个例子,
其中没使用callback主要是这里callback不是重点,
我们的重点是props.put(“acks”, “all”);
这个acks配置属性就是我们callback成功的具体含义:

acks=0
acks = 0如果设置为零,那么生产者将完全不会管服务器是否收到消息。
该记录将立即添加到套接字缓冲区中并视为已发送。
并且重试配置不会生效(因为客户端通常不会知道任何故障)。
返回值的偏移量将始终等于 -1。
该方式具有最大的吞吐量,
一般建议直接配合 send(msg)使用。

acks=1
当leader接受到消息就会直接给客户端返回成功,
一般情况下这种模式都能很好的保证数据的不丢失,
只有在laeder接受到数据,
然后还没来得及同步到follower,
就挂掉了才会导致数据的丢失,
这种概率还是比较小的。
这也是默认的选择方式,
兼具较好的吞吐和较高的可靠性

acks=all 或者 acks=-1
当leader接受到消息,并同步到了一定数量的follower,
才向生产者发生成功的消息,
同步到的follower数量由 broker 端的 min.insync.replicas 决定
除非一些不可抗力因素,
这种方式基本可以确保数据的完全不丢失。

Broker 端的配置
其实到这里,生产者端基本已经做好了数据不丢失的大部分准备,
但是有些东西是要配合 Broker 端一起,
才能达到预期的不丢失数据的,
比如我们上面说到的

min.insync.replicas 配置
我们上面知道了,
当 生产者 acks = -1 的时候,
写入的副本数就必须 >= min.insync.replicas 数,
当达不到这个要求的时候,
生产者端会收到一个either NotEnoughReplicas or NotEnoughReplicasAfterAppend的异常。
所以我们这个参数必须不能大于 replication.factor 副本数。
否则生产者将无法写入任何数据,
一般建议 replication.factor 数要大于 min.insync.replicas,
比如3个机器的集群,设置 replication.factor = 3,
那么设置 min.insync.replicas = 2 就可以了,
这样既保证了数据写入的时候有一个副本的冗余,
也能保证在一些情况下,
某台Broker宕机导致数据无法达到3个副本时,
依然可以正常写入数据。

unclean.leader.election.enable
这里 Broker 端还有一个重要的配置就是 unclean.leader.election.enable = false
这个配置代表着一些数据落后比较多的 follower,
是否能在leader宕机后被选举成新的 leader
如果你设置成 true,
很明显,如果这样的follower成为新leader,
就会造成最新的一部分数据丢失掉,

重试 retries
上面已经基本完成了不丢数据的方方面面了,
但是有些东西不是我们能控制的,
比如 网络抖动 等不可抗拒的因素,
这时候重试次数就很关键了,
配置合适的retries重试次数,
和 合适的retry.backoff.ms重试间隔时间,
将为我们的数据发送提供更高的稳定性,
当然如果实在发送不成功,怎么办呢?
一般我们也可以把发送不成功的数据保存在一个日志文件,
如果数据很重要,那就发送警告信息,
人工干预一下。

作者:code_solve
链接:https://www.jianshu.com/p/68c173e4c549
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Kafka如何保证数据不丢失
1.生产者数据的不丢失
kafka的ack机制:在kafka发送数据的时候,每次发送消息都会有一个确认反馈机制,确保消息正常的能够被收到,其中状态有0,1,-1。

如果是同步模式:ack机制能够保证数据的不丢失,如果ack设置为0,风险很大,一般不建议设置为0。即使设置为1,也会随着leader宕机丢失数据。
producer.type=sync
request.required.acks=1
如果是异步模式:也会考虑ack的状态,除此之外,异步模式下的有个buffer,通过buffer来进行控制数据的发送,有两个值来进行控制,时间阈值与消息的数量阈值,如果buffer满了数据还没有发送出去,有个选项是配置是否立即清空buffer。可以设置为-1,永久阻塞,也就数据不再生产。
异步模式下,即使设置为-1。也可能因为程序员的不科学操作,操作数据丢失,比如kill -9,但这是特别的例外情况。
producer.type=async
request.required.acks=1
queue.buffering.max.ms=5000
queue.buffering.max.messages=10000
queue.enqueue.timeout.ms = -1
batch.num.messages=200
结论:producer有丢数据的可能,但是可以通过配置保证消息的不丢失。

2.消费者数据的不丢失
通过offset commit 来保证数据的不丢失,kafka自己记录了每次消费的offset数值,下次继续消费的时候,会接着上次的offset进行消费。

而offset的信息在kafka0.8版本之前保存在zookeeper中,在0.8版本之后保存到topic中,即使消费者在运行过程中挂掉了,再次启动的时候会找到offset的值,找到之前消费消息的位置,接着消费,由于offset的信息写入的时候并不是每条消息消费完成后都写入的,所以这种情况有可能会造成重复消费,但是不会丢失消息。

唯一例外的情况是,我们在程序中给原本做不同功能的两个consumer组设置KafkaSpoutConfig.bulider.setGroupid的时候设置成了一样的groupid,这种情况会导致这两个组共享同一份数据,就会产生组A消费partition1,partition2中的消息,组B消费partition3的消息,这样每个组消费的消息都会丢失,都是不完整的。 为了保证每个组都独享一份消息数据,groupid一定不要重复才行。

2.kafka集群中的broker的数据不丢失
每个broker中的partition我们一般都会设置有replication(副本)的个数,生产者写入的时候首先根据分发策略(有partition按partition,有key按key,都没有轮询)写入到leader中,follower(副本)再跟leader同步数据,这样有了备份,也可以保证消息数据的不丢失。
————————————————
版权声明:本文为CSDN博主「上方谷的雨」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sillyzhangye/article/details/86181345

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值