kafka 初步学习

kafka 是一种消息引擎,了这一步,你可以熟读一遍Kafka官网文档,确保你理解了那些可能影响可靠性和性能的参数。

如何根据实际业务需求评估、搭建生产线上环境将是你主要的学习目标。另外对生产环境的监控也是重中之重的工作,Kafka提供了超多的JMX监控指标,你可以选择任意你熟知的框架进行监控。有了监控数据,作为系统
运维管理员的你,势必要观测真实业务负载下的Kafka集群表现。之后如何利用已有的监控指标来找出系统瓶颈,然后提升整个系统的吞吐量,这也是最能体现你工作价值的地方

消息引擎系统是一种规范。企业利用这组规范在不同的系统之间传递语义准确的消息,实现松耦合的异步式数据传递。

纯二进制的字节序列

Raft算法:共识算法

Leader Follower

kafka的副本是和分区绑定一起的

能否把数据分割成多份保存在不同的Broker上?

如果你就是这么想的,那么恭喜你,Kafka就是这么设计的。
这种机制就是所谓的分区(Partitioning)

Kafka中的分区机制指的是将每个主题划分成多个分区(Partition),每个分区是一组有序的消息日志。生产者生产的每条消息只会被发送到一个分区中,也就是说如果向一个双分区的主题发送一条消息,这条消息要么在分区0中,要么在分区1中。如你所见,Kafka的分区编号是从0开始的,如果Topic有100个分区,那
么它们的分区号就是从0到99。

讲到这里,你可能有这样的疑问:刚才提到的副本如何与这里的分区联系在一起呢?

实际上,副本是在分区这个层级定义的。

消息:Record。Kafka是消息引擎嘛,这里的消息就是指Kafka处理的主要对象

主题:Topic。主题是承载消息的逻辑容器,在实际使用中多用来区分具体的业务。

分区:Partition。一个有序不变的消息序列。每个主题下可以有多个分区。消息位移:Offset。表示分区中每条消息的位置信息,是一个单调递增且不变的值。

副本:Replica。Kafka中同一条消息能够被拷贝到多个地方以提供数据冗余,这些地方就是所谓的副本。副本还分为领导者副本和追随者副本,各自有不同的角色划分。副本是在分区层级下的,即每个分区可配置多个副本实现高可用。

生产者:Producer。向主题发布新消息的应用程序。

消费者:Consumer。从主题订阅新消息的应用程序。

消费者位移:Consumer Offset。表征消费者消费进度,每个消费者都有自己的消费者位移。

消费者组:Consumer Group。多个消费者实例共同组成的一个组,同时消费多个分区以实现高吞吐。

重平衡:Rebalance。消费者组内某个消费者实例挂掉后,其他消费者实例自动重新分配订阅主题分区的过程。Rebalance是Kafka消费者端实现高可用的重要手段。

请思考一下为什么Kafka不像MySQL那样允许追随者副本对外提供读服务?

不从follower读几个原因:
1,kafka的分区已经让读是从多个broker读从而负载均衡,不是MySQL的主从,压力都在主上;
2,kafka保存的数据和数据库的性质有实质的区别就是数据具有消费的概念,是流数据,kafka是消息队列,所以消费需要位移,而数据库是实体数据不存在这个概念,如果从kafka的follower读,消费端offset控制更复杂;
3,生产者来说,kafka可以通过配置来控制是否等待follower对消息确认的,如果从上面读,也需要所有的follower都确认了才可以回复生产者,造成性能下降,如果follower出问题了也不好处理 [4赞]

Kafka是消息引擎系统,也是分布式流处理平台

Kafka线上集群部署方案怎么做?

I/O模型的使用
在Linux上的实现机制是epoll
数据网络传输效率
在Linux部署Kafka能够享受到零拷贝技术所带来的快速数据传输特性。
社区支持度

追求性价比的公司可以不搭建RAID,使用普通磁盘组成存储空间即可。
使用机械磁盘完全能够胜任Kafka线上环境

