Kafka学习笔记

Kafka

分布式日志系统
分区、多副本、多生产者、多订阅者
设计目标:
时间复杂度为O(1)的处理能力 即使是TB级
高吞吐率 垃圾机器也能秒/10万条信息传输
消息分区、分布式,可设置独享或共享,分区内有序.
离线处理能力,
在线扩展

Kakfa结构:

在这里插入图片描述

Kafka优势:
高吞吐量、高性能、持久化存储、分布式系统、可靠性、客户端状态维护、在线/离线场景、多客户端语言
Kafka应用场景:
日志收集
消息系统
	用户活动追踪:对用户操作行为进行记录.进行推荐算法执行
运营指标
	提供一些监控指标
流式处理
	流式计算来提供高速的推荐算法.

Kafka基本架构:

在这里插入图片描述
在这里插入图片描述

分区机制:
	主题中包含多个FIFO消息队列,每个队列也称之为分区.将这些分区可以分布在不同的节点中,那么就是分片机制.但只能保证队列的出入规则,不能保证整个主题也是同样的规则.
	为了防止分区宕机造成数据丢失,分区再设计副本机制,副本存储到其他节点中,这样就可以保证每个分区都是高可用.
负载策略:
	轮询,均匀发送到每个分区. 但消费就会出现顺序问题;
	规则指定分区,需要指定出入规则的单独放入指定分区.
	根据key进行分区.消费时就可根据key进行顺序消费
消息和批次:
	可以分批次发送,某一批次内的所有消息都会发送到一个主题内的分区;
	根据需求可以做批次发送,压缩,提高吞吐量,但单个消息速度就会被拖慢.需要等嘛.
消费组:
	针对消费者可能会重复消费的情况,提出了消费组的概念,组内的消费者同时只有一个消费者消费某一条消息.

在这里插入图片描述

broker和集群: 
	生产和消费都只会在主分区上做,副本分区只做故障转移.也会有一个broker leader,负责将分区分配给每个节点broker,监控所有节点broker做故障转移.并重新调整分区分配情况.
	leader选举为抢占式,利用zookeeper的分布式锁特性,修改同一个节点,谁先占上 谁leader

Kafka核心概念:

producer:
	发送消息,带key根据key到制定分区,带分区号给到分区号的分区,都不写默认轮询
consumer
	消费者在每个分区都会设置一个偏移量,整数标记,表示当前读到队列中的哪条消息.
	设置消费者组,就可以让组内的消费者不重复的消费主题内的数据,一个消费者可消费多个消息,但一个分区只能被一个消费者消费;消费者节点挂掉,可重新平衡分配;
broker:kafka的服务器
	N个分区N个broker,那么每个broker有一个分区
	N个分区 有N+M的broker 那么会有M个broker没有分区
	N个分区 N-M的broker 那么有几个broker将会把M个分区领取.
topic:
	逻辑概念,将几个分区进行统一的归类.
分区 partition:
	无法保证主题内消息顺序,但可保证分区内消息顺序
副本 replicas:
	分区的备份,不负责处理业务,只负责备份主分区和故障转移.有一个副本就相当于分区本身.
偏移量 offset:
	分区内的当前消息位置标记;消费者根据偏移量进行正常消费;保证不被重复消费
AR:
	所有副本统称为AR,副本分为同步副本和不同步副本,加一起叫AR
ISR同步副本:
	相对来说是同步主副本消息的;
OSR非同步副本:
	定时同步的 或者攒量同步
HW和LEO:
	HW为同步成功的最大偏移量,也是当前可消费的最大偏移量,也就表明这个AR同步最少的那个副本同步到了HW位置的消息数据
	LEO自身当前下一偏移量,这些数据可能没有同步,所以不对外展示,防止数据不一致呀,同样,整个AR中LEO最小的那个副本一定和HW是一样的,因为HW就是因为LEO最小的那个决定出来的

Kafka的安装:

JDK装1.8 会与kafka的1.02版本较为稳定,更高可能无法运行
安装zookerper 配置zookeeper
解压kafka 安装
配置kafka的 配置文件
	配置zookeeper连接
	配置log.dir= 存储kafka持久化数据的,改一下目录
启动kafka:
kafka-server-start.sh -daemon(后台启动)  配置文件目录

控制台的一些操作:
主题的操作:
kafka-topics.sh --zookeeper 节点url 主题操作命令
*创建主题时必须指定分区数和副本数,单实例模式就没必要创建多个副本了;
消费者操作:
kafka-console-consumer.sh --bootstrap-server ip:port
生产者操作:
kafaka-console-producer.sh --broker-list host:port --topic 主题
kafka发送与接收:
在这里插入图片描述

发送消息的参数说明:
在这里插入图片描述

相关代码
生产者:
	引入依赖
	配置属性:
		bootstrap.servers
		key.serializer
		value.serializer
		ack...
	KafkaProducer.new
	ProcuderRecord.new
		参数:主题、分区、key、value,headers 可选
	同步确认:
		producer.send(record);
		fature.get()
	异步确认:
		producer.send(record,callback的方法实现)
消费者:
	无法推送.只有拉取
	消费者的参数:贴图
	配置属性:
		bootstrap.servers
		key.deserializer 反序列化
		value.deserializer 反序列化
		group.id
		auto.offset.reset.config 偏移量设置
	KafkaConsumer.new
	订阅主题consumer.subscribe(集合或者正则)
	consumer.poll()拉取
	遍历消息收集器forEach(new Consumer()的方法实现)

SpringBoot整合Kafka:

配置文件:
	bootstrap-servers=kafka server host
	producer:
		key、value序列化
		batch-size=每批次最多消息树
		buffer-memory总可用缓存大小,字节单位
	consumer:
		group-id
		反序列化
		auto-offset-reset=偏移量自动重置
		enable-auto-commit是否自动提交
		anto-commit-interval多长时间自动提交一次
生产者:
	同步发送:KafkaTemplate.send(topic,partition,key,message)
	futrue.get() 获取发送结果
	result.getRecordMetadata()获取结果的元数据
	异步发送:KafkaTemplate.send(topic,partition,key,message)
	futrue.addCallback()
消费者:
	@KafkaListener来自动拉取消息,修饰方法的参数:
		ConsumerRecord获取消息对象.属性比较全
配置类用法:
	创建主题 NewTopic 
	设置Admin KafkaAdmin
	设置Tmeplate KafkaTemplate
kafka服务端参数配置:
server.properties:
	zookeeper.connect=zookeeper单个或者集群,集群就配过半数量的zk节点,zk节点的路径不用跟着多写,最后一个带上就行
	listeners:监听配置,该配置可将kafka进行管理业务分离,通过不同的url进行区分.
内外网隔离配置:
	listener.security.protocol.map
	监听器名称和安全协议的映射配置。
	比如,可以将内外网隔离,即使它们都使用SSL。
	listener.security.protocol.map=INTERNAL:SSL,EXTERNAL:SSL
	每个监听器的名称只能在map中出现一次。
	inter.broker.listener.name
	用于配置broker之间通信使用的监听器名称,该名称必须在advertised.listeners列表中。
	inter.broker.listener.name=EXTERNAL
	listeners
	用于配置broker监听的URI以及监听器名称列表,使用逗号隔开多个URI及监听器名称。
	如果监听器名称代表的不是安全协议,必须配置listener.security.protocol.map。
	每个监听器必须使用不同的网络端口。
	advertised.listeners
	需要将该地址发布到zookeeper供客户端使用,如果客户端使用的地址与listeners配置不同。
	可以在zookeeper的 get /myKafka/brokers/ids/<broker.id> 中找到。
	在IaaS环境,该条目的网络接口得与broker绑定的网络接口不同。
	如果不设置此条目,就使用listeners的配置。跟listeners不同,该条目不能使用0.0.0.0网络端口。
	advertised.listeners的地址必须是listeners中配置的或配置的一部分。

