Kafka 笔记一

早过忘川 提交于 2019-12-22 20:00:31

前言

早先过了一遍Kafka,摄取了不少知识细节,未免遗忘梳理记录下,推荐书本 《Kafka 权威指南》。

Quick Start

基础概念

关于Kafka是什么,可以参考官网介绍,一个分布式流处理平台,通俗点理解就是一款基于发布和订阅的消息系统。Kafka设计实现的目标在于:

  • 使用推送和拉取模式解藕生产者和消费者
  • 为消息系统中传递的消息提供数据持久化
  • 通过优化系统实现高吞吐量
  • 系统可以随着数据流的增长进行横向拓展

既然kafka的实质是一个消息系统,类似其他MQ他也有
生产者:消息产生这,向kafka推送消息
消费者:消息的实际使用者,从kafka拉取生产者推送至kafka的消息
Topic:消息主题,亦可理解为消息类型,生产者发送了什么主题的消息,对应订阅了该主题的消费者方可拉取到该消息

Kakfa系统中一些概念
broker:一个独立的kafka服务被称为一个broker
集群:kafka是集群式的提供服务,broker是集群的一个组成部分
分区:一个topic下的至少要包含一个分区,亦可包含多个分区,topic下的消息是存储于分区中的,如图下示。对于给定分区中,消息是按照进入分区的顺序,先到者先被消费。
在这里插入图片描述
偏移量:消费者根据偏移量来区分哪些消息已经别消费过。
如果觉得概念枯燥繁多可先忽略。

Kafka部署

先快速将kafka搭建起来,对于kafka系统,其以来zookeeper作为集群的配置管理,其中包括kafka集群的broker信息,topic信息等等一系列的元信息,kafka集群的调度变更也是基于这些元信息做调配。选择机器部署kakfa则先部署zookeeper,而后在再部署kafka。此处选择容器部署,关于docker部署服务可以参见 docker 笔记一, docker 笔记二
docker-compose.yaml内容如下

version: '3'
services:
  zookeeper:
    image: wurstmeister/zookeeper
    ports:
      - "2181:2181"
  kafka:
    image: wurstmeister/kafka
    depends_on: [ zookeeper ]
    ports:
      #- "9092:9092"
      - "9092"
    environment:
      KAFKA_ADVERTISED_HOST_NAME: 192.168.99.100
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
# 启动kafka
docker-compose up -d
# 进入zookeeper所在contaienr,开启shell client
./bin/zkCli.sh
ls /brokers/ids

容器启动kafka服务:
在这里插入图片描述
zookeeper查看broker元信息
在这里插入图片描述

python Kafka

python接入kafka可以安装 kafka-python,演示环境Mac平台,python3.6。demo code如下:

# producer.py
import time
import json
from kafka import KafkaProducer

producer = KafkaProducer(bootstrap_servers='localhost:32774')  # 之前启动时container默认映射出的端口32774,kafka默认端口为9092
topic = 'first_kafka_topic'
for i in range(100):
    v = json.dumps(f'content -- {i}')
    print(f'producer send message: {v}')
    r = producer.send(topic, v.encode())
    time.sleep(2)  # note

# consumer.py
from kafka import KafkaConsumer
topic = 'first_kafka_topic'
consumer = KafkaConsumer(topic, bootstrap_servers=['localhost:32774'])
for msg in consumer:
    print('consumer get message: ', msg)

执行结果:
在这里插入图片描述
至此,kafka的基础了解算是一个总括了解,但并非真正了解kafkaxijie,继续梳理。

Kafka 生产者

生产者的使用不仅是上文demo中的形式,其还有多种配置信息,此前我们先了解Kafka 生产者发送消息的过程,如下图( kafka权威指南):
在这里插入图片描述
对于一个生产者,首先要明确链接borker的地址,此外就是生产者发送消息的形式。对于一些场景,诸如银行转账此类,是重要性信息,生产者必须确认消息发送成功,kafka已经成功接收。另一种,如产品使用的打点记录,用以统计访问pv/uv的打点记录,并非严格要求发送打点不可丢失。那么对应的producer可以有不同的ack模式

  • ack=0,发送即不管,producer发送消息后不会等待服务器的任何响应返回,表示发送完消息后中途出现某些异常导致broker没有收到,producer完全不会感知。
  • ack=1,发送后会等待集群的首领节点收到消息的确认后表示成功,如果当中出现消息无法到达首领节点(首领节点崩溃,而新的首领节点尚未诞生),则producer会收到一个错误响应。
  • ack=all,集群中所有节点均收到消息后,生产者会收到服务器返回的成功信息,此种方式发送效率较低。
    更多生产者配置请参加 Producer 配置,python可以直接类比查看from kafka import KafkaProducerKafkaProducer 初始化参数。
    常用的生产者参数除ack外,还包括:
  • buffer.memory – 生产者缓冲区大小
  • compression.type – 消息压缩格式,默认不压缩,可以设置为snappy、 gzi.p 或 lz4
  • retries – 消息发送失败重试次数,默认每次重拾之间间隔100ms
  • batch.size – 多消息同批次发送时,批次最大字节容量,size表示字节数量。消息发送统一分区时,生产者会将多条消息同一批次发送
  • linger.ms – 指定生产者在将多条消息做一个批次发送时的等待时间

