201901建站运维笔记 54

Kafka介绍

根据前面的介绍,我们已经大概了解了Kafka也是一款性能非常好的并且支持分布式的消息队列中间件。由于它的高吞吐特性,Kafka通常使用在大数据领域,如日志收集平台。其实Kafka是一个流处理平台,这个概念不太好理解,之所以叫做流,是因为它在工作中就像是一个可以支撑高吞吐量的管道,数据像水一样流进去,然后另外一端再去读取这些数据。我们就可以把Kafka看作是一种特殊的消息队列中间件。

Kafka与传统消息系统相比,有以下不同:

它被设计为一个分布式系统,易于向外扩展;
它同时为发布和订阅提供高吞吐量;
它支持多订阅者,当失败时能自动平衡消费者;
它将消息持久化到磁盘,因此可用于批量消费,例如ETL,以及实时应用程序。

在Kafka中有几个关键角色和概念。

  • Producer

    ""消息生产者,是消息的产生源头,负责生成消息并发送给Kafka。

  • Topic

    主题,由用户自定义,并配置在Kafka服务器,用于建立生产者和消费者之间的订阅关系,生产者将消息发送到指定的Topic,然后消费者再从该Topic下去取消息。

  • Partition

    消息分区,一个Topic下面会有多个Partition,每个Partition都是一个有序队列,Partition中的每条消息都会被分配一个有序的id。

  • Broker

    这个其实就是Kafka服务器了,无论是单台Kafka还是集群,被统一叫做Broker,有的资料上把它翻译为代理或经纪人。

  • Group

    消费者分组,将同一类的消费者归类到一个组里。在Kafka中,多个消费者共同消费一个Topic下的消息,每个消费者消费其中的部分消息,这些消费者就组成了一个分组,拥有同一个组名。

ZooKeeper

官网:http://zookeeper.apache.org/

Kafka的运行依赖ZooKeeper。ZooKeeper是一个分布式协调服务,它的主要作用是为分布式系统提供一致性服务,提供的功能包括:配置维护、命名服务、分布式同步、组服务等。

ZooKeeper最早起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部很多大型系统基本都需要依赖一个类似的系统来进行分布式协调,但是这些系统往往都存在分布式单点问题。所以,雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。

关于ZooKeeper这个项目的名字,其实也有一段趣闻。在立项初期,考虑到之前内部很多项目都是使用动物的名字来命名的(例如著名的Pig项目),雅虎的工程师希望给这个项目也取一个动物的名字。时任研究院的首席科学家RaghuRamakrishnan开玩笑地说:“在这样下去,我们这儿就变成动物园了!”此话一出,大家纷纷表示就叫动物园管理员吧 一一 因为各个以动物命名的分布式组件放在一起,雅虎的整个分布式系统看上去就像一个大型的动物园了,而ZooKeeper正好要用来进行分布式环境的协调。于是,ZooKeeper的名字也就由此诞生了。

ZooKeeper的数据结构

类似于Linux的文件系统,是一种树形的结构。如下:

                    /
                 /     \
		/       \
             Lang     Service
             / \        /  \
            /   \      /    \
          JAVA   PHP Nginx Tomcat

如果已经搭建了ZooKeeper服务,可以进入到ZooKeeper命令行终端,然后执行ls /看到下面的目录结构

/usr/local/zookeeper/bin/zkCli.sh -server aming01:2181
进入到Zookeeper的命令行终端下面,执行:ls /

树是由节点所组成,ZooKeeper的数据存储也同样是基于节点,这种节点叫做Znode。/Lang/PHP是一个节点,/Service/Tomcat也是一个节点,这样就可以让每一个Znode拥有唯一的路径。每一个Znode里包含了数据、子节点引用、访问权限等。

如上图,data即Znode里面的数据,ACL为权限规则,它规定了哪些用户或哪些IP才有权限访问此Znode,stat记录了Znode相关的元数据,比如事务ID、版本号、时间戳、大小,child为当前节点的子节点引用,类似于二叉树的左孩子右孩子。ZooKeeper有个限制,每个Znode的数据大小不会超过1M。

