kafka 教程(三)-远程访问
远程连接 kafka 配置
默认的 kafka 配置是无法远程访问的,解决该问题有几个方案。
方案1
advertised.listeners=PLAINTEXT://IP:9092
注意必须是 ip,不能是 hostname
方案2
advertised.listeners=PLAINTEXT://node0:9092
node0 是 hostname,需在 /etc/hosts 中 添加一行
172.16.89.80 node0
然后 必须在 远程机(要访问 kafka 的机器 windows)上修改 hosts文件,
C:\Windows\System32\drivers\etc\hosts
在末尾加上
IP1 节点1
IP2 节点2
节点名与服务器上的 hostname 相同。
测试异常记录
WARN [Consumer clientId=consumer-1, groupId=console-consumer-4184] Connection to node -1 (/172.16.89.80:9092) could not be established. Broker may not be available
. (org.apache.kafka.clients.NetworkClient)
kafka 配置 与 console 启动的 ip 不一致,如 配置文件中 listeners=PLAINTEXT://172.16.89.80:9092,启动 是 localhost
kafka.errors.NoBrokersAvailable: NoBrokersAvailable
listeners=PLAINTEXT://172.16.89.80:9092
基础操作
最简单的场景,生产者发送,消费者接收
Producer
send(self, topic, value=None, key=None, headers=None, partition=None, timestamp_ms=None)
producer = KafkaProducer(bootstrap_servers = '172.16.89.80:9092')
# producer = KafkaProducer(bootstrap_servers = 'node0:9092')
# 如果这里是 ip,后面必须加 producer.flush() 或者 producer.close();
# 如果是 hostname,则不需要,但是好像有丢包
print(producer.config) # 打印配置信息 topic = ''
for i in range(200):
msg = "msg%d" % i
producer.send(topic, msg) producer.flush()
# producer.close()
上面的注释是我亲测的结果,至于为什么,我还没明白,谁能帮我解答
Consumer
topic = ''
consumer = KafkaConsumer(topic, bootstrap_servers=['172.16.89.80:9092'])
# consumer是一个消息队列,当后台有消息时,这个消息队列就会自动增加.所以遍历也总是会有数据,当消息队列中没有数据时,就会堵塞等待消息带来
for msg in consumer:
recv = "%s:%d:%d: key=%s value=%s" % (msg.topic, msg.partition, msg.offset, msg.key, msg.value)
print recv
time.sleep(2)
注意 这种消费方式只能消费实时数据,不能消费历史数据
如果想读历史消息,可以这样写
consumer = KafkaConsumer(topic, auto_offset_reset='earliest', bootstrap_servers=['172.16.89.80:9092'])
auto_offset_reset:重置 offset,earliest 表示移到最早的可用消息,lastest 为最新消息,默认 latest
源码定义:{‘smallest’: ‘earliest’, ‘largest’: ‘latest’}
输出
生产者不指定分区,消费者输出如下
91101:1:8: key=None value=msg0
91101:2:12: key=None value=msg1
91101:0:17: key=None value=msg2
3 条消息分到了3个分区
如果不指定分区,一个 topic 的多个消息会被分发到不同的分区;消费者也收到了所有分区的消息
生产者指定分区,消费者输出如下
91101:2:13: key=None value=msg0
91101:2:14: key=None value=msg1
91101:2:15: key=None value=msg2
3 条消息被分到同一个分区
阻塞发送
kafka send 消息是异步的,即使 send 发生错误,程序也不会提示,我们可以通过 阻塞 的方式确认是否发送。
method1-get
import pickle
import time
from kafka import KafkaProducer
from kafka.errors import kafka_errors
producer = KafkaProducer(
bootstrap_servers=['172.16.89.80:9092'],
key_serializer=lambda k: pickle.dumps(k),
value_serializer=lambda v: pickle.dumps(v))
start_time = time.time()
for i in range(0, 100):
future = producer.send(topic="", key="num", value=i)
# 同步阻塞,通过调用get()方法保证有序性.
try:
record_metadata = future.get(timeout=20)
# print(record_metadata.topic)
# print(record_metadata.partition)
# print(record_metadata.offset)
except kafka_errors as e:
print(str(e))
end_time = time.time()
time_counts = end_time - start_time
print(time_counts)
method2-flush
import pickle
import time
from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers=['172.16.89.80:9092'],
key_serializer=lambda k: pickle.dumps(k),
value_serializer=lambda v: pickle.dumps(v))
start_time = time.time()
for i in range(0, 100):
future = producer.send('', key='num', value=i, partition=0)
# 将缓冲区的全部消息push到broker当中
producer.flush()
producer.close()
end_time = time.time()
time_counts = end_time - start_time
print(time_counts)
格式化输入输出
KafkaProducer 指定生产者输入的格式转换方式,key_serializer、value_serializer 用于格式化 key 和 value
KafkaConsumer 指定消费者输出的格式转换方式,value_deserializer
指定消费者组
之前讲过,不同消费者组消费相同的 topic,互不影响;同一个消费者组的不同成员在同一时刻不能消费同一个 topic 相同的分区;一个线程相当于一个消费者 【验证】
这里来验证一下
Producer
不指定分区,20条消息,3个分区
producer = KafkaProducer(bootstrap_servers = '172.16.89.80:9092')
print(producer.config)##打印配置信息 topic = ''
for i in range(20):
msg = "msg%d" % i
producer.send(topic, msg)
time.sleep(2)
producer.close()
Consumer
开两个线程,或者两个窗口,指定相同的消费者组,数组名 随便写,一样即可;
也是实时消费;
topic = ''
consumer = KafkaConsumer(topic, group_id='', bootstrap_servers=['172.16.89.80:9092'])
for msg in consumer:
recv = "%s:%d:%d: key=%s value=%s" % (msg.topic, msg.partition, msg.offset, msg.key, msg.value)
print recv
输出
一个消费者取到 0和1 分区的 value
91101:1:28: key=None value=msg1
91101:0:51: key=None value=msg3
91101:0:52: key=None value=msg5
91101:0:53: key=None value=msg9
91101:0:54: key=None value=msg10
91101:1:29: key=None value=msg11
91101:0:55: key=None value=msg12
91101:1:30: key=None value=msg15
91101:0:56: key=None value=msg16
91101:1:31: key=None value=msg17
91101:0:57: key=None value=msg18
一个消费者取到 2 分区的 value
91101:2:46: key=None value=msg0
91101:2:47: key=None value=msg2
91101:2:48: key=None value=msg4
91101:2:49: key=None value=msg6
91101:2:50: key=None value=msg7
91101:2:51: key=None value=msg8
91101:2:52: key=None value=msg13
91101:2:53: key=None value=msg14
91101:2:54: key=None value=msg19
也就是没有消费不同的分区,结论正确。
由于只有2个消费者,3个分区,所以必须有一个消费者消费2个分区;
如果是3个消费者应该就不存在这种情况,经验证,确实如此;
如果有再多的消费者,就分不到消息了;
这也验证了 之前讲的,同一个topic,不推荐多于 partition 个数的 消费者来消费,会造成资源浪费。 【验证】
小结
1. 消费者不指定组,能收到所有分区的 消息
2. 如果指定了组,同组的不同消费者会消费不同的分区
3. 如果2个分区2个消费者,则一人一个分区 ;如果2个分区3个消费者,则有一个人收不到消息;
4. 如果想消费同一分区,指定不同的组
这种特性可以用作 负载均衡
设定 offset
kafka 提供了 偏移量 offset 的概念,根据偏移量可以读取 终端开启前 未接收的数据, 也可以读取任意位置的数据 【可读取历史数据】
为了验证效果,操作如下
1. 创建一个新的 topic
2. 开启生产者,不开启消费者,并发送一些数据
3. 开启消费者,并指定 分区 和 偏移量,设置偏移量为 0
4. 再次运行消费者,指定相同的分区,偏移量设置为 4
topic = ''
consumer = KafkaConsumer(group_id='', bootstrap_servers=['172.16.89.80:9092']) # consumer 指定主题和分区
consumer.assign([TopicPartition(topic, partition=0), TopicPartition(topic, partition=1)]) # # 获取主题的分区信息,
print consumer.partitions_for_topic(topic) # None # 获取 consumer 的指定
print consumer.assignment() # set([TopicPartition(topic='91107', partition=0), TopicPartition(topic='91107', partition=1)]) # 获取 consumer 指定分区 的 起始offset
print consumer.beginning_offsets(consumer.assignment())
# {TopicPartition(topic=u'91107', partition=0): 0, TopicPartition(topic=u'91107', partition=1): 0} consumer.seek(TopicPartition(topic, partition=1), 4)
for msg in consumer:
recv = "%s:%d:%d: key=%s value=%s" % (msg.topic, msg.partition, msg.offset, msg.key, msg.value)
print recv
输出
# offset 0
91107:1:0: key=None value=msg2
91107:1:1: key=None value=msg6
91107:1:2: key=None value=msg10
91107:1:3: key=None value=msg11
91107:1:4: key=None value=msg13
91107:1:5: key=None value=msg19 # offset 4
91107:1:4: key=None value=msg13
91107:1:5: key=None value=msg19
相当于一个文件中从头到尾 6 行,offset 4 从第 4 行开始读,【行数从 0 开始】
异常记录
kafka.errors.IllegalStateError: IllegalStateError: You must choose only one way to configure your consumer: (1) subscribe to specific topics by name, (2) subscribe to topics matching a regex pattern, (3) assign itself specific topic-partitions.
KafkaConsumer 和 assign 不能同时 指定 topic
小结
1. offset 相当于文件中的 offset 概念
2. 指定 offset 时,必须指定分区,一个分区相当于一个文件,指定分区就相当于指定文件,offset 表示 从文件中 offset 行开始读
3. offset 功能可以读取 历史数据
定时主动拉取
主动拉取可能拉不到
from kafka import KafkaConsumer
import time # consumer = KafkaConsumer(bootstrap_servers=['node0:9092']) # 这样写只能获取最新消息
consumer = KafkaConsumer(bootstrap_servers=['node0:9092'], auto_offset_reset='earliest') # 这样可以从头拉取
consumer.subscribe(topics=('','')) while True:
msg = consumer.poll(timeout_ms=5) # 从kafka获取消息
print(msg.keys())
print('*' * 100)
time.sleep(2)
主动从多个 topic 拉取数据
输出
[]
****************************************************************************************************
[TopicPartition(topic=u'', partition=1), TopicPartition(topic=u'', partition=0)]
****************************************************************************************************
[TopicPartition(topic=u'', partition=0), TopicPartition(topic=u'', partition=2)]
****************************************************************************************************
[TopicPartition(topic=u'', partition=1), TopicPartition(topic=u'', partition=2)]
可以看到有的回合没有拉倒数据
消息挂起与恢复
挂起,消费者不能消费,恢复后,才能消费
from kafka import KafkaConsumer
from kafka.structs import TopicPartition
import time topic = ''
consumer = KafkaConsumer(bootstrap_servers=['node0:9092'])
consumer.subscribe(topics=(topic))
consumer.topics() consumer.pause(TopicPartition(topic=topic, partition=0)) # pause执行后,consumer不能读取,直到调用resume后恢复。
num = 0
while True:
print(num)
print(consumer.paused()) # 获取当前挂起的消费者
msg = consumer.poll(timeout_ms=5)
print(msg)
time.sleep(2)
num = num + 1
if num == 10:
print("resume...")
consumer.resume(TopicPartition(topic=topic, partition=0))
print("resume......")
参考资料:
https://www.cnblogs.com/tigerzhouv587/p/11232398.html python 发送kafka
https://kafka-python.readthedocs.io/en/master/usage.html
https://blog.csdn.net/luanpeng825485697/article/details/81036028 好全的资料
https://www.jianshu.com/p/776c188cefa9 从 zookeeper 消费
https://cloud.tencent.com/developer/news/202116 也挺全的资料
kafka 教程(三)-远程访问的更多相关文章
- CRL快速开发框架系列教程三(更新数据)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- 手把手教从零开始在GitHub上使用Hexo搭建博客教程(三)-使用Travis自动部署Hexo(1)
前言 前面两篇文章介绍了在github上使用hexo搭建博客的基本环境和hexo相关参数设置等. 基于目前,博客基本上是可以完美运行了. 但是,有一点是不太好,就是源码同步问题,如果在不同的电脑上写文 ...
- Windows OS上安装运行Apache Kafka教程
Windows OS上安装运行Apache Kafka教程 下面是分步指南,教你如何在Windows OS上安装运行Apache Zookeeper和Apache Kafka. 简介 本文讲述了如何在 ...
- 无废话ExtJs 入门教程三[窗体:Window组件]
无废话ExtJs 入门教程三[窗体:Window组件] extjs技术交流,欢迎加群(201926085) 1.代码如下: 1 <!DOCTYPE html PUBLIC "-//W3 ...
- CocoStudio教程三:认识并利用CocoStudio的果实 运行2.2.1版本
原文:CocoStudio教程三:认识并利用CocoStudio的果实 原文用的老版,用2.21搞起来好像有些问题,然后自己摸索了下,有的都是乱找的方法,只求能运行... 1,原文的CCJsonRea ...
- Android Studio系列教程三--快捷键
Android Studio系列教程三--快捷键 2014 年 12 月 09 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzhang.com/ ...
- Laravel教程 三:视图变量传递和Blade
Laravel教程 三:视图变量传递和Blade 此文章为原创文章,未经同意,禁止转载. Blade 上一篇我们简单地说了Router,Views和Controllers的工作流程,这一次我就按照上一 ...
- NGUI系列教程三
接下来我们再来看Progress Bar和Slider,对比参数我们可以发现,Progress Bar和slider的明显区别在于slider多一个Thumb选项,这里的Thumb就是我们拖动的时候点 ...
- 中文翻译:pjsip教程(三)之ICE stream transport的使用
1:pjsip教程(一)之PJNATH简介 2:pjsip教程(二)之ICE穿越打洞:Interactive Connectivity Establishment简介 3:pjsip教程(三)之ICE ...
随机推荐
- poj 3320 jessica's Reading PJroblem 尺取法 -map和set的使用
jessica's Reading PJroblem Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9134 Accep ...
- hdu 1208 Ignatius and the Princess III 划分数,dp
题目 题意:给你一个数字n,求将其划分成若干个数字相加总共有多少种划分数: <span style="font-size:24px;">#include <ios ...
- [HG]腿部挂件 题解
前言 暴力跑的比正解快. 以下暴力(循环展开+fread读入输出优化) #include<cstdio> #pragma GCC optimize(3, "Ofast" ...
- 3105: [cqoi2013]新Nim游戏
貌似一道经典题 在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴.可以一堆都不拿,但不可以全部拿走.第二回合也一样,第二个游戏者也有这样一次机会.从第三个回合(又轮到第一个游戏者)开始,规则和 ...
- jQuery_完成表单注册检验
在校验表单的时候会很麻烦,但是jq可以用很简单的方法来检验,即使用validate. 原表单: 代码 <!DOCTYPE html> <html> <head> & ...
- HAOI2018简要题解
大概之后可能会重写一下,写的详细一些? Day 1 T1 简单的背包:DP 分析 可以发现,如果选出了一些数,令这些数的\(\gcd\)为\(d\),那么这些数能且仅能组合成\(\gcd(d,P)\) ...
- 杜教筛&min_25筛复习
杜教筛 适用条件 你要能构造出\(g(x),h(x)\),使得\(h=f*g\). \(G(x),H(x)\)的值可以快速计算. 过程 我们要求的是\(F(n)=\sum_{i=1}^{n}f(i)\ ...
- JS框架_(Vue.js)带有星期日期的数字时钟
百度云盘 传送门 密码:tv1v 数字时钟效果: <!doctype html> <html> <head> <meta charset="utf- ...
- Jmeter -- 同步定时器
作用: 模拟并发. 设置一个阀值(请求数量),当请求数达到这个阀值时,允许请求同时发出.例如:想测试一座桥的并发(忽略载重等其他因素,只考虑通过),那么并发的请求就是类似于多少辆车可同时通过桥,而车辆 ...
- scrollWidth、clientWidth、offsetWidth、width的区别
scrollWidth:对象的实际内容的宽度,不包边线宽度,会随对象中内容超过可视区后而变大. clientWidth:对象内容的可视区的宽度,不包滚动条等边线,会随对象显示大小的变化而改变. off ...