Kafka高级:

消息发送流程:

在这里插入图片描述

重发机制要注意消息的顺序性.
批次发送的触发机制:消息达到批次容量或者第一条消息等待时间达到linger.ms上限,谁先达标

生产者必要参数设置:

bootstrap.servers 连接broker集群必备参数呀
key.serializer key的序列化
value.serializer value的序列化
acks:	
	消息持久性控制参数
	0:不等待消息确认,以最快速度发出去,因为不关系是否确认,所以不需要偏移量,就永远是-1.
	1:允许少量的丢失.这个少量的丢失就是leader挂机故障转移时丢失的.有一些消息没有被同步.
	all/-1:所有同步的副本都确认才认为消息发送成功,注意是同步副本,不包括OSR异步副本.
compresson.type:
	压缩格式,默认是none不压缩,为了提高网络传输效率,可以将批次消息进行压缩,可设置gzip、snappy、lz4.
retries:
	消息发送失败时重试的次数,如果开启了,那么就无法保证消息的顺序性.但可以设置max.in.flight.requests.per.connection=1,这样就会等待消息确认的数量,在没有收到这些数量的消息确认之前,不会再发送新消息.针对异步的哈,同步的直接方法处理就行啦
生产者其他的补充参数:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

kafka序列化器:
自定义序列化器:
	我们可以将自己的pojo啊或者一些实体进行序列化,转换成流数据,实现Serializer的接口,按照自己的需求设计,组装byte数组.
kafka分区器分析:
默认的分区器,选择分区的流程是开始没有发送过消息,根据key计算时,随机一个数字,然后返回进行%运算,然后上层进行取出分区号进行返回,如果我们自己设置了分区号,那么就没有上面的流程了.
自定义分区器:
	实现Partitioner接口;
	根据业务编写分区的选择;
kafka拦截器:
producer和consumer都有,对发送的消息和接收的消息可以进行拦截过滤,采用的不是责任链顺序的后进先出,如进被1234拦截器顺序拦截,而出时还是1234顺序拦截.
自定义拦截器:
	生产者进代表kafka返回,出代表发到kafka,客户端则反之;
	自定义拦截器可以像spring mvc和mybatis拦截器一样,添加一些公用的参数啦,或者进行一些权限检测啦,一些通用的防空,无效数值等;
	实现ProducerInterceptor接口
	拦截器被多线程使用,注意线程安全
	onSend为发送时(出)的拦截器执行方法;
	onAcknowledgement为确认时(进)的拦截器执行方法
生产者原理:

在这里插入图片描述

主线程负责producer、拦截器、序列化器、分区器.执行,添加到消息累加器,作为批次发送的缓存区.
sender线程负责request创建、已发送缓存、selector的response对象、与kafka broker交互
消费组:
高并发环境下,我们不光要扩展消费者,同时也要扩展分区.
多个消费组消费同一个主题互不干扰
消费者的心跳机制:
组内消费者挂机或者主体内分区挂机,进行重新分配和故障转移;
broker端会有 Coordinator进行检测,consumer通过sessionTimeoutMs和rebalanceTimeoutMs参数来控制.
消费者的必要参数:
bootstrap.servers 连接broker集群必备参数呀
key.deserializer key的反序列化
value.deserializer value的反序列化
client.id 客户端ID,进行唯一,追踪方便
group.id 消费群组
auto.offset.reset偏移量重置机制
	earliest:自动重置到最早偏移量
	latest:自动重置到最新的偏移量
	none:之前记录的偏移量(previous) 不存在了就抛异常.
	anything:直接抛异常
enable.auto.commit:周期性向broker提交当前读取的偏移量
其他参数:
auto.commit.interval.ms
	如果设置了 enable.auto.commit 的值为true,则该值定义了消费者偏移量向Kafka提交的频率。
fetch.min.bytes
	服务器对每个拉取消息的请求返回的数据量最小值。如果数据量达不到这个值,请求等待,以让更多的数据累积,达到这个值之后响应请求。默认设置是1个字节,表示只要有一个字节的数据,就立即响应请求,或者在没有数据的时候请求超时。将该值设置为大一点儿的数字,会让服务器等待稍微长一点儿的时间以累积数据。如此则可以提高服务器的吞吐量,代价是额外的延迟时间。
fetch.max.wait.ms
	如果服务器端的数据量达不到 fetch.min.bytes 的话,服务器端不能立即响应请求。该时间用于配置服务器端阻塞请求的最大时长。
fetch.max.bytes
	服务器给单个拉取请求返回的最大数据量。消费者批量拉取消息,如果第一个非空消息批次的值比该值大,消息批也会返回,以让消费者可以接着进行。即该配置并不是绝对的最大值。broker可以接收的消息批最大值通过message.max.bytes (broker配置) 或 max.message.bytes (主题配置)来指定。需要注意的是,消费者一般会并发拉取请求。
connections.max.idle.ms
	在这个时间之后关闭空闲的连接。
check.crcs
	自动计算被消费的消息的CRC32校验值。可以确保在传输过程中或磁盘存储过程中消息没有被破坏。它会增加额外的负载,在追求极致性能的场合禁用。
exclude.internal.topics
	是否内部主题应该暴露给消费者。如果该条目设置为true,则只能先订阅再拉取。
solation.level
	控制如何读取事务消息。如果设置了 read_committed ,消费者的poll()方法只会返回已经提交的事务消息。如果设置了 read_uncommitted (默认值),消费者的poll方法返回所有的消息,即使是已经取消的事务消息。非事务消息以上两种情况都返回。消息总是以偏移量的顺序返回。read_committed 只能返回到达LSO的消息。在LSO之后出现的消息只能等待相关的事务提交之后才能看到。结果, read_committed 模式,如果有为提交的事务,消费者不能读取到直到HW的消息。read_committed 的seekToEnd方法返回LSO。
heartbeat.interval.ms
	当使用消费组的时候,该条目指定消费者向消费者协调器发送心跳的时间间隔。心跳是为了确保消费者会话的活跃状态,同时在消费者加入或离开消费组的时候方便进行再平衡。该条目的值必须小于 session.timeout.ms ,也不应该高于session.timeout.ms 的1/3。可以将其调整得更小,以控制正常重新平衡的预期时间。
session.timeout.ms
	当使用Kafka的消费组的时候,消费者周期性地向broker发送心跳数据,表明自己的存在。如果经过该超时时间还没有收到消费者的心跳,则broker将消费者从消费组移除,并启动再平衡。该值必须在broker配置 group.min.session.timeout.ms 和 group.max.session.timeout.ms 之间。
max.poll.records
	一次调用poll()方法返回的记录最大数量。
max.poll.interval.ms
	使用消费组的时候调用poll()方法的时间间隔。该条目指定了消费者调用poll()方法的最大时间间隔。如果在此时间内消费者没有调用poll()方法,则broker认为消费者失败,触发再平衡,将分区分配给消费组中其他消费者。
max.partition.fetch.bytes
	对每个分区,服务器返回的最大数量。消费者按批次拉取数据。如果非空分区的第一个记录大于这个值,批处理依然可以返回,以保证消费者可以进行下去。broker接收批的大小由 message.max.bytes (broker参数)或max.message.bytes (主题参数)指定。fetch.max.bytes 用于限制消费者单次请求的数据量。
