本文已参与「新人创作礼」活动,一起开启掘金创作之路。
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, 如下图所示
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
---------------------------------------------------------------
参考文档: