MQTTフルリンク可観測性の構築:EMQXイベントトピックとテーブルに基づくイベント監査ソリューション
本番環境において、IoTチームは以下のような課題に直面することが多いです。
- デバイスの頻繁な切断
- クライアント認証失敗
- トピックACL拒否
- メッセージの正常な配信失敗
- 異常なメッセージドロップ
従来のログは通常、ブローカー、認証システム、業務システムに分散しています。問題をトラブルシューティングする際には複数システムのデータを関連付ける必要があり、非効率です。
EMQXイベントトピック、ルールエンジン、テーブルを活用することで、クライアント接続、認証、認可、サブスクリプション、メッセージフローのイベントを統一的に保存できます。これにより、MQTTフルリンクのイベント監査と問題の追跡が可能になります。
ソリューションの目的
EMQXイベントトピック、ルールエンジン、テーブルに基づく統一されたMQTTフルリンクイベントログプラットフォームを構築します。
本ソリューションは以下を実現します:
- クライアントライフサイクルの追跡
- MQTT認証監査
- MQTT認可監査
- MQTTメッセージフローのトレース
- 長期イベント保存
- SQLによるクエリと分析
アーキテクチャ設計
EMQX Event Topics
|
v
Rule Engine
|
v
Single Action
|
v
EMQX Tables
|
v
SQL Query特徴:
- 単一ルール
- 単一アクション
- 単一のワイドテーブル
- 長期保存
- SQLクエリ対応
テーブルスキーマ
テーブル名:
emqx_full_link_eventsテーブル作成文:
CREATE TABLE emqx_full_link_events (
"timestamp" TIMESTAMP TIME INDEX,
"event" STRING,
"clientid" STRING SKIPPING INDEX,
"username" STRING SKIPPING INDEX,
"peername" STRING SKIPPING INDEX,
"sockname" STRING,
"node" STRING,
"topic" STRING,
"id" STRING,
"from_clientid" STRING,
"from_username" STRING,
"qos" BIGINT,
"payload" STRING,
"reason" STRING,
"reason_code" STRING,
"action" STRING,
"result" STRING,
"authz_source" STRING,
"keepalive" BIGINT,
"clean_start" BOOLEAN,
"expiry_interval" BIGINT,
"connected_at" BIGINT,
"disconnected_at" BIGINT,
"publish_received_at" BIGINT,
"client_attrs" STRING
)
WITH (
'append_mode'='true',
'ttl'='7d'
);テーブルパラメータの説明
本ソリューションでは以下のテーブルパラメータを使用しています:
WITH (
'append_mode'='true',
'ttl'='7d'
);append_mode='true'
MQTTイベントは典型的な時系列監査データです。クライアントの接続、認証、認可、サブスクリプション、メッセージ配信は継続的に新しいイベントレコードを生成します。
Append Modeを有効にすると:
- すべてのイベントは追記モードで書き込まれます。
- 過去のレコードは更新されません。
- 完全なイベントフローが保持されます。
- イベント監査と問題の追跡が可能です。
したがって、MQTTフルリンクイベント保存シナリオに適しています。
ttl='7d'
イベントトピックは大量のイベントデータを継続的に生成します。
無制限のデータ増加を防ぐため、本例では以下を設定しています:
ttl='7d'これは直近7日間のイベントデータのみを保持し、それを超えるデータは自動的にクリーンアップされることを意味します。
本番環境では業務要件に応じて保持期間を調整可能です。
テーブルコネクター設定
まず、EMQXテーブルにデータを書き込むためのコネクターを作成します。
テーブルコネクターの作成
データ統合 -> コネクター -> 新規コネクター -> EMQX Tables に進みます。
対応するテーブルデプロイメントの接続情報を入力し、作成を完了してください。
ルール設定
すべてのイベントを統一的に収集します:
SELECT *
FROM "$events/#"利点:
- 単一ルールで全イベントトピックをカバー
- 複数ルールの管理不要
- 統一された収集エントリポイント
アクション設定
emqx_full_link_events clientid=${clientid},event=${event},topic=${topic},username=${username},node=${node},peername=${peername},sockname=${sockname},qos=${qos}i,id=${id},payload=${payload},reason=${reason},reason_code=${reason_code},result=${result},from_clientid=${from_clientid},from_username=${from_username},action=${action},authz_source=${authz_source},keepalive=${keepalive}i,clean_start=${clean_start},expiry_interval=${expiry_interval}i,connected_at=${connected_at}i,disconnected_at=${disconnected_at}i,publish_received_at=${publish_received_at}i,client_attrs=${client_attrs} ${timestamp}インデックス設計
clientid STRING SKIPPING INDEX
username STRING SKIPPING INDEX
peername STRING SKIPPING INDEX| フィールド | 用途 |
|---|---|
clientid | デバイスの完全なフローを検索 |
username | ユーザーの行動を検索 |
peername | 発信元IPアドレスを検索 |
典型的なトラブルシューティングシナリオ
異なるイベントトピックは異なるフィールドを公開するため、一部のフィールドが空になることは正常です。これは問題の追跡やトラブルシューティングに影響しません。
本ソリューションは単一のワイドテーブルにクライアント接続、認証、認可、サブスクリプション、メッセージフローイベントを統一的に保存します。これにより単一のSQLクエリでフルリンクのトラブルシューティング分析が容易になります。
シナリオ1:クライアントライフサイクルのトラブルシューティング
対象の課題:
- デバイスはブローカーに正常に接続できたか?
- なぜデバイスがオフラインになったか?
- デバイスは認証を完了したか?
- デバイスはトピックを正常にサブスクライブしたか?
関連イベント:
| イベント名 | イベント | 説明 |
|---|---|---|
| 認証イベント | client.check_authn_complete | クライアント認証完了 |
| 接続イベント | client.connected | クライアント接続成功 |
| 接続応答イベント | client.connack | ブローカーからの接続応答 |
| サブスクリプションイベント | session.subscribed | クライアントのサブスクライブ成功 |
| オフラインイベント | client.disconnected | クライアント切断 |
主要フィールド:
| フィールド | 説明 |
|---|---|
clientid | クライアントID |
username | ユーザー名 |
peername | クライアント発信元アドレス |
connected_at | オンライン時間 |
disconnected_at | オフライン時間 |
reason | オフライン理由 |
reason_code | 認証結果 |
クエリ例:
SELECT *
FROM emqx_full_link_events
WHERE clientid='device001'
AND event IN (
'client.check_authn_complete',
'client.connected',
'client.connack',
'session.subscribed',
'client.disconnected'
)
ORDER BY timestamp ASC;シナリオ2:認証および認可のトラブルシューティング
対象の課題:
- なぜデバイスが接続に失敗したか?
- ユーザー名とパスワードは正しいか?
- なぜトピックのサブスクライブに失敗したか?
- なぜACLがリクエストを拒否したか?
関連イベント:
| イベント名 | イベント | 説明 |
|---|---|---|
| 認証イベント | client.check_authn_complete | ユーザー認証結果 |
| 認可イベント | client.check_authz_complete | ACLチェック結果 |
主要フィールド:
| フィールド | 説明 |
|---|---|
reason_code | 認証結果 |
action | publish / subscribe |
result | allow / deny |
authz_source | ACLソース |
一般的な結果説明:
| フィールド | 例値 | 説明 |
|---|---|---|
reason_code | success | 認証成功 |
reason_code | bad_username_or_password | ユーザー名またはパスワードが誤り |
result | allow | アクセス許可 |
result | deny | アクセス拒否 |
認証失敗のクエリ:
SELECT *
FROM emqx_full_link_events
WHERE event='client.check_authn_complete'
AND reason_code<>'success'
ORDER BY timestamp DESC;ACL拒否のクエリ:
SELECT *
FROM emqx_full_link_events
WHERE event='client.check_authz_complete'
AND result='deny'
ORDER BY timestamp DESC;シナリオ3:メッセージ配信の分析
対象の課題:
- メッセージは正常に配信されたか?
- どのクライアントがメッセージを受信したか?
- ACKは受信されたか?
関連イベント:
| イベント名 | イベント | 説明 |
|---|---|---|
| メッセージ配信イベント | message.delivered | メッセージ配信成功 |
| メッセージアックイベント | message.acked | ACK受信 |
主要フィールド:
| フィールド | 説明 |
|---|---|
topic | MQTTトピック |
payload | メッセージ内容 |
qos | QoS(サービス品質) |
from_clientid | パブリッシュ元クライアント |
clientid | 受信クライアント |
クエリ例:
SELECT *
FROM emqx_full_link_events
WHERE event IN (
'message.delivered',
'message.acked'
)
ORDER BY timestamp DESC;シナリオ4:メッセージドロップの分析
対象の課題:
- なぜメッセージが届かなかったか?
- なぜブローカーでメッセージがドロップされたか?
関連イベント:
| イベント名 | イベント | 説明 |
|---|---|---|
| メッセージドロップイベント | message.dropped | 転送中にメッセージがドロップ |
| メッセージ配信ドロップイベント | message.delivery_dropped | 配信中にメッセージがドロップ |
主要フィールド:
| フィールド | 説明 |
|---|---|
topic | トピック |
payload | メッセージ内容 |
clientid | クライアント |
reason | ドロップ理由 |
一般的な理由説明:
| 理由 | 説明 |
|---|---|
no_subscribers | サブスクライバーなし |
queue_full | キューが満杯 |
expired | メッセージ期限切れ |
acl_denied | ACL拒否 |
disconnected | クライアントオフライン |
パブリッシュドロップのクエリ:
SELECT *
FROM emqx_full_link_events
WHERE event='message.dropped'
ORDER BY timestamp DESC;配信ドロップのクエリ:
SELECT *
FROM emqx_full_link_events
WHERE event='message.delivery_dropped'
ORDER BY timestamp DESC;よく使うクエリテンプレート
クライアントIDによる検索
指定したクライアントのすべてのイベントを検索:
SELECT *
FROM emqx_full_link_events
WHERE clientid='device009'
ORDER BY timestamp DESC;ユーザー名による検索
指定したユーザーのすべてのイベントを検索:
SELECT *
FROM emqx_full_link_events
WHERE username='test'
ORDER BY timestamp DESC;発信元IPアドレスによる検索
指定した発信元アドレスからクライアントの行動を分析:
SELECT *
FROM emqx_full_link_events
WHERE peername LIKE '78.234.%'
ORDER BY timestamp DESC;トピックによる検索
指定したトピックのメッセージおよび権限の動作を分析:
SELECT *
FROM emqx_full_link_events
WHERE topic='factory/device/status'
ORDER BY timestamp DESC;イベントタイプによる検索
指定したイベントを分析:
SELECT *
FROM emqx_full_link_events
WHERE event='message.dropped'
ORDER BY timestamp DESC;まとめ
イベントトピック、ルールエンジン、テーブルを組み合わせることで、軽量なMQTTフルリンクイベント可観測性プラットフォームを構築できます。
本ソリューションは単一ルール、単一アクション、単一のワイドテーブルでクライアント接続、認証、認可、サブスクリプション、メッセージフローイベントを統一的に保存します。これにより以下を実現します:
- クライアントライフサイクル追跡
- MQTT認証監査
- MQTT認可監査
- MQTTメッセージフロー分析
- メッセージドロップの根本原因分析
- 発信元IP行動分析
- 長期イベント保持
- SQLによるクエリと分析
- Grafanaによる可視化
単一のワイドテーブル設計により、クライアント接続、認証、認可、サブスクリプション、メッセージイベントを統一されたテーブル構造で保存・検索可能です。これにより単一SQLクエリでフルリンクのトラブルシューティング分析が容易になります。
本ソリューションは以下に適しています:
- IoTデバイスの運用保守
- MQTTプラットフォーム運用
- クライアント行動分析
- トピック権限監査
- メッセージ配信トラブルシューティング
- 長期イベント保持と追跡
運用、開発、業務チームが迅速に問題を特定し、過去イベントを追跡し、行動を分析するのに役立ち、トラブルシューティングコストを削減し、MQTTプラットフォームの運用効率と可観測性を向上させます。