Machbase Neoでシステム監視サービスを構築する
概要
Machbase Neoは、データの収集、保存、抽出、可視化を一体で提供する時系列データベースです。定期的に状態を測定するセンサーデータや、IT分野でメトリクスと呼ばれるシステムリソースの値を保存・管理する用途に適しています。
監視システムでは、可視化にGrafanaを使う構成がよく採用され、それにも利点があります。一方、大量のデータでは性能上の制約が生じたり、データベースと可視化ツールを別々に管理する手間がかかったりします。Machbase Neoのような統合構成を試すことで、それぞれの長所と短所を比較できます。
本稿では、ダッシュボードに対応したMachbase Neoを使い、コンピューターのリソース使用量をリアルタイムに収集し、アラームを処理するサービスを構築します。開発手順を省いてすぐに動かしたい場合は、末尾の「クイックセットアップ」を参照してください。

<Neoで構築したシンプルなシステム監視画面>
メトリクスの収集
一般的なサーバーやパソコンでは、次のリソースを収集します。
CPU使用率(%)
ディスク使用量(GB)
ディスク空き容量(GB)
受信ネットワークトラフィック(bytes/sec)
送信ネットワークトラフィック(bytes/sec)
データセンターでは、湿度、温度、騒音、消費電力、瞬間的な最大電力なども測定します。今回はデモなので、一般的なサーバーに必要な少数の項目で十分です。
次は、これらをどう収集するかです。Telegrafなどの専用オープンソースツールや各種収集製品もありますが、ここでは複数のOSで動く簡単なPythonプログラムを使います。
収集エージェントの設計
収集エージェントは、少量のPythonコードで作成できます。
学習用に、JSON方式とTQL方式の2種類を用意しました。
JSON方式
収集したメトリクスをMachbase Neoのデータベースエンジンへ直接送ります。
高速に取り込むため、INSERTではなくAPPENDを使います。
保存前に処理を挟めないため、追加処理には保存後のデータを読み直す必要があります。
保存したデータを読み直して条件を検査すればアラームを実装できますが、この例では実装していません。
TQL方式
収集したメトリクスをCSV形式でMachbase NeoのTQLへ送ります。
TQLでは、データベースへ保存する前にさまざまな処理を実行できます。
この例では、CPUのメトリクスで使用率が10%を超えた場合、別のログテーブルにアラーム情報を記録します。この機能は実装済みです。
その後、APPENDでメトリクスを高速に保存します。
2種類のエージェントは、収集の中核コードを共有します。GitHubで公開しているファイル構成は次のとおりです。
収集するメトリクスは次のとおりです。この例のディスクとネットワークの値は、対象デバイスの合計です。個別のデバイスを指定したい場合は、ソースコードを変更してください。
タグ名(接頭辞) | 説明 |
CPU-{機器名} | CPU使用率(%) |
DT-{機器名} | ディスク総容量(バイト) |
DU-{機器名} | ディスク使用量(バイト) |
DR-{機器名} | ディスク空き容量(バイト) |
NI-{機器名} | ネットワーク受信量(バイト) |
NO-{機器名} | ネットワーク送信量(バイト) |
監視する機器ごとに6つのメトリクスが生成され、設定した間隔でデータベースへ送信されます。
エージェントの実行
JSONエージェント
コマンドラインオプション
$ python3 run-agent-json.py -h
usage: run-agent-json.py [-h] [--ip_address IP_ADDRESS] [--interval INTERVAL] [--servername SERVERNAME]
[--debug DEBUG]
url tablename
System Statistics Collector
positional arguments:
url NEO-URL (e.g., http://host:port)
tablename Table name for data storage
options:
-h, --help show this help message and exit
--ip_address IP_ADDRESS
IP Address prefix to filter (default: "")
--interval INTERVAL Interval between posts in seconds (default: 3)
--servername SERVERNAME
servername
--debug DEBUG debuggingurl(必須):NeoデータベースのURLです。ローカルでのテストでは、通常 http://127.0.0.1:5654 を指定します。
tablename(必須):メトリクス保存用のタグテーブル名です。この例では monitoring を指定します。
--ip_address:機器名の識別に使うIPアドレスの接頭辞を指定します。指定しない場合は、192.で始まる最初のデバイスアドレスを使います。
--interval:収集間隔を秒単位で指定します。既定値は3秒です。
--servername:機器名を明示的に指定します。分かりやすい名前を使いたい場合に利用します。
--debug:診断用の追加情報を表示します。
Linuxで実行する
Linuxで次のように表示されれば、正常に動作しています。
この例では、Neoのアドレスは127.0.0.1、ポートは5654、テーブル名はmonitoring、サーバー名はlinuxです。
$ python3 run-agent-json.py http://127.0.0.1:5654 monitoring --servername linux
{'data': {'columns': ['name', 'time', 'value'], 'rows': [['CPU-linux', 1713667837, 0.0], ['DU-linux', 1713667837, 154169008128], ['DT-linux', 1713667837, 538854957056], ['DR-linux', 1713667837, 384685948928], ['NI-linux', 1713667837, 0], ['NO-linux', 1713667837, 0]]}}
{'success': True, 'reason': 'success, 6 record(s) appended', 'elapse': '2.630386ms'}
{'data': {'columns': ['name', 'time', 'value'], 'rows': [['CPU-linux', 1713667841, 0.0], ['DU-linux', 1713667841, 154169008128], ['DT-linux', 1713667841, 538854957056], ['DR-linux', 1713667841, 384685948928], ['NI-linux', 1713667841, 1245], ['NO-linux', 1713667841, 1245]]}}
{'success': True, 'reason': 'success, 6 record(s) appended', 'elapse': '7.586805ms'}
......この出力は、データ収集が始まったことを示します。データベースの内容も確認しましょう。
次のクエリを実行します。
select * from monitoring order by name, time;
メトリクスが正常に保存されていることを確認できます。
Windowsで実行する
C:\Temp> python3 run-agent-json.py http://127.0.0.1:5654 monitoring --servername windowsWindowsでも同じソースコードを使えます。この例では機器名だけが異なります。
異常検知とアラームの構築
概要
監視の目的は、異常を予測したり、発生時に素早く対処したりすることです。一般には、メトリクスが設定した上限や下限を超えたときに検知します。AIを使えば、より複雑な異常を検出することもできます。
本稿では、しきい値に基づく検知を実装します。主な方法は2つあります。
後処理方式
動作
発生したデータをまず保存し、その保存先を定期的にポーリングして検査します。
利点と課題
検査間隔を短くすると早く検知できますが、システム負荷が高くなります。長くすると負荷は下がりますが、検知が遅れる可能性があります。
前処理方式
動作:保存前にデータを検査し、異常があれば必要な処理を行ってから保存します。異常がなければ、そのまま保存します。
利点と課題
ポーリングが不要なので、データの到着時に異常を検知できます。ただし、流入量が処理能力を超えると、全体の性能が低下する場合があります。
この例では、Machbase NeoのTQLを活用し、前処理方式で異常を検知します。
append.tql
コードの説明
run-agent-tql.py がHTTP POSTでデータを送ると、append.tql が受信し、アラーム条件を検査してからデータベースへ保存します。
CSV(payload())
MAPVALUE(1, parseFloat(value(1)) * 1000000000)
MAPVALUE(2, parseFloat(value(2)))
WHEN(glob("CPU-*", value(0)) && value(2) > 10,
do( value(0), value(1), value(2), {
ARGS()
MAPVALUE(3, strSprintf("CPU usage above %.1f%%", 10))
INSERT("name", "time", "value", "desc", table("alarm_history"))
}
)
)
APPEND(table(param('table') ?? 'monitoring'))CSV(payload())
HTTPで届いたCSVを読み取り、行ごとに次の処理へ渡します。3列は name、time、value で、value(番号) によって参照できます。
MAPVALUE(1, ...):秒単位の時刻を10億倍し、Neoが扱うナノ秒へ変換します。
MAPVALUE(2, ...):文字列として届いた値を、64ビット浮動小数点数へ明示的に変換します。
WHEN(...):ここが条件判定の中心です。
glob():value(0) のタグ名が「CPU-」で始まるかを確認します。この例では、CPU使用率が10を超えるとアラームとします。10を任意のしきい値に変更できます。範囲外を検知するなら、value(2) < 10 || value(2) > 90 のような条件を使います。
do():条件が真の場合に実行され、アラーム発生時の処理を定義します。
ここでは、アラーム情報を alarm_history ログテーブルへ1件挿入します。4番目の値 value(3) は、strSprintf() で生成した説明文です。
APPEND():CSVデータをテーブルへ高速に追加します。
param():URLの ?name=value 形式で指定された、名前付きパラメーターの値を取得します。
この例では table パラメーターを読み取り、省略されていれば monitoring テーブルを使います。
拡張の例
append.tql は、次のような要件にも対応できます。
異常値をタグテーブルに保存しない
異常な値が不要なノイズである場合、タグテーブルへ残さないように、TQLの FILTER() を使えます。
FILTER() は条件に合う行だけを通し、それ以外を破棄します。
次の例では、アラームを記録した後、その原因となったCPU値を除外してからメトリクスを保存します。
CSV(payload())
MAPVALUE(1, parseFloat(value(1)) * 1000000000)
MAPVALUE(2, parseFloat(value(2)))
WHEN(glob("CPU-*", value(0)) && value(2) > 10,
do( value(0), value(1), value(2), {
ARGS()
MAPVALUE(3, strSprintf("CPU usage above %.1f%%", 10))
INSERT("name", "time", "value", "desc", table("alarm_history"))
}
)
)
FILTER(!(glob("CPU-*", value(0)) && value(2) > 10))
APPEND(table(param('table') ?? 'monitoring'))テーブルへの保存の代わりに、REST APIへアラームを送る
doHttp() を使うと、HTTPエンドポイントへデータを送信できます。次はGETとPOSTの例です。詳しくはリンク先の研修資料を参照してください。
HTTP呼び出し
doHttp("GET", strSprintf("http://127.0.0.1:5654/db/tql/alarm-input-get.tql?name=%s&time=%f&value=%f", value(0), value(1), value(2)), nil)
doHttp("POST", strSprintf("http://127.0.0.1:5654/db/tql/alarm-input-post.tql"), strSprintf(`%s,%.0f,%.0f`, value(0), value(1), value(2)), "Content-Type: text/csv", "X-Custom-Header: notification")
TQLエージェントの実行
LinuxとWindowsで基本的な方法は同じです。URLには、append.tql の正しい配置先を指定してください。
GitHubのリポジトリをNeo内へ直接クローンした場合は、次のように実行します。
$ python3 run-agent-tql.py http://127.0.0.1:5654/db/tql/neo-apps/server-mon/append.tql monitoring --servername linux出力には、TQLへ送るCSVが表示されます。### は、JSONからCSVへの変換内容を示すデバッグ出力の区切りです。
$ python3 run-agent-tql.py http://127.0.0.1:5654/db/tql/neo-apps/server-mon/append.tql monitoring --servername linux
http://127.0.0.1:5654/db/tql/neo-apps/server-mon/append.tql?table=monitoring
{'data': {'columns': ['name', 'time', 'value'], 'rows': [['CPU-linux', 1713673816, 0.0], ['DU-linux', 1713673816, 154170302464], ['DT-linux', 1713673816, 538854957056], ['DR-linux', 1713673816, 384684654592], ['NI-linux', 1713673816, 0], ['NO-linux', 1713673816, 0]]}}
###
CPU-linux,1713673816,0.0
DU-linux,1713673816,154170302464
DT-linux,1713673816,538854957056
DR-linux,1713673816,384684654592
NI-linux,1713673816,0
NO-linux,1713673816,0
{'success': True, 'reason': 'success', 'elapse': '6.961687ms', 'data': {'message': 'append 6 rows (success 6, fail 0)'}}
{'data': {'columns': ['name', 'time', 'value'], 'rows': [['CPU-linux', 1713673820, 0.1], ['DU-linux', 1713673820, 154170302464], ['DT-linux', 1713673820, 538854957056], ['DR-linux', 1713673820, 384684654592], ['NI-linux', 1713673820, 1156], ['NO-linux', 1713673820, 1156]]}}
###
CPU-linux,1713673820,0.1
DU-linux,1713673820,154170302464
DT-linux,1713673820,538854957056
DR-linux,1713673820,384684654592
NI-linux,1713673820,1156
NO-linux,1713673820,1156
{'success': True, 'reason': 'success', 'elapse': '2.676484ms', 'data': {'message': 'append 6 rows (success 6, fail 0)'}}データ収集の準備ができました。次に、表示用のダッシュボードを作ります。
ダッシュボードの作成
ダッシュボードを開く
Neoのタブ領域で「+」をクリックし、表示されたメニューで DASHBOARD を選ぶと、空のダッシュボードが開きます。

最初のパネルを追加する
初期画面で Create New Panel をクリックすると、パネルの編集画面が開きます。

ここからチャートを追加できます。
CPU Usage
Lineチャートを選び、図のようにテーブルとタグを指定します。

Applyでプレビューを確認し、問題なければ右上のSaveで保存します。
CPUゲージ — Windows
CPU使用率をゲージで表示します。図の設定に従い、最新の測定値を取得するため、valueには last value を指定してください。

CPU DIFF
CPU使用率の変化量を表示します。valueを diff にすると、選択した期間の変化を可視化できます。

ネットワーク使用量(IN/OUT)
CPU Usageと同様に、テーブルとタグを指定します。
チャートの選択

計算の設定
バイトをKiBで表示するため、valueを1024で割ります(value / 1024)。

ディスク空き容量
ディスクの空き容量をリアルタイムに表示します。この例ではLinuxとWindowsの容量差が大きいため、線がほぼ水平に見えます。1台ずつ表示すると、増減を確認しやすくなります。
チャートの選択

計算の設定
赤枠の計算アイコンをクリックし、各系列に value / 1024 / 1024 / 1024 を設定します。これでバイトからGiBへ変換されます。変換しない場合は、バイト単位の長い数値が表示されます。

アラーム履歴(散布図)
この散布図は、alarm_history ログテーブルを使い、直近5分間のアラーム発生状況を一覧表示します。

ログテーブルには、取り込み時に自動設定される _ARRIVAL_TIME があります。チャートには、利用者が定義した TIME 列と _ARRIVAL_TIME のいずれかを選べます。元記事は性能面から後者を推奨していますが、両者は異なる時刻を表すため、目的に合わせて選択してください。
ダッシュボード全体を表示する
チャートを図のように配置したものが、公開リポジトリ machbase/neo-apps の DASHBOARD.dsh に保存されています。右上のリンクアイコンで専用URLを取得すると、別のブラウザータブにダッシュボードだけを表示できます。

専用URLでダッシュボードを表示する
これが完成画面です。専用URLで独立した画面に表示し、時間設定で直近5分間のデータを3秒ごとに更新しています。

【クイックセットアップ】Neoのシステム監視アプリを使う
ここでは、Neoでシステムメトリクスを表示する最短手順を説明します。
Machbase Neoのインストール
このデモではNeo 8.0.17を使っています。以下の動画は、本稿で使用したバージョンのダウンロード、インストール、起動手順を紹介しています。
Windowsへのインストールと起動
Linux/macOSへのインストールと起動
neo-appsをNeoへダウンロードする
NeoはGitHubのソースコードを直接クローンできます。以下は、Neoがインストールされ、起動していることを前提とします。
左上の3番目のアイコンから Git Clone を開きます。https://github.com/machbase/neo-apps.git を入力してOKをクリックすると、アプリケーションがダウンロードされます。

インストールしたパッケージを確認する
完了すると、最上位に neo-apps ディレクトリが作成されます。その中の server-mon を開くと、図のファイルを確認できます。Pythonエージェントのソースも含まれますが、Neoのファイル表示には出てきません。

ワークシートでテーブルを作成する
setup.wrk を開くと、次のワークシートが表示されます。ワークシートは、説明と実行可能な処理を組み合わせられるNeoの文書形式です。

ワークシートからSQLを直接実行できます。
最初の CREATE TAG TABLE 文にカーソルを置き、右上の再生ボタンをクリックして、メトリクス用テーブルを作成します。
成功したら、CREATE TABLE alarm_history 文にカーソルを置いて実行し、2つ目のテーブルを作成します。
TQLエージェントを起動する
詳細は前半で説明したので、ここでは実行手順だけを示します。アラーム検査も行うTQLエージェントを使います。
この例では、NeoがWSL2上のLinuxで動作し、機器名を linux とします。ホストのWindowsでも、windows という名前でエージェントを起動します。
Pythonの依存パッケージをインストールする
エージェントに必要な外部パッケージをインストールします。argparse、logging、platform、socketはPython標準ライブラリなので、別途インストールする必要はありません。
pip3 install psutil requests
Linux
server-mon のソースディレクトリで、以下を実行します。
ディレクトリの内容を確認する
~/neo/current/neo-apps/server-mon$ ls
DASHBOARD.dsh agent_core.py append.tql mon.sql run-agent-json.py run-agent-tql.py run.sh setup.wrkエージェントを実行する
~/neo/current/neo-apps/server-mon$ python3 run-agent-tql.py http://127.0.0.1:5654/db/tql/neo-apps/server-mon/append.tql monitoring --servername linux
http://127.0.0.1:5654/db/tql/neo-apps/server-mon/append.tql?table=monitoring
{'data': {'columns': ['name', 'time', 'value'], 'rows': [['CPU-linux', 1713678506, 0.1], ['DU-linux', 1713678506, 154355449856], ['DT-linux', 1713678506, 538854957056], ['DR-linux', 1713678506, 384499507200], ['NI-linux', 1713678506, 0], ['NO-linux', 1713678506, 0]]}}
###
CPU-linux,1713678506,0.1
DU-linux,1713678506,154355449856
DT-linux,1713678506,538854957056
DR-linux,1713678506,384499507200
NI-linux,1713678506,0
NO-linux,1713678506,0
{'success': True, 'reason': 'success', 'elapse': '2.824225ms', 'data': {'message': 'append 6 rows (success 6, fail 0)'}}
{'data': {'columns': ['name', 'time', 'value'], 'rows': [['CPU-linux', 1713678510, 0.1], ['DU-linux', 1713678510, 154355449856], ['DT-linux', 1713678510, 538854957056], ['DR-linux', 1713678510, 384499507200], ['NI-linux', 1713678510, 1156], ['NO-linux', 1713678510, 1156]]}}
###
CPU-linux,1713678510,0.1
DU-linux,1713678510,154355449856
DT-linux,1713678510,538854957056
DR-linux,1713678510,384499507200
NI-linux,1713678510,1156
NO-linux,1713678510,1156
{'success': True, 'reason': 'success', 'elapse': '4.977728ms', 'data': {'message': 'append 6 rows (success 6, fail 0)'}}
.....正常に収集できていることを確認できます。
Windows
ディレクトリの内容
C:\Users\ratse\work\neo-apps\server-mon>dir
C 드라이브의 볼륨에는 이름이 없습니다.
볼륨 일련 번호: 9CFC-DC76
C:\Users\ratse\work\neo-apps\server-mon 디렉터리
2024-04-21 오후 02:50 <DIR> .
2024-04-20 오후 12:33 <DIR> ..
2024-04-20 오후 12:33 3,578 agent_core.py
2024-04-21 오후 02:50 431 append.tql
2024-04-21 오후 02:50 15,439 DASHBOARD.dsh
2024-04-20 오후 12:33 312 mon.sql
2024-04-20 오후 12:33 1,622 run-agent-json.py
2024-04-21 오후 02:50 2,358 run-agent-tql.py
2024-04-20 오후 12:33 51 run.sh
2024-04-21 오후 02:50 12,474 setup.wrk
2024-04-20 오후 12:33 <DIR> __pycache__
8개 파일 36,265 바이트
3개 디렉터리 20,532,850,688 바이트 남음エージェントを実行する
C:\Users\ratse\work\neo-apps\server-mon>python3 run-agent-tql.py http://127.0.0.1:5654/db/tql/neo-apps/server-mon/append.tql monitoring --servername windows
http://127.0.0.1:5654/db/tql/neo-apps/server-mon/append.tql?table=monitoring
{'data': {'columns': ['name', 'time', 'value'], 'rows': [['CPU-windows', 1713678697, 13.4], ['DU-windows', 1713678697, 1835372167168], ['DT-windows', 1713678697, 1922094321664], ['DR-windows', 1713678697, 86722154496], ['NI-windows', 1713678697, 0], ['NO-windows', 1713678697, 0]]}}
###
CPU-windows,1713678697,13.4
DU-windows,1713678697,1835372167168
DT-windows,1713678697,1922094321664
DR-windows,1713678697,86722154496
NI-windows,1713678697,0
NO-windows,1713678697,0
{'success': True, 'reason': 'success', 'elapse': '5.638746ms', 'data': {'message': 'append 6 rows (success 6, fail 0)'}}
{'data': {'columns': ['name', 'time', 'value'], 'rows': [['CPU-windows', 1713678701, 5.2], ['DU-windows', 1713678701, 1835372167168], ['DT-windows', 1713678701, 1922094321664], ['DR-windows', 1713678701, 86722154496], ['NI-windows', 1713678701, 279462], ['NO-windows', 1713678701, 12224643]]}}
###
CPU-windows,1713678701,5.2
DU-windows,1713678701,1835372167168
DT-windows,1713678701,1922094321664
DR-windows,1713678701,86722154496
NI-windows,1713678701,279462
NO-windows,1713678701,12224643
{'success': True, 'reason': 'success', 'elapse': '925.549µs', 'data': {'message': 'append 6 rows (success 6, fail 0)'}}
.....ダッシュボードを開く
設定は完了です。付属のダッシュボードは linux と windows の2つの機器名で設定済みなので、開くとすぐにデータが表示されます。
左側の DASHBOARD.dsh をクリックします。
標準テーマ

起動から約3分の画面なので、チャートはまだ埋まっていません。3秒ごとに更新され、リアルタイムの値が表示されます。
インフォグラフィックテーマを試す
リポジトリには、別テーマの DASHBOARD-infographic.dsh もあります。次のような表示を試せます。

おわりに
本稿ではNeo 8.0.17で、システム監視のためのメトリクス収集、アラーム処理、可視化を構築しました。デモは2台だけですが、元記事は8コア・16GB程度のサーバーで10万種類以上のメトリクス、1,000億件以上のレコードを扱う構成を紹介しています。実際の容量や性能は、負荷と設定によって変わります。
本番環境では、長期間の可視化に使うロールアップクエリ、バックアップとマウント、外部製品との連携なども検討する必要があります。
最初の一歩として、Machbase Neoでシステムメトリクスを収集し活用する流れを理解するには、十分な例になるでしょう。
今後、さまざまな用途への応用が広がることを期待しています。


