ZooKeeper基础与入门
1、ZooKeeper概念介绍
在介绍ZooKeeper之前,先来介绍一下分布式协调技术
所谓分布式协调技术主要是用来解决分布式环境当中多个进程之间的同步控制,让他们有序的去访问某种共享资源,防止造成资源竞争(脑裂)的后果。
这里首先介绍下什么是分布式系统
所谓分布式系统就是在不同地域分布的多个服务器,共同组成的一个应用系统来为用户提供服务,在分布式系统中最重要的是进程的调度
这里假设有一个分布在三个地域的服务器组成的一个应用系统,在第一台机器上挂载了一个资源,然后这三个地域分布的应用进程都要竞争这个资源,但我们又不希望多个进程同时进行访问,这个时候就需要一个协调器,来让它们有序的来访问这个资源。
这个协调器就是分布式系统中经常提到的那个锁。
例如进程1在使用该资源的时候,会先去获得这把锁,进程1获得锁以后会对该资源保持独占,此时其它进程就无法访问该资源,进程1在用完该资源以后会将该锁释放掉,以便让其它进程来获得锁。
由此可见,通过这个锁机制,就可以保证分布式系统中多个进程能够有序的访问该共享资源。
这里把这个分布式环境下的这个锁叫作分布式锁。
这个分布式锁就是分布式协调技术实现的核心内容。
综上所述,ZooKeeper是一种为分布式应用所设计的高可用、高性能的开源协调服务,它提供了一项基本服务:分布式锁服务,同时,也提供了数据的维护和管理机制,如:统一命名服务、状态同步服务、集群管理、分布式消息队列、分布式应用配置项的管理等等。
2、ZooKeeper应用举例
这里以ZooKeeper提供的基本服务分布式锁为例进行介绍。
在分布式锁服务中,有一种最典型应用场景,就是通过对集群进行Master角色的选举,来解决分布式系统中的单点故障问题。
单点故障,就是在一个主从的分布式系统中,主节点负责任务调度分发,从节点负责任务的处理,而当主节点发生故障时,整个应用系统也就瘫痪了,那么这种故障就称为单点故障。
解决单点故障,传统的方式是采用一个备用节点,这个备用节点定期向主节点发送ping包,主节点收到ping包以后向备用节点发送回复Ack信息,当备用节点收到回复的时候就会认为当前主节点运行正常,让它继续提供服务。而当主节点故障时,备用节点就无法收到回复信息了,此时,备用节点就认为主节点宕机,然后接替它成为新的主节点继续提供服务。
这种传统解决单点故障的方法,虽然在一定程度上解决了问题,但是有一个隐患,就是网络问题。
可能会存在这样一种情况:主节点并没有出现故障,只是在回复ack响应的时候网络发生了故障,这样备用节点就无法收到回复,那么它就会认为主节点出现了故障,接着,备用节点将接管主节点的服务,并成为新的主节点。
此时,分布式系统中就出现了两个主节点(双Master节点)的情况,双Master节点的出现,会导致分布式系统的服务发生混乱。这样的话,整个分布式系统将变得不可用。
为了防止出现这种情况,就需要引入ZooKeeper来解决这种问题。
3、ZooKeeper工作原理
下面通过三种情形,介绍下Zookeeper是如何进行工作的。
(1) Master启动
在分布式系统中引入Zookeeper以后,就可以配置多个主节点,这里以配置两个主节点为例,假定它们是主节点A和主节点B,当两个主节点都启动后,它们都会向ZooKeeper中注册节点信息。
我们假设主节点A锁注册的节点信息是master00001,主节点B注册的节点信息是master00002,注册完以后会进行选举,选举有多种算法,这里以编号最小作为选举算法,那么编号最小的节点将在选举中获胜并获得锁成为主节点,也就是主节点A将会获得锁成为主节点,然后主节点B将被阻塞成为一个备用节点。这样,通过这种方式Zookeeper就完成了对两个Master进程的调度。完成了主、备节点的分配和协作。
(2) Master故障
如果主节点A发生了故障,这时候它在ZooKeeper所注册的节点信息会被自动删除,而ZooKeeper会自动感知节点的变化,发现主节点A故障后,会再次发出选举,这时候主节点B将在选举中获胜,替代主节点A成为新的主节点,这样就完成了主、被节点的重新选举。
(3)Master恢复
如果主节点恢复了,它会再次向ZooKeeper注册自身的节点信息,只不过这时候它注册的节点信息将会变成master00003,而不是原来的信息。
ZooKeeper会感知节点的变化再次发动选举,这时候主节点B在选举中会再次获胜继续担任主节点,主节点A会担任备用节点。
Zookeeper就是通过这样的协调、调度机制如此反复的对集群进行管理和状态同步的。
4、Zookeeper集群架构
Zookeeper一般是通过集群架构来提供服务的,下图是Zookeeper的基本架构图。
Zookeeper集群主要角色有Server和client
其中,Server又分为Leader、Follower和Observer三个角色
每个角色的含义如下:
-
Leader:领导者角色,主要负责投票的发起和决议,以及更新系统状态。
-
Follower:跟随者角色,用于接收客户端的请求并返回结果给客户端,在选举过程中参与投票。
-
Observer:观察者角色,用户接收客户端的请求,并将写请求转发给leader,同时同步leader状态,但不参与投票。 Observer目的是扩展系统,提高伸缩性。
-
Client:客户端角色,用于向Zookeeper发起请求。
Zookeeper集群中每个Server在内存中存储了一份数据,在Zookeeper启动时,将从实例中选举一个Server作为leader,Leader负责处理数据更新等操作,当且仅当大多数Server在内存中成功修改数据,才认为数据修改成功。
Zookeeper写的流程为:客户端Client首先和一个Server或者Observe通信,发起写请求,然后Server将写请求转发给Leader, Leader再将写请求转发给其它Server,其它Server在接收到写请求后写入数据并响应Leader,Leader在接收到大多数写成功回应后,认为数据写成功,最后响应Client,完成一次写操作过程。
kafka基础与入门
1、kafka基本概念
Kafka是一种高吞吐量的分布式发布/订阅消息系统,这是官方对kafka的定义,kafka是Apache组织下的一个开源系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop平台的数据分析、低时延的实时系统、storm/spark流式处理引擎等。
kafka现在它已被多家大型公司作为多种类型的数据管道和消息系统使用。
2、kafka角色术语
在介绍架构之前,先了解下kafka中一些核心概念和各种角色。
-
Broker:Kafka集群包含一个或多个服务器,每个服务器被称为broker。
-
Topic:每条发布到Kafka集群的消息都有一个分类,这个类别被称为Topic(主题)。
-
Producer:指消息的生产者,负责发布消息到Kafka broker。
-
Consumer :指消息的消费者,从Kafka broker拉取数据,并消费这些已发布的消息。
-
Partition:Parition是物理上的概念,每个Topic包含一个或多个Partition,每个partition都是一个有序的队列。partition 中的每条消息都会被分配一个有序的id(称为offset)。
-
Consumer Group:消费者组,可以给每个Consumer指定消费者组,若不指定消费者组,则属于默认的group。
-
Message:消息,通信的基本单位,每个producer可以向一个topic发布一些消息。
3、Kafka拓扑架构
一个典型的Kafka集群包含若干Producer,若干broker、若干Consumer Group,以及一个Zookeeper集群。
Kafka通过Zookeeper管理集群配置,选举leader,以及在Consumer Group发生变化时进行再平衡。
Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。
4、Topic与Partition
Kafka中的topic是以partition的形式存放的,每一个topic都可以设置它的partition数量,Partition的数量决定了组成topic的log的数量。
推荐partition的数量一定要大于同时运行的consumer的数量。另外,建议partition的数量大于集群broker的数量,这样消息数据就可以均匀的分布在各个broker中。
那么,Topic为什么要设置多个Partition呢,这是因为kafka是基于文件存储的,通过配置多个partition可以将消息内容分散存储到多个broker上,这样可以避免文件尺寸达到单机磁盘的上限。
同时,将一个topic切分成任意多个partitions,可以保证消息存储、消息消费的效率,因为越多的partitions可以容纳更多的consumer,可有效提升Kafka的吞吐率。
因此,将Topic切分成多个partitions的好处是可以将大量的消息分成多批数据同时写到不同节点上,将写请求分担负载到各个集群节点。
5、 Kafka消息发送的机制
每当用户往某个Topic发送数据时,数据会被hash到不同的partition,这些partition位于不同的集群节点上,所以每个消息都会被记录一个offset消息号,就是offset号。
消费者通过这个offset号去查询读取这个消息。
发送消息流程为:
首先获取topic的所有Patition,如果客户端不指定Patition,也没有指定Key的话,使用自增长的数字取余数的方式实现指定的Partition。这样Kafka将平均的向Partition中生产数据。
如果想要控制发送的partition,则有两种方式,一种是指定partition,另一种就是根据Key自己写算法。实现其partition方法。
每一条消息被发送到broker时,会根据paritition规则选择被存储到哪一个partition。
如果partition规则设置的合理,所有消息可以均匀分布到不同的partition里,这样就实现了水平扩展。同时,每条消息被append到partition中时,是顺序写入磁盘的,因此效率非常高,经验证,顺序写磁盘效率比随机写内存还要高,这是Kafka高吞吐率的一个很重要的保证。
6、Kafka消息消费机制
Kafka中的Producer和consumer采用的是push(推送)、pull(拉取)的模式
即Producer只是向broker push消息,consumer只是从broker pull消息,push和pull对于消息的生产和消费是异步进行的。
pull模式的一个好处是Consumer可自主控制消费消息的速率,同时Consumer还可以自己控制消费消息的方式是批量的从broker拉取数据还是逐条消费数据。
当生产者将数据发布到topic时,消费者通过pull的方式,定期从服务器拉取数据,当然在pull数据的时候,服务器会告诉consumer可消费的消息offset。
消费规则:
-
不同 Consumer Group下的消费者可以消费partition中相同的消息,相同的Consumer Group下的消费者只能消费partition中不同的数据。
-
topic的partition的个数和同一个消费组的消费者个数最好一致,如果消费者个数多于partition个数,则会存在有的消费者消费不到数据。
-
服务器会记录每个consumer的在每个topic的每个partition下的消费的offset,然后每次去消费去拉取数据时,都会从上次记录的位置开始拉取数据。
7、Kafka消息存储机制
在存储结构上,每个partition在物理上对应一个文件夹,该文件夹下存储这个partition的所有消息和索引文件,每个partion(目录)相当于一个巨型文件被平均分配到多个大小相等segment(段)数据文件中。
partiton命名规则为topic名称+序号,第一个partiton序号从0开始,序号最大值为partitions数量减1。
在每个partition (文件夹)中有多个大小相等的segment(段)数据文件,每个segment的大小是相同的,但是每条消息的大小可能不相同,因此segment 数据文件中消息数量不一定相等。
segment数据文件有两个部分组成,分别为index file和data file,此两个文件是一一对应,成对出现,后缀".index"和“.log”分别表示为segment索引文件和数据文件。
其实Kafka最核心的思想是使用磁盘,而不是使用内存,使用磁盘操作有以下几个好处:
-
磁盘缓存由Linux系统维护,减少了程序员的不少工作。
-
磁盘顺序读写速度超过内存随机读写。
-
JVM的GC效率低,内存占用大。使用磁盘可以避免这一问题。
-
系统冷启动后,磁盘缓存依然可用。