基于hadoop及python的Kafka实践浅析

一、什么是Kafka

ApacheKafka是一个分布式流媒体平台,这到底是什么意思呢?接下来我们看一下流媒体平台有三个关键功能如下:
    第一:发布和订阅记录流,类似于消息队列或企业消息传递系统。
    第二:以容错持久的方式存储记录流。
    第三:处理记录发生的流。

我们可以将Kafka理解成一个总线,任何节点都可以将记录流发布到总线上,任何节点也都可以订阅记录流,订阅时会通过Topic区分。

kafka起先由领英(linkedin创建)公司,开源后被Apache基金会纳入子项目。我们在下载Kafka时,你是如何区分它的版本呢?比如本篇博客下载kafka的版本是“kafka_2.11-1.1.0”,这个“2.11”是scala(java语言脚本化)版本而“1.1.0”是kafka版本。

二、配置Kafka

2.1、所需资源

所需资源:
1)linux机器(我的环境是linux,而且linux更方便)
2)hadoop服务
3)zookeeper服务
4)kafka服务

上文已经介绍,Kafka目前属于hadoop生态,那么要使用Kafka,我们必须先启动hadoop,同时Kafka依赖zookeeper,我们还必须启动zookeeper服务。

2.2、安装配置hadoop(单机)

我们的目的是测试kafka服务,并理解机制,因此简单的单机配置就可以了,生产环境自然会有后台同事搭建大型集群。

hadoop的详细搭建配置步骤在此不再赘述,可以参看 Hadoop(二)搭建伪分布式集群 这篇blog,我认为写得非常清晰。
大体顺序是:
1)下载jdk并解压
2)修改系统环境配置(添加jdk路径)
3)下载hadoop并解压
4)修改系统环境配置(添加hadoop路径)
5)修改hadoop配置文件(配置ip等)
6)启动hadoop并测试

2.3、安装配置zookeeper(单机)

同样,我们还需要配置单机的zookeeper,可以参看 安装zookeeper(单机,伪集群) 进行下载配置。

2.4、安装配置kafka(单机)

本来也想甩几个优质blog的,但发现都是各讲一块,不够系统,所以亲自归纳。

2.4.1 第一步 Kafka下载与解压

下载地址 https://www.apache.org/dyn/closer.cgi?path=/kafka/1.1.0/kafka_2.11-1.1.0.tgz
下载完后上传到linux服务器解压

tar -zxvf kafka_2.11-1.1.0.tgz /opt/
# 做软链接,方便记录地址和修改版本
ln -s /opt/kafka_2.11-1.1.0/ /opt/kafka

2.4.2 第二步 配置环境变量

编辑/etc/profile文件,添加如下信息:

#ADD KafKa PATH
export KAFKA_HOME=/opt/kafka
PATH=$PATH:$KAFKA_HOME/bin

并执行source /etc/profile使配置生效。

2.4.3 第三步 修改Kafka配置文件

这里我们简单地使用sed -i命令添加信息:

sed -i 's@#listeners=PLAINTEXT://:9092@listeners=PLAINTEXT://s101:9092@g' /opt/kafka/config/server.properties
sed -i 's@log.dirs=/tmp/kafka-logs@log.dirs=/home/yinzhengjie/kafka/logs@g' /opt/kafka/config/server.properties
sed -i 's@zookeeper.connect=localhost:2181@zookeeper.connect=s102:2181,s103:2181,s104:2181@g' /opt/kafka/config/server.properties

当然也可以打开配置文件/opt/kafka/config/server.properties手动添加。

2.4.4 第四步 启动Kafka服务

执行脚本启动服务(加上-daemon 让其后台运行),然后用jps命令可以看到Kafka已经启动。
通过netstat -untalp | grep 9092命令查看kafka服务的ip,

[root@com bin]$ /opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties
[root@com bin]$ jps
18608 Application
29232 Kafka
20721 NodeManager
22258 QuorumPeerMain
20535 DataNode
10440 jar
28682 Application
29292 Jps
[root@com bin]$ netstat -untalp | grep 9092
tcp        0      0 10.25.77.54:35914       30.23.9.175:9092        ESTABLISHED 28682/java 

2.5 使用kafka发送和接收消息

2.5.1 启动生产者(消息发送方)

从命令行输出我们得到ip为30.23.9.175,使用以下命令建立生产者。
“–topic”后面填写topic名称,接收方将通过topic名称找到要接收的数据流。

[root@com bin]$ kafka-console-producer.sh --broker-list 30.23.9.175:9092 --topic test_20190516
>

接下来我们发现都在一个对话环境交互,输入要发送的文字:

>
>
>can you hear me?
>

2.5.2 启动消费者(消息接收方)

输入如下命令启动消费者,将通过topic监听数据流,启动后马上就会受到刚刚发出的文字。

[root@com bin]$ kafka-console-consumer.sh  --bootstrap-server 30.23.9.175:9092 --topic test_20190516 --from-beginning
can you hear me?

