【ITニュース解説】Reconstructing Edtech Outages — Node.js Express Health Checks with /ready and /live
2026年10月07日に「Dev.to」が公開したITニュース「Reconstructing Edtech Outages — Node.js Express Health Checks with /ready and /live」について初心者にもわかりやすく解説しています。
ITニュース概要
システム障害の際、サービスが生きてるか(/live)と、新たな処理を受け入れ可能か(/ready)を区別して監視することが重要だ。これにより、問題が起きた時に原因を特定しやすくなり、迅速な対応と再発防止に役立つ。状態変化のログや外部監視も併用しよう。
ITニュース解説
システムエンジニアを目指す皆さんにとって、Webサービスが常に安定して稼働し続けることは非常に重要だ。しかし、システムはいつか必ず停止したり、部分的に機能しなくなったりするもの。そのような障害が発生した際に、何が起きていて、どこに問題があるのかを素早く特定し、復旧させるための仕組みが「健全性チェック」と「監視」である。今回のニュース記事は、Node.jsとExpressを使ったアプリケーションでの健全性チェックの具体的な実装方法と、それによって得られる情報がいかに障害対応に役立つかについて詳しく解説している。
Webサービスでは、さまざまなコンポーネントが連携して動作している。例えば、ユーザーが教材を閲覧したり、新しい教材を公開したりするような教育テクノロジー(EdTech)サービスを想像してみてほしい。このサービスが「ダウンした」と一言で言っても、それが何を意味するのかによって対応は大きく変わる。データベースへの接続ができないのか、サービス自体が応答していないのか、特定の機能だけが使えないのかなど、状況は様々だ。そこで役立つのが、サービスの健康状態を細かく教えてくれる専用のパス、いわゆる「ヘルスチェックエンドポイント」である。
記事では、特に三つの異なるエンドポイントの重要性が強調されている。一つ目は/liveエンドポイントだ。これは「Liveness Probe(ライブネスプローブ)」とも呼ばれ、サービスプロセスがまだ動いていて、基本的なHTTPリクエストに応答できる状態にあるかを確認する。このチェックは、外部のデータベースや他のサービスとの接続状況などは確認せず、プロセス自身の状態のみを見る。主にKubernetesのようなコンテナオーケストレーションツールが、応答のないコンテナを再起動する判断に使うことが多い。
二つ目は/readyエンドポイントである。こちらは「Readiness Probe(レディネスプローブ)」と呼ばれ、サービスが新しいユーザーからのリクエストを受け入れる準備ができているかを確認する。例えば、データベースへの接続が確立されているか、必要な外部サービスにアクセスできるかなど、サービスが正常に機能するために不可欠な依存関係が健全であるかをチェックする。もしデータベースに接続できないなどの問題があれば、このエンドポイントは「準備ができていない」と報告し、ロードバランサーは一時的にそのサービスインスタンスへのトラフィックのルーティングを停止する。これにより、問題のあるインスタンスに新しいリクエストが送られるのを防ぎ、既存のリクエストが処理され次第、安全にサービスを切り離すことができるのだ。Livenessが正常でもReadinessが異常になることは十分あり得る。例えば、Node.jsのイベントループ自体は動いていても、データベース接続プールが枯渇して新しい接続を取得できないような状況だ。
三つ目の/healthエンドポイントは、主にシステムを運用するエンジニアや内部の監視システム向けに、より詳細な診断サマリーを提供する。このエンドポイントは、/readyで実行されたチェックの結果をキャッシュしておき、それを整形して表示するイメージだ。再度高負荷なチェックを実行するのではなく、最新のチェック結果を迅速に提供することで、システムのパフォーマンスへの影響を最小限に抑える。これらのエンドポイントは、正常な場合はHTTPステータスコード200を返し、問題がある場合は503(Service Unavailable)を返すのが一般的である。レスポンスボディには、現在の状態、タイムスタンプ、デプロイメントID、そして各チェック項目の状態などを含めるが、機密情報や詳細なエラーメッセージは決して含めるべきではない。それらの詳細情報はアクセス制限されたログに記録するのが鉄則だ。
サービスの起動時とシャットダウン時の挙動も重要である。起動時は、プロセスが応答可能になった段階で/liveが正常になり、その後、すべての依存関係が準備完了になってから/readyが正常になる、という順序が期待される。逆にシャットダウン時には、まず/readyが「準備未完了」となり、ロードバランサーが新しいトラフィックを停止し、既存のリクエストが処理され終わるのを待ってからプロセスが停止する、という流れが理想的だ。
健全性チェックの記録方法についても工夫が求められる。単にすべてのチェックが成功するたびにログを出すと、正常時のログで埋め尽くされ、本当に重要な障害発生時のログを見つけにくくなる。そのため、状態が変化した時、例えば「準備完了」から「劣化状態」に移行した時や、チェックの理由が大きく変わった時のみ、構造化されたイベントログを記録するべきだと記事は指摘している。このログには、いつ、どのサービスで、どの環境で、どのリージョンで、どのデプロイメントIDのサービスが、以前どんな状態からどんな状態へ変化し、その理由は何か、といった情報を漏れなく含めることで、後のインシデント調査に役立つ。しかし、学習者の個人情報や機密情報は絶対に含めてはならない。
メトリクス、つまり数値データとして監視することも重要だ。レディネスの状態を0か1で示すゲージ(現在の値を表す)や、状態遷移の回数を数えるカウンター、各エンドポイントへのリクエスト数と成功/失敗数を記録するカウンターなどを導入する。これらのメトリクスは、システムの全体的な健全性やトレンドを把握するのに役立つ。
また、サービス内部からのチェックだけでなく、外部からの監視も不可欠だ。Go言語で書かれたプローブの例が示されているように、実際のユーザーがアクセスする経路に近い場所からヘルスチェックエンドポイントを定期的に叩き、その結果を記録・送信することで、ネットワーク経路の問題やDNSの障害など、サービス内部のチェックでは検知しにくい問題を早期に発見できる。外部からのプローブは、サービスが実際に外部から到達可能であることの証明になる。
これらの健全性チェックと監視システムは、インシデント発生時に真価を発揮する。例えば、教材公開APIが応答しない障害が発生したとする。もし適切な健全性チェックとログ、メトリクスが整備されていれば、単に「APIダウン」という漠然とした情報ではなく、「〇月〇日〇時、〇〇リージョンの教材公開サービスにおいて、デプロイメントID〇〇のインスタンスが、データベース接続のタイムアウトによりレディネスが低下した」といった具体的な状況を把握できるようになる。これにより、「学習者は教材にアクセスできなかったのか?」「新しい教材の公開だけが失敗したのか?」「どのリリースがトラフィックを処理していたのか?」といった疑問に対し、迅速に答えることができるようになる。そして、これらの情報から障害発生の初動から復旧までのタイムラインを正確に再構築し、原因を特定し、今後の対策を検討することが可能となる。
監視ツールの選択肢も様々だ。Prometheusのように自身で運用するメトリクススタックや、Datadogのように統合されたマネージドプラットフォーム、Better StackやHealthchecks.ioのように特定の監視機能に特化したサービスなどがある。どのツールを選ぶかは、チームの運用体制、予算、必要な機能によって変わる。例えば、Prometheusはメトリクス収集とアラート管理に優れており、Datadogはログ、メトリクス、外形監視を統合的に扱える。Healthchecks.ioは、定期的に実行されるべきタスクが実行されなかった場合の「デッドマンズスイッチ」的な監視に特化している。大切なのは、それぞれのツールの得意分野を理解し、自分のサービスに最適な組み合わせを選ぶことである。
監視における閾値の設定も難しい問題だ。一回の失敗でアラートを出すと「ノイズ」が多くなり、エンジニアが疲弊する可能性がある。しかし、あまりにも多くの失敗を許容すると、問題の発見が遅れてユーザーへの影響が拡大してしまう。そのため、複数の地域からのプローブで、かつ複数回の連続した失敗があった場合に初めてアラートを出す、といった具体的なポリシーを策定し、それを実際の過去のデータで検証することが推奨されている。また、/readyエンドポイントでの依存関係チェックは、それ自体がシステムに負荷をかける可能性があるため、チェックには短いタイムアウトを設定し、結果をキャッシュして再利用することで、負荷を最小限に抑える工夫が必要だ。
最終的に、これらの健全性チェックと監視の仕組みは、単にシステムが動いていることを確認するだけでなく、障害が発生した際に「何が、いつ、どのように、なぜ」起きたのかを明確にし、迅速な問題解決と再発防止に繋げるための強力な武器となる。システムエンジニアにとって、信頼性の高いサービスを提供し続けるために、これらの概念と実装方法を理解することは不可欠だ。