1. kafka理论部分

1)重要术语

kafka集群 图 kafka集群原理_kafka集群 图

在上图中,主题(topic)被配置为三个分区。
分区1(Partition 1)具有两个偏移因子0和1。分区2(Partition 2)具有四个偏移因子0,1,2和3,分区3(Partition 3)具有一个偏移因子0。replica 的id与托管它的服务器的id相同。
假设,如果该主题的复制因子设置为3(也即–replication-factor=3),则Kafka将为每个分区创建3个相同的副本,并将它们放入群集中以使其可用于其所有操作。 为了平衡集群中的负载,每个代理存储一个或多个这些分区。 多个生产者和消费者可以同时发布和检索消息。

  • Topics - 属于特定类别的消息流被称为主题(Topics),数据存储在主题中。主题分为多个分区。 对于每个主题,Kafka都保留一个分区的最小范围。 每个这样的分区都以不可变的有序顺序包含消息。 分区被实现为一组相同大小的段文件。
  • Partition - 主题可能有很多分区,所以它可以处理任意数量的数据。
  • Partition offset - 每个分区消息都有一个称为偏移量的唯一序列标识。
  • Replicas of partition - 副本只是分区的备份。 副本从不读取或写入数据。 它们用于防止数据丢失。
  • Brokers 指的是集群,broker指的是集群的节点
  • Kafka Cluster - Kafka拥有多个经纪人称为Kafka集群。 Kafka集群可以在无需停机的情况下进行扩展。 这些集群用于管理消息数据的持久性和复制
  • Producers - 生产者(Producer)是一个或多个Kafka主题的发布者。 生产者向Kafka经纪人发送数据。 每当生产者向经纪人发布消息时,经纪人只需将消息附加到最后一个段文件。 实际上,该消息将被附加到分区。 生产者也可以将消息发送到他们选择的分区
  • Consumers - 消费者从经纪人那里读取数据。 消费者通过从经纪人处获取数据来订阅一个或多个主题并消费发布的消息
  • Leader - Leader是负责所有分区读写的节点。 每个分区都有一台服务器充当领导者
  • Follower - 遵循领导者(Leader)指示的节点称为追随者(Follower)。 如果领导失败,其中一个追随者将自动成为新领导。 追随者扮演正常的消费者角色,拉动消息并更新自己的数据存储。

2)要点

  • kafka server称为一个broker,多个kafka server行程brokers
  • 一个Broker上可以创建一个或者多个Topic。同一个topic可以在同一集群下的多个Broker中分布(如:一个topic的多个partition存在于多个broker上)
  • 每个分区是一个有序的,不可变的消息序列,新的消息不断追加到这个有组织的有保证的日志上。分区会给每个消息记录分配一个顺序ID号 – 偏移量, 能够唯一地标识该分区中的每个记录
  • Kafka集群保留所有发布的记录,不管这个记录有没有被消费过,Kafka将消息存储两天,在记录公布后两天内,它可用于消费,之后它将被丢弃以腾出空间
  • 每个消费者元数据中的最基础的数据就是消费者正在处理的当前记录的偏移量(offset)或位置(position位置),这种偏移是由消费者控制:通常偏移会随着消费者读取记录线性前进,但事实上,因为其位置是由消费者进行控制,消费者可以在任何它喜欢的位置读取记录
  • 为了保证kafka较高的处理效率,消息的读写都是在固定的一个副本上完成,这个副本就是所谓的Leader,而其他副本则是Follower,而Follower则会定期地到Leader上同步数据,leader处理所有的读取和写入分区的请求,而follower不工作;如果leader失败了,followers之一将自动成为新的领导者
  • Kafka并不允许replicas 数设置大于 broker数,因为在一个broker上如果有2个replica其实是没有意义的,因为再多的replica同时在一台broker上,随着该broker的crash,一起不可用
  • 如果leader出问题,则会从ISR(in-sync replica),也就是已同步副本中选择一个作为新的leader;ISR由zookeeper维护;通过ISR,kafka需要的冗余度较低,可以容忍的失败数比较高,假设某个topic有f+1个副本,kafka可以容忍f个服务器不可用
  • 消费者以消费群(consumer group)的名称来标识自己,每个发布到主题的消息都会发送给订阅了这个主题的消费群里面的一个消费者实例,即一个消费群只发送一次。消费者的实例可以在单独的进程或单独的机器上。
  • kafka只能保证一个partition中消息是有序的,而不能保证消息在多个partition中的分布是有序的

3)Kafka消息存储机制—稀疏索引文件机制