send.buffer.bytes
	用于TCP发送数据时使用的缓冲大小(SO_SNDBUF),-1表示使用OS默认的缓冲区大小。
retry.backoff.ms
	在发生失败的时候如果需要重试,则该配置表示客户端等待多长时间再发起重试。该时间的存在避免了密集循环。
request.timeout.ms
	客户端等待服务端响应的最大时间。如果该时间超时,则客户端要么重新发起请求,要么如果重试耗尽,请求失败。
reconnect.backoff.ms
	重新连接主机的等待时间。避免了重连的密集循环。该等待时间应用于该客户端到broker的所有连接。
reconnect.backoff.max.ms
	重新连接到反复连接失败的broker时要等待的最长时间(以毫秒为单位)。如果提供此选项,则对于每个连续的连接失败,每台主机的退避将成倍增加,直至达到此最大值。在计算退避增量之后,添加20%的随机抖动以避免连接风暴。
receive.buffer.bytes
	TCP连接接收数据的缓存(SO_RCVBUF)。-1表示使用操作系统的默认值。
partition.assignment.strategy
	当使用消费组的时候,分区分配策略的类名。
metrics.sample.window.ms
	计算指标样本的时间窗口。
metrics.recording.level
	指标的最高记录级别。
metrics.num.samples
	用于计算指标而维护的样本数量
interceptor.classes
	拦截器类的列表。默认没有拦截器拦截器是消费者的拦截器,该拦截器需要实现org.apache.kafka.clients.consumer .ConsumerInterceptor 接口。拦截器可用于对消费者接收到的消息进行拦截处理。
订阅详解:
Topic:逻辑概念,将一个消息队列进行分片的概念.
partition:具体的消息分片存储单元.
cosumer group:消费组就是为了避免几个consumer重复消费数据而设计的
kafka是针对大数据的,推送一旦数据过大,就会造成cosumer的崩溃,所以kafka消息MQ的性能,是取决于consumer的性能的,所以consumer要根据自己的处理能力进行拉取,就不需要搞push;kafka的应用就适合收集大量数据,而对时效要求不高
反序列化:
将Byte数组进行反序列化,进行正常的展示和操作.
自定义反序列化:
	实现Deserializer接口
		buffer.flinp()反转方法,将byte数组进行反转.

位移提交:

consumer记录了自己当前消费的消息位置标记,早期存储在zk,后期存储在consumer和kafka端,但是存储在kafka,consumer去提交.broker是每个分区都会有单独的记录偏移量
自动提交enable.auto.commit 默认开启
提交间隔auto.commit.interval.ms  默认5s
自动提交不会导致消息丢失,但是会导致重复消费,分区再平衡时就会丢失提交间隔内的消费记录. 只能从上一次提交的偏移量中开始拉消息
同步提交:
	阻塞式进行提交,保证偏移量,但影响性能.
异步提交:
	避免阻塞,但不会自动重试,有可能提交失败了哦,所以用 同步和异步组合提交. 双重保险

消费者位移管理:

正常情况下在分区级不会出现顺序问题,一旦消费者挂机导致的再平衡,新的消费者就会出现顺序问题.但是在消费者组内的话,broker存储的偏移量就以主题:消费组:分区 为key进行存储偏移量,所以不管如何更换组内的消费者,都不会出现消费顺序问题.
KafkaConsumer的一些方法:
	public void assign(Collection<TopicPartition> partitions)
		给当前消费者手动分配一系列主题分区。手动分配分区不支持增量分配,如果先前有分配分区,则该操作会覆盖之前的分配。如果给出的主题分区是空的,则等价于调用unsubscribe方法。手动分配主题分区的方法不使用消费组管理功能。当消费组成员变了,或者集群或主题的元数据改变了,不会触发分区分配的再平衡。手动分区分配assign(Collection)不能和自动分区分配subscribe(Collection,ConsumerRebalanceListener)一起使用。如果启用了自动提交偏移量,则在新的分区分配替换旧的分区分配之前,会对旧的分区分配中的消费偏移量进行异步提交。
	public Set<TopicPartition> assignment()
		获取给当前消费者分配的分区集合。如果订阅是通过调用assign方法直接分配主题分区,
		则返回相同的集合。如果使用了主题订阅,该方法返回当前分配给该消费者的主题分区集
		合。如果分区订阅还没开始进行分区分配,或者正在重新分配分区,则会返回none。
	public Map<String, List<PartitionInfo>> listTopics()
		获取对用户授权的所有主题分区元数据。该方法会对服务器发起远程调用。
	public List<PartitionInfo> partitionsFor(String topic)
		获取指定主题的分区元数据。如果当前消费者没有关于该主题的元数据,就会对服务器发
		起远程调用。
	public Map<TopicPartition, Long> beginningOffsets(Collection<TopicPartition>partitions)
		对于给定的主题分区,列出它们第一个消息的偏移量。
		注意,如果指定的分区不存在,该方法可能会永远阻塞。
		该方法不改变分区的当前消费者偏移量。
	public void seekToEnd(Collection<TopicPartition> partitions)
		将偏移量移动到每个给定分区的最后一个。
		该方法延迟执行,只有当调用过poll方法或position方法之后才可以使用。
		如果没有指定分区,则将当前消费者分配的所有分区的消费者偏移量移动到最后。
		如果设置了隔离级别为:isolation.level=read_committed,则会将分区的消费偏移量移动
		到最后一个稳定的偏移量,即下一个要消费的消息现在还是未提交状态的事务消息。
	public void seek(TopicPartition partition, long offset)
		将给定主题分区的消费偏移量移动到指定的偏移量,即当前消费者下一条要消费的消息偏
		移量。
		若该方法多次调用,则最后一次的覆盖前面的。
		如果在消费中间随意使用,可能会丢失数据。
	public long position(TopicPartition partition)
		检查指定主题分区的消费偏移量
	public void seekToBeginning(Collection<TopicPartition> partitions)
		将给定每个分区的消费者偏移量移动到它们的起始偏移量。该方法懒执行,只有当调用过
		poll方法或position方法之后才会执行。如果没有提供分区,则将所有分配给当前消费者的
		分区消费偏移量移动到起始偏移量。
消费者接入新的分区时,偏移量默认会设置成最新偏移量.这个偏移量创建了后,如果不修改,那么就在broker一直是这个数,不会变,换消费者也是.

kafka再平衡:

一个双刃剑的机制,平衡会导致暂时无法消费消息,但又相对保证了可用性,所以是个双刃剑,有利有弊.
再平衡触发机制:
	消费组内成员变化,触发
	主题内分区变化,触发
	正则匹配到新主题,触发
如何避免:
	扩容时间主动化,搞闲时弄.
	心跳超时时间长点,我跳的慢,但是跳
	将心跳频率搞一搞,但影响性能.
	修改两次拉取消息间隔,我处理的慢了点,没挂没挂 默认5分,在最长处理时间基础上再加一分钟应该没啥问题了
消费者拦截器:
在到KafkaConsumer返回前拦截,也是123进123出;
自定义拦截器:
	实现ConsumerInterceptor接口
	onConsume()接的消息前方法
	onCommit提交偏移量前的方法

消费组管理:

