kafka 架构

 

  1. producer:消息生产者,发布消息到 kafka 集群的终端或服务
  2. broker:kafka 集群中包含的服务器。broker (经纪人,消费转发服务)
  3. topic:每条发布到 kafka 集群的消息属于的类别,即 kafka 是面向 topic 的
  4. partition:partition 是物理上的概念,每个 topic 包含一个或多个 partition。kafka 分配的单位是 partition。多个partition可以分配到不同的节点上
  5. consumer:从 kafka 集群中消费消息的终端或服务
  6. Consumer group:在较高的版本的consumer API 中,每个 consumer 都属于一个 consumer group,每条消息只能被 consumer group 中的一个 Consumer 消费,但可以被多个 consumer group 消费。即组间数据是共享的,组内数据是竞争
  7. replica:partition 的副本,保障 partition 的高可用
  8. leader:replica 中的一个角色, producer 和 consumer 只跟 leader 交互
  9. follower:replica 中的一个角色,从 leader 中复制数据
  10. controller:kafka 集群中的其中一个服务器,用来进行 leader election 以及各种 failover
  11. zookeeper:kafka 通过 zookeeper 来存储集群的 meta 信息

TOP与分区

 

 

  1. Topic在逻辑上可以被认为是一个queue,每条消息都必须指定它的Topic,可以简单理解为必须指明把这条消息放进哪个queue里。
  1. 为了使得Kafka的吞吐率可以线性提高,物理上把Topic分成一个或多个Partition每个Partition在物理(磁盘)上对应一个文件夹,该文件夹下存储这个Partition的所有消息和索引文件
  2. 因为每条消息都被append到该Partition中,属于顺序写磁盘,因此效率非常高(经验证,顺序写磁盘效率比随机写内存还要高,这是Kafka高吞吐率的一个很重要的保证
  3. 对于传统的消息队列而言,一般会删除已经被消费的消息,而Kafka集群会保留所有的消息,无论其被消费与否。当然,因为磁盘限制,不可能永久保留所有数据(实际上也没必要),因此Kafka提供两种策略删除旧数据。一是基于时间,二是基于Partition文件大小。配置如下所示

#  日志删除间隔时间
log.retention.hours=168
# 日志文件大小,达到这个大小会产生一个新的日志文件
log.segment.bytes=1073741824
# 设置是否启用日志清理
log.cleaner.enable=false

Kafka消息流处理

 

  1. producer 先从 zookeeper 的 "/brokers/.../state" 节点找到该 partition 的 leader
  2. producer 将消息发送给该 leader
  3. leader 将消息写入本地 log
  4. followers 从 leader pull 消息,写入本地 log后,给leader 发送 ACK
  5. leader 收到所有 ISR中的 replica 的 ACK 后,增加 HW(high watermark,最后 commit 的 offset) 并向 producer 发送 ACK

ISR指的是:比如有三个副本 ,编号是① ② ③ ,其中② 是Leader  ① ③是Follower。假设在数据同步过程中,①跟上Leader,但是③出现故障或没有及时同步,则① ②是一个ISR,而③不是ISR成员。后期在Leader选举时,会用到ISR机制。会优先从ISR中选择Leader

kafka HA

一、概述

  1. 同一个 partition 可能会有多个 replica(对应 server.properties 配置中的 default.replication.factor=N)
  2. 没有 replica 的情况下,一旦 broker 宕机,其上所有 patition 的数据都不可被消费,同时 producer 也不能再将数据存于其上的 patition
  3. 引入replication 之后,同一个 partition 可能会有多个 replica,而这时需要在这些 replica 之间选出一个 leader,producer 和 consumer 只与这个 leader 交互,其它 replica 作为 follower 从 leader 中复制数据

 

二、leader failover

  1. 当 partition 对应的 leader 宕机时,需要从 follower 中选举出新 leader
  2. 在选举新leader时,一个基本的原则是,新的 leader 必须拥有旧 leader commit 过的所有消息
  3. 由写入流程可知 ISR 里面的所有 replica 都跟上了 leader,只有 ISR 里面的成员才能选为 leader。对于n个 replica,一个 partition 可以在容忍 n-1个 replica 失效的情况下保证消息不丢失。例如 一个分区 有5个副本,挂了4个,剩一个副本,依然可以工作
  4. kafka的选举不同于zookeeper,用的不是过半选举
  5. 所有 replica 都不工作时,有两种可行的方案:
    1. 等待 ISR 中的任一个 replica 活过来,并选它作为 leader。可保障数据不丢失,但时间可能相对较长
    2. 选择第一个活过来的 replica(不一定是 ISR 成员)作为 leader。无法保障数据不丢失,但相对不可用时间较短

kafka 0.8.* 使用第二种方式

  1. kafka 通过 Controller 来选举 leader

Kafka API使用

一、 生产者

@Test
public void producer() throws InterruptedException, ExecutionException {
        
// 设置属性
        Properties props = new Properties();
        
// 设置键的类型,实际上是偏移量
        props.put("key.serializer", "org.apache.kafka.common.serialization.IntegerSerializer");
        
// 设置值的类型,实际上是实际数据
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        
// 设置Kafka的连接地址
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.234.11:9092");

// 添加数据

Producer<Integer, String> kafkaProducer = new KafkaProducer<Integer, String>(props);

for (int i = 0; i < 100; i++) {

ProducerRecord<Integer, String> message = new ProducerRecord<Integer, String>("enbook", "" + i);

kafkaProducer.send(message);

}

while (true)        ;

}

 

二、创建Topic

@Test
public void create_topic() {

        ZkUtils zkUtils = ZkUtils.apply("192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181", 30000, 30000,
                        JaasUtils.isZkSecurityEnabled());
        
// 创建一个单分区单副本名为t1的topic
        AdminUtils.createTopic(zkUtils, "t1", 1, 1, new Properties(), RackAwareMode.Enforced$.MODULE$);
        zkUtils.close();
}

 

三、删除Topic

@Test
public void delete_topic() {
        ZkUtils zkUtils = ZkUtils.apply(
"192.168.234.11:2181,192.168.234.210:2181,192.168.234.211:2181", 30000, 30000,
                        JaasUtils.isZkSecurityEnabled());
        
// 删除topic 't1'
        AdminUtils.deleteTopic(zkUtils, "t1");
        zkUtils.close();
}

四、消费者组

@Test
public void consumer_1() {

Properties props = new Properties();

props.put("bootstrap.servers", "192.168.234.11:9092");

props.put("group.id", "consumer-tutorial");

props.put("key.deserializer", StringDeserializer.class.getName());

props.put("value.deserializer", StringDeserializer.class.getName());

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

consumer.subscribe(Arrays.asList("enbook", "t2"));

try {

while (true) {

ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);

for (ConsumerRecord<String, String> record : records)

System.out.println("c1消费:" + record.offset() + ":" + record.value());

}

} catch (Exception e) {

} finally {

consumer.close();

}

}

