Skip to content

炭鉱のカナリア

炭鉱のカナリア(Canary in a Coal Mine)

Section titled “炭鉱のカナリア(Canary in a Coal Mine)”

「炭鉱のカナリア」は、システムやプロセスの問題を早期に発見するための監視や警告メカニズムを表す用語です。かつて炭鉱で、有毒ガスを検知するためにカナリアを連れて行ったことに由来します。

実際の事例:

あるWebアプリケーションで、本番環境にデプロイした後、パフォーマンスの問題が発生しました:

  • 問題: 本番環境でパフォーマンスの問題が発生
  • 原因: データベースクエリの最適化が不十分
  • 影響: ユーザー体験の悪化、サーバーの負荷増加
  • 教訓: 早期に問題を発見できれば、影響を最小限に抑えられた

炭鉱のカナリアのメリット:

  • 早期発見: 問題を早期に発見できる
  • 影響の最小化: 影響を最小限に抑えられる
  • 信頼性: システムの信頼性が向上する

1. ヘルスチェックエンドポイント

Section titled “1. ヘルスチェックエンドポイント”

ヘルスチェックの実装:

app/api/health/route.ts
export async function GET() {
try {
// データベース接続の確認
await db.ping();
// 外部APIの確認
const response = await fetch('https://api.example.com/health');
if (!response.ok) {
throw new Error('External API is down');
}
return Response.json({
status: 'healthy',
timestamp: new Date().toISOString(),
checks: {
database: 'ok',
externalApi: 'ok',
},
});
} catch (error) {
// 問題を検知
return Response.json(
{
status: 'unhealthy',
timestamp: new Date().toISOString(),
error: error.message,
},
{ status: 503 }
);
}
}
// メリット:
// - システムの状態を監視できる
// - 問題を早期に発見できる
// - ロードバランサーで使用できる

メトリクス監視の実装:

lib/metrics.ts
import { metrics } from '@opentelemetry/api';
const requestDuration = metrics.getMeter('app').createHistogram('request_duration', {
description: 'Request duration in milliseconds',
});
const errorCount = metrics.getMeter('app').createCounter('error_count', {
description: 'Number of errors',
});
export function trackRequest(duration: number) {
requestDuration.record(duration);
// 閾値を超えた場合にアラート
if (duration > 1000) {
console.warn(`Slow request detected: ${duration}ms`);
// アラートを送信
sendAlert('slow_request', { duration });
}
}
export function trackError(error: Error) {
errorCount.add(1);
// エラー率が高い場合にアラート
const errorRate = getErrorRate();
if (errorRate > 0.05) {
console.error(`High error rate detected: ${errorRate}`);
// アラートを送信
sendAlert('high_error_rate', { errorRate });
}
}
// メリット:
// - パフォーマンスの問題を早期に発見できる
// - エラーを早期に発見できる
// - 自動的にアラートを送信できる

ログ監視の実装:

lib/logger.ts
import { createLogger } from 'winston';
const logger = createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
// エラーログの監視
logger.error('Database connection failed', {
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
});
// アラートを送信
sendAlert('database_error', {
error: error.message,
timestamp: new Date().toISOString(),
});
// メリット:
// - エラーを記録できる
// - 問題の原因を特定できる
// - 自動的にアラートを送信できる

カナリアデプロイメントの実装:

// カナリアデプロイメントの例
// 1. 新しいバージョンを少数のサーバーにデプロイ
// 2. メトリクスを監視
// 3. 問題がなければ、全サーバーにデプロイ
async function canaryDeployment(newVersion: string) {
// 1. カナリアサーバーにデプロイ
const canaryServers = getCanaryServers();
await deployToServers(newVersion, canaryServers);
// 2. メトリクスを監視
const metrics = await monitorMetrics(canaryServers, 5 * 60 * 1000); // 5分間監視
// 3. 問題がないか確認
if (metrics.errorRate > 0.01 || metrics.responseTime > 1000) {
// 問題がある場合はロールバック
await rollback(canaryServers);
throw new Error('Canary deployment failed');
}
// 4. 全サーバーにデプロイ
const allServers = getAllServers();
await deployToServers(newVersion, allServers);
}
// メリット:
// - 問題を早期に発見できる
// - 影響を最小限に抑えられる
// - 安全にデプロイできる

炭鉱のカナリアのポイント:

  • 早期発見: 問題を早期に発見するための監視メカニズム
  • ヘルスチェック: システムの状態を監視
  • メトリクス: パフォーマンスやエラーを監視
  • ログ: エラーや問題を記録
  • カナリアデプロイメント: 安全にデプロイする方法

適切な「炭鉱のカナリア」を実装することで、問題を早期に発見し、影響を最小限に抑えられます。