AI自動給油許可監視システム (AiQ PERMISSION) における IoT デバイスの死活監視
はじめに
「AI自動給油許可監視システム(AiQ PERMISSION)」では、現場に設置された IoT デバイス群の死活状態を AWS IoT Core 経由で収集し、Slack に通知するサーバーレス構成を採用しています。
IoT Core / Lambda / DynamoDB / EventBridge で組んでいます。本記事では「いつ」「どこに」「どんな条件で」通知が飛ぶのか、実装パターンを中心に解説します。実装内容は他の IoT デバイス監視にも応用できる汎用的なパターンとして整理しました。
IoT 死活監視で直面する 4 つの課題
IoT デバイス監視を Slack 通知と組み合わせると、必ずぶつかる課題が 4 つあります。これらをすべて素直に実装すると、運用が破綻するか、障害を見逃します。
課題 1: 同一異常で Slack が埋まる
1 つの異常が継続している間、受信するメッセージごとに通知すると、Slack チャンネルが同じアラートで埋め尽くされ、運用チームが本当に重要な情報を見逃します。
課題 2: 一瞬の揺らぎで誤検知する
無線通信や電源の瞬断を単発で異常通知すると、夜間に何度も叩き起こされてしまうので、瞬断に反応しないように実装を工夫する必要があります。
課題 3: 履歴と最新状態を両立しにくい
履歴データは時系列分析のために残したい一方、データ量は増え続けます。リアルタイム判定には最新状態だけを即座に参照したい — 蓄積と即時参照という 2 つの要求をどう両立させるかが課題になります。
課題 4: 完全な沈黙は検知できない
デバイスがクラッシュしてメッセージ送信そのものが止まると、届いたメッセージを見ているだけでは異常に気付けません。「来ないこと」を能動的に確認する仕組みが必要です。
設計の 5 つの原則
上記の課題に対し、本システムは以下の 5 原則で設計しています。
| # | 原則 | 解決する課題 |
|---|---|---|
| 1 | 状態遷移時のみ通知する | 課題 1 |
| 2 | 連続性とクールダウンで誤検知を抑える(デバウンス + レートリミット) | 課題 1, 2 |
| 3 | データの寿命に応じてテーブルを分ける | 課題 3 |
| 4 | 沈黙は能動的に検知する(定期スキャン) | 課題 4 |
| 5 |
経路を意図的に統合・分離する (5-a 入口を統合 / 5-b 処理を分ける / 5-c 出口を分ける) |
横断的(拡張性・責務分離) |
以降の実装パターンはすべて、この 5 原則のいずれかに対応します。各セクションのタイトルに原則番号を入れているので、「どの課題への解決策か」を意識しながら読んでみてください。
アーキテクチャ全体像

