kafka ksqldb 流处理入门案例

1,114 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

6. ksqlDB

ksqldb是一个事件流数据库, 用于 简化kakfa 流处理 和 将kafka流处理和其他外部系统(比如关系数据库)集成。

6.1 安装配置

利用 docker-compose 运行ksqldb,把以下文件保存为 docker-compose.yml

# 启动 docker-compose up -d && docker-compose logs -f
# 关闭 docker-compose down &&  docker-compose rm -vf

version: '2'

services:
  zookeeper-ksqldb:
    image: confluentinc/cp-zookeeper:7.1.1
    hostname: zookeeper-ksqldb
    container_name: zookeeper-ksqldb
    ports:
      - "12181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000

  broker:
    image: confluentinc/cp-kafka:7.1.1
    hostname: broker
    container_name: broker
    depends_on:
      - zookeeper-ksqldb
    ports:
      - "29092:29092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper-ksqldb:2181'
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:9092,PLAINTEXT_HOST://localhost:29092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1

  ksqldb-server:
    image: confluentinc/ksqldb-server:0.26.0
    hostname: ksqldb-server
    container_name: ksqldb-server
    depends_on:
      - broker
    ports:
      - "18088:8088"
    environment:
      KSQL_LISTENERS: http://0.0.0.0:8088
      KSQL_BOOTSTRAP_SERVERS: broker:9092
      KSQL_KSQL_LOGGING_PROCESSING_STREAM_AUTO_CREATE: "true"
      KSQL_KSQL_LOGGING_PROCESSING_TOPIC_AUTO_CREATE: "true"

  ksqldb-cli:
    image: confluentinc/ksqldb-cli:0.26.0
    container_name: ksqldb-cli
    depends_on:
      - broker
      - ksqldb-server
    entrypoint: /bin/sh
    tty: true
# 进入 docker-compose.yml 所在目录启动服务
docker-compose up

# 查看服务状态
docker-compose ps

NAME                COMMAND                  SERVICE             STATUS              PORTS
broker              "/etc/confluent/dock??   broker              running             0.0.0.0:29092->29092/tcp, :::29092->29092/tcp
ksqldb-cli          "/bin/sh"                ksqldb-cli          running             
ksqldb-server       "/usr/bin/docker/run"    ksqldb-server       running             0.0.0.0:18088->8088/tcp, :::18088->8088/tcp
zookeeper-ksqldb    "/etc/confluent/dock??   zookeeper-ksqldb    running             0.0.0.0:12181->2181/tcp, :::12181->2181/tcp

6.2 测试

# 进入客户端
docker exec -it ksqldb-cli ksql http://ksqldb-server:8088

进入客户端后 查看Server Status 是否 RUNNING, 如下图所示

image.png

6.2.1 创建流

Stream 本质上将 Stream结构模式 与 kafka_topic 相关联。

CREATE STREAM语句中每个参数的作用:

kafka_topic :

流底层的 Kafka 主题的名称。在这种情况下,它将自动创建,因为它还不存在,但也可以在已经存在的主题上创建流。

value_format :

存储在 Kafka 主题中的消息的编码。对于 JSON 编码,每一行都将存储为一个 JSON 对象,其键/值是列名/值。例如:

{"profileId": "c2309eec", "latitude": 37.7877, "longitude": -122.4205}

partitions:

locations topic 创建的分区数。注意,已存在的topic 不需要此参数。

# 第一个客户端上操作
# 1. 创建一个流 riderLocations 骑手位置数据流
# 数据样例: {"profileId": "c2309eec", "latitude": 37.7877, "longitude": -122.4205}

ksql> CREATE STREAM riderLocations (profileId VARCHAR, latitude DOUBLE, longitude DOUBLE)
>  WITH (kafka_topic='locations', value_format='json', partitions=1);

 Message        
----------------
 Stream created 
----------------

6.2.2 在流上创建查询

我们想使用物化视图来跟踪骑手的最新位置。为此,我们通过在先前创建的流上发出SELECT语句来创建表currentLocation。

请注意,随着新的骑手位置数据的到来,该表将逐步更新。

使用LATEST_BY_OFFSET聚合函数来表示只对骑手的最新位置感兴趣。

为了让它更有趣,让我们还实现一个派生表 (Table ridersNearMountainView),

该表捕获骑手离给定位置或城市的距离。

