1 kafka架构进阶

1.1 Kafka底层数据的同步机制(面试常问)

1、Kafka的Topic被分为多个分区,分区是是按照Segments(文件段)存储文件块。分区日志是存储在磁盘上的日志序列,Kafka可以保证分区里的事件是有序的。其中Leader负责对应分区的读写、Follower负责同步分区的数据,0.11 版本之前Kafka使用highwatermarker机制保证数据的同步,但是基于highwatermarker的同步数据可能会导致数据的不一致或者是乱序。在Kafka数据同步有以下概念。

2、LEO:log end offset 标识的是每个分区中最后一条消息的下一个位置,分区的每个副本都有自己的LEO.

3、HW: high watermarker称为高水位线,所有HW之前的的数据都理解是已经备份的,当所有节点都备 份成功,Leader会更新水位线。

4、ISR:In-sync-replicas,kafka的leader会维护一份处于同步的副本集,如果在replica.lag.time.max.ms时间内系统没有发送fetch请求,或者已然在发送请求,但是在该限定时间内没有赶上Leader的数据就被剔除ISR列表。在Kafka-0.9.0版本剔除replica.lag.max.messages消息个数限定,因为这个会导致其他的Broker节点频繁的加入和退出ISR。即如果某个从机总是赶不上leader的leo,该节点在达到限制时间后,会被剔除isr列表

1.1.1 高水位截断的同步方式可能带来数据丢失(Kafka 0.11版本前的问题)

场景1丢数据: B为leader,A同步B的数据,同步到m1之后,A宕机重启,A恢复后B宕机,B的m2没人同步,B宕机后zk选举A为leader。此时A只有m1的数据,B恢复后,同步A的数据,此时m2会丢失。

场景2数据不一致:开始B为leader,写入了两条数据m1和m2。A同步B的数据只同步到m1时,A和B同时宕机。A启动恢复的快一点,选举A为leader,此时有用户往A中写了一条m3,A的水位线变为1,当B启动后,B为fowller。B检查自己的水位线也是1,不会被截断。产生高水位相同,但是数据不一致的问题

为了避免这个问题,建议把Kafka的版本升级到kafka-0.11+版本

1.1.2 解决高水位截断数据丢失和不一致问题(leaderEpoch)

可以看出0.11版本之前Kafka的副本备份机制的设计存在问题。依赖HW的概念实现数据同步,但是存在数据不一致问题和丢失数据问题,因此Kafka-0.11版本引入了 Leader Epoch解决这个问题,不在使用HW作为数据截断的依据。而是已引入了Leader epoch的概念,任意一个Leader持有一个LeaderEpoch。该LeaderEpoch这是一个由Controller管理的32位数字,存储在Zookeeper的分区状态信息中,并作为LeaderAndIsrRequest的一部分传递给每个新的Leader。Leader接受Producer请求数据上使用LeaderEpoch标记每个Message。然后,该LeaderEpoch编号将通过复制协议传播,并用于替换HW标记,作为消息截断的参考点。

生产者发送给leader消息,都会存下来每条消息的leader epoch。所有从机同步leader数据的时候,都会同步一份leaderrEpoch存下来。leaderEpoch中存储了重新选取哪个机器作为leader的信息等

改进消息格式,以便每个消息集都带有一个4字节的Leader Epoch号。在每个日志目录中,会创建一个新的Leader Epoch Sequence文件,在其中存储Leader Epoch的序列和在该Epoch中生成的消息的Start Offset。它也缓存在每个副本中,也缓存在内存中。

follower变成Leader

当Follower成为Leader时,它首先将新的Leader Epoch和副本的LEO添加到Leader Epoch Sequence序列文件的末尾并刷新数据。给Leader产生的每个新消息集都带有新的“Leader Epoch”标记。

Leader变成Follower

如果需要需要从本地的Leader Epoch Sequence加载数据,将数据存储在内存中,给相应的分区的Leader发送epoch 请求,该请求包含最新的EpochID,StartOffset信息.Leader接收到信息以后返回该EpochID所对应的LastOffset信息。该信息可能是最新EpochID的StartOffset或者是当前EpochID的Log End Offset信息.

  • 情形1:Fllower的Offset比Leader的小

  • 情形2:用户的Leader Epoch的信息startOffset信息比Leader返回的LastOffset要大,Follower回去重置自己的Leader Epoch文件,将Offset修改为Leader的LastOffset信息,并且截断自己的日志信息

