数据源管理 | Kafka集群环境搭建,消息存储机制详解

本文源码:GitHub·点这里 || GitEE·点这里java

1、Kafka集群环境

一、环境版本

版本:kafka2.11,zookeeper3.4

注意:这里zookeeper3.4也是基于集群模式部署。node

二、解压重命名

tar -zxvf kafka_2.11-0.11.0.0.tgz
mv kafka_2.11-0.11.0.0 kafka2.11

建立日志目录git

[root@en-master kafka2.11]# mkdir logs

注意:以上操做须要同步到集群下其余服务上。github

三、添加环境变量

vim /etc/profile
export KAFKA_HOME=/opt/kafka2.11
export PATH=$PATH:$KAFKA_HOME/bin
source /etc/profile

四、修改核心配置

[root@en-master /opt/kafka2.11/config]# vim server.properties
-- 核心修改以下
# 惟一编号
broker.id=0
# 开启topic删除
delete.topic.enable=true
# 日志地址
log.dirs=/opt/kafka2.11/logs
# zk集群
zookeeper.connect=zk01:2181,zk02:2181,zk03:2181

注意:broker.id安装集群服务个数编排便可,集群下不能重复。bootstrap

五、启动kafka集群

# 启动命令
[root@node02 kafka2.11]# bin/kafka-server-start.sh -daemon config/server.properties
# 中止命令
[root@node02 kafka2.11]# bin/kafka-server-stop.sh
# 进程查看
[root@node02 kafka2.11]# jps

注意:这里默认启动了zookeeper集群服务,而且集群下的kafka分别启动。vim

六、基础管理命令

建立topicapp

bin/kafka-topics.sh --zookeeper zk01:2181 \
--create --replication-factor 3 --partitions 1 --topic one-topic

参数说明:异步

  • replication-factor 定义副本个数
  • partitions 定义分区个数
  • topic:定义topic名称

查看topic列表分布式

bin/kafka-topics.sh --zookeeper zk01:2181 --list

修改topic分区ide

bin/kafka-topics.sh --zookeeper zk01:2181 --alter --topic one-topic --partitions 5

查看topic

bin/kafka-topics.sh --zookeeper zk01:2181 \
--describe --topic one-topic

发送消息

bin/kafka-console-producer.sh \
--broker-list 192.168.72.133:9092 --topic one-topic

消费消息

bin/kafka-console-consumer.sh \
--bootstrap-server 192.168.72.133:9092 --from-beginning --topic one-topic

删除topic

bin/kafka-topics.sh --zookeeper zk01:2181 \
--delete --topic first

七、Zk集群用处

Kafka集群中有一个broker会被选举为Controller,Controller依赖Zookeeper环境,管理集群broker的上下线,全部topic的分区副本分配和leader选举等工做。

2、消息拦截案例

一、拦截器简介

Kafka中间件的Producer拦截器主要用于实现消息发送的自定义控制逻辑。用户能够在消息发送前以及回调逻辑执行前有机会对消息作一些自定义,好比消息修改等,发送状态监控等,用户能够指定多个拦截器按顺序执行拦截。

核心方法

  • configure:获取配置信息和初始化数据时调用;
  • onSend:消息被序列化以及和计算分区前调用该方法,能够对消息作操做;
  • onAcknowledgement:消息发送到Broker以后,或发送过程失败时调用;
  • close:关闭拦截器调用,执行一些资源清理工做;

注意:这里说的拦截器是针对消息发送流程。

二、自定义拦截

定义方式:实现ProducerInterceptor接口便可。

拦截器一:在onSend方法中,对拦截的消息进行修改。

@Component
public class SendStartInterceptor implements ProducerInterceptor<String, String> {

    private final Logger LOGGER = LoggerFactory.getLogger("SendStartInterceptor");
    @Override
    public void configure(Map<String, ?> configs) {
        LOGGER.info("configs...");
    }
    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
        // 修改消息内容
        return new ProducerRecord<>(record.topic(), record.partition(),
                                    record.timestamp(), record.key(),
                              "onSend:{" + record.value()+"}");
    }
    @Override
    public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
        LOGGER.info("onAcknowledgement...");
    }
    @Override
    public void close() {
        LOGGER.info("SendStart close...");
    }
}

拦截器二:在onAcknowledgement方法中,判断消息是否发送成功。

@Component
public class SendOverInterceptor implements ProducerInterceptor<String, String> {