# 2. 在流上创建表查询,查询骑手当前位置
ksql> CREATE TABLE currentLocation AS
>  SELECT profileId,
>         LATEST_BY_OFFSET(latitude) AS la,
>         LATEST_BY_OFFSET(longitude) AS lo
>  FROM riderlocations
>  GROUP BY profileId
>  EMIT CHANGES;

 Message                                      
----------------------------------------------
 Created query with ID CTAS_CURRENTLOCATION_3 
----------------------------------------------

# 3. 创建基于步骤2 中的表的一个视图,
ksql> CREATE TABLE ridersNearMountainView AS
>  SELECT ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1) AS distanceInMiles,
>         COLLECT_LIST(profileId) AS riders,
>         COUNT(*) AS count
>  FROM currentLocation
>  GROUP BY ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1);

 Message                                             
-----------------------------------------------------
 Created query with ID CTAS_RIDERSNEARMOUNTAINVIEW_5 
-----------------------------------------------------

6.2.3 在流上运行实时查询

在流上运行实时查询。使用交互式 CLI 会话运行给定的查询。 此查询将输出RiderLocations流中在坐标(37.4133, -122.1162) 5 英里范围内的所有骑手数据。 这个查询在终止之前永远不会返回,会一直运行。

当事件写入RiderLocations流时,它将永久地将输出行推送到客户端。

暂时让这个查询在 CLI 会话中运行。我们会在下一步插入数据

# 4. 查询表,第一次查询没有数据,阻塞在查询上。
# 在第二个客户端第5步上插入数据后这里会显示出数据 
ksql> SELECT * FROM riderLocations
>  WHERE GEO_DISTANCE(latitude, longitude, 37.4133, -122.1162) <= 5 EMIT CHANGES;
+-----------+---------+-----------+
|PROFILEID  |LATITUDE |LONGITUDE  |
+-----------+---------+-----------+
|4ab5cbad   |37.3952  |-122.0813  |
|8b6eae59   |37.3944  |-122.0813  |
|4a7c7b41   |37.4049  |-122.0822  |

6.2.4 启动第二个会话插入数据并检查查询结果

# 启动第二个会话
docker exec -it ksqldb-cli ksql http://ksqldb-server:8088

# 在第二个客户端上操作
# 5.插入数据,插入数据后会在 6.2.3 节中的查询中看到数据
ksql> INSERT INTO riderLocations (profileId, latitude, longitude) VALUES ('c2309eec', 37.7877, -122.4205);
ksql> INSERT INTO riderLocations (profileId, latitude, longitude) VALUES ('18f4ea86', 37.3903, -122.0643);
ksql> INSERT INTO riderLocations (profileId, latitude, longitude) VALUES ('4ab5cbad', 37.3952, -122.0813);
ksql> INSERT INTO riderLocations (profileId, latitude, longitude) VALUES ('8b6eae59', 37.3944, -122.0813);
ksql> INSERT INTO riderLocations (profileId, latitude, longitude) VALUES ('4a7c7b41', 37.4049, -122.0822);
ksql> INSERT INTO riderLocations (profileId, latitude, longitude) VALUES ('4ddad000', 37.7857, -122.4011);

# 6. 对物化视图运行拉取查询,以检索当前距离坐标(37.4133, -122.1162) 10 英里范围内的所有骑手。
#    与之前(6.2.3 节)连续运行的推送查询相比,拉取查询遵循传统的请求-响应模型,从物化视图中检索最新结果。
ksql> SELECT * from ridersNearMountainView WHERE distanceInMiles <= 10;
+----------------+--------------------------------+--------+
|DISTANCEINMILES |RIDERS                          |COUNT   |
+----------------+--------------------------------+--------+
|0.0             |[4ab5cbad, 8b6eae59, 4a7c7b41]  |3       |
|10.0            |[18f4ea86]                      |1       |
Query terminated

# 查看存在的TOPICS
ksql> SHOW TOPICS ;

 Kafka Topic                 | Partitions | Partition Replicas 
---------------------------------------------------------------
 CURRENTLOCATION             | 1          | 1                  
 RIDERSNEARMOUNTAINVIEW      | 1          | 1                  
 default_ksql_processing_log | 1          | 1                  
 locations                   | 1          | 1                  
---------------------------------------------------------------

参考文档:

官方文档