我们来计算一下:每天1亿条1KB大小的消息,保存两份且留存两周的时间,那么总的空间大小就等于1亿 *
1KB * 2 / 1000 / 1000 = 200GB。一般情况下Kafka集群除了消息数据还有其他类型的数据,比如索引数据
等,故我们再为这些数据预留出10%的磁盘空间,因此总的存储容量就是220GB。既然要保存两周,那么整
体容量即为220GB * 14,大约3TB左右。Kafka支持数据的压缩,假设压缩比是0.75,那么最后你需要规划
的存储空间就是0.75 * 3 = 2.25TB。

总之在规划磁盘容量时你需要考虑下面这几个元素

新增消息数
消息留存时间
平均消息大小
备份数
是否启用压缩

在这里插入图片描述一些关键参数

auto.create.topics.enable=false
unclean.leader.election.enable=false
auto.leader.rebalance.enable=false

这log.retention.{hour|minutes|ms}:这是个“三兄弟”,都是控制一条消息数据被保存多长时间。从优先级上来说ms设置最高、minutes次之、hour最低。
log.retention.bytes:这是指定Broker为消息保存的总磁盘容量大小。
message.max.bytes:控制Broker能够接收的最大消息大小

最后一组参数是数据留存方面的,即:
先说这个“三兄弟”,虽然ms设置有最高的优先级,但是通常情况下我们还是设置hour级别的多一些,比如log.retention.hour=168表示默认保存7天的数据,自动删除7天前的数据。很多公司把Kafka当做存储来使用,那么这个值就要相应地调大。

其次是这个log.retention.bytes。这个值默认是-1,表明你想在这台Broker上保存多少数据都可以,至少在容量方面Broker绝对为你开绿灯,不会做任何阻拦。这个参数真正发挥作用的场景其实是在云上构建多租户的Kafka集群:设想你要做一个云上的Kafka服务,每个租户只能使用100GB的磁盘空间,为了避免有个“恶意”租户使用过多的磁盘空间,设置这个参数就显得至关重要了。

message.max.bytes

最后说说message.max.bytes。实际上今天我和你说的重要参数都是指那些不能使用默认值的参数,个参数也是一样,默认的1000012太少了,还不到1KB。实际场景中突破1MB的消息都是屡见不鲜的,因此在线上环境中设置一个比较大的值还是比较保险的做法。毕竟它只是一个标尺而已,仅仅衡量Broker能够处理的最大消息大小,即使设置大一点也不会耗费什么磁盘空间的

Topic级别参数

说起Topic级别的参数,你可能会有这样的疑问:如果同时设置了Topic级别参数和全局Broker参数,到底听谁的呢?哪个说了算呢?答案就是Topic级别参数会覆盖全局Broker参数的值,而每个Topic都能设置自己的参数值,这就是所谓的Topic级别参数。

retention.ms:规定了该Topic消息被保存的时长。默认是7天,即该Topic只保存最近7天的消息。一旦设置了这个值,它会覆盖掉Broker端的全局参数值。

retention.bytes:规定了要为该Topic预留多大的磁盘空间。和全局参数作用相似,这个值通常在多租户的Kafka集群中会有用武之地。当前默认值是-1,表示可以无限使用磁盘空间。

将你的JVM堆大小设置成6GB吧

我想无脑给出一个通用的建议:将你的JVM堆大小设置成6GB吧,这是目前业界比较公认的一个合理值

KAFKA_HEAP_OPTS:指定堆大小。
KAFKA_JVM_PERFORMANCE_OPTS:指定GC参数

$>	export	KAFKA_HEAP_OPTS=--Xms6g		--Xmx6g
$>	export		KAFKA_JVM_PERFORMANCE_OPTS=	-server	-XX:+UseG1GC	-XX:MaxGCPauseMillis=20	-XX:InitiatingHeapOccupancyPercent=35	-XX:+ExplicitGCInvokesConcurrent	-Djava.awt.headless=true
$>	bin/kafka-server-start.sh	config/server.properties

