Python消费Kafka数据并批量插入Elasticsearch的实现方案
本文介绍利用Python通过pykafka消费Kafka数据,并批量插入Elasticsearch的方法。针对Kafka 0.8版本,使用get_simple_consumer确保多应用不重消费。通过设置consumer_timeout_ms避免阻塞,并配合死循环持续处理。当数据达到阈值时,利用bulk接口批量写入ES,适用于高并发数据场景。
1、Elasticsearch的批量插入机制
为了便于后期配置信息的修改与维护,将相关配置信息统一放置在logging.conf文件中。
使用elasticsearch库来实现批量操作功能。首先需要安装相应的依赖包,执行命令sudo pip install Elasticsearch2进行安装。
from elasticsearch import Elasticsearch
class ImportEsData:
logging.config.fileConfig("logging.conf")
logger = logging.getLogger("msg")
def __init__(self,hosts,index,type):
self.es = Elasticsearch(hosts=hosts.strip(',').split(','), timeout=5000)
self.index = index
self.type = type
def set_date(self,data):
# 批量处理
# es.index(index="test-index",doc_type="test-type",id=42,body={"any":"data","timestamp":datetime.now()})
self.es.index(index=self.index,doc_type=self.index,body=data)
2、使用pykafka消费Kafka数据
1. 由于Kafka版本为0.8,pykafka不支持ZooKeeper(zk)连接方式,因此只能采用get_simple_consumer方法来实现消费者功能。
2. 为了实现多个应用同时消费数据且避免重复消费的问题,采取一个应用对应一个partition(分区)的策略。
3. 为确保消费的数据量即使未达到10000这个批量阈值,也能在一定时间范围内插入到Elasticsearch中,这里设置了consumer_timeout_ms参数作为超时等待时间,从而退出因等待消费而产生的阻塞状态。
4. 退出等待消费阻塞后会导致无法继续消费数据,因此在获取self.consumer的外层加入了while True死循环,以确保持续处理。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
from pykafka import KafkaClient
import logging
import logging.config
from ConfigUtil import ConfigUtil
import datetime
class KafkaPython:
logging.config.fileConfig("logging.conf")
logger = logging.getLogger("msg")
logger_data = logging.getLogger("data")
def __init__(self):
self.server = ConfigUtil().get("kafka","kafka_server")
self.topic = ConfigUtil().get("kafka","topic")
self.group = ConfigUtil().get("kafka","group")
self.partition_id = int(ConfigUtil().get("kafka","partition"))
self.consumer_timeout_ms = int(ConfigUtil().get("kafka","consumer_timeout_ms"))
self.consumer = None
self.hosts = ConfigUtil().get("es","hosts")
self.index_name = ConfigUtil().get("es","index_name")
self.type_name = ConfigUtil().get("es","type_name")
def getConnect(self):
client = KafkaClient(self.server)
topic = client.topics[self.topic]
p = topic.partitions
ps={p.get(self.partition_id)}
self.consumer = topic.get_simple_consumer(
consumer_group=self.group,
auto_commit_enable=True,
consumer_timeout_ms=self.consumer_timeout_ms,
# num_consumer_fetchers=1,
# consumer_id='test1',
partitions=ps
)
self.starttime = datetime.datetime.now()
def beginConsumer(self):
print("beginConsumer kafka-python")
imprtEsData = ImportEsData(self.hosts,self.index_name,self.type_name)
#创建ACTIONS
count = 0
ACTIONS = []
while True:
endtime = datetime.datetime.now()
print (endtime - self.starttime).seconds
for message in self.consumer:
if message is not None:
try:
count = count + 1
# print(str(message.partition.id)+","+str(message.offset)+","+str(count))
# self.logger.info(str(message.partition.id)+","+str(message.offset)+","+str(count))
action = {
"_index": self.index_name,
"_type": self.type_name,
"_source": message.value
}
ACTIONS.append(action)
if len(ACTIONS) >= 10000:
imprtEsData.set_date(ACTIONS)
ACTIONS = []
self.consumer.commit_offsets()
endtime = datetime.datetime.now()
print (endtime - self.starttime).seconds
#break
except (Exception) as e:
# self.consumer.commit_offsets()
print(e)
self.logger.error(e)
self.logger.error(str(message.partition.id)+","+str(message.offset)+","+message.value+"\n")
# self.logger_data.error(message.value+"\n")
# self.consumer.commit_offsets()
if len(ACTIONS) > 0:
self.logger.info("等待时间超过,consumer_timeout_ms,把集合数据插入es")
imprtEsData.set_date(ACTIONS)
ACTIONS = []
self.consumer.commit_offsets()
def disConnect(self):
self.consumer.close()
from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
class ImportEsData:
logging.config.fileConfig("logging.conf")
logger = logging.getLogger("msg")
def __init__(self,hosts,index,type):
self.es = Elasticsearch(hosts=hosts.strip(',').split(','), timeout=5000)
self.index = index
self.type = type
def set_date(self,data):
# 批量处理
success = bulk(self.es, data, index=self.index, raise_on_error=True)
self.logger.info(success)
3、运行环境说明
if __name__ == '__main__': kp = KafkaPython() kp.getConnect() kp.beginConsumer() # kp.disConnect()
注:简单编写了一个从Kafka中读取数据到list列表的功能,当数据积累达到指定阈值时,再批量插入到Elasticsearch的插件中。
目前该方案仍在进行批量的压力测试阶段。
以上这篇Python消费Kafka数据并批量插入Elasticsearch的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