三个特性:组内消费者可以是进程也可以是线程;主题内的一个分区只能对应消费组的一个消费者;group.id是消费组的唯一标识;
消费组消费者的偏移量记录在kafka中存储的key为topic:groupid:partition,就可以标记这个主题对应这个组的偏移量记录了.与别的消费组不冲突.
再平衡的执行角色Group Coordinator,消费组内消费者与broker连接后就会商量哪一个broker是协调者这个角色.
确定协调者流程:
	确定消费组偏移量信息写入主题_consumers_offsets(专门存偏移量的那个主题)的哪个分区.
	存哪个分区的计算公式:
		Math.abs(groupId.hashCode() % offsets.topic.num.partitions配置指定的数值,默认50),那不够50个分区呢...只有一个分区呢.算来是49咋整啊?
	该分区的leader所在的broker就是协调器broker
	Rebalance Generation:
	每次再平衡都为换代一次.消费者都会记录当前自己所在的映射代数,再平衡后,就会进入下一代,消费者重新记录.当某个上一代的消费者重新进入,因为代数有差异就不会继续读取之前映射关系的分区,防止读取错误.

消费组的偏移量管理:

管理命令:
./kafka-consumer-groups.sh 详细属性就会显示
常用的命令:
--rdescribe  --group group组内偏移量信息
--reset-offsets --group group --topic topicName --to-earliest/latest --execute 重置组内所有分区的消费者偏移量.可选择设置成0还是设置成最新消息的偏移量.
--reset-offsets --group group --topic topicName:分区号  --shift-by 移动数量 --execute
将指定主题内指定某个分区(多个分区逗号隔开)的偏移量移动指定数的距离.负数就往左移动.
kafka协议:
针对消费组与协调者的相关请求通讯:
	heartbeat:心跳通讯;
	leaveGroup:我离组了.平衡吧
	SyncGourp:分配分区的方案通知消费者一下
	JoinGroup:有新的消费者加入消费组了
	DescribeGroup:显示组的所有信息.
先连接上的消费者作为组内leader与协调者进行通信开始平衡策略.消费组告知组内其他成员谁是leader,消费者进行分配组内成员与分区的映射情况告诉协调器,协调器再告诉其他组内消费者

消费组状态机:
在这里插入图片描述

kafka主题管理:

主题的配置信息,用于对主题的一些属性进行配置.
一些参数:
	通过./kakfa-topic.sh可查看具体的属性
主题的command操作:
	创建主题
	kafka-topics.sh --zookeeper localhost:2181/myKafka --create --topic topic_x --partitions 1 -- replication-factor 1
	kafka-topics.sh --zookeeper localhost:2181/myKafka --create --topic topic_test_02 --partitions 3 -- replication-factor 1 --config max.message.bytes=1048576 --config segment.bytes=10485760
	查看主题
	kafka-topics.sh --zookeeper localhost:2181/myKafka --list
	kafka-topics.sh --zookeeper localhost:2181/myKafka --describe --topic topic_x
	kafka-topics.sh --zookeeper localhost:2181/myKafka --topics-with-overrides --describe
	修改主题
	kafka-topics.sh --zookeeper localhost:2181/myKafka --create --topic topic_test_01 --partitions 2 -- replication-factor 1
	kafka-topics.sh --zookeeper localhost:2181/myKafka --alter --topic topic_test_01 --config
	max.message.bytes=1048576
	kafka-topics.sh --zookeeper localhost:2181/myKafka --describe --topic topic_test_01
	kafka-topics.sh --zookeeper localhost:2181/myKafka --alter --topic topic_test_01 --config segment.bytes=10485760
	kafka-topics.sh --zookeeper localhost:2181/myKafka --alter --delete-config max.message.bytes -- topic topic_test_01
	删除主题
	kafka-topics.sh --zookeeper localhost:2181/myKafka --delete --topic topic_x
给主题增加分区:
	不支持删除啊只能添加
	kafka-topics.sh --zookeeper localhost/myKafka --alter --topic myTop1 --partitions 2

分区副本的机制:

副本就负责同步leader分区的数据,不干活,随时准备替换死掉的leader分区.
副本就像一个消费者一样,持续消费leader分区的消息.
ISR同步副本OSR异步部分,一般OSR不会成为leader分区,数据会丢失,但unclean.leader.election.enable配置可以设置OSR可否作为leader分区.
分区leader选举:
默认只有ISR会成为leader分区.OSR不会.可设置unclean.leader.election.enable 来决定OSR能否成为leader,但是会丢消息哦.不设置,ISR全死掉了OSR也不会成为Leader,这个分区会变为不可用.
分区副本的分配:
副本均匀的分散在集群内每个broker上.
某个broker的分区,副本必定会在其他broker上;
副本不光在不同broker,如果有机架信息,也要尽量分配在不同的机架上.
分配时候,副本会在leader跳一位的broker上存放,到尾部就不跳.直接从头放,这样可以最大保证副本的分散.再从头放就会再多跳一个broker.
分区在集群中新增节点的重新分配:
节点只要注册在相同的ZK上就可以成为集群.
kafka-reassign-partitions.sh --zookeeper zkhost:port/node --topics-to-move-json-file *.json --broker-list "集群brokerID都列出来" --工作模式
重新分配分区命令.
具体的工作模式:
	generate把当前的分配情况写入一个json文件, 文件要自己建,然后给你展示推荐的分配方案供你选择,但你可以不接受它的建议;
	execute 按照json文件里的方案进行重新分配;
	verify 查看当前这个json文件分配的方案是否执行完毕;
分区副本分配的自动再平衡:
kafka-topics.sh --zookeeper zkhost:port/node --create --topic topicName --replica-assignment "0:1,1:0,0:1 引号中数字多个分区用逗号隔开,每个分区多个副本用":"隔开,每个分区里第一个数字代表leader,后面数字代表副本,具体的数字代表brokerId,N个逗号就代表N+1个分区,分区内X个冒号就代表X+1个副本.
kafka-preferred-relica-election.sh --zookeeper zkhost:port/node  
按照之前定好的leader是哪个副本进行重置.可用json文件重置具体某个主题的某个分区,json格式:
	{partitions:[{"topic":"topicName","partition":pNum},{...}]},执行命令添加--path-to-json-file *.json
修改副本因子(副本数量):
同样是用json文件来指定副本因子,跟重新分配分区一样的sh,只不过后面的命令是 --reassignment-json-file *.json --execute
kafka-reassign-partitions.sh
消费者与分区分配策略:
默认采用RangeAssignor分配算法,分区数/消费者数=得分区数,余数就从第0号消费者开始+1,该消费者被分配的分区就是(得分区数+1)个的连续不间断分区
RoundRobinAssignor轮询分配,主题内的分区采用轮流分配,0给0消费者,1给1消费者以此类推,轮流分配给消费组内的消费者.不管消费者已经订阅几个分区和主题.会造成分配不均匀,而且分区或消费者宕机,会导致全部再平衡.
StickyAssignor粘性分配(低调模式):在消费者下线时,只重新分配该消费者订阅的分区.将这个几个分区重新分配给其他消费者.
自定义分配:
	实现PartitionAssignor接口
	也可继承AbstractPartitionAssignor抽象类
kafka-topic.sh的必要配置参数:
cleanup.policy:默认delete 
	要么是”delete“要么是”compact“; 这个字符串指明了 针对旧日志部分的利用方式;默 认方式("delete")将会丢弃旧 的部分当他们的回收时间或者尺 寸限制到达时。”compact“将会 进行日志压缩
compression.type:默认none
	producer用于压缩数据的压缩类 型。默认是无压缩。正确的选项 值是none、gzip、snappy、 lz4。压缩最好用于批量处理,批 量处理消息越多,压缩性能越 好。
max.messahe.bytes:默认1000000
	kafka追加消息的最大字节数。注 意如果你增大这个字节数,也必 须增大consumer的fetch字节 数,这样consumer才能fetch到 这些最大字节数的消息。