主な構成要素は以下です:
- IoT Core: デバイスからの MQTT メッセージを受信、Topic Rule で Lambda に振り分け
- Lambda: メッセージ処理・通知判定・DynamoDB 更新
- DynamoDB: 最新状態テーブル + 履歴テーブル(TTL 付き)の 2 段構成
- EventBridge: 定期実行による沈黙検知(タイムアウト監視)
- Slack Webhook: 通知配信(正常用 / 異常用の 2 系統)
実装パターン
原則 5-a: 入口を統合する(MQTT トピック設計)
複数カテゴリのヘルスチェックを扱う場合、カテゴリごとに Lambda を作ると数が爆発します。MQTT トピックは health/{category}/{env} のようにカテゴリで分割しつつ、IoT Rule のワイルドカード health/+/{env} と WHERE 句で 1 つの Lambda にルーティングを集約します。
トピック階層の例:
health/{category}/{env} # ヘルスチェック
統合 IoT Rule SQL:
SELECT *, topic(2) as category
FROM 'health/+/{env}'
WHERE topic(2) = 'category_a'
OR topic(2) = 'category_b'
OR topic(2) = 'category_c'
-
topic(N)でトピックの N 階層目を抽出して Lambda イベントに付加できる - Lambda 側でカテゴリ別に処理を分岐
- IoT Rule の数を抑えながら、新しいメトリクスカテゴリを追加しやすい
原則 5-b: 処理を分ける(Lambda の役割分担)
リアルタイム処理と定期実行で Lambda を 2 つに分けます。リアルタイム側は状態遷移検知(原則 1)とノイズフィルタ(原則 2)を担い、定期実行側は沈黙検知(原則 4)を担います。
| リアルタイム処理 (IoT MQTT トリガー) | 定期実行 (EventBridge) |
|---|---|
| message-processor | timeout-monitor |
| メッセージ受信 | DynamoDB スキャン |
| 状態遷移検知 | 沈黙検知 |
| DynamoDB 更新 | レートリミット |
| Slack 通知(遷移時) | Slack 通知 |
- message-processor は MQTT メッセージ(正常/異常)を受信して、Slack に通知
- timeout-monitor は EventBridge で定期起動し、長期間メッセージが来ていないデバイスを検出して通知
責務を物理的に分離することで、リアルタイム処理が落ちても定期スキャンは生き残るなど、障害の影響範囲を局所化できます。
原則 3: データの寿命に応じてテーブルを分ける(履歴と最新状態)
履歴テーブルは TTL で自動削除しつつ、最新状態テーブルは常に保持する — この異なる寿命を 1 つのテーブルで扱うと、最新状態が誤って消えるリスクが残ります。用途ごとにテーブルを分離するのが安全です。
履歴テーブル:
| 項目 | 値 |
|---|---|
| TTL | あり(例: 7 日) |
| 用途 | 時系列分析、過去調査 |
最新状態テーブル:
| 項目 | 値 |
|---|---|
| TTL | なし |
| 用途 | タイムアウト監視、デバウンス管理、レートリミット |
キーは複合キーにしています。デバイス × コンポーネント × メトリクス単位で状態を管理できます。
履歴テーブルは TTL で古いデータを自動削除しますが、最新状態テーブルは常に保持する必要があります。1 テーブルにまとめると TTL で消える行と消さない行が混在し、最新状態が誤って消失するリスクがあるため、用途ごとに分離しています。
原則 1・2: 状態遷移時のみ通知し、連続性とクールダウンで誤検知を抑える(3 段フィルタ)
リアルタイム処理側で、3 段階のフィルタを通すことで Slack ノイズを最小化します。
受信メッセージ
↓
[1] 状態遷移検知 ── 状態が変化したときだけ通知 (原則 1)
↓
[2] デバウンス ── 連続 N 回継続したら通知 (原則 2)
↓
[3] レートリミット ── 同一メトリクスは X 分に 1 回まで (原則 2)
↓
Slack へ
1. 状態遷移のみ通知
正常 ↔ 異常の 遷移時にしか通知しない ことで、Slack の通知数を激減させます。直前の状態と比較し、正常→異常なら「異常発生」、異常→正常なら「復旧」として通知し、変化がなければ何もしません。
2. デバウンス(誤検知抑制)
エッジ側のハートビートが一瞬途切れただけで通知すると、ノイズが多くなります。連続 N 回 異常を受けてから初めて異常通知 を出すように制御します。連続した異常回数をカウントしておき、閾値に達したときだけ通知し、正常が戻ったらカウントをリセットします。
3. レートリミット(重複通知抑制)
同一メトリクスに対しては X 分(例: 10 分)に 1 回しか通知しない ようにします。最後に通知した時刻を最新状態テーブルに記録しておき、一定時間が経つまでは再通知をスキップします。
原則 4: 沈黙は能動的に検知する(定期スキャン)
EventBridge が一定間隔で timeout-monitor Lambda を起動し、最新状態テーブルを走査して 最終受信から閾値以上経過したメトリクス を検出します。閾値を超えていればタイムアウトとみなして Slack に通知します。
タイミング設計の例:
| 項目 | 値 |
|---|---|
| タイムアウト閾値 | 12 分 |
| EventBridge チェック間隔 | 9 分 |
| Slack レートリミット | 10 分 |
| 最悪検知遅延 | 21 分(閾値 + チェック間隔) |
| デバウンス連続異常回数の閾値 | 3 回 |
EventBridge の間隔をタイムアウト閾値より短く設定するのがポイントです。これにより最悪ケースの検知遅延を「閾値 + 間隔」に抑えられます。
原則 5-c: 出口を分ける(Slack チャンネル構成)
入口を統合した一方、出口(Slack チャンネル)は意図的に分離します。緊急対応が必要な異常と、確認用の正常通知を同じチャンネルに混ぜると、運用チームの注意リソースを浪費するためです。
| チャンネル | 用途 | 通知色 |
|---|---|---|
| OK チャンネル | 正常遷移通知 | 🟢 緑 |
| Alert チャンネル | 異常検知通知・タイムアウト通知 | 🔴 赤 / 🟠 黄 |
まとめ
IoT デバイスの死活監視 + Slack 通知を組むときに効くパターンを、5 つの原則として整理しました。
- 状態遷移時のみ通知する — 同一異常の連投を防ぐ
- 連続性とクールダウンで誤検知を抑える — 瞬断ノイズを除去
- データの寿命に応じてテーブルを分ける — 履歴と最新状態を両立
- 沈黙は能動的に検知する — 来ないことに気付く
- 経路を意図的に統合・分離する — 入口統合・処理分離・出口分離で拡張性と運用負荷をバランス
同じような IoT デバイス監視を構築する方の参考になれば幸いです。
Discussion