kafka是用于构建实时数据管道和流应用程序。具有横向扩展,容错,wicked fast(变态快)等优点,并已在成千上万家公司运行。
简单说明什么是kafka
Apache kafka是消息中间件的一种,我发现很多人不知道消息中间件是什么,在开始学习之前,我这边就先简单的解释一下什么是消息中间件,只是粗略的讲解,目前kafka已经可以做更多
的事情。
举个例子,生产者消费者,生产者生产鸡蛋,消费者消费鸡蛋,生产者生产一个鸡蛋,消费者就消费一个鸡蛋,假设消费者消费鸡蛋的时候噎住了(系统宕机了),生产者还在生产鸡蛋,那新生产的鸡蛋就丢失了。再比如生产者很强劲(大交易量的情况),生产者1秒钟生产100个鸡蛋,消费者1秒钟只能吃50个鸡蛋,那要不了一会,消费者就吃不消了(消息堵塞,最终导致系统超时),消费者拒绝再吃了,”鸡蛋“又丢失了,这个时候我们放个篮子在它们中间,生产出来的鸡蛋都放到篮子里,消费者去篮子里拿鸡蛋,这样鸡蛋就不会丢失了,都在篮子里,而这个篮子就是”kafka“。
鸡蛋其实就是“数据流”,系统之间的交互都是通过“数据流”来传输的(就是tcp、https什么的),也称为报文,也叫“消息”。
消息队列满了,其实就是篮子满了,”鸡蛋“ 放不下了,那赶紧多放几个篮子,其实就是kafka的扩容。
各位现在知道kafka是干什么的了吧,它就是那个"篮子"。
kafka名词解释
后面大家会看到一些关于kafka的名词,比如topic、producer、consumer、broker,我这边来简单说明一下。
producer
:生产者,就是它来生产“鸡蛋”的。consumer
:消费者,生出的“鸡蛋”它来消费。topic
:你把它理解为标签,生产者每生产出来一个鸡蛋就贴上一个标签(topic),消费者可不是谁生产的“鸡蛋”都吃的,这样不同的生产者生产出来的“鸡蛋”,消费者就可以选择性的“吃”了。broker
:就是篮子了。
大家一定要学会抽象的去思考,上面只是属于业务的角度,如果从技术角度,topic标签实际就是队列,生产者把所有“鸡蛋(消息)”都放到对应的队列里了,消费者到指定的队列里取。
搭建kafka:
Kafka安装与终端使用
1.下载
kafka官网 下载到最新的kafka安装包,注意下载 Scala 2.11 - kafka_2.11-2.3.0.tgz (asc, sha512)
2.解压安装
首先确保你的机器上安装了jdk,kafka需要java运行环境,新版的kafka已经内置了一个zookeeper环境
tar -axvf kafka_2.11-2.3.0.tgz
cd kafka_2.11-2.3.0
3.配置 默认即可
4.启动
启动服务呢,可能需要java,如果没有安装java,可以去Centos7安装配置java环境:_不能如期而至的专栏-CSDN博客_centos安装java环境
4.1启动zookeeper
bin/zookeeper-server-start.sh config/zookeeper.properties >logs/kafka131-1.log >&1 &
4.2启动kafka服务器
bin/kafka-server-start.sh config/server.properties >logs/kafka131-server-1.log >&1 &
4.3查看zookeeper和kafka启动情况
jps
显示
35632 Kafka
36004 Jps
35279 QuorumPeerMain
5.创建一个topic
Kafka通过topic对同一类的数据进行管理,同一类的数据使用同一个topic可以在处理数据时更加的便捷,创建一个名为test的topic
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
在创建topic后查看已经创建的topic
bin/kafka-topics.sh --list --zookeeper localhost:2181
6 创建一个消息消费者 创建一个用于消费topic为test的消费者
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
消费者创建完成之后,因为还没有发送任何数据,因此这里在执行后没有打印出任何数据
不要关闭这个终端,打开一个新的终端,接下来我们创建第一个消息生产者
7 创建一个消息生产者
打开新的终端,cd进入kafka解压目录,输入
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
在执行完毕后会进入的编辑器页面
在发送完消息之后,可以回到我们的消息消费者终端中,可以看到,终端中已经打印出了我们刚才发送的消息
8 查看groups
bin/kafka-consumer-groups.sh --bootstrap-server 127.0.0.1:9092 -list
使用python操作kafka
python3操作kafka需要安装kafka模块,可以通过pip直接安装,pip install kafka
from kafka import KafkaProducer
from kafka import KafkaConsumer
from kafka.errors import KafkaError
import json
import time
class Kafka_producer():
'''
使用kafka的生产模块
'''
def __init__(self, kafkahost, kafkaport, kafkatopic):
self.kafkaHost = kafkahost
self.kafkaPort = kafkaport
self.kafkatopic = kafkatopic
self.producer = KafkaProducer(bootstrap_servers='{kafka_host}:{kafka_port}'.format(
kafka_host=self.kafkaHost,
kafka_port=self.kafkaPort
))
def sendjsondata(self, params):
try:
parmas_message = json.dumps(params)
producer = self.producer
producer.send(self.kafkatopic, parmas_message.encode('utf-8'))
producer.flush()
except KafkaError as e:
print(e)
class Kafka_consumer():
'''
使用Kafka—python的消费模块
'''
def __init__(self, kafkahost, kafkaport, kafkatopic, groupid):
self.kafkaHost = kafkahost
self.kafkaPort = kafkaport
self.kafkatopic = kafkatopic
self.groupid = groupid
self.consumer = KafkaConsumer(self.kafkatopic, group_id=self.groupid,
bootstrap_servers='{kafka_host}:{kafka_port}'.format(
kafka_host=self.kafkaHost,
kafka_port=self.kafkaPort))
def consume_data(self):
try:
for message in self.consumer:
# print json.loads(message.value)
yield message
except KeyboardInterrupt as e:
print(e)
def main():
'''
测试consumer和producer
:return:
'''
# 测试生产模块
producer = Kafka_producer("127.0.0.1", 9092, "test")
for i in range(10):
params = 'test---' + str(i)
print(params)
producer.sendjsondata(params)
time.sleep(1)
def main1():
# 测试消费模块
# 消费模块的返回格式为ConsumerRecord(topic=u'ranktest', partition=0, offset=202, timestamp=None,
# \timestamp_type=None, key=None, value='"{abetst}:{null}---0"', checksum=-1868164195,
# \serialized_key_size=-1, serialized_value_size=21)
consumer = Kafka_consumer('127.0.0.1',
9092,
"test",
'test')
message = consumer.consume_data()
for i in message:
print(i.value)
if __name__ == '__main__':
main()
import os
print(os.uname)
main1()