get /node_name
getAcl /node_name 

节点类型

  • 持久节点(PERSISTENT)

    所谓持久节点,是指在节点创建后,就一直存在,直到有删除操作来主动清除这个节点——不会因为创建该节点的客户端会话失效而消失。

    	create /node 'persistent node'
    
  • 持久顺序节点(PERSISTENT_SEQUENTIAL,节点会自动加上编号)

    这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名。这个数字后缀的范围是整型的最大值。

    在创建节点的时候只需要传入节点 “/test_”,这样之后,zookeeper自动会给”test_”后面补充数字。

    	create -s /s_node 'persistent sequential'
    
  • 临时节点(EPHEMERAL)

    和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。

    这里还要注意一件事,就是当你客户端会话失效后,所产生的节点也不是一下子就消失了,也要过一段时间,大概是10秒以内,本机操作生成节点,在服务器端用命令来查看当前的节点数目,你会发现客户端已经stop,但是产生的节点还在。

    	create -e /e_node 'ephemeral'
    
  • 临时顺序节点(EPHEMERAL_SEQUENTIAL)

    此节点是属于临时节点,不过带有顺序,客户端会话结束节点就消失。下面是一个利用该特性的分布式锁的案例流程。

    	create -e -s /e_s_node 'ephemeral sequential'
    

ZooKeeper集群中的角色

ZooKeeper提供服务时,是需要通过集群来实现,ZooKeeper集群中有一个leader,多个follower角色,其中leader提供写服务,follower提供读服务。

  • Leader

Leader是整个ZooKeeper集群工作机制中的核心 。Leader作为整个ZooKeeper集群的主节点,负责响应所有对ZooKeeper状态变更的请求。其主要工作包括下面两个方面

1)事务请求的唯一调度和处理,保障集群处理事务的顺序性。

2)集群内各服务器的调度者。

Leader选举是ZooKeeper最重要的技术之一,也是保障分布式数据一致性的关键所在。我们以三台机器为例,在服务器集群初始化阶段,当有一台服务器Server1启动时候是无法完成选举的,当第二台机器Server2启动后两台机器能互相通信,每台机器都试图找到一个leader,于是便进入了leader选举流程.

每个server发出一个投票,投票的最基本元素是SID(服务器id)和ZXID(事物id)--> 接受来自各个服务器的投票 --> 处理投票,优先检查ZXID(数据越新ZXID越大),ZXID比较大的作为leader,ZXID一样的情况下比较SID --> 统计投票,这里有个过半的概念,大于集群机器数量的一半,即大于或等于(n/2+1),我们这里是三台,所以大于等于2即为达到“过半”的要求 --> 改变服务器状态,一旦确定了leader,服务器就会更改自己的状态,且一般不会再发生变化。

  • Follower

Follower即跟随者,他的逻辑比较简单。除了响应本服务器上的读请求外,还要处理leader的提议,并在leader提交该提议时在本地也进行提交。另外需要注意的是,leader和follower构成ZooKeeper集群的法定人数,也就是说,只有他们才参与新leader的选举、响应leader的提议。

  • Observer

服务器充当一个观察者的角色。如果ZooKeeper集群的读取负载很高,或者客户端多到跨机房,可以设置一些observer服务器,以提高读取的吞吐量。Observer和Follower比较相似,只有一些小区别:首先observer不属于法定人数,即不参加选举也不响应提议,也不参与写操作的“过半写成功”策略;其次是observer不需要将事务持久化到磁盘,一旦observer被重启,需要从leader重新同步整个命名空间。

Kafka和ZooKeeper

我们了解了ZooKeeper的分布式协调服务特性后,再来看看Zookeeper在Kafka集群中到底担任了一个什么样的角色?