min.cleanble.dirty.ratio:默认0.5
	此项配置控制log压缩器试图进行 清除日志的频率。默认情况下, 将避免清除压缩率超过50%的日 志。这个比率避免了最大的空间 浪费
min.insync.replicas:默认1 	
	当producer设置 request.required.acks为-1时, min.insync.replicas指定replicas 的最小数目(必须确认每一个 repica的写数据都是成功的), 如果这个数目没有达到, producer会产生异常。
retention.bytes:默认none
	如果使用“delete”的retention 策 略,这项配置就是指在删除日志 之前,日志所能达到的最大尺 寸。默认情况下,没有尺寸限制 而只有时间限制
retention.ms:默认7days
	如果使用“delete”的retention策 略,这项配置就是指删除日志前 日志保存的时间。
segment.bytes:默认1G
	kafka中log日志是分成一块块存 储的,此配置是指log日志划分成 块的大小
segment.index.bytes:10MB
	此配置是有关offsets和文件位置 之间映射的索引文件的大小;一 般不需要修改这个配置
segment.jitter.ms:默认0
segment.ms:默认7days
	即使log的分块文件没有达到需要 删除、压缩的大小,一旦log 的 时间达到这个上限,就会强制新 建一个log分块文件
unclean.leader.election.enable:默认true
	指明了是否能够使不在ISR中 replicas设置用来作为leader
kafkaAdminClient:
抽象类,主要负责对kafka的一些管理工作.
一些功能:
	1. 创建主题:
	1. createTopics(final Collection<NewTopic> newTopics, final CreateTopicsOptions
	options)
	2. 删除主题:
	1. deleteTopics(final Collection<String> topicNames, DeleteTopicsOptions options)
	3. 列出所有主题:
	1. listTopics(final ListTopicsOptions options)
	4. 查询主题:
	1. describeTopics(final Collection<String> topicNames, DescribeTopicsOptions
	options)
	5. 查询集群信息:
	1. describeCluster(DescribeClusterOptions options)
	6. 查询配置信息:
	1. describeConfigs(Collection<ConfigResource> configResources, final
	DescribeConfigsOptions options)
	7. 修改配置信息:
	1. alterConfigs(Map<ConfigResource, Config> configs, final AlterConfigsOptions
	options)
	8. 修改副本的日志目录:
	1. alterReplicaLogDirs(Map<TopicPartitionReplica, String> replicaAssignment, final
	AlterReplicaLogDirsOptions options)
	9. 查询节点的日志目录信息:
	1. describeLogDirs(Collection<Integer> brokers, DescribeLogDirsOptions options)
	10. 查询副本的日志目录信息:
	1. describeReplicaLogDirs(Collection<TopicPartitionReplica> replicas,
	DescribeReplicaLogDirsOptions options)
	11. 增加分区:
	1. createPartitions(Map<String, NewPartitions> newPartitions, final
	CreatePartitionsOptions options)
一些参数:
	bootstrap.servers
		向Kafka集群建立初始连接用到的host/port列表。客户端会使用这里列出的所有服务器进行集群其他服务器的发现,而不管是否指定了哪个服务器用作引导。这个列表仅影响用来发现集群所有服务器的初始主机。字符串形式:host1:port1,host2:port2,...由于这组服务器仅用于建立初始链接,然后发现集群中的所有服务器,因此没有必要将集群中的所有地址写在这里,一般最好两台,以防其中一台宕掉.
	client.id
		生产者发送请求的时候传递给broker的id字符串。用于在broker的请求日志中追踪什么应用发送了什么消息。一般该id是跟业务有关的字符串。
	connections.max.idle.ms 当连接空闲时间达到这个值,就关闭连接。long型数据,默认:300000
	receive.buffer.bytes
		TCP接收缓存(SO_RCVBUF),如果设置为-1,则使用操作系统默认的值。int类型值,默认65536,可选值:[-1,...]
	request.timeout.ms
		客户端等待服务端响应的最大时间。如果该时间超时,则客户端要么重新发起请求,要么如果重试耗尽,请求失败。int类型值,默认:120000
	security.protocol
		跟broker通信的协议:PLAINTEXT, SSL,SASL_PLAINTEXT, SASL_SSL.string类型值,默认:PLAINTEXT
	send.buffer.bytes
		用于TCP发送数据时使用的缓冲大小(SO_SNDBUF),-1表示使用OS默认的缓冲区大小。int类型值,默认值:131072
	reconnect.backoff.max.ms
		对于每个连续的连接失败,每台主机的退避将成倍增加,直至达到此最大值。在计算退避增量之后,添加20%的随机抖动以避免连接风暴。long型值,默认1000,可选值:[0,...]
	reconnect.backoff.ms
		重新连接主机的等待时间。避免了重连的密集循环。该等待时间应用于该客户端到broker的所有连接。long型值,默认:50
	retries
		The maximum number of times to retry a callbefore failing it.重试的次数,达到此值,失败。int类型值,默认5。
	retry.backoff.ms
		在发生失败的时候如果需要重试,则该配置表示客户端等待多长时间再发起重试。该时间的存在避免了密集循环。long型值,默认值:100
主要实现:
	自定义XXOptions来设置一些配置;
	自定义XXXResult返回值
	自定义Call,然后挑选合适的XXXRequest和XXXResponse来实现Call类中的3个抽象方法
kafka物理存储:

在这里插入图片描述

LogSegment:
	日志文件包含很多片段
	顺序写入
	分段减小整体日志文件的小,把大的拆分成小块.再按顺序写,查的更快.
		.index偏移量索引文件
		.timestamp时间戳索引文件
		.log日志
		.snapshor快照
		.deleted删除

日志索引文件
在这里插入图片描述

文件切分:
	日志切割
	超过log.segment.bytes设置 切
	超过log.roll.hours时间, 切
	超过索引的log.index.size.max.bytes 大小, 切
	追加的消息偏移量,与当前日志分段的偏移量,大于了int的maxValue, 切.
	索引文件切割:
	先预先分配空间,等攒够了,切,再开辟一个空间,攒;
日志存储:
	索引:可根据偏移量查询,也可根据时间戳查询.
	创建主题时,设置分段的大小.
	kakka-run-class.sh kafka.tools.DumpLogSegments --files 日志文件 --print-data-log | head设置个管道,就显示10条
	时间戳日志文件是先通过时间戳查到到偏移量,再根据偏移量查询便宜索引文件定位到position拿到数据
	偏移量索引文件:index文件
		写入4K log.index.interval.bytes设置时,就会写入一条索引信息到index文件,所以是稀疏索引.
		索引文件格式由相对偏移量和position组成,用于快速定位到数据范围.
	时间戳索引文件:
		索引文件格式由时间戳和相对偏移量组成,就可根据时间戳查到偏移量,再去index文件通过偏移量查到poisition
日志清理:
log.cleanup.policy配置来决定哪个删除策略,主题级别是cleanup.policy配置
基于时间戳删除:
	1:删除 按照一定策略进行删除;
		策略:
		基于时间:log.retention.hours/log.retention.minutes/log.retention.ms 小时,分钟,毫秒.
		根据时间戳查询到索引,取出最后一个索引,索引的时间戳如果大于0就用它作为当前时间,否则就用最近修改时间来确定当前时间.再去用上面的设置的参数计算符合删除的时间戳,然后小于这个时间戳的日志和索引都将被删除.
		如何删除的?
			给分段文件填上.delete后缀
	2:压缩按照key,只保留该key的最后一个版本,其余都干掉;
	删除过程:先给要删的文件加个.delete后缀,遇到该日志文件有一段需要删,会新建一个文件,把不删内容拿出来放在新文件,然后干掉要删的文件.