Java8默认的新生代垃圾回收器是:UseParallelGC,可以用-XX:+PrintCommandLineFlags -version查看,
还有如果显示指定 -XX:+UseCurrentMarkSweepGC 的话,会默认开启 -XX:+UseParallelGC
G1是jdk9中默认的,jdk8还是需要显式指定的

文件描述符限制

ulimit -n 1000000

文件系统类型

Swappiness

基于这个考虑,我个人建议将swappniess配置成一个接近0但不为0的值,比如1

提交时间

最后是提交时间或者说是Flush落盘时间。向Kafka发送数据并不是真要等数据被写入磁盘才会认为成功,而是只要数据被写入到操作系统的页缓存(Page Cache)上就可以了,随后操作系统根据LRU算法会定期将页缓存上的“脏”数据落盘到物理磁盘上。这个定期就是由提交时间来确定的,默认是5秒。一般情况下我们会认为这个时间太频繁了,可以适当地增加提交间隔来降低物理磁盘的写操作。当然你可能会有这样的疑问:如果在页缓存中的数据在写入到磁盘前机器宕机了,那岂不是数据就丢失了。的确,这种情况数据确实
就丢失了,但鉴于Kafka在软件层面已经提供了多副本的冗余机制,因此这里稍微拉大提交间隔去换取性能还是一个合理的做法。

生产者消息分区机制原理剖析

所谓分区策略是决定生产者将消息发送到哪个分区的算法。Kafka为我们提供了默认的分区策略,同时它也支持你自定义分区策略

轮询策略有非常优秀的负载均衡表现,它总是能保证消息最大限度地被平均分配到所有分区上,故默认情况下它是最合理的分区策略,也是我们最常用的分区策略之一

怎么压缩?

不论是哪个版本,Kafka的消息层次都分为两层:消息集合(message set)以及消息(message)。一个消
息集合中包含若干条日志项(record item),而日志项才是真正封装消息的地方。Kafka底层的消息日志由
一系列消息集合日志项组成。Kafka通常不会直接操作具体的一条条消息,它总是在消息集合这个层面上进
行写入操作

所谓“ZeroCopy”就是“零拷贝”,说的是当数据在磁盘和网络进行传输时避免昂贵的内核态数据拷贝,从而实现快速的数据传输

除了CPU资源充足这一条件,如果你的环境中带宽资源有限,那么我也建议你开启压缩

CPU 资源 充足 + 带宽有限 === 开启压缩

如何配置Kafka无消息丢失。

在Kafka的世界里什么才算是消息丢失,或者说Kafka在什么情况下能保证消息不丢失

一句话概括,Kafka只对“已提交”的消息(committed message)做有限度的持久化保证

第一个核心要素是“已提交的消息”。什么是已提交的消息?当Kafka的若干个Broker成功地接收到一条消息并写入到日志文件后,它们会告诉生产者程序这条消息已成功提交。此时,这条消息在Kafka看来就正式变为“已提交”消息了。

这种发送方式有个有趣的名字,叫“fire and forget”,翻译一下就是“发射后不管”。这个术语原本属于
导弹制导领域,后来被借鉴到计算机领域中,它的意思是,执行完一个操作后不去管它的结果是否成功。调
用producer.send(msg)就属于典型的“fire and forget”,因此如果出现消息丢失,我们是无法知晓的。这
个发送方式挺不靠谱吧,不过有些公司真的就是在使用这个API发送消息。

同理,Kafka中Consumer端的消息丢失就是这么一回事。要对抗这种消息丢失,办法很简单:维持先消费
消息(阅读),再更新位移(书签)的顺序即可。这样就能最大限度地保证消息不丢失

12-客户端都有哪些不常见但是很高级的功能?

事实上,我们可以利用拦截器满足实际的需求,比如端到端系统性能检测、消息审计等