简单讲,ZooKeeper用于分布式系统的协调,Kafka使用ZooKeeper也是基于相同的原因。ZooKeeper主要用来协调Kafka的各个broker,不仅可以实现broker的负载均衡,而且当增加了broker或者某个broker故障了,ZooKeeper将会通知生产者和消费者,这样可以保证整个系统正常运转。

  • Broker注册

    Broker在ZooKeeper中保存为一个临时节点,节点的路径是/brokers/ids/[brokerid],每个节点会保存对应broker的IP以及端口等信息.

    	/usr/local/zookeeper/bin/zkCli.sh -server aming01:2181
    	进入到Zookeeper的命令行终端下面,执行:ls /brokers/ids
    
  • Topic注册

    在Kafka中,一个topic会被分成多个区并被分到多个broker上,分区的信息以及broker的分布情况都保存在ZooKeeper中,根节点路径为/brokers/topics,每个topic都会在topics下建立独立的子节点,每个topic节点下都会包含分区以及broker的对应信息

        /usr/local/zookeeper/bin/zkCli.sh -server aming01:2181
        进入到Zookeeper的命令行终端下面,执行:ls /brokers/topics
    
  • 生产者负载均衡

    当Broker启动时,会注册该Broker的信息,以及可订阅的topic信息。生产者通过注册在Broker以及Topic上的watcher动态的感知Broker以及Topic的分区情况,从而将Topic的分区动态的分配到broker上.

    	ls2 /brokers/topics watch
    
  • 消费者

    Kafka有消费者分组的概念,每个分组中可以包含多个消费者,每条消息只会发给分组中的一个消费者,且每个分组之间是相互独立互不影响的。

  • 消费者与分区的对应关系

    对于每个消费者分组,Kafka都会为其分配一个全局唯一的Group ID,分组内的所有消费者会共享该ID, Kafka还会为每个消费者分配一个consumer ID,通常采用hostname:uuid的形式。在kafka的设计中规定,对于topic的每个分区,最多只能被一个消费者进行消费,也就是消费者与分区的关系是一对多的关系。消费者与分区的关系也被存储在ZooKeeper中节点的路劲为 /consumers/[group_id]/owners/[topic]/[broker_id-partition_id],该节点的内容就是消费者的Consumer ID

  • 消费者负载均衡

    消费者服务启动时,会创建一个属于消费者节点的临时节点,节点的路径为 /consumers/[group_id]/ids/[consumer_id],该节点的内容是该消费者订阅的Topic信息。每个消费者会对/consumers/[group_id]/ids节点注册Watcher监听器,一旦消费者的数量增加或减少就会触发消费者的负载均衡。消费者还会对/brokers/ids/[brokerid]节点进行监听,如果发现服务器的Broker服务器列表发生变化,也会进行消费者的负载均衡

  • 消费者的offset

    在Kafka的消费者API分为两种(1)High Level Api:由ZooKeeper维护消费者的offset (2) Low Level API,自己的代码实现对offset的维护。由于自己维护offset往往比较复杂,所以多数情况下都是使用High Level的API, offset在ZooKeeper中的节点路径为/consumers/[group_id]/offsets/[topic]/[broker_id-part_id],该节点的值就是对应的offset

Kafka工作流程

1)生产者定期向主题发送消息。

2)Kafka broker将所有消息存储在为该特定主题配置的分区中。它确保消息在分区之间平等共享。如果生产者发送两个消息,并且有两个分区,则Kafka将在第一个分区中存储一个消息,在第二个分区中存储第二个消息。

3)消费者订阅一个特定的主题。

4)一旦消费者订阅了一个主题,Kafka将向消费者提供该主题的当前偏移量,并将偏移量保存在ZooKeeper中。

5)消费者将定期请求Kafka新消息。

6)一旦Kafka收到来自生产者的消息,它会将这些消息转发给消费者。

7)消费者将收到消息并处理它。

8)一旦消息被处理,消费者将向Kafka broker发送确认。

9)一旦Kafka收到确认,它会将偏移量更改为新值,并在ZooKeeper中进行更新。由于ZooKeeper中保留了偏移量,因此即使在服务器出现故障时,消费者也可以正确读取下一条消息。

一篇不错的文档 https://www.jianshu.com/p/d3e963ff8b70

概览

