如何通过 Kafka 将数据导入 Elasticsearch

339 阅读8分钟

作者:来自 Elastic Andre Luiz

将 Apache Kafka 与 Elasticsearch 集成的分步指南,以便使用 Python、Docker Compose 和 Kafka Connect 实现高效的数据提取、索引和可视化。

在本文中,我们将展示如何将 Apache Kafka 与 Elasticsearch 集成以进行数据提取和索引。我们将概述 Kafka、其生产者(producers)和消费者(consumers)的概念,并创建一个日志索引,其中将通过 Apache Kafka 接收和索引消息。该项目以 Python 实现,代码可在 GitHub 上找到。

先决条件

  • Docker 和 Docker Compose:确保你的机器上安装了 Docker 和 Docker Compose。
  • Python 3.x:运行生产者和消费者脚本。

Apache Kafka 简介

Apache Kafka 是一个分布式流媒体平台,具有高可扩展性和可用性以及容错能力。在 Kafka 中,数据管理通过主要组件进行:

  • Broker/代理:负责在生产者和消费者之间存储和分发消息。
  • Zookeeper:管理和协调 Kafka 代理,控制集群的状态、分区领导者和消费者信息。
  • Topics/主题:发布和存储数据以供使用的渠道。
  • **Consumers 及 Producers/**消费者和生产者:生产者向主题发送数据,而消费者则检索该数据。

这些组件共同构成了 Kafka 生态系统,为数据流提供了强大的框架。

项目结构

为了理解数据提取过程,我们将其分为几个阶段:

  • 基础设施配置/Infrastructure Provisioning:设置 Docker 环境以支持 Kafka、Elasticsearch 和 Kibana。
  • 创建生产者/Producer Creation:实现 Kafka 生产者,将数据发送到日志主题。
  • 创建消费者/Consumer Creation:开发 Kafka 消费者以读取和索引 Elasticsearch 中的消息。
  • 提取验证/Ingestion Validation:验证和确认已发送和已使用的数据。

使用 Docker Compose 进行基础设施配置

我们利用 Docker Compose 来配置和管理必要的服务。下面,你将找到 Docker Compose 代码,它设置了 Apache Kafka、Elasticsearch 和 Kibana 集成所需的每项服务,确保数据提取过程。

docker-compose.yml

`

1.  version: "3"

3.  services:

5.    zookeeper:
6.      image: confluentinc/cp-zookeeper:latest
7.      container_name: zookeeper
8.      environment:
9.        ZOOKEEPER_CLIENT_PORT: 2181

11.    kafka:
12.      image: confluentinc/cp-kafka:latest
13.      container_name: kafka
14.      depends_on:
15.        - zookeeper
16.      ports:
17.        - "9092:9092"
18.        - "9094:9094"
19.      environment:
20.        KAFKA_BROKER_ID: 1
21.        KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
22.        KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST:${HOST_IP}:9092
23.        KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
24.        KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
25.        KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

27.    elasticsearch:
28.      image: docker.elastic.co/elasticsearch/elasticsearch:8.15.1
29.      container_name: elasticsearch-8.15.1
30.      environment:
31.        - node.name=elasticsearch
32.        - xpack.security.enabled=false
33.        - discovery.type=single-node
34.        - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
35.      volumes:
36.        - ./elasticsearch:/usr/share/elasticsearch/data
37.      ports:
38.        - 9200:9200

40.    kibana:
41.      image: docker.elastic.co/kibana/kibana:8.15.1
42.      container_name: kibana-8.15.1
43.      ports:
44.        - 5601:5601
45.      environment:
46.        ELASTICSEARCH_URL: http://elasticsearch:9200
47.        ELASTICSEARCH_HOSTS: '["http://elasticsearch:9200"]'

`代码解读

你可以直接从 Elasticsearch Labs GitHub repo 访问该文件。

使用 Kafka 生产器发送数据

生产器负责将消息发送到日志主题。通过批量发送消息,可以提高网络使用效率,允许使用 batch_size 和 linger_ms 设置进行优化,这两个设置分别控制批次的数量和延迟。配置 acks='all' 可确保消息持久存储,这对于重要的日志数据至关重要。

`

1.  producer = KafkaProducer(
2.     bootstrap_servers=['localhost:9092'],  # Specifies the Kafka server to connect
3.     value_serializer=lambda x: json.dumps(x).encode('utf-8'),  # Serializes data as JSON and encodes it to UTF-8 before sending
4.     batch_size=16384,     # Sets the maximum batch size in bytes (here, 16 KB) for buffered messages before sending
5.     linger_ms=10,         # Sets the maximum delay (in milliseconds) before sending the batch
6.     acks='all'            # Specifies acknowledgment level; 'all' ensures message durability by waiting for all replicas to acknowledge
7.  )

10.  def generate_log_message():
11.     levels = ["INFO", "WARNING", "ERROR", "DEBUG"]
12.     messages = [
13.         "User login successful",
14.         "User login failed",
15.         "Database connection established",
16.         "Database connection failed",
17.         "Service started",
18.         "Service stopped",
19.         "Payment processed",
20.         "Payment failed"
21.     ]
22.     log_entry = {
23.         "level": random.choice(levels),
24.         "message": random.choice(messages),
25.         "timestamp": time.time()
26.     }
27.     return log_entry

29.  def send_log_batches(topic, num_batches=5, batch_size=10):
30.     for i in range(num_batches):
31.         logger.info(f"Sending batch {i + 1}/{num_batches}")
32.         for _ in range(batch_size):
33.             log_message = generate_log_message()
34.             producer.send(topic, value=log_message)
35.         producer.flush()

38.  if __name__ == "__main__":
39.     topic = "logs"
40.     send_log_batches(topic)
41.     producer.close()

`代码解读

当启动 producer 的时候,会批量的向 topic 发送消息,如下图:

`

1.  INFO:kafka.conn:Set configuration …
2.  INFO:log_producer:Sending batch 1/5 
3.  INFO:log_producer:Sending batch 2/5
4.  INFO:log_producer:Sending batch 3/5
5.  INFO:log_producer:Sending batch 4/5

`代码解读

使用 Kafka Consumer 消费和索引数据

Consumer 旨在高效处理消息,消费来自日志主题的批次并将其索引到 Elasticsearch 中。使用 auto_offset_reset='latest',可确保 Consumer 开始处理最新消息,忽略较旧的消息,max_poll_records=10 将批次限制为 10 条消息。使用 fetch_max_wait_ms=2000,Consumer 最多等待 2 秒以积累足够的消息,然后再处理批次。

在其主循环中,Consumer 消费日志消息、处理并将每个批次索引到 Elasticsearch 中,确保持续的数据摄取。

`

1.  consumer = KafkaConsumer(
2.     'logs',                               
3.     bootstrap_servers=['localhost:9092'],
4.     auto_offset_reset='latest',            # Ensures reading from the latest offset if the group has no offset stored
5.     enable_auto_commit=True,               # Automatically commits the offset after processing
6.     group_id='log_consumer_group',         # Specifies the consumer group to manage offset tracking
7.     max_poll_records=10,                   # Maximum number of messages per batch
8.     fetch_max_wait_ms=2000                 # Maximum wait time to form a batch (in ms)
9.  )

11.  def create_bulk_actions(logs):
12.     for log in logs:
13.         yield {
14.             "_index": "logs",
15.             "_source": {
16.                 'level': log['level'],
17.                 'message': log['message'],
18.                 'timestamp': log['timestamp']
19.             }
20.         }

22.  if __name__ == "__main__":
23.     try:
24.         print("Starting message processing…")
25.         while True:

27.             messages = consumer.poll(timeout_ms=1000)  # Poll receive messages

29.             # process each batch messages
30.             for _, records in messages.items():
31.                 logs = [json.loads(record.value) for record in records]
32.                 bulk_actions = create_bulk_actions(logs)
33.                 response = helpers.bulk(es, bulk_actions)
34.                 print(f"Indexed {response[0]} logs.")
35.     except Exception as e:
36.         print(f"Erro: {e}")
37.     finally:
38.         consumer.close()
39.         print(f"Finish")

`代码解读

在 Kibana 中可视化数据

借助 Kibana,我们可以探索和验证从 Kafka 提取并在 Elasticsearch 中编入索引的数据。通过访问 Kibana 中的开发工具,你可以查看已编入索引的消息并确认数据符合预期。例如,如果我们的 Kafka 生产者发送了 5 个批次,每个批次 10 条消息,我们应该在索引中看到总共 50 条记录。

要验证数据,你可以在 Dev Tools 部分使用以下查询:

`

1.  GET /logs/_search
2.  {
3.    "query": {
4.      "match_all": {}
5.    }
6.  }

`代码解读

相应:

此外,Kibana 还提供了创建可视化和仪表板的功能,可帮助使分析更加直观和具有交互性。下面,你可以看到我们创建的一些仪表板和可视化示例,它们以各种格式展示了数据,增强了我们对所处理信息的理解。

使用 Kafka Connect 进行数据提取

Kafka Connect 是一种旨在促进数据源和目标(接收器)之间的集成的服务,例如数据库或文件系统。它使用预定义的连接器来自动处理数据移动。在我们的例子中,Elasticsearch 充当数据接收器。

使用 Kafka Connect,我们可以简化数据提取过程,无需手动将数据提取工作流实施到 Elasticsearch 中。借助适当的连接器,Kafka Connect 允许将发送到 Kafka 主题的数据直接在 Elasticsearch 中编入索引,只需进行最少的设置,无需额外编码。

使用 Kafka Connect

要实现 Kafka Connect,我们将 kafka-connect 服务添加到我们的 Docker Compose 设置中。此配置的一个关键部分是安装 Elasticsearch 连接器,它将处理数据索引。

配置服务并创建 Kafka Connect 容器后,将需要一个 Elasticsearch 连接器的配置文件。此文件定义基本参数,例如:

  • connection.url:Elasticsearch 的连接 URL。
  • topics:连接器将监视的 Kafka 主题(在本例中为 “logs”)。
  • type.name:Elasticsearch 中的文档类型(通常为 _doc)。
  • value.converter:将 Kafka 消息转换为 JSON 格式。
  • value.converter.schemas.enable:指定是否应包含架构。
  • schema.ignorekey.ignore:在索引期间忽略 Kafka 架构和键的设置。

以下是在 Kafka Connect 中创建 Elasticsearch 连接器的 curl 命令:

`

1.  curl --location '{{url}}/connectors' \
2.  --header 'Content-Type: application/json' \
3.  --data '{
4.      "name": "elasticsearch-sink-connector",
5.      "config": {
6.          "connector.class": "io.confluent.connect.elasticsearch.ElasticsearchSinkConnector",
7.          "topics": "logs",
8.          "connection.url": "http://elasticsearch:9200",
9.          "type.name": "_doc",
10.          "value.converter": "org.apache.kafka.connect.json.JsonConverter",
11.          "value.converter.schemas.enable": "false",
12.          "schema.ignore": "true",
13.          "key.ignore": "true"
14.      }
15.  }'

`代码解读

通过此配置,Kafka Connect 将自动开始提取发送到 “logs” 主题的数据并在 Elasticsearch 中对其进行索引。这种方法允许完全自动化的数据提取和索引,而无需额外的编码,从而简化整个集成过程。

结论

集成 Kafka 和 Elasticsearch 为实时数据提取和分析创建了一个强大的管道。本指南提供了一种构建强大数据提取架构的基础方法,并在 Kibana 中实现无缝可视化和分析,以适应未来更复杂的要求。

此外,使用 Kafka Connect 使 Kafka 和 Elasticsearch 之间的集成更加简化,无需额外的代码来处理和索引数据。Kafka Connect 使发送到特定主题的数据能够以最少的配置自动在 Elasticsearch 中编入索引。

想要获得 Elastic 认证?了解下一次 Elasticsearch 工程师培训的时间!

Elasticsearch 包含许多新功能,可帮助你为你的用例构建最佳搜索解决方案。深入了解我们的示例笔记本以了解更多信息,开始免费云试用,或立即在本地机器上试用 Elastic。

原文:How to ingest data to Elasticsearch through Kafka - Elasticsearch Labs