Follower在提取过程中,如果关注者看到的LeaderEpoch消息集大于其最新的LeaderEpoch,则会在其LeaderEpochSequence中添加新的LeaderEpoch和起始偏移量,并将Epoch数据文件刷新到磁盘。同时将Fetch的日志信息刷新到本地日志文件。

1.1.3 LeaderEpoch解决数据丢失

1.1.4 LeaderEpoch解决数据不一致

1.2 kafka监控之Kafka-Eagle

1.2.1 Kafka-Eagle安装

源码地址:github.com/smartloli/kafka-eagle

下载地址: download.kafka-eagle.org

这是一个监视系统,监视您的kafka群集以及可视的使用者线程,偏移量,所有者等。当您安装Kafka Eagle时,用户可以看到当前的使用者组,对于每个组,他们正在消耗的Topic以及该组在每个主题中的偏移量,滞后,日志大小和位置。这对于了解用户从消息队列消耗的速度以及消息队列增加的速度很有用。

[root@CentOSB ~]# tar -zxf kafka-eagle-web-1.4.0-bin.tar.gz -C /usr/
[root@CentOSB ~]# mv /usr/kafka-eagle-web-1.4.0 /usr/kafka-eagle
[root@CentOSB ~]# vi .bashrc
KE_HOME=/usr/kafka-eagle
JAVA_HOME=/usr/java/latest
PATH=$PATH:$JAVA_HOME/bin:$KE_HOME/bin
CLASSPATH=.
export JAVA_HOME
export PATH
export CLASSPATH
export KE_HOME
[root@CentOSB ~]# source .bashrc
[root@CentOSB ~]# cd /usr/kafka-eagle/
[root@CentOSB kafka-eagle]# vi conf/system-config.properties kafka.eagle.zk.cluster.alias=cluster1
cluster1.zk.list=CentOSA:2181,CentOSB:2181,CentOSC:2181
cluster1.kafka.eagle.offset.storage=kafka
kafka.eagle.metrics.charts=true
kafka.eagle.driver=com.mysql.jdbc.Driver
kafka.eagle.url=jdbc:mysql://192.168.52.1:3306/ke?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
kafka.eagle.username=root
kafka.eagle.password=root [root@CentOSB kafka-eagle]# chmod u+x bin/ke.sh
[root@CentOSB kafka-eagle]# ./bin/ke.sh start

如果需要检测Kafka性能指标需要修改Kafka启动文件

vi kafka-server-start.sh
...
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
export KAFKA_HEAP_OPTS="-server -Xms2G -Xmx2G -XX:PermSize=128m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=8 -XX:ConcGCThreads=5 -XX:InitiatingHeapOccupancyPercent=70"
export JMX_PORT="9999"
#export KAFKA_HEAP_OPTS="-Xmx1G -Xms1G"
fi

可视化操作和监控kafka集群状态

1.3 Kafka-Flume集成

flume也是日志采集器,类似于elk中的logstash。通过flume采集过来的数据,一方面我们可以把数据写入hdfs,我们也可以把采集的数据写入到mq当中,例如kafka,kafka在写入到主流的流处理中。

组件1:r1-采集组件,测试使用netcat

组件2:k1-输出组件

组件3:c1-缓存组件,测试使用内存做缓冲

flume提供了kafka集成方案,在flume中添加kafka的配置信息即可

  • jdk8+环境,准备flume的安装包,安装flume

参考 flume.apache.org 官方文档

tar -zxf apache-flume-1.9.0-bin.tar.gz -C /usr/

cd /usr/apache-flume-1.9.0-bin

vi conf/kafka.properties


# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1 # Describe/configure the source
a1.sources.r1.type = netcat
a1.sources.r1.bind = CentOS
a1.sources.r1.port = 44444 # Describe the sink
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.topic = topic01
a1.sinks.k1.kafka.bootstrap.servers = CentOSA:9092,CentOSB:9092,CentOSC:9092
a1.sinks.k1.kafka.flumeBatchSize = 20
a1.sinks.k1.kafka.producer.acks = -1
a1.sinks.k1.kafka.producer.linger.ms = 100
a1.sinks.k1.kafka.producer.compression.type = snappy # Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100 # Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