通过前面的学习,我们了解到Kafka依赖ZooKeeper,所以需要先部署ZooKeeper集群。

环境准备

主机名 IP
aming01 192.168.222.128
aming02 192.168.222.129
aming03 192.168.222.130

设置主机名,并设置hosts

关闭Selinux、firewalld并安装JDK

安装部署ZooKeeper

说明:以下操作在aming01上操作

  • 下载ZooKeeper安装包

    wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/stable/zookeeper-3.4.13.tar.gz

  • 解压并挪到/usr/local/下

    tar zxf zookeeper-3.4.13.tar.gz

    mv zookeeper-3.4.13 /usr/local/zookeeper

  • 创建数据、日志存放目录及当前节点ID

    cd /usr/local/zookeeper

    mkdir data

    mkdir dataLog

    echo "1" > data/myid

  • 配置

    cp conf/zoo_sample.cfg conf/kafka_zk.cfg

    vi conf/kafka_zk.cfg ##更改为如下配置

    	tickTime=2000
    	# 数据文件存放位置
    	dataDir=/usr/local/zookeeper/data
    	dataLogDir=/usr/local/zookeeper/dataLog
    	#服务监听端口
    	clientPort=2181
    	#选举等待时间
    	initLimit=5
    	syncLimit=2
    	#集群节点信息
    	server.1=aming01:2888:3888
    	server.2=aming02:2888:3888
    	server.3=aming03:2888:3888
    
  • 分发文件

    scp -r /usr/local/zookeeper aming02:/usr/local/

    scp -r /usr/local/zookeeper aming02:/usr/local/

  • 修改id

    在aming02上,修改/usr/local/zookeeper/data/myid内容为2,aming03上修改为3

  • 添加同步时间的任务计划啊(三台机器都执行)

    yum install -y ntpdate

    echo "*/5 * * * * ntpdate time.windows.com" >> /var/spool/cron/root

  • 启动集群(三台都执行)

    /usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/kafka_zk.cfg

    /usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/kafka_zk.cfg #查看集群状态

    /usr/local/zookeeper/bin/zkServer.sh stop /usr/local/zookeeper/conf/kafka_zk.cfg #关闭集群

  • 测试连接ZooKeeper

    /usr/local/zookeeper/bin/zkCli.sh -server aming01:2181

ZooKeeper常见用法

首先进入到ZooKeeper命令行模式下,可以进行如下操作:

1)查询节点

ls /

2)创建节点

create /test_node 'test node' 
说明:节点名称必须以/开头,test_node为节点名称,'test node'为具体数据

创建临时节点
create -e /test_node2 'ephemeral node'

创建序列节点,它会自动加上一堆数字
create -s /s_node 'sequential node'

创建临时序列节点
create -e -s /e_s_node 'ephemeral and sequential node'

3)查看节点状态

stat /test_node

4)查看节点数据内容

get /test_node

5)设置节点数据

set /test_node 'update node data' 10
说明:最后面的数字为版本号

6)删除节点

delete /test_node
注意:如果/test_node下有子节点,则删除会报错,此时可以使用递归删除命令rmr

rmr /test_node

7)设置节点Acl

setAcl /test_node ip:192.168.222.129:rcdwa

8)获取节点Acl

getAcl /test_node

更多指令参考 https://blog.csdn.net/xyang81/article/details/53053642

Kafka集群搭建