kafka的消息是存储在磁盘的,所以数据不易丢失,partition是存放消息的基本单位,每个partition都会保存成一个文件,这个文件又包含两部分。 .index索引文件、.log消息内容文件。
index文件结构很简单,每一行都是一个键值对,key 是消息的offset,value 是消息的物理位置偏移量, index索引文件 (offset消息编号<—>消息在对应文件中的偏移量)

kafka集群 图 kafka集群原理_zookeeper_02


比如:要查找绝对offset为7的Message:

首先是用二分查找确定它是在哪个LogSegment中,自然是在第一个Segment中(Kafka把topic中一个parition大文件分成多个小文件段segment,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用)。

打开这个Segment的index文件,也是用二分查找找到offset小于或者等于指定offset的索引条目中最大的那个offset。自然offset为6的那个索引是我们要找的,通过索引文件我们知道offset为6的Message在数据文件中的位置为9807。

打开数据文件,从位置为9807的那个地方开始顺序扫描直到找到offset为7的那条Message。

这套机制是建立在offset是有序的。索引文件被映射到内存中,所以查找的速度还是很快的。

这是一种稀疏索引文件机制,并没有把每个消息编号和文件偏移量记录下来,而是稀疏记录一部分,这样可以防止索引文件占据过多空间。每次查找消息时,需要将整块消息读入内存,然后获取对应的消息。
比如消息offset编号在36,37,38的消息,都会通过38找到对应的offset

4)kafka的特征:

1 kafka收到的消息,最终以文件的形式保存在本地
2 kafka集群的容灾技术。比如,n台服务器,可以承受n-1台故障
3 kafka会根据topic以及partition进行消息的本地物理划分
4 kafka依赖zookeeper实现offset
5 kafka的性能不受信息的数量影响

2. kafka操作部分

1)LNMP打rdkafka模块

194  nginx
  195  /etc/init.d/php-fpm start
  196  service mysqld start
  197  firefox 127.0.0.1&
  198  unzip librdkafka-master.zip
  199  cd librdkafka-master
  200  ls
  201  ./configure
  202  make
  203  make install
  204  cd ..
  205  unzip php-rdkafka-master.zip
  206  cd php-rdkafka-master
  207  phpize
  208  yum -y install autoconf
  209  ./configure  --with-php-config=/usr/local/php/bin/php-config --with-rdkafka
  210  make
  211  make install
  212  ls /usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/
  213  vim /usr/local/php/php.ini
  214  /etc/init.d/php-fpm restart
  215  firefox 127.0.0.1&

2)kafaka单机版本

220  tar -zxf zookeeper-3.4.5.tar.gz
  222  cd zookeeper-3.4.5
  224  cd conf
  225  cp -p zoo_sample.cfg zoo.cfg
  226  cd ..
  227  mkdir data
  228  echo 1 > data/myid
  229 cd ..
  232  mv zookeeper-3.4.5 /usr/local/zookeeper
cd /usr/local/zookeeper/bin
[ root@localhost bin]# vim zkEnv.sh
 56     ZOO_LOG_DIR="/usr/local/zookeeper/data"
 61     ZOO_LOG4J_PROP="INFO,ROLLINGFILE"
root@localhost bin]# vim zkServer.sh
 46 ZOOBIN=`readlink -f "${BASH_SOURCE-$0}"`
root@localhost bin]# vim zkCli.sh
 29 ZOOBIN=`readlink -f "${BASH_SOURCE-$0}"`
root@localhost bin]# ln -s /usr/local/zookeeper/bin/zkServer.sh /usr/local/bin/zk-server
root@localhost bin]# ln -s /usr/local/zookeeper/bin/zkCli.sh /usr/local/bin/zk-cli
238 zk-server start
  237  tar -zxf kafka_2.9.1-0.8.2.2.tgz
  238  mv kafka_2.9.1-0.8.2.2 /usr/local/kafka
root@localhost ~]# cd /usr/local/kafka/bin/
root@localhost bin]# ./kafka-server-start.sh  ../config/server.properties &
root@localhost bin]# ./kafka-console-producer.sh  --broker-list localhost:9092 --topic test
打开另一个终端:
root@localhost bin]# ./kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning
在第一个终端发消息 第二个可以收到
【kafka集群】(传消息走zookeeper,发消息、收消息走kafka)
主机1 192.168.1.22
主机2 192.168.1.17
主机3 192.168.1.19
做集群的准备:关闭守护进程,网卡必须是eth0,每个zookeeper的myid不可以相同 