除上述参数外,生产者还可在发送message时指定key,对于一个包含多个分区的topic,生产者发送指定相同的key时,消息会落在相同的分区上,且相同分区的消息符合上文说的,有序性。

Kafka 消费者

消费者订阅 topic会获取到broker中对应topic的信息,消费者中可以指定消费群组group,那么相同group的多个消费者,不会消费同一个topic,同一个分区的消息。不同分组下的消费会,互不影响,如下图:
在这里插入图片描述
注意: 当消费者的数量大于topic的partition数量时,多余的consumer会被闲置,不消费topic中信息。不同的消费群组可能会跟不同的broker之间通信心跳信息,此broker为该群组的群组协调器
当topic分区数量发生变化,或者消费者数量发生变化时,每个消费者跟topic的partition的对应关系会发生,分区消费权利从一个consumer转移变化的过程称之为 再均衡。第一个加入该消费组的consumer是“群主”,群主consumer保有该群组每个其他成员consumer的消费partition的具体信息,当发生再均衡时,群主consumer会重新分配每个分区归于的consumer,确定后会发送给 群组协调器。

consumer消费消息,发送心跳等等一系列同数据交互,都是通过对Kafka对应API的轮训完成,对应启动消费者时会有诸多的参数配置:

  • fetch.min.bytes – 消费者从服务端获取数据的最小字节数
  • fetch.max.wa it.ms – 消费者最大等待时间,毫秒,该参数与fetch.min.bytes对应,在python sdk中对应 fetch_max_wait_ms 默认为500ms,当500ms内服务端对应的topic的partition内没有累计足够的数据量,则返回当前所有的消息
  • max.pa内ition.fetch.bytes – 指定服务器从每个分区中返回给消费者的最大字节数,默认1MB
  • session.timeout.ms – consumer 在被判定死亡前能够与服务器断开链接的时间
  • auto.offset.reset – 指定没有偏移量的分区或者偏移量失效时,从何处获取数据,通常默认为latest
  • enable.auto.commit – 消费者是否开启自动提交偏移量,默认为True

更多consumer的参数可以参数见 Consumer 配置

Kafka Command

常用的查看Kafka信息的命令

# 先docker进入kafka broker 的container中
# zookeeper 换做对应container 的名称
# 查看kafka版本信息
$ find / -name \*kafka_\* | head -1 | grep -o '\kafka[^\n]*'
# 查看名称为 test的topic详细信息
$ kafka-topics.sh --describe --zookeeper zookeeper:2181  --topic test
# 查看消息数量
$ kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list 127.0.0.1:9092 --topic test
# 查看kafka group列表
$ kafka-consumer-groups.sh --bootstrap-server localhost:9092 --all-groups --list
# 创建名称为 test 的topic,并且指定topic包含3个partition,每个partition包含 3 个副本
$ kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 3 --topic test

修改生产者代码:

import time
import json
from kafka import KafkaProducer

def send_callback(*args, **kwargs):
    print('in send_callback')
    print('args --- ', args)
    print('kwargs --- ', kwargs)
    
topic = 'test'
producer = KafkaProducer(bootstrap_servers=['localhost:32790'])  # 根据实际修改
for i in range(2):
    v = json.dumps(f'content -- {i}')
    print(f'producer send message: {v}')
    r = producer.send(topic, value=v.encode(), key=b'my_key')
    # 指定partition发送消息
    # r = producer.send(topic, value=v.encode(), partition=1)
    r.add_callback(send_callback)  # 添加发送成功后的callback
    time.sleep(2)  

修改生产者代码

topic = 'test'
consumer = KafkaConsumer(topic, group_id='group1', bootstrap_servers=['localhost:32790'])
for msg in consumer:
    print('consumer get message: ', msg)

通过修改不同的生产者参数运行后,broker中消息数量:
在这里插入图片描述

上述consumer的介绍中,有enable.auto.commit的设置,正常情况下,消费者消费完批量获取的消息后,提交offset偏移量后,继续获取尚未消费的消息,但是如果期间发生了在均衡,会发生何种情况?
对于Kafka服务,如何保证数据的完整性,不会丢失生产者发送来的数据,当broker出现故障时?
demo中的数据为简单json序列化,多数使用Avro,后续再行梳理。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!