本番環境でのVector活用:ロギングのオーバーヘッドを90%削減した方法

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

オブザーバビリティの代償

6ヶ月前、私たちのオブザーバビリティ・スタックは、本来防ぐべき対象である「本番環境の障害」そのものになってしまいました。標準的なELK(Elasticsearch, Logstash, Kibana)構成を運用していましたが、マイクロサービスが50以上にスケールするにつれ、Logstashインスタンスが監視対象のビジネスロジック本体よりも多くのメモリを消費し始めたのです。

JVMのオーバーヘッドは単なる厄介者ではなく、頻繁なOOM(メモリ不足)エラーによる強制終了を引き起こすリスク要因でした。私たちは、軽量で高速、かつJVMのチューニングに頭を悩ませる必要のないソリューションを求めていました。

そこで出会ったのが Vector です。Rustでゼロから構築されたVectorは、オブザーバビリティ・データのための高性能なルーターです。本番環境で半年間運用した結果、答えは明白でした。毎秒数百万ものイベントを処理しながら、実行していることを忘れるほど小さなフットプリントを維持しています。回復力のあるインフラを構築するエンジニアにとって、レガシーなログシッパーからの脱却はもはや選択肢ではなく、必須事項です。

競合比較:Vector vs. 既存のツール

Logstashは長年業界標準でしたが、Javaエコシステムに依存しているため動作が重いのが難点です。FluentdはCとRubyのハイブリッド構成でこれを改善しましたが、高スループット環境で複雑な変換ロジックを処理する際にボトルネックとなることがよくあります。Vectorは、この進化における第3世代を象徴しています。

機能 Logstash Fluentd Vector
言語 JRuby/Java C/Ruby Rust
メモリ使用量 高 (500MB+) 中程度 (100MB+) 極めて低 (<30MB)
型安全性 弱い 中程度 強い
配信保証 少なくとも1回 少なくとも1回 エンドツーエンドの確認応答

Vectorのアーキテクチャは根本的に異なります。ログ、メトリクス、トレースを統一されたデータストリームとして扱います。Logstashが独自のDSLを使用するのに対し、VectorはVRL(Vector Remap Language)を採用しています。VRLでの記述は、クリーンな関数型コードを書くような感覚です。テレメトリデータのためのTypeScriptのようなものだと考えてください。

移行を決めた理由:具体的なデータ

強み

  • 圧倒的な効率性: ログ用サイドカーのメモリ消費が500MBからわずか28MBに減少しました。200ノードのKubernetesクラスター全体では、フリート全体で約100GBものメモリを回収できたことになります。
  • 鉄壁の信頼性: Vectorにはディスクバッファ機能が組み込まれています。ClickhouseやS3がメンテナンスのためにオフラインになっても、Vectorはデータをローカルにキャッシュし、自動的にリトライします。移行以来、ログの欠損は一行も発生していません。
  • VRLエンジン: RubyやJavaベースのフィルターで見られるような大幅なパフォーマンス低下を招くことなく、複雑なパース(Grok, Regex, JSON)や条件分岐ロジックを実行できます。
  • 依存関係ゼロ: 単一の静的バイナリです。ランタイムやglibcのバージョン競合、巨大なゲストVMに起因するセキュリティの脆弱性を心配する必要はありません。

トレードオフ

  • エコシステムの成熟度: 主要なプロバイダー向けのSinkは揃っていますが、Fluentdエコシステムにあるような、10年前のマイナーなプラグインライブラリなどはまだ不足しています。
  • 構文の学習曲線: YAMLやRubyの構成に慣れている場合、Vectorの構造、特に高度なVRL関数を使いこなすには1〜2週間ほどの慣れが必要です。

本番環境での階層化戦略

本格的なDevOps環境では、2層構造のアーキテクチャを推奨します。アプリケーションからデータベースへ直接通信させるのではなく、役割を2つに分けます。

  1. エージェント (Source): 各ノードで軽量なDaemonSetとしてVectorを実行します。その唯一の役割は、ファイルやソケットからログを取得し、即座にハブへ転送することです。
  2. ハブ (Aggregator): 中央に配置された、より強力なVectorクラスターです。ここで重複排除、PII(個人情報)のマスキング、複数の転送先へのルーティングといった重い処理を行います。

この分離により、ローカルノードを軽量に保ちつつ、ハブで複雑なロジックやバッファリングを管理できるようになります。

ステップ・バイ・ステップ:最初のパイプライン構築

Syslogデータを収集し、環境メタデータを注入して、分析用のClickhouseと長期保存用のS3の両方にルーティングする、本番対応のパイプラインを構築してみましょう。

1. インストール

Linuxでは、数秒で実行可能です:

curl --proto '=https' --tlsv1.2 -sSf https://sh.vector.dev | sh

2. パイプライン設定

vector.yamlファイルを作成します。ロジックはシンプルな Source -> Transform -> Sink のパターンに従います。

sources:
  syslog_in:
    type: "syslog"
    address: "0.0.0.0:514"
    mode: "tcp"

transforms:
  clean_logs:
    type: "remap"
    inputs:
      - "syslog_in"
    source: |
      # JSONとしてパースを試行。生テキストの場合は無視
      parsed, err = parse_json(.message)
      if err == null {
        . = merge(., parsed)
      }

      # デプロイコンテキストを注入
      .env = "production"
      .cluster = "k8s-us-east"
      
      # クレジットカード番号の可能性がある箇所をマスク
      .message = redact(.message, filters: [r'\d{4}-\d{4}-\d{4}-\d{4}'])

sinks:
  clickhouse_out:
    type: "clickhouse"
    inputs:
      - "clean_logs"
    endpoint: "http://clickhouse-internal:8123"
    table: "logs"
    database: "observability"

  s3_archive:
    type: "aws_s3"
    inputs:
      - "clean_logs"
    bucket: "prod-log-archive"
    region: "us-east-1"
    compression: "gzip"
    encoding:
      codec: "ndjson"

3. 検証:実行前に確認

Vectorの過小評価されている機能の一つに、内蔵バリデータがあります。本番のロギングを停止させる前に、構文エラーをキャッチできます。

vector validate --config vector.yaml
vector --config vector.yaml

4. VRLによるロジック記述

VRLを使用すると、複雑なGrokパターンをネストする代わりに、可読性の高いロジックを記述できます。例えば、遅いAPIリクエストにフラグを立てる場合は以下のようになります:

.duration_ms = to_float!(.response_time) * 1000.0
.is_slow = .duration_ms > 500

if .is_slow {
  .priority = "high"
  .tags = push(.tags, "performance-alert")
}

このアプローチにより、ログパイプラインをアプリケーションコードと同じように保守・テスト可能にできます。

最後に

Vectorへの移行は、単にCPUサイクルのクラウド費用を節約するためだけではありません。データストリームを完全に制御するためでもあります。パフォーマンスの向上は疑いようもありませんが、本当のメリットは安定性です。LogstashのヒープエラーやFluentdのプラグイン競合に疲弊しているなら、まずは単一のサービスでVectorのパイロット運用を始めてみてください。もう元には戻れなくなるはずです。

Share: