从今天开始更新一些业务常用到的中间件的学习,Redis已经进行了几篇了Kafka也开个头吧,计划总共用五篇博客来学习和了解这个消息框架,当然一开始不会花太多的精力去深入探究,自己整理了一个学习路线大纲,之后依据对业务的了解和公司内部的使用情况需要了再更新和学习:
- 【Kafka从入门到放弃系列 一】概述及基本架构:前置概念理解(消息队列、生产者消费者模式)、消息系统的使用、Kafka的基本架构等基本知识。
- 【Kafka从入门到放弃系列 二】ZooKeeper集成及详细执行机制:ZooKeeper和Kafka的集成使用以及Kafka的详细设计机制等原理性知识。
- 【Kafka从入门到放弃系列 三】Kafka安装及使用:了解了基本架构和原理等内容就来进行简单的操作吧
- 【Kafka从入门到放弃系列 四】Kafka的高可用实现: 增加了中间件,可用性必然会降低,那么Kafka使用何种机制来实现高可用呢
- 【Kafka从入门到放弃系列 五】Kafka性能测试:在实战中观察和调试kafka的性能
本篇博客是Kafka系列的第一篇,旨在解答问题的why和when,也就是为什么需要用kafka和什么时候用kafka,至于为何是从入门到放弃系列,因为俺相信,框架总会过时,总有更优秀的会出现,重要的是思想,所以这里的放弃是脱离框架而探寻框架的实现原理和思想,这个相较而言更重要吧。
为了方便阅读和学习,采用我一贯喜欢使用的金字塔模式:总分结构,所以本篇博客的结构如下:
- 前置概念了解:消息系统、生产者消费者模式等
- Kafka基本概念:Kafka的术语了解以及基本概念
- Kafka基本架构:术语介绍、架构图解析、常用策略和机制等
本篇博客参考了以下博主的内容,这里提前贴出来,欢迎一起学习:
技术世界,关于分布式架构:http://www.jasongj.com/2015/03/10/KafkaColumn1/
同时也参考了在线学习教程W3C School(也开始采用会员制资源获取了,不错,转型了):
W3C School :https://www.w3cschool.cn/apache_kafka/apache_kafka_cluster_architecture.html
以及阿里云栖社区的一篇对消息队列内容的介绍的博客。
前置概念了解
在正式介绍Kafka之前,先来了解下什么是生产者消费者模式,以及什么是消息队列。
生产者消费者模型
生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品。
简而言之就是生产者生产数据,放到一个篮子里,消费者按顺序从篮子里拿到数据去消费。
消息队列
首先我感觉大家应该都了解队列的概念,队列是一种先进先出的数据结构,可以理解为一个管道,在我的另一篇博客里有详细的介绍 数据结构—队列 其结构如下:
那显而易见,消息队列就是存放消息的队列。
消息队列应用场景
消息队列具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。那么为什么要使用队列呢?我这么理解:
- 1,在分布式高并发场景下,如何保证系统性能不受影响,也就是用户无感知(削峰、减少响应所需时间),一般网站响应时间超过200ms就难以忍受了,高并发同步向数据库内写数据,数据库会扛不住压力的,而且响应速度也会明显减慢。
*2,不同系统之间的异步通信如何实现( 降低系统耦合性),一个系统必然有很多模块组成,不同模块各自有实现,各自有自己的迭代,如果耦合性低,不存在强依赖,那最好了,微服务架构的思想也类似此,降低耦合性。
第一个场景下,例如有个业务:下班打车,企业滴滴,晚上8点半上地这边爆满,各种打车订单同时涌入系统,系统要爆,加上消息队列后,订单进入消息队列,然后反馈给用户订单在处理,然后按照入队顺序一个个处理该消息,直到消费到该消息订单后才将订单入库,当然这个时候才能反馈给用户说打车成功。这样有效的抵抗了峰值时间的冲击。
第二个场景下,系统的不同模块之间各自有各自的实现。模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,所以如果有个消息系统在中间作为中转,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不需要知道该消息从何而来。对新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计。
消息队列问题
系统里平白无故加入一个消息队列服务器当然会影响系统的整体性能,增加系统的复杂性,还需要担心异步消息发送的一致性问,消息服务器的稳定性等问题:
- 系统可用性降低: 系统可用性在某种程度上降低,在加入MQ之前,不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后就需要去考虑了
- 系统复杂性提高: 加入MQ之后,需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性,消息服务器有没有宕机等问题
- 一致性问题: 消息队列可以实现异步,异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息就会导致数据不一致的情况了。
所以不管使用哪个消息队列,都需要在能使用优势的同时,尽可能解决这些问题。
消息队列模型
消息队列目前有两种协议:JMS和AMQP,JMS轻量不能跨平台,AMQP性能强但是复杂,感觉就是美图秀秀和PS的区别,但是大家用的多的还是美图秀秀,那么就以JMS为主吧,咱就好好用轮子吧。
1 点到点(P2P)模型
使用队列(Queue)作为消息通信载体:满足生产者与消费者模式,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。
2 发布/订阅(Pub/Sub)模型
发布订阅模型(Pub/Sub) 使用主题(Topic)作为消息通信载体,类似于广播模式,发布者发布一条消息,该消息通过主题传递给所有的订阅者,一条消息可以被多个消费者使用。在一条消息广播之后才订阅的用户则是收不到该条消息的。
消息队列框架
目前市场上主流的框架比较多,但是目前接触到的就是两种Kafka和RabbitMQ ,前段时间公司内部开始将框架从RabbitMQ 更改为Kafka,之前不太懂,通过对比来了解下吧:
- RabbitMQ 基于 AMQP 协议实现的,Kafka基于JMS协议,所以Kafka支持的消息类型更多:StreamMessage (Java原始值的数据流);MapMessage(一套名称-值对);TextMessage(一个字符串对象);ObjectMessage(一个序列化的 Java对象);BytesMessage(一个字节的数据流),而RabbitMQ 只支持二进制字符流
- RabbitMQ 在吞吐量方面虽然稍逊于 Kafka ,但是由于它基于 erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。如果业务场景对并发量要求不是太高(十万级、百万级),RabbitMQ 一定是首选。如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题
综合而言就是公司内业务量增加,对并发量有了要求,RabbitMQ 的性能可能不太跟的上了。就好像PS启动一次贼麻烦,但能完成很复杂的功能,美图秀秀秒开,只能美颜,如果你只用美颜功能,没必要下PS。
Kafka基本概念
了解了生产者消费者模式、消息队列的基本概念和使用场景以及最后的技术选型定为Kafka,接下来就要对Kafka的基本概念做个详细的了解了。
基本定义
从使用者角度来讲,Kafka是一个分布式、支持分区的、多副本的基于Zookeeper协调的分布式日志服务,非常适合在线日志收集等高吞吐场景。与大多数消息系统比较,kafka有更好的吞吐量,内置分区,副本和故障转移,这有利于处理大规模的消息,所以kafka被各大公司广泛运用于消息队列的构建。
基本术语
kafka的基本组成如下图所示:消息由生产者生产,依据类别发往不同的主题,每个主题包含一个或多个分区
先了解下架构里的有哪些常用术语,理解概念然后在架构里就比较好定位:
1 Producer(生产者):负责发布消息到Kafka broker,就是向kafka broker发消息的客户端。
2 主题和分区:一个主题包含一个或多个Partition
- Topics(主题)****: 属于特定类别的消息流**称为主题。 数据存储在主题中。主题被拆分成分区。 对于每个主题,Kafka保存一个分区的数据。 每个这样的分区包含不可变有序序列的消息。 分区被实现为具有相等大小的一组分段文件。(物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处),也可以理解为一个队列,通过对消息指定主题可以将消息分类,消费者可以只关注自己需要的Topic中的消息。
- Partition(分区),Parition是物理上的概念,每个Topic包含一个或多个Partition. 为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列。
- 分区索引 partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序,
- Replicas of partition(分区备份):副本只是一个分区的备份。 副本从不读取或写入数据。 它们用于防止数据丢失。
- Leader(领导者): Leader 是负责给定分区的所有读取和写入的节点。 每个分区都有一个服务器充当Leader。
- Follower(追随者):跟随领导者指令的节点被称为Follower。 如果领导失败,一个追随者将自动成为新的领导者。 跟随者作为正常消费者,拉取消息并更新其自己的数据存储。
3 Kafka集群和Kafka服务器:一个Kafka集群包含多个Kafka服务器
- Kafka Cluster(Kafka集群):Kafka有多个服务器被称为Kafka集群。 可以扩展Kafka集群,无需停机。 这些集群用于管理消息数据的持久性和复制。
- Broker(Kafka服务器):一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
4 Consumer(消费者)和 Consumer Group(消费者集群):一个消费者集群包含多个消费者
- Consumer Group(消费者集群):consumer group是kafka提供的可扩展且具有容错性的消费者机制。组内可以有多个消费者或消费者实例,它们共享一个公共的group ID。组内的所有消费者协调在一起来共享订阅主题的所有分区。
- Consumer(消费者):消息消费者,向Kafka broker读取消息的客户端。
综合而言我理解就是,Kafka集群和Kafka服务器属于物理机器上的概念,而主题和分区属于发出去的消息的分类,一个纵向,一个横向,一个broker上可以有很多主题的分区,一个主题也可以在很多broker上放置分区,是多对多的关系。
Kafka基本架构
一个典型的Kafka集群中包含若干Producer(可以是web前端产生的Page View,或者是服务器日志,系统CPU、Memory等),若干broker(Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高),若干Consumer Group,以及一个Zookeeper集群。Kafka通过Zookeeper管理集群配置,选举leader,以及在Consumer Group发生变化时进行rebalance。Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。
消息传递流程
消息由生产者生产,并发往Kafka集群,Kafka集群获取到消息后再发往消费者,以下是Pub-Sub消息的逐步工作流程 :
- Producer生产者,定期向Kafka集群发送消息,在发送消息之前,会对消息进行分类,即Topic
- Broker存储为该特定主题配置的分区中的所有消息。 它确保消息在分区之间平等共享。 如果生产者发送两个消息并且有两个分区,Kafka将在第一分区中存储一个消息,在第二分区中存储第二消息。
- 消费者订阅特定主题,一旦消费者订阅主题,Kafka将向消费者提供主题的当前偏移,并且还将偏移保存在Zookeeper系综中。
- 消费者通过与kafka集群建立长连接的方式,不断地从集群中拉取消息,然后可以对这些消息进行处理
- 一旦Kafka收到来自生产者的消息,它将这些消息转发给消费者。
- 消费者将收到消息并进行处理,一旦消息被处理,消费者将向Kafka代理发送确认。
- 一旦Kafka收到确认,它将偏移更改为新值,并在Zookeeper中更新它。 由于偏移在Zookeeper中维护,消费者可以正确地读取下一封邮件,即使在服务器暴力期间。
以上流程将重复,直到消费者停止请求。消费者可以随时回退/跳到所需的主题偏移量,并阅读所有后续消息(这点就比较牛逼了)。
kafka基本存储策略
在以上流程中需要注意的是Kafka的存储,主要的特点就是分区,即partitions,分区是实现其高吞吐量和均衡负载的关键。创建一个topic时,同时可以指定分区数目,分区数越多,其吞吐量也越大,但是需要的资源也越多,同时也会导致更高的不可用性,kafka在接收到生产者发送的消息之后,会根据均衡策略将消息存储到不同的分区中
Kafka与生产者交互
生产者在向kafka集群发送消息的时候,可以通过指定分区来发送到指定的分区中,也可以通过指定均衡策略来将消息发送到不同的分区中,如果不指定,就会采用默认的随机均衡策略,将消息随机的存储到不同的分区中
kafka与消费者的交互
在消费者消费消息时,kafka使用offset来记录当前消费的位置。在kafka的设计中,可以有多个不同的group来同时消费同一个topic下的消息,如图,两个不同的group同时消费,他们的的消费的记录位置offset各不相同,不互相干扰。对于一个group而言,消费者的数量不应该多于分区的数量,因为在一个group中,每个分区至多只能绑定到一个消费者上,即一个消费者可以消费多个分区,一个分区只能给一个消费者消费,因此,若一个group中的消费者数量大于分区数量的话,多余的消费者将不会收到任何消息。
ZooKeeper的作用
Kafka的一个关键依赖是Zookeeper,它是一个分布式配置和同步服务。 Zookeeper是Broker和消费者之间的协调接口。 Kafka服务器通过Zookeeper集群共享信息。 Kafka在Zookeeper中存储基本元数据,例如关于主题,Broker,消费者偏移(队列读取器)等的信息。
由于所有关键信息存储在Zookeeper中,并且它通常在其整体上复制此数据,因此Kafka代理/ Zookeeper的故障不会影响Kafka集群的状态。一旦Zookeeper重新启动 ,Kafka将恢复状态。 这为Kafka带来了零停机时间。 Kafka代理之间的领导者选举也通过使用Zookeeper在领导者失败的情况下完成。
总结
通过写这篇博客我了解和学习了以下的一些内容,算是入门和简单对Kafka的使用有个大致了解吧,综合而言学了:
- 了解和学习了消息系统是什么,以及什么使用场景,它的优势:解耦和异步削峰
- 了解和学习了哪些常用的消息框架,并且技术如何选型
- 了解和学习了Kafka的基本术语,基本概念、基本架构、基本流程和一些常用机制
下一篇博客就来详细探究下Kafka如何和ZooKeepe搭配使用以及详细使用时候的一些机制。每天进步一点点!!!