概覽
在 EdgeX Geneva 版本中, EMQ X Kuiper - 基於 SQL 的輕量級流式數據處理軟件與 EdgeX 進行了集成。在進入這篇教程之前,讓我們先花一些時間來了解一些 Kuiper 的基本知識。EMQ X Kuiper 是 Golang 實現的輕量級物聯網邊緣分析、流式處理開源軟件,可以運行在各類資源受限的邊緣設備上。Kuiper 基於源 (Source)
,SQL (業務邏輯處理)
, 目標 (Sink)
的方式來支持流式數據處理。
-
源(Source):流式數據的數據源,例如來自於 MQTT 服務器 的數據。在 EdgeX 的場景下,數據源就是 EdgeX 消息總線(EdgeX message bus),可以是來自於 ZeroMQ 或者 MQTT 服務器;
-
SQL:SQL 是你流式數據處理指定業務邏輯的地方,Kuiper 提供了 SQL 語句可以對數據進行抽取、過濾和轉換;
-
目標(Sink):目標用於將分析結果發送到特定的目標。例如,將分析結果發送到另外的 MQTT 服務器,或者一個 HTTP Rest 地址;
使用 Kuiper,一般需要完成以下三個步驟。
- 創建流,就是你定義數據源的地方
- 寫規則
- 爲數據分析寫 SQL
- 指定一個保存分析結果的目標
- 部署,並且運行規則
該教程描述如何使用 Kuiper 處理來自於 EdgeX 消息總線的數據。
Kuiper EdgeX 集成
在不同的微服務之間,EdgeX 使用消息總線進行數據交換。它包含了一個抽象的消息總線接口,並分別實現了 ZeroMQ 與 MQTT,在不同的微服務之間信息交互的支持。Kuiper 和 EdgeX 的集成工作包含了以下三部分,
-
擴展了一個 EdgeX 消息總線源,支持從 EdgeX 消息總線中接收數據
-
爲了可以分析數據,Kuiper 需知道傳入的數據流的格式。一般來說,用戶最好在創建流的時候指定被分析的流數據的格式。如下所示,一個
demo
流包含了一個名爲temperature
的字段。這與在關係型數據庫中創建表格定義的時候非常像。在創建了流定義以後,Kuiper 可以在編譯或者運行時對進入的數據進行類型檢查,相應錯誤也會報告給用戶。CREATE STREAM demo (temperature bigint) WITH (FORMAT="JSON"...)
然而在 EdgeX 中,數據類型定義在 EdgeX
Core contract Service
中已經指定,爲了提升使用體驗,用戶可以在創建流的時候不指定數據類型。Kuiper 源會在初始化規則的時候,從Core contract Service
中獲取所有的value descriptors
定義(所以如果有任何數據類型定義的變化,你需要重啓規則)。當接收到來自於消息總線的數據的時候,會根規則轉換爲相應的數據類型。 -
擴展支持 EdgeX 消息總線目標(sink),用於將處理結果寫回至 EdgeX 消息總線。用戶也可以選擇將分析結果發送到 Kuiper 之前已經支持的 RestAPI 接口等。
運行 EdgeX Docker 實例
打開 EdgeX develop-scripts 項目,並且下載 Geneva 版本的 Docker compose file,然後啓動所有的 EdgeX 容器。
# docker-compose -f ./docker-compose-nexus-redis-no-secty.yml up -d --build
所有的容器啓動完畢之後,請使用 docker ps
命令確定所有的容器已經正常啓動。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5618c93027a9 nexus3.edgexfoundry.org:10004/docker-device-virtual-go:master "/device-virtual --p…" 37 minutes ago Up 37 minutes 0.0.0.0:49990->49990/tcp edgex-device-virtual
fabe6b9052f5 nexus3.edgexfoundry.org:10004/docker-edgex-ui-go:master "./edgex-ui-server" 37 minutes ago Up 37 minutes 0.0.0.0:4000->4000/tcp edgex-ui-go
950135a7041d emqx/kuiper:0.3.1 "/usr/bin/docker-ent…" 37 minutes ago Up 37 minutes 0.0.0.0:20498->20498/tcp, 9081/tcp, 0.0.0.0:48075->48075/tcp edgex-kuiper
c49b0d6f9347 nexus3.edgexfoundry.org:10004/docker-support-scheduler-go:master "/support-scheduler …" 37 minutes ago Up 37 minutes 0.0.0.0:48085->48085/tcp edgex-support-scheduler
4265dcc2bb48 nexus3.edgexfoundry.org:10004/docker-core-command-go:master "/core-command -cp=c…" 37 minutes ago Up 37 minutes 0.0.0.0:48082->48082/tcp edgex-core-command
4667160e2f41 nexus3.edgexfoundry.org:10004/docker-app-service-configurable:master "/app-service-config…" 37 minutes ago Up 37 minutes 48095/tcp, 0.0.0.0:48100->48100/tcp edgex-app-service-configurable-rules
9bbfe95993f5 nexus3.edgexfoundry.org:10004/docker-core-metadata-go:master "/core-metadata -cp=…" 37 minutes ago Up 37 minutes 0.0.0.0:48081->48081/tcp, 48082/tcp edgex-core-metadata
2e342a3aae81 nexus3.edgexfoundry.org:10004/docker-support-notifications-go:master "/support-notificati…" 37 minutes ago Up 37 minutes 0.0.0.0:48060->48060/tcp edgex-support-notifications
3cfc628e013a nexus3.edgexfoundry.org:10004/docker-sys-mgmt-agent-go:master "/sys-mgmt-agent -cp…" 37 minutes ago Up 37 minutes 0.0.0.0:48090->48090/tcp edgex-sys-mgmt-agent
f69e9c4d6cc8 nexus3.edgexfoundry.org:10004/docker-core-data-go:master "/core-data -cp=cons…" 37 minutes ago Up 37 minutes 0.0.0.0:5563->5563/tcp, 0.0.0.0:48080->48080/tcp edgex-core-data
9e5091928409 nexus3.edgexfoundry.org:10004/docker-support-logging-go:master "/support-logging -c…" 37 minutes ago Up 37 minutes 0.0.0.0:48061->48061/tcp edgex-support-logging
74e8668f892c redis:5.0.7-alpine "docker-entrypoint.s…" 37 minutes ago Up 37 minutes 0.0.0.0:6379->6379/tcp edgex-redis
9b341bb217f9 consul:1.3.1 "docker-entrypoint.s…" 37 minutes ago Up 37 minutes 0.0.0.0:8400->8400/tcp, 8300-8302/tcp, 8301-8302/udp, 8600/tcp, 8600/udp, 0.0.0.0:8500->8500/tcp edgex-core-consul
ed7ad5ae08b2 nexus3.edgexfoundry.org:10004/docker-edgex-volume:master "/bin/sh -c '/usr/bi…" 37 minutes ago Up 37 minutes edgex-files
創建流
該步驟是創建一個可以從 EdgeX 消息總線進行數據消費的流。有兩種方法來支持管理流,你可以選擇喜歡的方式。
方式1: 使用 Rest API
請注意: EdgeX 中的 Kuiper Rest 接口使用48075
端口,而不是缺省的9081
端口。所以在 EdgeX 調用 Kuiper Rest 的時候,請將文檔中所有的 9081 替換爲 48075。
請將 $kuiper_server
替換爲本地運行的 Kuiper 實例的地址。
curl -X POST \
http://$kuiper_server:48075/streams \
-H 'Content-Type: application/json' \
-d '{
"sql": "create stream demo() WITH (FORMAT=\"JSON\", TYPE=\"edgex\")"
}'
關於其它 API,請參考該文檔.
方式2: 使用 Kuiper 命令行
使用以下命令,進入運行中的 Kuiper docker 實例。
docker exec -it kuiper /bin/sh
使用以下命令,創建一個名爲 demo
的流定義.
bin/cli create stream demo'() WITH (FORMAT="JSON", TYPE="edgex")'
其它命令行,請參考該文檔。
現在流已經創建好了,但是你可能好奇 Kuiper 是如何知道消息總線的地址和端口,因爲此類信息在 CREATE STREAM
並未指定。實際上這些信息是在配置文件 etc/sources/edgex.yaml
中指定的,你可以在命令行窗口中輸入 cat etc/sources/edgex.yaml
來查看文件的內容。如果你有不同的服務器、端口和服務的地址,請更新相應的配置。正如之前提到的,這些配置選項可以在容器啓動的時候進行重寫。
#Global Edgex configurations
default:
protocol: tcp
server: localhost
port: 5566
topic: events
serviceServer: http://localhost:48080
.....
更多關於配置文件的信息,請參考該文檔.
創建規則
讓我們創建一條規則,將分析結果發送至 MQTT 服務器,關於 MQTT 目標的相關配置,請參考這個鏈接。與創建流的過程類似,你可以選擇使用 REST 或者命令行來管理規則。
以下例子將選出所有 events
主題上所有的數據,分析結果將被
- 發佈到公共的 MQTT 服務器
broker.emqx.io
的主題result
上; - 打印至日誌文件
選項1: 使用 Rest API
curl -X POST \
http://$kuiper_server:9081/rules \
-H 'Content-Type: application/json' \
-d '{
"id": "rule1",
"sql": "SELECT * FROM demo",
"actions": [
{
"mqtt": {
"server": "tcp://broker.emqx.io:1883",
"topic": "result",
"clientId": "demo_001"
}
},
{
"log":{}
}
]
}
選項2: 使用 Kuiper 命令行
你可以使用任意編輯器來創建一條規則,將下列內容拷貝到編輯器中,並命名爲 rule.txt
。
{
"sql": "SELECT * from demo",
"actions": [
{
"mqtt": {
"server": "tcp://broker.emqx.io:1883",
"topic": "result",
"clientId": "demo_001"
}
},
{
"log":{}
}
]
}
在運行的容器中,執行以下命令。
# bin/cli create rule rule1 -f rule.txt
Connecting to 127.0.0.1:20498...
Creating a new rule from file rule.txt.
Rule rule1 was created successfully, please use 'cli getstatus rule rule1' command to get rule status.
如想將結果發送到別的目標,請參考 Kuiper 中支持的其它目標。你現在可以看一下在 log/stream.log
中的日誌文件,查看規則的詳細信息。
time="2020-04-17T06:32:24Z" level=info msg="Serving kuiper (version - 0.3.1-4-g9e63fe1) on port 20498, and restful api on port 9081. \n" file="server.go:101"
time="2020-04-17T06:32:24Z" level=info msg="The connection to edgex messagebus is established successfully." file="edgex_source.go:95" rule=rule1
time="2020-04-17T06:32:24Z" level=info msg="Successfully subscribed to edgex messagebus topic events." file="edgex_source.go:104" rule=rule1
time="2020-04-17T06:32:24Z" level=info msg="The connection to server tcp://broker.emqx.io:1883 was established successfully" file="mqtt_sink.go:161" rule=rule1
time="2020-04-17T06:32:25Z" level=info msg="Get 24 of value descriptors from service." file="edgex_source.go:223"
time="2020-04-17T06:32:25Z" level=info msg="sink result for rule rule1: [{\"int32\":-697766590}]" file="log_sink.go:16" rule=rule1
time="2020-04-17T06:32:25Z" level=info msg="sink result for rule rule1: [{\"int8\":-47}]" file="log_sink.go:16" rule=rule1
time="2020-04-17T06:32:25Z" level=info msg="sink result for rule rule1: [{\"int16\":-318}]" file="log_sink.go:16" rule=rule1
time="2020-04-17T06:32:25Z" level=info msg="sink result for rule rule1: [{\"int64\":-8680421421398846880}]" file="log_sink.go:16" rule=rule1
time="2020-04-17T06:32:31Z" level=info msg="sink result for rule rule1: [{\"bool\":true}]" file="log_sink.go:16" rule=rule1
監控分析結果
因爲所有的分析結果都被髮布到tcp://broker.emqx.io:1883
,你可以直接使用以下的 mosquitto_sub
命令來監聽結果,你也可以參考別的 MQTT 客戶端工具.
# mosquitto_sub -h broker.emqx.io -t result
[{"bool":true}]
[{"bool":false}]
[{"bool":true}]
[{"randomvalue_int16":3287}]
[{"float64":8.41326e+306}]
[{"randomvalue_int32":-1872949486}]
[{"randomvalue_int8":-53}]
[{"int64":-1829499332806053678}]
[{"int32":-1560624981}]
[{"int16":8991}]
[{"int8":-4}]
[{"bool":true}]
[{"bool":false}]
[{"float64":1.737076e+306}]
...
你也可以敲入以下的命令來查看規則執行的狀態。相關的查看規則狀態的 REST API 也有提供,請檢查相關文檔.
# bin/cli getstatus rule rule1
Connecting to 127.0.0.1:20498...
{
"source_demo_0_records_in_total": 29,
"source_demo_0_records_out_total": 29,
"source_demo_0_exceptions_total": 0,
"source_demo_0_process_latency_ms": 0,
"source_demo_0_buffer_length": 0,
"source_demo_0_last_invocation": "2020-04-17T10:30:09.294337",
"op_preprocessor_demo_0_records_in_total": 29,
"op_preprocessor_demo_0_records_out_total": 29,
"op_preprocessor_demo_0_exceptions_total": 0,
"op_preprocessor_demo_0_process_latency_ms": 0,
"op_preprocessor_demo_0_buffer_length": 0,
"op_preprocessor_demo_0_last_invocation": "2020-04-17T10:30:09.294355",
"op_filter_0_records_in_total": 29,
"op_filter_0_records_out_total": 21,
"op_filter_0_exceptions_total": 0,
"op_filter_0_process_latency_ms": 0,
"op_filter_0_buffer_length": 0,
"op_filter_0_last_invocation": "2020-04-17T10:30:09.294362",
"op_project_0_records_in_total": 21,
"op_project_0_records_out_total": 21,
"op_project_0_exceptions_total": 0,
"op_project_0_process_latency_ms": 0,
"op_project_0_buffer_length": 0,
"op_project_0_last_invocation": "2020-04-17T10:30:09.294382",
"sink_sink_mqtt_0_records_in_total": 21,
"sink_sink_mqtt_0_records_out_total": 21,
"sink_sink_mqtt_0_exceptions_total": 0,
"sink_sink_mqtt_0_process_latency_ms": 0,
"sink_sink_mqtt_0_buffer_length": 1,
"sink_sink_mqtt_0_last_invocation": "2020-04-17T10:30:09.294423"
總結
在本教程中,我們介紹了使用 EdgeX Kuiper 規則引擎的非常簡單的例子,如果使用過程中發現任何問題,請到 EdgeX,或者 Kuiper Github 中報問題。
更多練習
目前的規則沒有過濾發送給 Kuiper 的任何數據,那麼如何過濾數據呢?請使用刪除規則,然後試着更改一下 SQL 語句,完成更改後,重新部署規則。這時候如果監聽 MQTT 服務的結果主題,檢查一下相關的規則是否起作用?
擴展閱讀
- 閱讀 EdgeX 源 獲取更多詳細信息,以及類型轉換等。
- 如何使用 meta 函數抽取在 EdgeX 消息總線中發送的更多信息? 設備服務往總線上發送數據的時候,一些額外的信息也隨之發送,比如時間創建時間,id 等。如果你想在 SQL 語句中使用這些信息,請參考這篇文章。
- EdgeX 消息總線目標. 該文檔描述瞭如何使用 EdgeX 消息總線目標。如果你想把分析結果發送到消息總線中,你可能對此文章感興趣。
如想了解更多的 EMQ X Kuiper 的信息,請參考以下資源。
本文作者: EMQ X
原文鏈接:https://www.emqx.io/cn/blog/kuiper-becomes-edgex-rule-engine
版權聲明: 本文爲 EMQ 原創,轉載請註明出處