基于日志大小删除:
	根据log.retention.bytes设置来决多大就删除;
基于偏移量删除:
	根据LogStartOffset设置的偏移量决定,分段偏移量从开始比较,该段下一个偏移量小于设置偏移量,那么就删除该分段,如果等于或者大于,那就不动了
压缩:
	根据KEY,相同的key保留一个版本数据.
	cleanup.policy设置为compact
	将topic遍历两次,第一次记录每个key hash值对应的最后一次偏移量.
	第二次检查每个offset对应的key是否在后面的日志出现过,出现了就删除,否则就不删除.
	日志压缩可以让任何保持在日志头部以内的使用者在max.compaction.lag.ms内看到自己发送消息.过了就没了.
	消息始终保持顺序,不会重新排序
	偏移量永远不变.
	日志开始后,任何使用者都能看到所有记录的最终状态,按记录的顺序写入,如果使用者在主题的log.cleanup.delete.retention.ms时间内达到日志的头部,还能看到删除记录的delete标记.这个设置默认是24小时
	日志清理器:
		log.cleanup.policy删除策略,设置为compact
		log.cleaner.max.compaction.lag.ms 设置最大等待压缩时间,防止消息产出少而导致一直不压缩
		log.cleaner.min.compaction.ms,防止新来的消息就被压缩了,设置个最小检查时间.

kafka磁盘存储:

零拷贝机制:
传统的磁盘机制:
	1磁盘文件读取到内核缓冲区
	2内核穿冲区数据到app的huffer
	3app的buffer 到socket缓冲区
	4:socket到网络协议栈,网卡负责传输
kafka的零拷贝机制跳过了2和3步.使之加速.

kafka页缓存:

先写到页,OS决定什么时候刷盘
mmap机制,将磁盘文件映射到内存,修改内存就能修改磁盘文件;
工作机制是利用OS的page交换空间来实现磁盘到内存的文件映射,这样操作就会就直接从内存同步到磁盘上.
同步:写入到mmap后立即flush
异步,写入到mmap不flush

顺序写入:

kafka顺序读写,利用磁盘特性.
生产的数据持久化到broker,用mmap映射机制实现快速写入.
读取数据时采用sendfile机制,磁盘文件读到OS内核缓冲后,直接转到scoket的buffer进行网络发送.

kafka事务:

事务场景:
	1一批消息让消费者同时全部可收到,或不可收到.
	2生产多个topic或多个partition消息时,放入一个事务一起发送.典型的分布式事务
	3消费了一条消息处理后再发送到另一个topic中,如果处理失败或者再发送失败,那么前面消费的偏移量就不能变,属于消费失败了;
	4生产者挂掉,新的生产者需要接着发送挂掉生产者的事务
	5原子操作,分为三种情况:
		1procuder生产批次消息那种,不能一部分成功,一副本不行
		2:消费信息和生产消息并存,consumer-transform-produce模式; 
		3只有consumer消费消息;消费者可控,所以不需要事务搞
一些概念:
1:2PC事务协调器,处理事务与kafka其他机制的协调工作.
2:事务有一个内部topic来保存事务日志,但只保留最近的事务状态;topic叫transaction_state;
3:有commit和abort操作,涉及隔离级别,队列需要标记事务状态,成为控制消息:controller message
4:根据手动设置transcationId来保证produer挂掉新producer能继续处理,防止僵尸实例.所有生产者将会组建成一个生产组.单个transcationId只能有组内一个生产者处理,kafka是没有针对整体的队列做一个全局ID的,所以需要自己手动设置一个;
5:txId关联producer,避免多个producer使用同一个事务,tx epoch机制
事务定义:
	原子性:要么执行,要么失败,没有一般成一半没成.
	持久性:一旦提交,即为永久
	排序:每个分区以原始顺序查看消息
	交织:可以是事务消息,可以是非事物消息
	事务中无重复消息
事务配置:
	消费者:
		配置自动提交关闭auto.commit
		代码里不能使用手动提交.
		设置isolocation.level:隔离级别Read_commited或READ_UNCOMMITED
	生产者
		必须transaction.id
		配置enbale.idempotence幂等性,怎么重试都这个事务都只会影响这些消息.
		transcation.timeout.ms
			事务超时时间事务协调器在主动中止正在进行的事务之前等待生产者更新事务状态的最长时间。这个配置值将与InitPidRequest一起发送到事务协调器。如果该值大于max.transaction.timeout。在broke中设置ms时,请求将失败,并出现InvalidTransactionTimeout错误。默认是60000。这使得交易不会阻塞下游消费超过一分钟,这在实时应用程序中通常是允许的。
事务组:
	把生产者因事务需要就放到一个组里,这个组有个专门的事务协调器,有相同的事务ID tx.id;
事务协调器:
	事务与kafka的其他机制进行协调进行的中间层,比如消息清理、HW的控制.由事务主题中对该事务的特定分区的leader分区所在broker担任.负责初始化、提交回滚事务.
	管理事务第一个消息的HW,周期性写到ZK节点;
	事务日志与业务日志HW对应的所有正在处理的事务,就是俩主题的日志要关联管理,要不就乱套了.
	事务消息主题分区的列表:
		事务的超时时间;
		事务关联的 producer ID
	注意保证 日志清理时 是否包含当前事务的消息
事务协调器处理流程:
初始化:
	1生产者计算哪个broker是协调器
	2生产者发送开始事务请求.
	3:broker生成事务ID
	4:想协调器主题追加开始的消息.发送响应给生产者
	5生产者收到相应
	6更新事务状态和数据信息
发送:
	生产者开始发送消息给主题leader分区的broker,消息包含TXid和tx的状态,提交还是中止的状态,也携带生产者ID,但日志处理时不需要了.就是检测用的.
结束:
	1producer发送OffsetcommitRequest.与事务结束关联的输入状态
	2producer发送提交事务给协调器,等待响应
	3协调器向消息追加commit请求,给生产者发送响应
	4给事务涉及到的每个leader分区的broker发送提交请求
	5其相关的leader分区broker做处理,如果是普通主题的leader分区,就向对应的分区borker发送空消息,但消息设置txid和tx状态(设置为commited)字段,leader分区broker给协调器返回响应;如果是中转类型的主题,那么追加消息时key就是最后提交量,value是txid,也设置本次处理的txid和tx状态,然后这leader分区的broker给协调器返回响应.
	6协调器向事务控制主题发送commit
	7协调器尝试更新HW
事务中止:
	生产发送中止请求
	协调器向主题追加取消 消息,后返回响应给生产者
	协调器 再向事务中涉及到的leader分区所在broker发送中止请求.
事务失败:
	producer开启事务时候异常,拿着相同的txid重试
	broker出现问题,producer会用新的txID发送事务.
	producer提交事务时出错了,也是使用相同的TXID重试.
主题压缩:
	压缩容易把事务的消息干掉了,所以注意避免