a1.sources = r1
a1.sinks = k1
a1.channels = c1 a1.sources.r1.type = avro
a1.sources.r1.bind = CentOS
a1.sources.r1.port = 44444 a1.channels.c1.type = memory
a1.channels.c1.capacity = 10000
a1.channels.c1.transactionCapacity = 10000
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000 a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.topic = topic01
a1.sinks.k1.kafka.bootstrap.servers = CentOS:9092
a1.sinks.k1.kafka.flumeBatchSize = 20
a1.sinks.k1.kafka.producer.acks = -1
a1.sinks.k1.kafka.producer.linger.ms = 1
a1.sinks.k1.kafka.producer.compression.type = snappy a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

1.4 Kafka-SpringBoot集成

  • 依赖引入(pom.xml)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency> <dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> </dependencies>
  • 配置(application.properties)
# 连接
spring.kafka.bootstrap-servers=CentOSA:9092,CentOSB:9092,CentOSC:9092 # 重试次数
spring.kafka.producer.retries=5
# 开启应答
spring.kafka.producer.acks=all
# 缓冲区大小
spring.kafka.producer.batch-size=16384 spring.kafka.producer.buffer-memory=33554432
# 事务控制,开启后KafkaTemplate发送消息,要处于事务控制中@Transation
spring.kafka.producer.transaction-id-prefix=transaction-id-
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
# 开启幂等
spring.kafka.producer.properties.enable.idempotence=true spring.kafka.consumer.group-id=group1
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.enable-auto-commit=true
spring.kafka.consumer.auto-commit-interval=100
spring.kafka.consumer.properties.isolation.level=read_committed
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
  • 配置日志
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%p %d{yyyy-MM-dd HH:mm:ss} - %m%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender> <!-- 控制台输出日志级别 -->
<root level="ERROR">
<appender-ref ref="STDOUT" />
</root> <logger name="org.springframework.kafka" level="INFO" additivity="false">
<appender-ref ref="STDOUT" />
</logger> <!--事务控制-->
<logger name="org.springframework.kafka.transaction" level="debug" additivity="false">
<appender-ref ref="STDOUT" />
</logger> </configuration>
  • 集成后Spring后KafkaTemplate类专门用来发送数据
@Transactional
@Service
public class OrderService implements IOrderService { @Autowired
private KafkaTemplate kafkaTemplate; @Override
public void saveOrder(String id,Object message) {
//发送消息给服务器
}
}
  • 通过监听实现发送端到消息处理的转发
@KafkaListeners(value = {@KafkaListener(topics = {"topic04"})})
@SendTo(value = {"topic05"})
public String listenner(ConsumerRecord<?, ?> cr) { return cr.value()+" mashibing edu";
}
  • 开启事务后,KafkaTemplate发送消息的方式1
kafkaTemplate.executeInTransaction(new KafkaOperation.OperationCallback<String, String, Object>(){
@Override
public Object doInOperations(KafkaOperation<String,String> kafkaOperations) {
kafkaOperations.send(new ProducerRecord<String,String>("topic02", "002", "this is value"));
return null;
}
});
  • 开启事务后,KafkaTemplate发送消息的方式2

发送方法外,加上Spring的@Transation注解

