Kafka队列的基本介绍

主要使用场景

阿里内部MetaQ 强化了消息堆积能力,用JAVA重写了kafka。

相关概念

  • 在Kafka文件存储中,同一个topic下有多个不同partition,每个partition为一个目录,partiton命名规则为topic名称+有序序号,第一个partiton序号从0开始,序号最大值为partitions数量减1。 想kafka发送消息时,可以通过制定key发送到制定partition上,否则随机分配。每个partition至多被一个consumer消费。这省去了加锁同步带来的性能问题。每个consumer可以订阅指定分区,也可以由协调者分配一个分区。

  • 各个consumer(consumer 线程)可以组成一个组(Consumer group ),partition中的每个message只能被组(Consumer group )中的一个consumer(consumer 线程)消费,如果一个message可以被多个consumer(consumer 线程)消费的话,那么这些consumer必须在不同的组。

  • 队列中的消息如果只有一份,显然不符合高可用性。引入Replication之后,同一个Partition可能会有多个Replica,而这时需要在这些Replication之间选出一个Leader,Producer和Consumer只与这个Leader交互,其它Replica作为Follower从Leader中复制数据。默认情况下,只有所有副本均写入本地日志,才算commited通知给生产者。leader会检查自己的Replica,如果Replica不能及时

  • kafka在所有broker中选出一个controller,所有Partition的Leader选举都由controller决定。controller也负责增删Topic以及Replica的重新分配。controller负责处理其他broker挂掉的情况,如果controller挂掉,其他broker将在zookeeper上尝试抢占controller节点。在老版本中(scala实现的kafka的年代),是没有协调者的,集群通过zookeeper完成一系列操作。

  • 向kafka发送数据,默认支持String和byte[]2种类型

  • rebalance机制 : 有新的消费者加入,有消费者宕机或者下线,消费者主动退出消费者组,消费者组订阅的topic出现分区数量变化,消费者调用unsubscrible取消对某topic的订阅都会触发rebalance。

Kafka原理

Kakfa Broker集群受Zookeeper管理。所有的Kafka Broker节点一起去Zookeeper上注册一个临时节点,因为只有一个Kafka Broker会注册成功,其他的都会失败,所以这个成功在Zookeeper上注册临时节点的这个Kafka Broker会成为Kafka Broker Controller,其他的Kafka broker叫Kafka Broker follower。

kafka的consumer消费数据时首先会从broker里读取一批消息数据进行处理(拉取而并非推送),处理完成后再提交offset(原来是向ZK,现在是kafka内部维护的offset队列)。这就会导致一个问题,如果一个消费者在消费完成后没能成功提交offset,或者在超时才提交offset,可能这些消息就会被其他消费者消费。导致重复消费问题,但是保证了所有消息最少处理一次。消费者也会把自己的分区信息。当然,通过使用低级API,上面的不是必须的。如果kafka消费者线提交offset再处理,就可以实现最多处理一次。kafka同样可以实现正好一次的处理。比如说借鉴分布式事务中的2阶段提交协议(2PC)。不过,无论是2PC还是3PC都无法彻底解决分布式事务的一致性问题。

kafka只保证同一个分区的消息有序性,跨分区消息是无序的。

kafka直接将数据持久化到自己的日志目录里,建立索引并定时清除。

kafka服务段采取NIO server来接收客户端的连接。每一个客户端连接为一个socket channel。

容错

消费者宕机后,Kafka需要进行消费组的再平衡。

##Kafka和Storm的配合使用

KafkaSpout基于kafka.javaapi.consumer.SimpleConsumer实现了consumer客户端的功能,包括 partition的分配,消费状态的维护(offset)。同时KafkaSpout使用了storm的可靠API,并实现了spout的ack 和 fail机制。KafkaSpout的基本处理流程如下:

1. 建立zookeeper客户端,在zookeeper zk_root + “/topics/” + _topic + “/partitions” 路径下获取到partition列表
2. 针对每个partition 到路径Zk_root + “/topics/” + _topic + “/partitions”+"/" + partition_id + "/state"下面获取到leader partition 所在的broker id
3. 到/broker/ids/broker id 路径下获取broker的host 和 port 信息,并保存到Map中Partition_id –-> learder broker
4. 获取spout的任务个数和当前任务的index,然后再根据partition的个数来分配当前spout 所消费的partition列表
5. 针对所消费的每个broker建立一个SimpleConsumer对象用来从kafka上获取数据
6. 提交当前partition的消费信息到zookeeper上面保存

如果出现kafka broker宕机,spout挂掉的情况,那么spout是要重新分配parition的,KafkaSpout并没有监听zookeeper上broker、partition和其他spout的状态,所以当有异常发生的时候KafkaSpout并不知道的。需要在ZkHosts中的refreshFreqSecs字段来定时更新partition列表。另外,当调用kafkaspout的nextTuple方法出现异常时,强制更新当前spout的partition消费列表。

一般推荐spout的并发度和kafka partition相等。

高级API

kafka的接收端提供高级API,是对从Kafka接收数据的抽象。
优点
● 高级API写起来简单
● 不需要去自行去管理offset,系统通过zookeeper自行管理
● 不需要管理分区,副本等情况,系统自动管理
● 消费者断线会自动根据上一次记录在 zookeeper中的offset去接着获取数据(默认设置5s更新一下 zookeeper 中存的的offset),版本为0.10.2
● 可以使用group来区分对访问同一个topic的不同程序访问分离开来(不同的group记录不同的offset,这样不同程序读取同一个topic才不会因为offset互相影响)
缺点
● 不能自行控制 offset(对于某些特殊需求来说)
● 不能细化控制如分区、副本、zk 等

如Consumer属于高级API。

低级API

低级API可以进行更底层的管理,比如只消费特定分区的实现。
优点
● 能够开发者自己控制offset,想从哪里读取就从哪里读取。
● 自行控制连接分区,对分区自定义进行负载均衡
● 对 zookeeper 的依赖性降低(如:offset 不一定非要靠 zk 存储,自行存储offset 即可,比如存在文件或者内存中)
缺点
● 太过复杂,需要自行控制 offset,连接哪个分区,找到分区 leader 等

如SimpleConsumer属于低级API。

KafkaProducer

提供send方法,返回Future对象。如果你希望同步调用,就在send完立刻调用future即可。

Kafka Streaming

流计算框架的最底层是流。storm和kafaka streaming是一条条处理,而spark streaming则是采用micro batch。对于kafaka streaming,一台节点只运行一个流实例

Kafka版本

性能

可以参考https://www.cnblogs.com/xiaodf/p/6023531.html

生产速度测试使用后kafka提供的kafka-producer-perf-test.sh进行测试。消费使用kafka-consumer-perf-test.sh来进行测试。

kafka高效的原因

  • 磁盘顺序读写
  • 零拷贝技术
    在这里插入图片描述
    而零拷贝技术使用了java.nio.channels.FileChannel中的transferTo,底层是操作系统提供的transferto API,可以实现下面的作用
    在这里插入图片描述
  • mmap
    在producer生产消息到broker时,我们还需要mmap技术。
    在这里插入图片描述
    这样,会又操作系统将脏内存页写回磁盘时,整个写入就完成了。

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间

java 提供的API为

public abstract MappedByteBuffer map(MapMode mode, long position, long size) throws IOException;

具体的代码为
https://www.cnblogs.com/jiading/articles/13047019.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值