    private final Logger LOGGER = LoggerFactory.getLogger("SendOverInterceptor");
    @Override
    public void configure(Map<String, ?> configs) {
        LOGGER.info("configs...");
    }

    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
        LOGGER.info("record...{}", record.value());
        return record ;
    }

    @Override
    public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
        if (exception != null){
            LOGGER.info("Send Fail...exe-msg",exception.getMessage());
        }
        LOGGER.info("Send success...");
    }

    @Override
    public void close() {
        LOGGER.info("SendOver close...");
    }
}

加载拦截器:基于一个KafkaProducer配置Bean,加入拦截器。

@Configuration
public class KafkaConfig {

    @Bean
    public Producer producer (){
        Properties props = new Properties();
        // 省略其余配置...
        // 添加拦截器
        List<String> interceptors = new ArrayList<>();
        interceptors.add("com.kafka.cluster.interceptor.SendStartInterceptor");
        interceptors.add("com.kafka.cluster.interceptor.SendOverInterceptor");
        props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, interceptors);
        return new KafkaProducer<>(props) ;
    }
}

三、代码案例

@RestController
public class SendMsgWeb {
    @Resource
    private KafkaProducer<String,String> producer ;
    @GetMapping("/sendMsg")
    public String sendMsg (){
        producer.send(new ProducerRecord<>("one-topic", "msgKey", "msgValue"));
        return "success" ;
    }
}

基于上述自定义Bean类型,进行消息发送,关注拦截器中打印日志信息。

3、Kafka存储分析

说明:该过程基于上述案例producer.send方法追踪的源码执行流程,源码中的过程相对清楚,涉及的核心流程以下。

一、消息生成过程

数据源管理 | Kafka集群环境搭建,消息存储机制详解

Producer发送消息采用的是异步发送的方式,消息发送过程以下:

  • Producer发送消息以后,通过拦截器,序列化,事务判断;
  • 流程执行后,消息内容放入容器中;
  • 容器在指定时间内若是装满(size),会唤醒Sender线程;
  • 容器若是在指定时间内没有装满,也会执行一次Sender线程唤醒;
  • 唤醒Sender线程以后,把容器数据拉取到topic中;

絮叨一句:读这些中间件的源码,不只能开阔思惟,也会让本身意识到平时写的代码可能真的叫搬砖。

二、存储机制

Kafka中消息是以topic进行标识分类,生产者面向topic生产消息,topic分区(partition)是物理上的存储,基于消息日志文件的方式。

数据源管理 | Kafka集群环境搭建,消息存储机制详解

  • 每一个partition对应于一个log文件,发送的消息不断追加到该log文件末端;
  • log文件中存储的就是producer生产的消息数据,采用分片和索引机制;
  • partition分为多个segment。每一个segment对应两个(.index)和(.log)文件;
  • index文件类型存储的索引信息;
  • log文件存储消息的数据;
  • 索引文件中的元数据指向对应数据文件中message的物理偏移地址;
  • 消费者组中的每一个消费者,都会实时记录消费的消息offset位置;
  • 固然消息消费出错时,恢复是从上次的记录位置继续消费;

三、事务控制机制

数据源管理 | Kafka集群环境搭建,消息存储机制详解

Kafka支持消息的事务控制

Producer事务

跨分区跨会话的事务原理,引入全局惟一的TransactionID,并将Producer得到的PID和TransactionID绑定。Producer重启后能够经过正在进行的TransactionID得到原来的PID。
Kafka基于TransactionCoordinator组件管理Transaction,Producer经过和TransactionCoordinator交互得到TransactionID对应的任务状态。TransactionCoordinator将事务状态写入Kafka的内部Topic,即便整个服务重启,进行中的事务状态能够获得恢复。

Consumer事务

Consumer消息消费,事务的保证强度很低,没法保证消息被精确消费,由于同一事务的消息可能会出现重启后已经被删除的状况。

4、源代码地址

GitHub·地址
https://github.com/cicadasmile/data-manage-parent
GitEE·地址
https://gitee.com/cicadasmile/data-manage-parent

数据源管理 | Kafka集群环境搭建,消息存储机制详解

推荐关联阅读:数据源管理系列

序号 标题
01 数据源管理:主从库动态路由,AOP模式读写分离
02 数据源管理:基于JDBC模式,适配和管理动态数据源
03 数据源管理:动态权限校验,表结构和数据迁移流程
04 数据源管理:关系型分库分表,列式库分布式计算
05 数据源管理:PostGreSQL环境整合,JSON类型应用
06 数据源管理:基于DataX组件,同步数据和源码分析
07 数据源管理:OLAP查询引擎,ClickHouse集群化管理
相关文章
相关标签/搜索