@Test
public void consumer_2() {

Properties props = new Properties();

props.put("bootstrap.servers", "192.168.234.11:9092");

props.put("group.id", "consumer-tutorial");

props.put("key.deserializer", StringDeserializer.class.getName());

props.put("value.deserializer", StringDeserializer.class.getName());

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

consumer.subscribe(Arrays.asList("enbook", "t2"));

try {

while (true) {

ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);

for (ConsumerRecord<String, String> record : records)

System.out.println("c2消费:" + record.offset() + ":" + record.value());

}

} catch (Exception e) {

} finally {

consumer.close();

}

}

Kafka offset机制

  1. Consumer在从broker读取消息后,可以选择commit,该操作会在Kakfa中保存该Consumer在该Partition中读取的消息的offset
  2. 该Consumer下一次再读该Partition时会从下一条开始读取
  3. 通过这一特性可以保证同一消费者从Kafka中不会重复消费数据
  4. 执行过程:
    1. 在创建消费者的时候产生消费者组:执行:sh kafka-console-consumer.sh --bootstrap-server hadoop01:9092 --topic enbook --from-beginning --new-consumer
    2. 获取消费者组的名字,执行:sh kafka-consumer-groups.sh --bootstrap-server hadoop01:9092 --list --new-consumer
  5. 进入kafka-logs目录查看,会发现多个很多目录,这是因为kafka默认会生成50个__consumer_offsets 的目录,用于存储消费者消费的offset位置
  6. Kafka在计算offset存储在哪一个目录中时,用:Math.abs(groupID.hashCode()) % 50计算S