2.5.3 使用kafka-python库建立生产者和消费者

到这里还没完,命令行的操作我们都熟悉了,但是在开发中我们经常需要在模型工程中和外部数据源交互,那么如何用python实现接收到发送kafka数据呢。

1)安装环境
使用anaconda环境,在prompt中输入pip install kafka即可完成安装。

2)发送消息
使用KafkaProducer发送消息

from kafka import KafkaProducer
 
kafka_host='30.23.9.175' # host
kafka_port=9092 # port
kafka_topic='test_20190516'
 
producer = KafkaProducer(
	bootstrap_servers=['{kafka_host}:{kafka_port}'.format(kafka_host=kafka_host, kafka_port=kafka_port)]
)
message_string = 'can you hear me?'
response = producer.send(kafka_topic, message_string.encode('utf-8'))

3)接收消息
使用KafkaComsuer接收消息

from kafka import KafkaConsumer
consumer = KafkaConsumer(
    'test_20190516',
    bootstrap_servers=['{kafka_host}:{kafka_port}'.format(kafka_host=kafka_host, kafka_port=kafka_port)]
)
for message in consumer:
    print(type(message.value), message.value, message)
    # ...

consumer可迭代,当队列中没有消息时,上面代码会一直等待。使用Control+C可以退出循环。
这样将接收到如下信息:

(<type 'str'>, 'can you hear me?', ConsumerRecord(topic=u'test_20190516', partition=0, offset=6, timestamp=1557997768959, timestamp_type=0, key=None, value='can you hear me?', checksum=658729517, serialized_key_size=-1, serialized_value_size=16))

观察发现,message是一个类的实例化对象,message.value可以取出数据信息。

2.5.4 Groupid到底什么意思

临近结束,有一点不得不提,就是Groupid这个参数,我们在关于Kafka的blog中经常看到Groupid这个参数的使用,但是这个到底干嘛用的?都讲的模棱两可。今天一定要摆事实讲道理列清楚。

1)Groupid是Kafka consumer的参数,不是Kafka producer的参数。
2)Groupid不是用来让Kafka consumer筛选Kafka producer的内容的,筛选内容是用Topic这个参数。
3)Groupid只是用于保证Kafka consumer得到的数据唯一且连续,不会因为接受端的冲突导致收到多份重复数据,这个怎么理解呢,下面摆个例子。

第一步!
借用上文的变量继续工作,我们使用Kafka producer发送字符串“No.1”:

>>> # Kafka producer
>>> response = producer.send(kafka_topic, 'No.1 ...')

同时准备两个Kafka consumer接收消息,Groupid分别为“group1”和“group2”,
“group1”得到的消息是:

ConsumerRecord(topic=u'test_20190516', partition=0, offset=16, timestamp=1559891940660, timestamp_type=0, key=None, value='No.1 ...', checksum=1447245960, serialized_key_size=-1, serialized_value_size=8)

“group2”得到的消息是:

ConsumerRecord(topic=u'test_20190516', partition=0, offset=16, timestamp=1559891940660, timestamp_type=0, key=None, value='No.1 ...', checksum=1447245960, serialized_key_size=-1, serialized_value_size=8)

两个完全一样对不对?好,下面继续。

第二步
使用Kafka producer发送字符串“No.2”:

>>> # Kafka producer
>>> response = producer.send(kafka_topic, 'No.1 ...')

同时再多准备一个Kafka consumer接收消息,Groupid为“group1”,注意,现在有三个consumer,Groupid分别为“group1”和“group2”和“group1”,我们分别按序号1、2、3表示:
1号consumer得到的新消息是空的!没有新消息:


2号consumer得到的消息是:

ConsumerRecord(topic=u'test_20190516', partition=0, offset=17, timestamp=1559893332851, timestamp_type=0, key=None, value='No.2 ...', checksum=-915836631, serialized_key_size=-1, serialized_value_size=8)

3号consumer得到的消息是:

ConsumerRecord(topic=u'test_20190516', partition=0, offset=17, timestamp=1559893332851, timestamp_type=0, key=None, value='No.2 ...', checksum=-915836631, serialized_key_size=-1, serialized_value_size=8)

总结
注意到没有,由于Groupid一致,3号consumer继续收到producer的消息,而1号就收不到了,保证了这个Groupid无论在什么端接收都是唯一且连续的。

2.5.5 注意事项

如果出现kafka.errors.NoBrokersAvailable: NoBrokersAvailable的报错,一般是因为Kafka服务没有正常启动。

三、引用

[1] https://kafka-python.readthedocs.io/en/master/index.html
[2] https://www.runoob.com/linux/linux-comm-netstat.html
[3] https://www.cnblogs.com/yinzhengjie/p/9209058.html
[4] https://blog.csdn.net/mingyunxiaohai/article/details/80613227
[5] https://www.cnblogs.com/yinzhengjie/p/9209319.html

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值