Kafka的Java生产者是如何管理TCP连接的

从社区的角度来看,在开发客户端时,人们能够利用TCP本身提供的一些高级功能,比如多路复用请求以及
同时轮询多个连接的能力。

所谓的多路复用请求,即multiplexing request,是指将两个或多个数据流合并到底层单一物理连接中的过
程。TCP的多路复用请求会在一条物理连接上创建若干个虚拟连接,每个虚拟连接负责流转各自对应的数据
流。其实严格来说,TCP并不能多路复用,它只是提供可靠的消息交付语义保证,比如自动重传丢失的报

首先,生产者应用在创建KafkaProducer实例时是会建立与Broker的TCP连接的。其实这种表述也不是很准
确,应该这样说:在创建KafkaProducer实例时,生产者应用会在后台创建并启动一个名为Sender的线程,
该Sender线程开始运行时首先会创建与Broker的连接。

你也许会问:怎么可能是这样?如果不调用send方法,这个Producer都不知道给哪个主题发消息,它又怎
么能知道连接哪个Broker呢?难不成它会连接bootstrap.servers参数指定的所有Broker吗?嗯,是的,Java
Producer目前还真是这样设计的

Producer端关闭TCP连接的方式有两种:一种是用户主动关闭;一种是Kafka自动关闭。

对最新版本的Kafka(2.1.0)而言,Java Producer端管理TCP连接的方式是:

  1. KafkaProducer实例创建时启动Sender线程,从而创建与bootstrap.servers中所有Broker的TCP连接。
  2. KafkaProducer实例首次更新元数据信息之后,还会再次创建与集群中所有Broker的TCP连接。
  3. 如果Producer端发送消息到某台Broker时发现没有与该Broker的TCP连接,那么也会立即创建连接。
  4. 如果设置Producer端connections.max.idle.ms参数大于0,则步骤1中创建的TCP连接会被自动关闭;如
    果设置该参数=-1,那么步骤1中创建的TCP连接将无法被关闭,从而成为“僵尸”连接

幂等生产者和事务生产者是一回事吗?

那么问题来了,Kafka是怎么做到精确一次的呢?简单来说,这是通过两种机制:幂等性(Idempotence)
和事务(Transaction)。它们分别是什么机制?两者是一回事吗?要回答这些问题,我们首先来说说什么
是幂等性。

幂等性Producer
在Kafka中,Producer默认不是幂等性的,但我们可以创建幂等性Producer。它其实是0.11.0.0版本引入的
新功能。在此之前,Kafka向分区发送数据时,可能会出现同一条消息被发送了多次,导致消息重复的情
况。在0.11之后,指定Producer幂等性的方法很简单,仅需要设置一个参数即可,即
props.put(“enable.idempotence”, ture),或
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)。
enable.idempotence被设置成true后,Producer自动升级成幂等性Producer,其他所有的代码逻辑都不需
要改变。Kafka自动帮你做消息的重复去重。底层具体的原理很简单,就是经典的用空间去换时间的优化思
路,即在Broker端多保存一些字段。当Producer发送了具有相同字段值的消息后,Broker能够自动知晓这
些消息已经重复了,于是可以在后台默默地把它们“丢弃”掉。当然,实际的实现原理并没有这么简单,但
你大致可以这么理解。

首先,它只能保证单分区上的幂等性,即一个幂等性Producer能够保证某个主题的一个分区上不出现重复
消息,它无法实现多个分区的幂等性。其次,它只能实现单会话上的幂等性,不能实现跨会话的幂等性。这
里的会话,你可以理解为Producer进程的一次运行。当你重启了Producer进程之后,这种幂等性保证就丧
失了。

那么你可能会问,如果我想实现多分区以及多会话上的消息无重复,应该怎么做呢?答案就是事务
(transaction)或者依赖事务型Producer。这也是幂等性Producer和事务型Producer的最大区别!