事务相关配置:
	transactional.id.timeout.ms
		在ms中,事务协调器在生产者TransactionalId提前过期之前等待的最长时间,并且没有从该生产者TransactionalId接收到任何事务状态更新。默认是604800000(7天)。这允许每周一次的生产者作业维护它们的id
	max.transaction.timeout.ms
		事务允许的最大超时。如果客户端请求的事务时间超过此时间,broke将在InitPidRequest中返回InvalidTransactionTimeout错误。这可以防止客户机超时过大,从而导致用户无法从事务中包含的主题读取内容。默认值为900000(15分钟)。这是消息事务需要发送的时间的保守上限。
	transaction.state.log.replication.factor 
		事务状态topic的副本数量。默认值:3
	transaction.state.log.num.partitions 
		事务状态主题的分区数。默认值:50
	transaction.state.log.min.isr 
		事务状态主题的每个分区ISR最小数量。默认值:2
	transaction.state.log.segment.bytes 
		事务状态主题的segment大小。默认值:104857600字节

幂等性:

producer发送消息后,broker收到了回响应时producer没有收到.这就导致producer重发,broker又存储了一条,这就造成了问题.
如何解决:
	添加唯一的ID;
	底层设计引入了producerID和SequenceNumber,发送消息时带着这两个属性,这样重试时,broker就会判断这个消息是否与存储的消息一致,一致就不存储了.

事务操作代码实现:

producer发送一堆消息;
在consumer-transform-producer模式下,为了保证幂等性,需要保证再消费时幂等性,就需要再消费确认后,才能让起始消费提交偏移量.
consumer那面就不考虑事务了,手动控制提交偏移就行啦;
kafka事务操作方法:
	initTransactions(); 初始化事务
	beginTransaction 开启事务
	sendOffSetCommit() 事务内的偏移量提交.
	commitTransaction() 提交事务
	abortTransaction() 取消事务

kafka集群控制器:

控制器来保证集群中的可用性,进行故障转移;
控制器选举时用ZK临时节点来做分布式锁,谁拥有节点,谁就是控制器broker,从zk节点信息去查看每个分区的副本和leader的节点信息,使用集群版本数来防止控制器脑裂,但zk出现了脑裂咋办...

kafka消息可靠性:

1创建分区时也创建副本
2leader负责读写,副本只负责从leader上同步消息;
3ISR需要一直与leader进行同步,但是如果与leader的偏移量落后太多的话,就会被降级,降为OSR异步副本,从而失去了替补权利.落后多少是通过replica.lag.max.messages来设置,默认为4000,ISR如果长时间与leader没发送fetch请求,那么也会被降为OSR,这个时间由replica.lag.time.max.ms设置,默认10000
4:给acks=all让所有的副本也得确认.这样保证消息可靠性
要注意副本的分配,尽量均匀的分配在每个不同的broker
防止副本失效,可以控制kafka的可用性,根据网络情况改改通信值啊等等
一致性保证:
HW和LEO:
	HW,所有人都同步到的偏移量.LEO当前最新的消息偏移量.
副本在开始向leader fetch时,如果leader这没有消息,那么会这个请求先扔到leader里的purgatory休息间休息一会,休息多长时间由replica.fetch.wait.max.ms决定,过了这个时间就强制完成,这段时间要是有消息了,那就唤醒他,给leader处理.
从副本合适更新leo呢
副本的leo会在本地存储一份,在leader那也存一份.
	leader因为存了副本的leo,所以leader中的leo为最新的,当从副本拉取完消息后,顺便更新自己的leo,所以hw和每个副本的leo都设计leader副本来管理的.
如何更新HW:
	leader就直接能通过所有副本的最小leo确定HW数
	副本的话就得在去leader fetch消息后,根据更新的leo和leader传来的HW来取最小值做为自己的HW,但会检查这些副本一要符合ISR,二要不能落后太多呀.
leader会尝试去更新副本的HW:
	新leader上任,先更新一波
	broker崩溃导致副本被提出ISR,就检查一下别出错了
	有新消息到leader时,leader更新leo就去看HW要不要更新
	leader处理副本fetch时,读log数据,然后尝试更新一下HW
	正常情况下,只有生产者发消息和副本fetch会更新HW.
当出现异常情况各个leo和HW可能出现的状况:

在这里插入图片描述

leader epoch集群版本来解决 leader重新选举后会出现消息丢失和消息离散.
存储在ZK中 epoch会存储当前集群版本和leader最新的偏移量.当出现故障转移时,根据这两个参数 进行多重判断来防止出现丢失和离散不一致的问题,但你要是开了OSR可上位Leader,那解决不了.
消息重复:
场景:
	生产者:
		生产者重发消息,没有事务的话消息就多了
		生产者可以同时保持多个发送消息没有的ack的连接,这是由max.in.flight.requests.per.connetcion配置决定的数量,如果设置大于1了,那么会出现消息顺序不一致的问题,A1发,A2发,A2成功了,A1失败了重发,A2连接的消息到了前面了
	解决:开启幂等性,ack=0不重试.
	producer到broker时:
		ack=1时,消息刚到leader挂了,副本还没拿到;再选举时会出现消息丢失;
		OSR可上leader模式开启了.更会出现问题
	解决:	
		ack=all和不用OSR上位leader模式.
		设置min.insync.replicas > 1,多点副本确认,就多点稳定.如果没到这个数就抛异常.
	consumer:
		没有及时提交偏移量,或者没来得及确认就挂了;
	解决:
		设置手动提交.
		下游做幂等性,做重复判断,防止重复消费
内部主题__consumer_offsets:
Kafka 1.0.2将consumer的位移信息保存在Kafka内部的topic中,即__consumer_offsets主题,并且默认提供了kafka_consumer_groups.sh脚本供用户查看consumer信息。

延时队列:

炼狱休息间儿:
	副本向leaderfetch请求时,leader没有新消息就会请去单间呆一会;有了就唤醒拿数据返回
ack=all:
	等所有的副本都确认后leader才会向生产者ack消息成功发送.kafka创建了一个延时生产操作DelayedProducer,可由request.timeout.ms定时触发,或者副本接收完成了直接触发.
发送批次消息时,消息不够一个批次数也有个等待时间,到了这个时间不够一个批次的消息也发送.
通过Timewavel时间轮来搞这个延时队列操作.

重试队列:

kafka没有重试队列,想实现,就自己进行处理;
业务队列消息如果处理失败,将消息扔到redis或者别的中间层,再由另一个生产者去获取中间层的消息,然后发送到重试队列中,再由另一个消费者去消费重试队列然后中转发送到业务队列去,消息设置一些唯一属性,在中间层生产者进行标记和判断.如果达到一定次数,则丢弃消息或者做其他处理.

Kafka集群:

单机kafka性能已经很好,但副本功能的使用,就需要集群模式才可以.提供很好扩展和容错;
记录用户的操作轨迹,这在配合大并发的请求,那么数据量会巨大,kafka的集群就可以胜任
监控APP的统计数据,这也需要kafka集群来支持
大量的日志数据,保存用户的一些记录,来保证大数据算法.这也需要集群
流处理,需要集群保证流式正常运转
数据采集也需要集群.
APP节点同步数据支持机制,需要kafka集群配置

集群搭建:

zk顺带也搭上集群
配置kafka配置文件:
	broker.id进行修改
	listeners=PLAINTEXT://:9092 内网监听
	advertised.listeners=PLAINTEXT://外网IP:9092 外网鉴定
配置zookeeper集群配置
启动zk
启动kafka

集群监控:

使用yammer Metrics在服务器和scala客户端
java 使用kafka Metrics,两者都需要JMX公开指标
在kafka broke上的kafka-server-start.sh文件中添加export JMX_PORT=9581
Jconsole 一个java的JMX连接工具
OS监控项:
	java.lang:type=OperatingSystem   FreePhysicalMemorySize 空闲物理内存
	java.lang:type=OperatingSystem SystemCpuLoad  系统CPU利用率
	java.lang:type=OperatingSystem  ProcessCpuLoad  进程CPU利用率
	java.lang:type=GarbageCollector, name=G1 YoungGeneration CollectionCount  GC次数