说明:我们使用三台机器搭建Kafka集群

  • 下载安装包(aming01操作)

    wget https://mirrors.tuna.tsinghua.edu.cn/apache/kafka/2.1.1/kafka_2.11-2.1.1.tgz

  • 解压并挪到/usr/local(aming01操作)

    tar zxf kafka_2.11-2.1.1.tgz

    mv kafka__2.11-2.1.1 /usr/local/kafka

  • 配置(aming01操作)

    cd /usr/local/kafka

    mkdir logs

    vim config/server.properties #按如下方法配置

    	broker.id=1  #当前机器在集群中的唯一标识,和zookeeper的myid性质一样
    	port=9092 #当前kafka对外提供服务的端口默认是9092
    	host.name=192.168.222.128 #本机IP
    	num.network.threads=3 #这个是borker进行网络处理的线程数
    	num.io.threads=8 #这个是borker进行I/O处理的线程数
    	log.dirs=/usr/local/kafka/logs #消息存放的目录,这个目录可以配置为“,”逗号分割的表达式,上面的num.io.threads要大于这个目录的个数这个目录,如果配置多个目录,新创建的topic他把消息持久化的地方是,当前以逗号分割的目录中,那个分区数最少就放那一个
    	socket.send.buffer.bytes=102400 #发送缓冲区buffer大小,数据不是一下子就发送的,先回存储到缓冲区了到达一定的大小后在发送,能提高性能
    	socket.receive.buffer.bytes=102400 #kafka接收缓冲区大小,当数据到达一定大小后在序列化到磁盘
    	socket.request.max.bytes=104857600 #这个参数是向kafka请求消息或者向kafka发送消息的请请求的最大数,这个值不能超过java的堆栈大小
    	num.partitions=1 #默认的分区数,一个topic默认1个分区数
    	log.retention.hours=168 #默认消息的最大持久化时间,168小时,7天
    	message.max.byte=5242880  #消息保存的最大值5M
    	default.replication.factor=2  #kafka保存消息的副本数,如果一个副本失效了,另一个还可以继续提供服务
    	replica.fetch.max.bytes=5242880  #取消息的最大直接数
    	log.segment.bytes=1073741824 #这个参数是:因为kafka的消息是以追加的形式落地到文件,当超过这个值的时候,kafka会新起一个文件
    	log.retention.check.interval.ms=300000 #每隔300000毫秒去检查上面配置的log失效时间(log.retention.hours=168 ),到目录查看是否有过期的消息如果有,删除
    	log.cleaner.enable=false #是否启用log压缩,一般不用启用,启用的话可以提高性能
    	zookeeper.connect=aming01:2181,aming02:2181,aming03:2181 #设置zookeeper的连接端口
    
  • 分发到另外两台机器(aming01操作)

    scp -r /usr/local/kafka aming02:/usr/local/

    scp -r /usr/local/kafka aming03:/usr/local/

  • 修改配置文件(aming02/aming03操作)

    vim config/server.properties #aming02, 将brokerid设置为2,host.name设置为192.168.222.129

    vim config/server.properties #aming03, 将brokerid设置为3,host.name设置为192.168.222.130

  • 启动服务(三台都操作)

    /usr/local/kafka/bin/kafka-server-start.sh -daemon /usr/local/kafka/config/server.properties

测试

aming01作为生产者,aming03作为消费者

在aming01上执行:

创建一个主题test:一个分区,两个副本
/usr/local/kafka/bin/kafka-topics.sh --create --zookeeper aming01:2181 --replication-factor 2 --partitions 1 --topic test   

创建一个生产者(消息发布者)
/usr/local/kafka/bin/kafka-console-producer.sh --broker-list aming01:9092 --topic test
#此时会进入到新的console(以>开头)


在aming03上执行

创建一个消费者(消息订阅者)
/usr/local/kafka/bin/kafka-console-consumer.sh --bootstrap-server aming01:9092  --topic test --from-beginning
#此时也会进入到另外一个console下
再到aming01上的> 下输入一些字符,然后aming03上就可以看到了。

常用命令

  • 查看主题

    /usr/local/kafka/bin/kafka-topics.sh --list --zookeeper localhost:2181

  • 查看主题详情

    /usr/local/kafka/bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic test

  • 删除主题(需设置参数delete.topic.enable=true)

    /usr/local/kafka/bin/kafka-topics.sh --zookeeper localhost:2181 --delete --topic test

  • 生产者参数查看

    /usr/local/kafka/bin/kafka-console-producer.sh

  • 消费者参数查看

    /usr/local/kafka/bin/kafka-console-consumer.sh

转载于:https://my.oschina.net/u/4067241/blog/3027102

你可能感兴趣的:(201901建站运维笔记 54)