《Kafka笔记》4、Kafka架构,与其他组件集成的更多相关文章

  1. Kafka(一)Kafka的简介与架构

    一.简介 1.1 概述 Kafka是最初由Linkedin公司开发,是一个分布式.分区的.多副本的.多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/ng ...

  2. Kafka剖析:Kafka背景及架构介绍

    <Kafka剖析:Kafka背景及架构介绍> <Kafka设计解析:Kafka High Availability(上)> <Kafka设计解析:Kafka High A ...

  3. Storm相关笔记(包括Kafka和HBase)

    一.Apache Kafka 1.了解Kafka 1.1.Kafka是什么?有什么用? 是什么? 1) Apache Kafka 是一个消息队列(生产者消费者模式) 2) Apache Kafka 目 ...

  4. Kafka笔记整理(一)

    Kafka简介 消息队列(Message Queue) 消息 Message 网络中的两台计算机或者两个通讯设备之间传递的数据.例如说:文本.音乐.视频等内容. 队列 Queue 一种特殊的线性表(数 ...

  5. 完整的ELK+filebeat+kafka笔记

    之前有写过elasticsearch集群和elk集群的博客, 都是基于docker的,使用docker-compose进行编排(K8S暂未掌握) 三台服务器搭建es集群:https://www.cnb ...

  6. 图解 Kafka 超高并发网络架构演进过程

    阅读本文大约需要 30 分钟. 大家好,我是 华仔, 又跟大家见面了. 上一篇作为专题系列的第一篇,我们深度剖析了关于 Kafka 存储架构设计的实现细节,今天开启第二篇,我们来深度剖析下「Kafka ...

  7. 基于Flume+LOG4J+Kafka的日志采集架构方案

    本文将会介绍如何使用 Flume.log4j.Kafka进行规范的日志采集. Flume 基本概念 Flume是一个完善.强大的日志采集工具,关于它的配置,在网上有很多现成的例子和资料,这里仅做简单说 ...

  8. 《Apache kafka实战》读书笔记-管理Kafka集群安全之ACL篇

    <Apache kafka实战>读书笔记-管理Kafka集群安全之ACL篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 想必大家能看到这篇博客的小伙伴,估计你对kaf ...

  9. Kafka笔记整理(三):消费形式验证与性能测试

    Kafka消费形式验证 前面的<Kafka笔记整理(一)>中有提到消费者的消费形式,说明如下: .每个consumer属于一个consumer group,可以指定组id.group.id ...

  10. kafka实时流数据架构

    初识kafka https://www.cnblogs.com/wenBlog/p/9550039.html 简介 Kafka经常用于实时流数据架构,用于提供实时分析.本篇将会简单介绍kafka以及它 ...

随机推荐

  1. Gradle系列之Android Gradle基础配置

    原文发于微信公众号 jzman-blog,欢迎关注交流. 通过前面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相关的知识,关于 Gradle 及其插件相关知识请先阅读下面几篇文章: ...

  2. java学习(九) —— java中的File文件操作及IO流概述

    前言 流是干什么的:为了永久性的保存数据. IO流用来处理设备之间的数据传输(上传和下载文件) java对数据的操作是通过流的方式. java用于操作流的对象都在IO包中. java IO系统的学习, ...

  3. jfinal3连接sqlserver2012 保存日期字段出现“不支持从 UNKNOWN 到 UNKNOWN 的转换”错误

    修改Dialect中的fillStatement方法,增加判断日期类型并转换为时间戳

  4. 请求转发和重定向实现与Ajax实现表单登陆

    private void login(HttpServletRequest request, HttpServletResponse response) throws ServletException ...

  5. Oracle添加键值对盲注

    前言 遇到一种注入点,存在于POST参数中,却不能用sqlmap扫出: 分析 request参数格式: %24Q_value1=test1&orderCol=&order=+ASC+& ...

  6. win10彻底卸载和删除MySql

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_41140741/article/de ...

  7. 我要吹爆这份阿里中间件技术内部的RM笔记,简直佩服到五体投地

    消息队列 RocketMQ 版是阿里云基于 Apache RocketMQ 构建的低延迟.高并发.高可用.高可靠的分布式消息中间件.该产品最初由阿里巴巴自研并捐赠给 Apache 基金会,服务于阿里集 ...

  8. C++对话框创建及修改对话框属性

    转载:http://www.51testing.com/html/48/n-3151648.html 创建对话框 C++中对话框分为模式对话框和非模式对话框. 模式对话框的创建: MyDialog m ...

  9. JavaCV FFmpeg采集摄像头YUV数据

    前阵子使用利用树莓派搭建了一个视频监控平台(传送门),不过使用的是JavaCV封装好的OpenCVFrameGrabber和FFmpegFrameRecorder. 其实在javacpp项目集中有提供 ...

  10. cp命令:复制文件和目录

    cp命令:复制文件和目录 [功能说明] cp命令可以理解英文单词copy的缩写,其功能为复制文件和目录. [语法格式] 1 cp [option] [source] [dest] 2 cp [选项] ...