代码获取监控指标:

public class JMXMonitorDemo {
	public static void main(String[] args) throws IOException, MalformedObjectNameException, AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException { 
		String jmxServiceURL = "service:jmx:rmi:///jndi/rmi://192.168.100.103:9581/jmxrmi";
		JMXServiceURL jmxURL = null;
		JMXConnector jmxc = null;
		MBeanServerConnection jmxs = null;
		ObjectName mbeanObjName = null;
		Iterator sampleIter = null; 
		SetsampleSet = null; //创建JMXServiceURL对象,参数是 jmxURL = new JMXServiceURL(jmxServiceURL);
		// 建立到指定URL服务器的连接 jmxc = JMXConnectorFactory.connect(jmxURL);
		// 返回代表远程MBean服务器的MBeanServerConnection对象
		 jmxs=jmxc.getMBeanServerConnection(); 
		 // 根据传入的字符串,创建ObjectName对象 
		 // mbeanObjName = new ObjectName("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec");
		mbeanObjName = new ObjectName("kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec,topic=tp_eagle_01"); 
		// 获取指定ObjectName对应的MBeans
		sampleSet = jmxs.queryMBeans(null,mbeanObjName); 
		// 迭代器 
		sampleIter = sampleSet.iterator(); 
		if (sampleSet.isEmpty()) { 

		} else {
			 // 如果返回了,则打印信息 
			 while (sampleIter.hasNext()) { 
			 // Used to represent the object name of an MBean and its class name. 
			 // If the MBean is a Dynamic MBean the class name should be retrieved from the MBeanInfo it provides. 
			 // 用于表示MBean的ObjectName和ClassName
			ObjectInstance sampleObj = (ObjectInstance) sampleIter.next();
			ObjectName objectName = sampleObj.getObjectName(); 
			// 查看指定MBean指定属性的值 
			String count = jmxs.getAttribute(objectName, "Count").toString();
			System.out.println(count); 
			} 
		}
		// 关闭 
		jmxc.close(); 
	} 
}
Kafka Eagle:
# 下载编译好的包 
wget http://pkgs-linux.cvimer.com/kafka-eagle.zip 
# 配置kafka-eagle unzip kafka-eagle.zip
cd kafka-eagle/kafka-eagle-web/target
mkdir -p test
cp kafka-eagle-web-2.0.1-bin.tar.gz test/ tar xf kafka-eagle-web-2.0.1-bin.tar.gz
cd kafka-eagle-web-2.0.1
conf下的配置文件:system-config.properties
# 集群的别名,用于在kafka-eagle中进行区分。 
# 可以配置监控多个集群,别名用逗号隔开 
# kafka.eagle.zk.cluster.alias=cluster1,cluster2,cluster3
kafka.eagle.zk.cluster.alias=cluster1 
# cluster1.zk.list=10.1.201.17:2181,10.1.201.22:2181,10.1.201.23:2181
# 配置当前集群的zookeeper地址,此处的值要与Kafka的server.properties中的zookeeper.connect的值一致 # 此处的前缀就是集群的别名
cluster1.zk.list=node2:2181,node3:2181,node4:2181/myKafka
#cluster2.zk.list=xdn10:2181,xdn11:2181,xdn12:2181 
###################################### zookeeper enable acl ######################################
cluster1.zk.acl.enable=false
cluster1.zk.acl.schema=digest
cluster1.zk.acl.username=test
cluster1.zk.acl.password=test123 
###################################### # broker size online list ######################################
cluster1.kafka.eagle.broker.size=20 
###################################### # zookeeper客户端连接数限制 ######################################
kafka.zk.limit.size=25 
###################################### # kafka eagle网页端口号 ######################################
kafka.eagle.webui.port=8048
 ###################################### # kafka 消费信息存储位置,用来兼容kafka低版本 ######################################
cluster1.kafka.eagle.offset.storage=kafka
cluster2.kafka.eagle.offset.storage=zk 
###################################### # kafka metrics, 15 days by default ######################################
kafka.eagle.metrics.charts=true
kafka.eagle.metrics.retain=15 
###################################### # kafka sql topic records max ######################################
kafka.eagle.sql.topic.records.max=5000
kafka.eagle.sql.fix.error=true 
###################################### # 管理员删除kafka中topic的口令 ######################################
kafka.eagle.topic.token=keadmin 
###################################### # kafka 集群是否开启了认证模式,此处是cluster1集群的配置,禁用 ######################################
cluster1.kafka.eagle.sasl.enable=false
cluster1.kafka.eagle.sasl.protocol=SASL_PLAINTEXT
cluster1.kafka.eagle.sasl.mechanism=SCRAM-SHA-256
cluster1.kafka.eagle.sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModu
le required username="kafka" password="kafka-eagle";
cluster1.kafka.eagle.sasl.client.id=
cluster1.kafka.eagle.sasl.cgroup.enable=false
cluster1.kafka.eagle.sasl.cgroup.topics= 
###################################### # kafka ssl authenticate,示例配置 ######################################
cluster2.kafka.eagle.sasl.enable=false
cluster2.kafka.eagle.sasl.protocol=SASL_PLAINTEXT
cluster2.kafka.eagle.sasl.mechanism=PLAIN
cluster2.kafka.eagle.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="kafka" password="kafka-eagle";
cluster2.kafka.eagle.sasl.client.id=
cluster2.kafka.eagle.sasl.cgroup.enable=false
cluster2.kafka.eagle.sasl.cgroup.topics= 
###################################### # kafka ssl authenticate,示例配置 ######################################
cluster3.kafka.eagle.ssl.enable=false
cluster3.kafka.eagle.ssl.protocol=SSL
cluster3.kafka.eagle.ssl.truststore.location=
cluster3.kafka.eagle.ssl.truststore.password=
cluster3.kafka.eagle.ssl.keystore.location=
cluster3.kafka.eagle.ssl.keystore.password=
cluster3.kafka.eagle.ssl.key.password=
cluster3.kafka.eagle.ssl.cgroup.enable=false
cluster3.kafka.eagle.ssl.cgroup.topics= 
###################################### 
# 存储监控数据的数据库地址 
# kafka默认使用sqlite存储,需要指定和创建sqlite的目录 
# 如 /home/lagou/hadoop/kafka-eagle/db
######################################
kafka.eagle.driver=org.sqlite.JDBC
kafka.eagle.url=jdbc:sqlite:/home/lagou/hadoop/kafka-eagle/db/ke.db
kafka.eagle.username=root
kafka.eagle.password=www.kafka-eagle.org 
###################################### # 还可以使用MySLQ存储监控数据 ###################################### 
#kafka.eagle.driver=com.mysql.jdbc.Driver 
#kafka.eagle.url=jdbc:mysql://127.0.0.1:3306/ke?useUnicode=true&characterEncoding=UTF- 8&zeroDateTimeBehavior=convertToNull 
#kafka.eagle.username=root #kafka.eagle.password=123456 
###################################### # kafka eagle 设置告警邮件服务器 ######################################
kafka.eagle.mail.enable=true
kafka.eagle.mail.sa=kafka_lagou_alert
kafka.eagle.mail.username=kafka_lagou_alert@163.com
kafka.eagle.mail.password=Pas2W0rd 
kafka.eagle.mail.server.host=smtp.163.com
kafka.eagle.mail.server.port=25
启动kafka-eagle

./bin/ke.sh start

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值