三个主机操作一样
 145  tar -zxf zookeeper-3.4.5.tar.gz
  148  mv zookeeper-3.4.5 /usr/local/zookeeper
  149  cd /usr/local/zookeeper/
  150  mkdir data
  151  cd conf/
  152  cp -p zoo_sample.cfg zoo.cfg
  153  vim zoo.cfg
  2 tickTime=1000 #Zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔
  5 initLimit=5    #集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数
  8 syncLimit=5 #集群中的follower服务器(F)与leader服务器(L)之间 请求和应答之间能容忍的最多心跳数
 12 dataDir=/usr/local/zookeeper/data
 13 clientPort=2181
 25 server.1 = 192.168.1.22:2888:3888  #.1和myid一样
 26 server.2 = 192.168.1.17:2888:3888 #2888表示接收端口号,3888表示发送端口号
 27 server.3 = 192.168.1.19:2888:3888
 
  154  cd ..
  155  echo 1 >data/myid
  156  cd bin/

  158  vim zkEnv.sh
       56     ZOO_LOG_DIR="/usr/local/zookeeper/data"
       61     ZOO_LOG4J_PROP="INFO,ROLLINGFILE"
  159  vim zkServer.sh
         46 ZOOBIN=`readlink -f "${BASH_SOURCE-$0}"`
  160  vim zkCli.sh
         29 ZOOBIN=`readlink -f "${BASH_SOURCE-$0}"`
         
  161  ln -s /usr/local/zookeeper/bin/zkServer.sh /usr/local/bin/zk-server
  162  ln -s /usr/local/zookeeper/bin/zkCli.sh /usr/local/bin/zk-cli
 
主机1
[root@localhost bin]# zk-server start
[root@localhost bin]# zk-server status
JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: follower
主机2
[root@localhost bin]# zk-server start
JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@localhost bin]# zk-server status
JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: leader   #可以看出主机2是leader
 
主机3
[root@localhost bin]# zk-server start
JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@localhost bin]# zk-server status
JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: follower
 
主机1
[root@localhost ~]# tar -zxf kafka_2.9.1-0.8.2.2.tgz
[root@localhost ~]# mv kafka_2.9.1-0.8.2.2 /usr/local/kafka
[root@localhost ~]# cd /usr/local/kafka/
[root@localhost kafka]# cd config/
[root@localhost config]# vim server.properties
 20 broker.id=1
28 #host.name=localhost
 29 host.name=192.168.1.22
 34 #advertised.host.name=<hostname routable by clients>
 35 advertised.host.name=192.168.1.22
120 zookeeper.connect=192.168.1.22:2181,192.168.1.17:2181,192.168.1.19:2181
 
主机2
[root@localhost ~]# tar -zxf kafka_2.9.1-0.8.2.2.tgz
[root@localhost ~]# mv kafka_2.9.1-0.8.2.2 /usr/local/kafka
[root@localhost ~]# cd /usr/local/kafka/
[root@localhost kafka]# cd config/
[root@localhost config]# vim server.properties
 20 broker.id=2
28 #host.name=localhost
 29 host.name=192.168.1.17
 34 #advertised.host.name=<hostname routable by clients>
 35 advertised.host.name=192.168.1.17
120 zookeeper.connect=192.168.1.22:2181,192.168.1.17:2181,192.168.1.19:2181
 
主机3
[root@localhost ~]# tar -zxf kafka_2.9.1-0.8.2.2.tgz
[root@localhost ~]# mv kafka_2.9.1-0.8.2.2 /usr/local/kafka
[root@localhost ~]# cd /usr/local/kafka/
[root@localhost kafka]# cd config/
[root@localhost config]# vim server.properties
 20 broker.id=3
28 #host.name=localhost
 29 host.name=192.168.1.19
 34 #advertised.host.name=<hostname routable by clients>
 35 advertised.host.name=192.168.1.19
120 zookeeper.connect=192.168.1.22:2181,192.168.1.17:2181,192.168.1.19:2181
 
主机1 2 3
[root@localhost bin]# ./kafka-server-start.sh  ../config/server.properties &
[root@localhost bin]# netstat -anpt | grep 9092
[root@localhost bin]# netstat -anpt | grep 2181
 
主机1
[root@localhost bin]# ./kafka-topics.sh --create --zookeeper 192.168.1.22:2181 --replication-factor 2 --partition 3 --topic my-troop
[root@localhost bin]#  ./kafka-console-producer.sh  --broker-list 192.168.1.22:9092 --topic my-troop
 
主机3
[root@localhost bin]# ./kafka-console-consumer.sh  --zookeeper 192.168.1.19:2181 --topic my-troop
 
在主机1上发消息  主机3可以收到