1.はじめに
モニタリング(監視)の環境を整備することによって、見える化を行ったら次はどんな情報が必要で、何を整理する必要があるか考えなければならないですね。
基本的には必要な情報はサーバ郡の役割によって異なる為、大きくAPサーバとDBサーバで分けて検討します。
求められるビジネスロジックによって必要なメトリクスは異なるが、今回はオーソドックスであると思われるものについてまとめていきたいと思います。
また今回想定している環境はprometheusの為、他の基盤を用いている方はメトリクスを自分の基盤と読み替えていただけると幸いです。
前提として、各メトリクスを取得する手段は、goによって作成されている**.exporterを使用しpull型の取得であるとしています。
2.APサーバへの基本的な監視項目
項目 | 閾値 | scrape_interval | evaluation_interval | alert_interval | 型 |
---|---|---|---|---|---|
死活監視 | 回 | 10sec | 10sec | 1min | bool |
CPU使用率 | % | 1min | 1min | 5min | avg |
メモリ使用率 | % | 1min | 1min | 5min | avg |
ストレージ空き容量 | % | 1min | 1min | 5min | max |
ロードアベレージ | 数 | 10sec | 10sec | 1min | avg |
diskIO | % | 10sec | 10sec | 1min | max |
diskbusy | % | 10sec | 10sec | 1min | max |
必要最低限を満たす大勢として、検討したメトリクスとしては上記のようなものでした。
上記の値を取得してアラートを発火するには、Grafana,もしくPrometheus側のアラートマネージャにクエリを記載しなければならないのですが、Prometheusへ蓄積した様々なメトリクスの参照は、PromQLという独自のクエリ言語を用いて行います。
また、GrafanaのTemplating機能を使うと、クエリに対して変数が適用できますが、IaC的な運用を目指すならばアラートマネージャ側でクエリを保持して管理する方が良いかと思われます。
3.Dataの取得方法
さて、ここで上記の項目値の取得方法の例を記載します。その前に必要な演算子は以下のようなものがあります。
max,min
任意の範囲内でのデータの最大、最小avg
avg演算子は、レコードごとに格納されたスカラー値の平均値を返します。レコードのvalueが配列(Range Vector)の場合は適用できません。rate()とirate()
rate()とirate()関数はどちらも、ある時間範囲で取得したデータが、1秒あたり平均どれだけ増加しているかを計算します。withoutとby
without句は上述の通り、指定したラベルを無視して集計関数を適用します。実際にwithout(cpu)を実行した場合の生データは以下のように、cpuラベルが欠落した状態になります。{instance="docker104:9100",job="node",mode="user"} 0.0005000000000002558
by句は逆に、指定したラベルに絞って、つまり他のラベルを無視して集計関数を適用します。by(mode)を実行すると、mode以外のすべてのラベルが欠落した状態になります。
4.実際のクエリの例
CPU使用率
sum by (instance)(avg(irate(node_cpu_seconds_total{instance=~"$node",mode=~"user"}[5m])) without(cpu) * 100)
指定インスタンス($node)の、単位時間($interval)内での1秒ごとのCPU使用率の平均を表示します。
# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{cpu="cpu0",instance="docker104:9100",job="node",mode="iowait"} 1.57
node_cpu{cpu="cpu0",instance="docker104:9100",job="node",mode="system"} 42.51
node_cpu{cpu="cpu0",instance="docker104:9100",job="node",mode="user"} 74.37
node_cpu{cpu="cpu1",instance="docker104:9100",job="node",mode="iowait"} 5.13
node_cpu{cpu="cpu1",instance="docker104:9100",job="node",mode="system"} 34.1
node_cpu{cpu="cpu1",instance="docker104:9100",job="node",mode="user"} 72.7
ロードアベレージ
node_load1{instance=~"13.231.98.14:9100"}
死活監視
単純な死活監視については別途Exporter(Blackboxexporter)が出ていますが、何らかの基本的な値が一定間隔でnullになった場合に発火するでも問題ないと考えています。
メモリ
process_resident_memory_bytes
process_virtual_memory_bytes
( node_memory_MemFree_bytes{instance=~'$node'} - node_memory_Buffers_bytes{instance=~'$node'} + node_memory_Cached_bytes{instance=~'$node'} + node_memory_SwapCached_bytes{instance=~'$node'} + node_memory_Slab_bytes{instance=~'$node'} + node_memory_PageTables_bytes{instance=~'$node'} + node_memory_VmallocUsed_bytes{instance=~'$node'} ) / node_memory_MemTotal_bytes{instance=~'$node'} * 100
ディスク使用量
100.0 - 100 * (node_filesystem_avail_bytes{instance=~'$node',device !~'tmpfs',device!~'by-uuid'} / node_filesystem_size_bytes{instance=~'13.231.98.14:9100',device !~'tmpfs',device!~'by-uuid'}) or 100.0 - 100 * (node_filesystem_avail{instance=~'13.231.98.14:9100',device !~'tmpfs',device!~'by-uuid'} / node_filesystem_size{instance=~'13.231.98.14:9100',device !~'tmpfs',device!~'by-uuid'})
ディスクIO
rate(node_disk_read_time_seconds_total[5s] / rate(node_disk_reads_completed_total[5s]) * 100
(rate(node_disk_read_time_seconds_total{instance=~"13.231.98.14:9100"}[5s] / rate(node_disk_reads_completed_total{instance=~"13.231.98.14:9100"}[5s]) )* 100
5.監視から得られる示唆
上記で挙げたような、項目は本当に一般的なものですが、注意深く見ると、時系列と共にデータから得られる示唆が沢山あります。
例えば、今回のケースでは社内のadminユーザが業務時間と共に複数セッションを開始しメモリの負荷が業務開始と共に上がっている、といったような示唆がありました。
そこから得られるのは、インスタンスタイプを直ぐにあげてメモリを増強する。ではなく、セッションの開く数を減らしてもらうように呼び掛けたり、admin周りの機能改修によってメモリの使用を抑えるような打ち手も考えられます。
結びとしては、監視⇨障害検知といったことだけではなく、スペックの最適化やシステムの使い方まで話が発展できる為、良い基盤の構築は業務を支える力強い味方になってくれると考えています。
Top comments (0)