好在对于已提交读(read committed)隔离级别的提法,各大主流数据库厂商都比较统一。所谓
的read committed,指的是当读取数据库时,你只能看到已提交的数据,即无脏读。同时,当写入数据库
时,你也只能覆盖掉已提交的数据,即无脏写。

消费者组到底是什么?

那么何谓Consumer Group呢?用一句话概括就是:Consumer Group是Kafka提供的可扩展且具有容错性的消费者机制。既然是一个组,那么组内必然可以有多个消费者或消费者实例(Consumer Instance),它们共享一个公共的ID,这个ID被称为Group ID。组内的所有消费者协调在一起来消费订阅主题(Subscribed Topics)的所有分区(Partition)。
当然,每个分区只能由同一个消费者组内的一个Consumer实例来消费。

消费者组三个特性

  1. Consumer Group下可以有一个或多个Consumer实例。这里的实例可以是一个单独的进程,也可以是同
    一进程下的线程。在实际场景中,使用进程更为常见一些。
  2. Group ID是一个字符串,在一个Kafka集群中,它标识唯一的一个Consumer Group。
  3. Consumer Group下所有实例订阅的主题的单个分区,只能分配给组内的某个Consumer实例消费。这个
    分区当然也可以被其他的Group消费

Consumer Group之间彼此独立,互不影响,它们能够订阅相同的一组主题而互不干涉。再加上Broker端的
消息留存机制,Kafka的Consumer Group完美地规避了上面提到的伸缩性差的问题。可以这么说,Kafka仅
仅使用Consumer Group这一种机制,却同时实现了传统消息引擎系统的两大模型:如果所有实例都属于同
一个Group,那么它实现的就是消息队列模型;如果所有实例分别属于不同的Group,那么它实现的就是发
布/订阅模型

理想情况下,Consumer实例的数量应该等于该Group订阅主题的分区总数

不过,慢慢地人们发现了一个问题,即ZooKeeper这类元框架其实并不适合进行频繁的写更新,而
Consumer Group的位移更新却是一个非常频繁的操作。这种大吞吐量的写操作会极大地拖慢ZooKeeper集
群的性能,因此Kafka社区渐渐有了这样的共识:将Consumer位移保存在ZooKeeper中是不合适的做法

Rebalance发生时,Group下所有的Consumer实例都会协调在一起共同参与。你可能会问,每个Consumer
实例怎么知道应该消费订阅主题的哪些分区呢?这就需要分配策略的协助了。

揭开神秘的“位移主题”面纱

__consumer_offsets在Kafka源码中有个更为正式的名字,叫位移主题,即Offsets Topic。

新版本Consumer的位移管理机制其实也很简单,就是将Consumer的位移数据作为一条条普通的Kafka消
息,提交到__consumer_offsets中。可以这么说,__consumer_offsets的主要作用是保存Kafka消费者的位移
信息。它要求这个提交过程不仅要实现高持久性,还要支持高频的写操作。显然,Kafka的主题设计天然就
满足这两个条件,因此,使用Kafka主题来保存位移这件事情,实际上就是一个水到渠成的想法了。

Key和Value分别表示消息的键值和消息体,在Kafka中它们就是字节数组而已。想象一下,如果让你来
设计这个主题,你觉得消息格式应该长什么样子呢?我先不说社区的设计方案,我们自己先来设计一下。

首先从Key说起。一个Kafka集群中的Consumer数量会有很多,既然这个主题保存的是Consumer的位移数
据,那么消息格式中必须要有字段来标识这个位移数据是哪个Consumer的。这种数据放在哪个字段比较合
适呢?显然放在Key中比较合适。

好了,我们来总结一下我们的结论。位移主题的Key中应该保存3部分内容:<Group ID,主题名,分区号

。如果你认同这样的结论,那么恭喜你,社区就是这么设计的!

总结一下,如果位移主题是Kafka自动创建的,那么该主题的分区数是50,副本数是3

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值