Kafka的索引机制

  1. Kafka解决查询效率的手段之一是将数据文件分段,可以配置每个数据文件的最大值,每段放在一个单独的数据文件里面,数据文件以该段中最小的offset命名
  2. 每个log文件默认是1GB生成一个新的Log文件,比如新的log文件中第一条的消息的offset 16933,则此log文件的命名为:000000000000000016933.log,此外,每生成一个log文件,就会生成一个对应的索引(index)文件。(一个log+一个index文件合称为一个segment)这样在查找指定offset的Message的时候,用二分查找就可以定位到该Message在哪个段中
  3. 数据文件分段使得可以在一个较小的数据文件中查找对应offset的Message了,但是这依然需要顺序扫描才能找到对应offset的Message。为了进一步提高查找的效率,Kafka为每个分段后的数据文件建立了索引文件,文件名与数据文件的名字是一样的,只是文件扩展名为.index。索引文件中包含若干个索引条目,每个条目表示数据文件中一条Message的索引——Offset与position(Message在数据文件中的绝对位置)的对应关系
  4. index文件中并没有为数据文件中的每条Message建立索引,而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引。这样避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中。但缺点是没有建立索引的Message也不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了(稀疏索引+二分查找,可以加快查找速度
  5. 索引文件被映射到内存中,所以查找的速度还是很快的

简介

一、概述

  1. Kafka是发布订阅模式的消息队列
  2. Kafka是由LinkedIn(领英)公司开发后来贡献给了Apache的消息队列
  3. Kafka的特征:
    1. 发布和订阅消息流
    2. 在存储消息流的时候要提供容错机制
    3. 当数据流出现的时候能够及时处理
  4. Kafka的应用场景
    1. 能够在系统或者应用之间构建可靠的数据传输的实时流管道
    2. 能够构建一个转化或者应对数据流的实时流应用
  5. Kafka是利用了Scala语言构建的,Scala天然支持并发和吞吐,保证Kafka的并发量和吞吐量是比较高的,实际过程中,Kafka的吞吐量是在60~80M/s - Kafka底层采用了零拷贝的技术
  6. Kafka在收到数据之后会把数据写入本地磁盘上保证数据不丢失。默认情况下,Kafka不会清理写入的数据
  7. Kafka中不存在单点故障
    1. Kafka集群中可以随时动态增删节点
    2. Kafka中存在副本策略

二、基本概念

  1. broker:
    1. 就表示Kafka中的节点
    2. 每一个broker都需要给一个编号,这个编号只要不相同的就可以
  2. topic:
    1. 作用是用于对数据进行分类的
    2. 在Kafka中,每一条数据都要发送到一个指定主题中
    3. 每一个主题对应一个到多个partition
    4. 当删除主题的时候,这个主题所对应的目录并不会被立即删除,而是被标记为删除状态,等待一分钟左右会将标记的目录删除
    5. 如果需要删除操作立即生效,需要将delete.topic.enable设置为true
  3. partition:
    1. 每一个partition对应一个目录
    2. 如果有多个Kafka节点,分区会平均分到每一个节点上,这样设计的目的是为了提高Kafka的吞吐量
    3. 如果出现了多个分区,则数据在向分区中写入的时候是轮训写入
  4. replicas:
    1. Kafka中,为了保证数据的可用,可以去设置多个副本
    2. 如果设置了多个副本,则副本是以分区为单位进行备份
  5. leader和follower
    1. 在Kafka中,如果设置了多个副本,则副本之间会自动通过Controller进行选举,选举出一个leader副本以及其他的follower副本
    2. 注意:leader和follower是指的副本之间的主从关系而不是Kafka节点之间的主从关系
    3. Producer和Consumer只和leader副本进行交互,不会和follower副本进行交互
  6. Controller:
    1. 用于进行leader副本和follower副本的选举
    2. Controller会在某一个Kafka节点上
    3. 如果Controller宕机,那么Zookeeper会在其他的Kafka节点上再来启动一个Controller进程
  7. Consumer Group:
    1. 默认情况下,每一个消费者对应一个消费者组
    2. 一个消费者组中可以包含1个到多个消费者
    3. 同一条消息可以被不同的消费者组订阅,但是同一个组内的消费者只能有一个去消费这个消息 - 组间共享,组内竞争

三、指令

指令

解释

sh kafka-server-start.sh ../config/server.properties

开启Kafka

sh kafka-topics.sh --create --zookeeper hadoop01:2181 --replication-factor 1 --partitions 1 --topic video

创建主题

sh kafka-topics.sh --delete --zookeeper hadoop01:2181 --topic novel

删除主题

sh kafka-topics.sh --list --zookeeper hadoop01:2181

查看所有的主题

sh kafka-topics.sh --describe --zookeeper hadoop01:2181 --topic txt

描述主题

sh kafka-console-consumer.sh --zookeeper hadoop01:2181 --topic video

启动消费者

sh kafka-console-producer.sh --broker-list hadoop01:9092 --topic video

启动生产者

四、数据同步

  1. 生产者将数据写到leader副本上
  2. follower副本会给leader发送消息询问是否有需要更新的数据
  3. leader会把需要更新的数据发送给follower,并且等待follower的反馈
  4. 如果follower记录成功,则返回一个ack信号
  5. leader收到ack之后,会把follower副本所在的brokerid放入ISR队列中
  6. ISR是维系在Zookeeper上的,一旦leader副本lost,则Controller会优先从ISR中选择一个副本成为leader

五、语义

 

扩展视野

  1. Kafka和MQ的区别
  2. 了解Kafka sink
  3. 了解零拷贝

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值