Qmonus SDK Core v23.1の監視設計ベストプラクティスについて教えてください。
公開日: 2023/6/21
更新日: 2024/6/25
本ページについて
v23.1で提供しているheartbeat APIを使用した監視設計のベストプラクティスについて紹介します。
Qmonus SDK Core v22.7以前の監視について
Qmonus SDK Core v22.7以前のバージョンでは、Qmonusチームが用意した独自の監視用pluginをユーザー環境に追加インストールすることで監視用のAPIを利用した監視設計を想定していました。
この監視用APIに対しリクエストすることで、APIGWを経由した各コンポーネントへの疎通があるかどうかをチェックすることが可能でした。 ex.) APIGW -> Scenario, APIGW -> Scenario -> DB, APIGW -> Schedule
この提供中のAPIについては、系として動作できているかどうかのみが担保されます。冗長構成の場合において、各コンポーネントpodのうち1台が処理を担うためです。したがって下記のように故障podが存在している場合も正常にリクエストを返却可能なため、特定podの故障には使用できないという課題がありました。
Qmonus SDK Core v23.1以降の監視について
Qmonus SDK Core v23.1以降のバージョンではheartbeat APIが機能拡張されたことにより、culster=trueパラメータをURIに付与することでnamespace内にデプロイされているコンポーネント全てに対してmasterlookup API/healthcheck APIをリクエストします。例としてAPIGW endpointにリクエストが着弾すると、リクエストを受け取ったAPIGWは冗長構成になっている他のAPIGWを含めたすべてのコンポーネントの全てのpodにheartbeat APIをリクエストし、レスポンスを整形しまとめて返却します。
監視ベストプラクティス(1) GET /heartbeat?cluster=true の利用
GET /heartbeat?cluster=true
のレスポンスボディを以下で簡単に解説します。
{
"endpoint": "10.98.38.119:9000", //ネットワーク内部のエンドポイントです。
"hostname": "apigw-guest-78b5f694f8-gj4jd", //pod名です。
"bootuptime":1678163546, // コンテナ起動時のUNIX時間です。
"host":"10.98.34.161", // Serviceに紐づくClusterIP(GCPの場合)です。
"port":9000, // endpointのport番号です。
"outofservice":false, //サービス提供状態のbooleanです。データベースとの疎通が失われた場合などでtrueが値に入ります。
"database":true, //アプリケーションとしてdatabaseと疎通があることのbooleanです。
"memorystore":true, //アプリケーションとしてredisと疎通があることのbooleanです。
"mode":"master", //アプリケーションでのコンポーネントの動作モードです。"master"もしくは"guest"が値に入ります。
"plugins_version": {
"instance":"fa7916bcdf2a4bd9a979c345f844d754", //plugin_installに成功している場合に格納されるインスタンスIDです。
"timestamp":"2023-03-07T13:34:29.789202+09:00" //plugin_installに成功した時間です。
}
}
レスポンスボディ例
GET /heartbeat?cluster=true のレスポンスボディ例
{
"APIGW": [
{
"endpoint": "10.98.38.119:9000",
"hostname": "apigw-guest-78b5f694f8-gj4jd",
"bootuptime": 1678062677,
"host": "10.98.38.119",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.33.219:9000",
"hostname": "apigw-guest-78b5f694f8-vlcx6",
"bootuptime": 1678062673,
"host": "10.98.33.219",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.34.8:9000",
"hostname": "apigw-7759c8c478-4vnmv",
"bootuptime": 1678062682,
"host": "10.98.34.8",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "master",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
}
],
"TRANSACTION": [
{
"endpoint": "10.98.33.216:9000",
"hostname": "transaction-f6c47c7-ffcrg",
"bootuptime": 1678062777,
"host": "10.98.33.216",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "master",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.41.168:9000",
"hostname": "transaction-guest-7f8cc4868f-qfsgn",
"bootuptime": 1678062759,
"host": "10.98.41.168",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.33.215:9000",
"hostname": "transaction-guest-7f8cc4868f-gp8rf",
"bootuptime": 1678062779,
"host": "10.98.33.215",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
}
],
"SCENARIO": [
{
"endpoint": "10.98.33.217:9000",
"hostname": "scenario-659c9b6944-zxq5q",
"bootuptime": 1678062781,
"host": "10.98.33.217",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "master",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.38.121:9000",
"hostname": "scenario-guest-cf84dccc6-s97g2",
"bootuptime": 1678062756,
"host": "10.98.38.121",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.43.177:9000",
"hostname": "scenario-guest-cf84dccc6-2wh28",
"bootuptime": 1678062766,
"host": "10.98.43.177",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
}
],
"SCHEDULE": [
{
"endpoint": "10.98.36.216:9000",
"hostname": "schedule-guest-6467b5c4c5-dlfg9",
"bootuptime": 1678062744,
"host": "10.98.36.216",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.36.214:9000",
"hostname": "schedule-6c88b9fcd9-864r7",
"bootuptime": 1678062744,
"host": "10.98.36.214",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "master",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.36.75:9000",
"hostname": "schedule-guest-6467b5c4c5-tkbg4",
"bootuptime": 1678062766,
"host": "10.98.36.75",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
}
],
"LAMBDA": [
{
"endpoint": "10.98.35.205:9000",
"hostname": "lambda-guest-8b4f6ddf-46ndw",
"bootuptime": 1678062745,
"host": "10.98.35.205",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.37.135:9000",
"hostname": "lambda-85bccb78c9-z2rcc",
"bootuptime": 1678062731,
"host": "10.98.37.135",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "master",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.41.169:9000",
"hostname": "lambda-guest-8b4f6ddf-ss4nd",
"bootuptime": 1678062759,
"host": "10.98.41.169",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
}
],
"COLLECTOR": [
{
"endpoint": "10.98.33.218:9000",
"hostname": "collector-f6cb9f48b-z99fz",
"bootuptime": 1678062777,
"host": "10.98.33.218",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "master",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.36.215:9000",
"hostname": "collector-guest-7d4c955d68-wz57s",
"bootuptime": 1678062744,
"host": "10.98.36.215",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.34.7:9000",
"hostname": "collector-guest-7d4c955d68-nfctm",
"bootuptime": 1678062737,
"host": "10.98.34.7",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
}
],
"REFLECTOR": [
{
"endpoint": "10.98.38.120:9000",
"hostname": "reflector-guest-6d5f4b4475-wwvhz",
"bootuptime": 1678062755,
"host": "10.98.38.120",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
},
{
"endpoint": "10.98.36.220:9000",
"hostname": "reflector-557cfd8f4d-mq4s2",
"bootuptime": 1678063274,
"host": "10.98.36.220",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "master",
"plugins_version": null
},
{
"endpoint": "10.98.43.176:9000",
"hostname": "reflector-guest-6d5f4b4475-z5bnf",
"bootuptime": 1678062766,
"host": "10.98.43.176",
"port": 9000,
"outofservice": false,
"database": true,
"memorystore": true,
"mode": "guest",
"plugins_version": {
"instance": "c37e890bae8e44d9a340b28ec48c9a73",
"timestamp": "2023-03-06T09:34:39.044561+09:00"
}
}
]
}
レスポンスボディに含まれる情報から、各コンポーネントがRDBやredisにそれぞれ接続できているかをチェックすることが可能です。また、podが立ち上がっているがplugin_installの成功可否についても、heartbeat APIの情報から取得することが可能です。
Warning
ステータスコードによる全コンポーネントの監視を行う場合はv23.2LTS-patch20240524 以降をお使いください。
v23.2LTS-patch20240409 以前では、GET /heartbeat?cluster=true
から派生するhttpリクエストがエラーとなった場合、レスポンスボディでは対応箇所に情報が格納されていないことから判断できますが、応答としては200を返却します。したがって、GET /heartbeat?cluster=true
のレスポンスステータスコードによる全コンポーネント監視はできない点に注意してください。
v23.2LTS-patch20240524 以降では、派生したhttpリクエストがエラーとなった場合、500を返却するようになります。
heartbeat APIにおける監視の起点を指定する
監視の要件として特定のコンポーネントを指定し、これを起点としたルートでhealthcheck APIをリクエストしたい場合はmasterlookup APIでエンドポイントを取得したのち、そのエンドポイントに対してGET /heartbeat?cluster=true
をリクエストすることで実現可能です。
必ずscenarioのmasterを起点としてhealthcheckを実施したい場合、以下のインタラクティブシェルの実行結果のような処理をスクリプトに組み込むことでscenario masterを起点とした全コンポーネントのhealthcheckが可能です。
>>> r = await callout("/masterlookup?role=SCENARIO")↵
... print(json.dumps(json.loads(r.body), indent=4))↵
... ↵
↵
{
"role": "SCENARIO",
"endpoint": "10.98.33.217:9000",
"hostname": "scenario-659c9b6944-zxq5q"
}
>>> endpoint = json.loads(r.body)["endpoint"]↵
... r = await callout(url=f"http://{endpoint}/heartbeat?cluster=true")↵
監視ベストプラクティス(2) GET /masterlookup?scope=cluster と GET /heartbeatの併用
各コンポーネントに対するheartbeat APIのレスポンスで評価したい場合はmasterlookup APIを利用して、以下のインタラクティブシェルの実行結果のような処理をscenario等のスクリプトに組み込むことで各コンポーネントへのheartbeat APIのレスポンスコードの評価が可能です。
Warning
masterlookup APIでデプロイされているSDKコンポーネントとレスポンスが一致しない場合はredisで管理しているエンドポイント情報がTTL超過により削除されている可能性があります。起動パラメーターcluster_watch_interval
(default:10000)にてより大きな値を指定することでTTLを長く設定することで事象が解消するケースがあります。TTLは指定した値の15倍に指定されます。単位はミリ秒となります。
>>> r = await callout("/masterlookup?scope=cluster")↵
... body = json.loads(r.body)↵
... l = sum(list(map(lambda x: body[x], body.keys())), [])↵
... endpoints = [_["endpoint"] for _ in l]↵
... endpoints↵
... ↵
↵
['10.98.38.119:9000', '10.98.33.219:9000', '10.98.34.8:9000', '10.98.33.216:9000', '10.98.41.168:9000', '10.98.33.215:9000', '10.98.33.217:9000', '10.98.38.121:9000', '10.98.43.177:9000', '10.98.36.216:9000', '10.98.36.214:9000', '10.98.36.75:9000', '10.98.35.205:9000', '10.98.37.135:9000', '10.98.41.169:9000', '10.98.33.218:9000', '10.98.36.215:9000', '10.98.34.7:9000', '10.98.38.120:9000', '10.98.36.220:9000', '10.98.43.176:9000']
>>> for endpoint in endpoints:↵
... r = await callout(url=f"http://{endpoint}/heartbeat?cluster=true")↵
... assert r.code == 200↵
監視の起点を特に問わない場合は、scenarioにて監視用APIを簡単に実装が可能です。サンプルの監視用APIは以下となります。
- transaction:
enable: false
async: true
xname: ''
global_variables: {}
variable_groups: []
spec:
response:
normal:
codes:
- 200
commands:
- command: script
kwargs:
code: |
r = await callout("/masterlookup?scope=cluster")
body = json.loads(r.body)
l = sum(list(map(lambda x: body[x], body.keys())), [])
services = {_["hostname"]:_["endpoint"] for _ in l}
res_body = {}
for service in services.items():
r = await callout(url=f"http://{service[1]}/heartbeat?cluster=true")
if r.code not in [200]:
res_body[f"{service[0]}"] = False
else:
res_body[f"{service[0]}"] = True
if not all(res_body.values()):
context.session.set_status(500)
context.session.finish(res_body)
id: c1958e720ff311ee9ec44ead5b71e4ce
category: ''
name: SystemHealthcheck
uri: /v1/healthcheck
method: GET
request_timeout: 60
connect_timeout: 60
additional_paths: []
routing_auto_generation_mode: true
routing_options:
scope: local
version: 1
update: '2023-06-21T14:35:58.858432+09:00'