はじめに
EXNOA プラットフォーム開発本部 プラットフォームインフラ部の角です。
近年、クラウドネイティブなシステム開発やモニタリングツールの充実によりモニタリングの考え方も変わりつつあると思います。
今回の投稿では、5つのプラクティスを通して
- より早く正確に障害を検知
- より早く障害から復旧
するための取り組みを紹介します。
一部、「入門 監視 ―モダンなモニタリングのためのデザインパターン Mike Julian (著), 松浦 隼人 (翻訳)」に記載のプラクティスもありますが、私たちのチームでどのように実践しているかを紹介します。
なお、監視対象のシステムの概要は以下の記事をご覧ください。
Amazon EKSの採用とAWS Well-Architected フレームワークの実践
今回、紹介するプラクティスは以下のとおりです。
- RED methodとUSE methodを使い分ける
- あらゆる情報を収集して可視化する
- 監視の設定を自動化する
- synthetics監視とE2Eテスト
- 定期的な負荷試験と障害試験による継続的な改善
1. RED methodとUSE methodを使い分ける
まず初めに、REDメソッドとUSEメソッドに関して簡単に説明します。
REDメソッドとは、weaveworks社が定義した監視メソッドのことで、エンドユーザ視点のメトリクスにフォーカスしているのが特徴です。
https://www.weave.works/docs/cloud/latest/tasks/monitor/best-instrumenting/
このメソッドでは、アプリケーション(マイクロサービス)の下記の3つのメトリクスを重要視しています。
- R: Request Rateのことで、クライアントからのリクエスト数
- E: Request Errorsのことで、クライアントへ送信したエラー数(率)
- D: Request Durationのことで、クライアントからのリクエストを処理するまでに要した時間
USEメソッドとは、サーバのCPUやメモリーなどのリソース状況にフォーカスした伝統的な監視メソッドのことです。
http://www.brendangregg.com/usemethod.html
USEは、Utilization、Saturation、Errorsの頭文字から取ったものです。
Webサービスの正常性の確認をREDメソッドで、障害の根本原因やボトルネックの確認・調査をUSEメソッドで行うのが理想的だと言われています。
もしも、クラウドネイティブなシステムではどちらを最初に実践すべきかと問われたら、RED methodを実践するほうが良いと私は考えています。
クラウドネイティブなシステムでは、オートスケーリングやオートヒーリング、 自動フェイルオーバ、サーバレスといった仕組みによって、サーバのリソース状況の面倒を見る必要がレガシーなシステムに比べ少なくなりました。
それに伴って、サーバのリソース状況を監視する重要性は低くなりつつあると私は考えています。
例えば、CPUの使用率であればリクエストの急激なスパイクを除いて、オートスケーリングの機能を利用して、一定の閾値を超えないように自動的に調整させることができます。
また、ほとんどのマネージドデータベースは、ストレージの使用率によって自動的に拡張されます。
一方で、クラウドネイティブなシステムで重要性が増したのが、ユーザ視点のモニタリングです。
その理由は、ユーザからの1リクエストあたりに発生する通信の数が大幅に増えたためです。
私が運用しているサービスでは、CloudFront、ALB、Nginx Ingress、Nginxの構成を採用しており、ユーザのリクエストがアプリケーションに届くまでに経由するproxyの数が従来よりも多くなりました。
さらに、kubernetesを利用しているので、proxy以外にもCoreDNSなどのコンポーネントにも通信が発生しています。
API Gateway、Lambda、DynamoDB、SQS、Kinesisなどを組み合わせて構成されたサーバレスなシステムでもコンポーネント間の通信の数が多くなるのは同じでしょう。
通信の数が多くなったことで問題になるのが、エラーの増加や障害がどこで発生しているのか見極めるのが難しくなったことです。
この問題を解決するための1つの仕組みとして、分散トレーシングがあると思うのですが、Cloudfront、ALB、Nginx Ingress、Nginx、DBの構成では、すべての通信を1つのtraceとして確認することは難しいです。
そこで、私はREDメソッドを参考にして、proxy、ミドルウェア、アプリケーションの以下の項目を重点的に監視するようになりました。
- リクエスト数
- エラーレート
- レイテンシー
例えば、CloudfrontとALB間が通信できない状況を想定します。
障害が発生する前は、Cloudfront、ALB、アプリケーションの上記のメトリクスに正の相関を確認することができますが、障害の発生後は相関が崩れるでしょう。
具体的なメトリクスの変化は以下の2つです。
- ALBとアプリケーションのリクエスト数が低下 (上の図)
- Cloudfrontのエラーレートの上昇 (下の図)
このケースのように、REDメソッドを使いproxy、ミドルウェア、アプリケーションのメトリクスを比較することで、原因となる箇所を素早く突き止めることができます。
さらに、私がREDメソッドに+αで重要視しているのが、proxyとアプリケーションごとのログです。
障害点を絞り込むことができれば、次は詳細な調査が必要になりますが、そこで確認すべきなのがログです。
障害が発生すると、一定のパターンのログが大量に発生しているケースが多いです。
例えば、MySQLやRedisで障害やフェイルオーバが発生した場合は、以下のようなアプリケーションログが大量に発生します。
- Connection timed out
- Connection refused
- MySQL server has gone away
ログをPatternごとに集計して、量が多いものから確認することで障害の原因を素早く把握できるようにしています。
もちろん、ログ監視として
- アプリケーションごとのログ量の異常な増加と減少をAnomaly Monitorで検知
- 特定のキーワードを含むログの増加をLog Monitorで検知
の2つの方法も導入しています。
このように、REDメソッドとログ監視を用いることで、より早く正確に障害を検知することに取り組んでいます。
2. あらゆる情報を収集して可視化する
あらゆる情報の具体例は下記の7つで、Datadogに集約しています。
- アプリケーションのパフォーマンス
- サーバのリソースの使用率
- ログ
- ネットワーク パフォーマンス
- セキュリティ
- ビジネスKPI
- Tweet
Datadogで利用しているサービスは、
- APM
- Infrastructure
- Log Management
- Security Monitoring
- Network Perfomance Monitoring
- Synthetic Monitoring
の6つのサービスを利用しています。
DMM GAMES プラットフォーム、Datadogはじめました!
上記の記事のとおり、私たちのチームでは3年ほど前からDatadogを利用しており、Datadogの機能追加に応じて導入する機能が増えています。
Datadogの魅力は、
- メトリクスやログ、APM、Syntheticなどの全ての情報を相互に関連付けて表示することができる
- 多様なアラート設定
- トレンドな機能を全て網羅している
- 課金体系
- カスタマイズ性
だと思います。
ログの料金が高いイメージでしたが、tag指定でIndexするログをフィルターすることが可能になったので、料金を気にしないでログを送信することもできるようになったと思います。
そして最近、利用を始めたのがNetwork Performance Monitoringです。
Network Performance Monitoringは、サーバ間やPod間、AZ間のネットワークトラフィックやDNSのメトリクスを可視化するための機能です。
他にも、自動的にNetwork Mapを作成してくれる機能もあります。
TCP Retransmits、TCP Latency、TCP Jitterを確認することもできるので、障害発生時の原因やボトルネックを特定するためのツールとして、とても有用です。
それだけでなく、ネットワーク構成が複雑なKubernetesを利用していることもあり、通信経路の把握やデバッグ、セキュリティの観点でも役に立っています。
情報の具体例のうちNo.5までは、どのインフラ系のチームでも一般的に行われていることかと思います。
私たちのチームでは最近、数個のビジネスKPIもDatadogへ送信して観察を始めました。
ビジネスKPIの収集方法は下記の二通りで、KPI取得のために何かしらの実装をしているのではなく、すでに蓄積されているデータから利用可能なものをdogstatdを利用してDatadogへ送信し、可視化しています。
- Datadog APMのURLごとの統計情報
- DBに保存されているビジネスKPIの値のサマリー
私は、インフラエンジニアもビジネスKPIを観察したほうが良いと考えています。
理由は、障害が発生した時にどれくらいの機会損失が発生したかを理解し、よりコストをかけて冗長構成にするか、あるいはディザスタリカバリを持つかの判断を行えるようにするためです。
また、クラウドの費用が売上高の何%を占めているのを確認して、
- 売上高に対してコストパフォーマンスが良いシステムなのか
- 売上高の増加に伴う、クラウド費用の増加率が適切であるか
を確認するためです。
最近、FinOpsという言葉を耳にしたことがある方もいるかと思います。
クラウドネイティブなシステムでは、時間単位あたりの課金形態のサービスとリクエスト数やIOPSなどの従量課金体系のサービスが混在しており、さらにSavings PlanやRIなどが組み合わさって複雑な課金体系となっています。
ビジネスKPIを理解したうえで、クラウドのコストとシステムの品質のバランスを最適化するというFinOpsの領域も担う必要があるのではないかと考え、ビジネスKPIの取得と可視化にも取り組んでいます。
3. モニターのコード化と設定の自動化
私たちのチームでは、Datadogの以下のようなmonitorの設定をHCLで記述して、Terraform Cloudを利用して、Gitopsで設定を反映させるようにしています。(図の①の部分)
# network checkによる外形監視のMonitor
resource "datadog_monitor" "http_can_connect" {
name = "{{url.name}} cannot connect from {{from.name}}"
type = "service check"
message = var.message
escalation_message = ""
query = "\"http.can_connect\".over(\"urlenv:${var.env}\").exclude(\"monitoring:disabled\").by(\"url\",\"from\").last(6).count_by_status()"
monitor_thresholds {
critical = 5
warning = 3
ok = 3
}
notify_no_data = false
new_host_delay = 300
renotify_interval = 0
notify_audit = false
timeout_h = 0
include_tags = true
tags = ["env:${var.env}", "monitorgroup:http"]
}
# 証明書の有効期限のMonitor
resource "datadog_monitor" "http_ssl_days_left" {
name = "{{url}} ssl days left is low"
type = "metric alert"
message = var.message
escalation_message = ""
query = "max(last_4h):avg:http.ssl.days_left{urlenv:${var.env},!monitoring:disabled} by {url} < 30"
monitor_thresholds {
warning = 45
critical = 30
}
notify_no_data = false
new_host_delay = 300
renotify_interval = 0
notify_audit = false
timeout_h = 0
include_tags = true
tags = ["env:${var.env}", "monitorgroup:http"]
}
工夫している点は、1 URL ごとに1 Monitorを設定するのではなく、by(\"url\")
, by {url}
を付けることで1つのMonitorで複数のURL(リソース)を監視対象にしてコードの冗長性をなくし、尚且つ、新規でhttp checkのURLが追加された時に自動的に監視対象となるようにしているところです。
http.can_connect
のメトリクスを取得するためには、以下のようなHttp Checkの設定をDatadog Agentの設定ファイルに追記してAgentを再起動する必要があります。
http_check:
init_config:
ca_certs: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
instances:
- name: sample url
url: https://www.sample.com/_/healthz
check_certificate_expiration: true
days_warning: 45
days_critical: 30
http_response_status_code: 200
timeout: 60
disable_ssl_validation: false
tags:
- env:prd
- from:jp
このDatadog Agentの設定ファイルもGit管理しており、VPC内のTerraform Cloud Agent経由でAnsibleを実行して設定を反映できるようにしています。(図の②の部分)
つまり、リポジトリ内のDatadog Agentのyamlを追記とMergeのみの作業で、外形監視の実行とMonitorの設定の両方が設定されます。
このように、監視設定でもGitOpsを取り入れて監視設定の自動化とコード化の取り組みを行っています。
4. Synthetics監視とE2Eテスト
先ほど、DatadogのHttp Checkでの外形監視について少し触れましたが、DatadogにはSyntheticの機能の1つにBrowser Testsという一連のシナリオでテストを実行できる機能があります。
主に、以下の2つの用途で利用しています。
- 本番サービスの正常性を確認する
- E2EテストとしてBrowser Testsを利用
まず、1つ目の 「本番サービスの正常性を確認する」用途としては、DatadogのHttp Checkを補完するために導入しています。
/healthz
などのヘルスチェック用のエンドポイントにアクセスした時に返されるステータスコードによってサービスの正常性を確認する方法もありますが、それだけでは不十分な場合があります。
例えば、Webフレームワークの仕様やバグでDBにアクセスできない場合に、200のステータスコードを返すものの意図したHTMLを返していないケースなどです。
また、ユーザが正常にログインできるかどうか、そこまでを監視したいケースにもBrowser Testsは有効です。
DatadogのBrowser Testsを利用すれば、アプリケーションの正常性までを確認する点において、単純なWeb Requestでの監視よりもDeepな外形監視を設定することができます。
2つ目の「E2EテストとしてBrowser Testsを利用」では、アプリケーションの開発者がChromeのプラグインを用いて、Datadogのコンソール上でテストシナリオを作成しています。
そして、開発、ステージング, 本番環境の各環境でアプリケーションのデプロイ完了時に、DatadogのAPIを呼び出して自動的にE2EテストとしてのBrower Testsが実行されます。
これにより、
- アプリケーションの更新時の手動によるテストの工数削減
- アプリケーションの更新により一部の機能にバグが発生した時の検知
が可能になります。
アプリケーションのデプロイ完了からDatadogのAPIを実行する部分は、ArgoCDのpostSync Jobと専用のDeploymentの更新を検知してDatadogのAPIを実行するアプリケーションをkubernetes上にデプロイして実現させています。
ちなみに、DatadogのSyntheticは、APMとも連携させることができます。
連携させることで、画像のようにリダイレクトを含む一連の処理を1つの画面で確認することも可能になります。
インフラエンジニアがアプリケーションのコードを読むことなく、アプリケーションでどのような処理が行われているかを把握するのにも役立っています。
5. 定期的な負荷試験と障害試験を通したモニタリングの継続的な改善
最近、定期的な負荷試験と障害試験にも取り組み始めています。
負荷を発生させる仕組みは、図のようなLocust + ECSを利用しています。
そして、定期的にEventBridge経由でECSのサービスを起動するLambdaを実行して、負荷試験をステージング環境に対して実行するようにしています。
負荷試験の状況は、locustfileに以下のevent hookの設定をして、dogstatsd経由でDatadogに連携させています。
@events.request.add_listener
def request_handler(request_type, name, response_time, response_length, response, context, exception, **kwargs):
if exception:
statsd.increment("locust.request.failure", tags=[])
else:
statsd.increment("locust.request.success", tags=[])
このような少しのコードで、いろんなツール群と連携できるのもDatadogの利点だと思います。
さらに、障害試験を行いたい時は、負荷試験中の時間帯にchaos-meshやawscliを使って障害を注入し、実施しています。
試験の内容や振り返りは、以下のようにDatadogのNotebookを利用してまとめています。
普段利用しているダッシュボードから2クリックで、Notebookへグラフをexportできるので便利です。
定期的な試験をやっている理由の1つに、「監視の継続的な改善」が含まれています。
おそらく、多くのチームで障害発生後にポストモーテムを作成して、振り返りを実施し、アラートを改善するといったフローを回しているかと思います。
しかし、実際に大きな障害が発生するケースはそれほど多くなく、障害が発生しなければアラートの改善がなされないという状況になってしまうこともあるでしょう。
本番環境と同じような環境で、擬似的にユーザのリクエストを発生させつつ障害を注入して、
- 想定どおりにアラートがトリガー、リカバリーしたか
- 意味のないアラートがトリガーされていないか
- 違うメトリクスでアラートをトリガーしたほうが良いのではないか
- アラートがトリガーされるタイミングは適切であったか
を確認して、必要であればアラートを修正するといったことを行っています。
もちろん、本番と近い環境で試験をするので、チーム内のメンバーの障害対応に対する経験値を上げることにも繋がっています。
これからの取り組み
ここまで私たちの監視の取り組みを紹介してきましたが、まだやれることは多いと考えています。
例えば、セキュリティのモニタリングです。
すでに、
- AWSのPatch ManagerやECRのイメージスキャンによる、脆弱性のあるパッケージの定期Scan
- GuardDuty, Security Hubを利用したセキュリティのモニタリング
に取り組んでいます。
しかし、サーバ内の不審な動作をしているprocessの検知や特権モードでのPodの起動などのモニタリング、監査が不十分なのが現状です。
最近、DatadogのCloud Security Posture Managementの機能がGAになり、Cloud Workload Securityの機能がPublic betaとして公開されました。
これまで、サーバにAgentをインストールして利用するソフトウェアは、新規のソフトウェアのインストールやパフォーマンスの劣化などの問題で、導入への敷居が高かったように思われます。
Cloud Workload Securityであれば、既にインストールしているdatadog agentの設定を変更するのみで利用可能なので、今後もDatadogにセキュリティ周りの情報も集約させていきたいと考えています。
最後に
只今、プラットフォームの安定運用やグロースに携わるインフラエンジニアをEXNOA プラットフォーム開発本部 インフラ部では募集しています。
ご興味のある方は下記の募集要項をご覧のうえ、ぜひご応募ください。