VictoriaLogsが良かったという話

# はじめに

* VictoriaLogsを検証してみて、その性能に惚れました
* 可用性に難があるという大きすぎる欠点はあるものの、ハマるところが絶対あるし今後改良されるはずなので知名度を上げたい
* Qiitaに1件も記事がねぇ！記事あげるしかねぇ！
* 信頼と実績のVictoriaMetrics社製

# VictoriaLogsとは

公式はこちら https://victoriametrics.com/products/victorialogs/

ドキュメント・マニュアル https://docs.victoriametrics.com/victorialogs/

まず、こちらのリリースを見ましょう。 https://victoriametrics.com/blog/victorialogs-release/

正直、悪意のある恣意的なグラフが並んでる（一番下が0じゃねぇ！）のであれですが、実際使ってみて書いてること自体は正しそうだと思っています。

# VictoriaLogsの概要

VictoriaLogsの概要をまとめると、以下の通りです。
s
- ログ管理OSSソリューション Trace Log MetricsのLogに該当する
- ElasticSearchやLokiと比較しても、非常に高性能・高圧縮率の利用が可能となっている
- 非常に新しいソフトウェアであり、機能はまだまだ追加中であるが、個人的には既に大体必要なものは動く状態になっていると言っていい
- クラスタ化機能が現在不足しているが、Kubernetesレベルの障害耐性程度で問題なければ非常にいい！
- Fluent-bitやPromtail、VectorやFilebeatなど様々な転送アプリに対応しており、各々に向けたドキュメントも提供


# 検証環境

個人的に検証用に構築したKubernetesクラスタにて、VictoriaLogsを普通に使ってみました。

- Fedora CoreOS × k3s kubernetes cluster
- 6ノード うち前半3ノードはmaster役割を含むノード、後半3ノードはworkerノード
- 以下のアプリケーションをHelmなどでインストール済み
  - Cilium CNI
  - Prometheus(kube-prometheus-stack)
  - Fleetlock(OSの自動アップデート)
  - MetalLB(VIP)
  - Traefik(Ingress)
  - argocd
  - k8sdashboard
  - fluent-bit(log agent)
  - zabbix
  - grafana
  - VictoriaMetrics
  - VictoriaLogs
  - minio
  - loki

# 現在のデータ量とか状態

| 項目 | 状態 | 備考とか感想とか |
| :---- | :---- | :---- |
| 現行ストレージ行数 | 117,508,789 | およそ136日分 |
| ログ取り込み速度 | 平均10行/秒 | |
| 未圧縮ログデータ量 | 135 GiB | |
| 圧縮後・ストレージ量 | 2.42 GiB | 1.8% !!!! | 
| CPU使用量 | 0.0141 | 検索クエリを投げている(stats countもしてるし、filterもしてる)のに、ぴくりともしない |
| メモリ使用量(WSS) | 182 MiB | ElasticやLokiと比較して恐ろしく小さい |

# WebUIについて

WebUIには、以下の機能があります。

- 検索クエリ(LogQL)を投げて、検索する
- 日時はElasticSearchやGrafanaと同様のインタフェースで指定可能
- 検索画面にはヒストグラムが表示される
- カラムを絞ってテーブル出力する機能（ただし、保存する機能はないので、今はクエリ側で絞る方が早い）

以下のような親切な機能はありませんので、本格的な可視化にはGrafanaを使いましょう。

- CSV出力
- Viewの保存機能
- 画面から簡単に使えるフィルタ機能
- 認証とか権限管理とか

# Grafanaのダッシュボード対応

現状、まだ公式の承認済みプラグインとしてはインストールできませんので、オプションを入れたりする対応を行います。

https://github.com/VictoriaMetrics/victorialogs-datasource

2024/7/1に試した現在、以下が問題なく対応できています。

- Table パネルへの対応
- Count Statsを使った各種可視化への対応
- Logs パネルへの対応

特に、気付いたらLogsパネルでの対応が進んでいたため、既にGrafana Lokiと同じ使用感で使えます。Logsテーブルは似てる行をまとめてくれる機能やSeverityっぽい文字列を見つけたらそれっぽく行に色を付けてくれる機能がお気に入りです。

# 実際どう？

- とっても検索が早い！文字列検索して1000件のデータを取っても、秒で返ってくる！
- Grafanaで数件可視化含めて登録しても一瞬で画面が出るので、何かおかしいのではと思ってしまうほど
- メモリ管理、ストレージ管理しなくてもいいくらいに省エネで動いているので、ものすごく助かる
- ローリングアップデート時でも問題なく動くように可用性を担保するアーキテクチャがまだ無いので、例えばkubernetesのアップデート中はログが欠落する(といってもエージェント側)
- 管理するのに必要なメトリクスを既に備えており、Prometheusで監視が出来る
- より大量のログの環境で動作させるとどうなるか、まだ未知数 しかし100行/秒は問題なさそう

# 考える使い処

まず、現在のVictoriaLogsはクラスタリングに対応していないため、本番環境でクリティカルな要件に対して使うことはあまり望ましくないと思います。

一方で、お金ないんだけどとりあえずログがなんかみれたら良いな…くらいの温度感のクラスタに対して、クラスタ1台につき1つ動かして見えるようにしておく分にはとても良さそうです。

# 設定

設定については大体公式ドキュメント記載の通りではありますが、一応手元の環境の記載しておきます。

## fluent-bitの設定

fluent-bit を https://fluent.github.io/helm-charts のHelmリポジトリからインストールしています。インストール方法は省略。
Helmに食わせるvalues.yamlは以下のような形でログをVictoriaLogsに投入しています。

```yaml
kind: DaemonSet
testFramework:
  enabled: false
logLevel: warn

## https://docs.fluentbit.io/manual/administration/configuring-fluent-bit/classic-mode/configuration-file
config:
  outputs: |
    [OUTPUT]
        Name http
        Match kube.*
        Host vmlogs-select.victorialogs   ← 適宜修正
        port 9428
        compress gzip
        uri /insert/jsonline?_stream_fields=stream,kubernetes_pod_name,kubernetes_container_name,kubernetes_host&_msg_field=log&_time_field=date
        format json_lines
        json_date_format iso8601
        header AccountID 0
        header ProjectID 0
  filters: |
    [FILTER]
        Name kubernetes
        Match kube.*
        Merge_Log On
        Keep_Log On
        K8S-Logging.Parser On
        K8S-Logging.Exclude On
    [FILTER]
        Name                nest
        Match               *
        Wildcard            pod_name
        Operation lift
        Nested_under kubernetes
        Add_prefix   kubernetes_


# The config volume is mounted by default, either to the existingConfigMap value, or the default of "fluent-bit.fullname"
volumeMounts:
  - name: config
    mountPath: /fluent-bit/etc/conf

daemonSetVolumes:
  - name: varlog
    hostPath:
      path: /var/log
  - name: varlibdockercontainers
    hostPath:
      path: /var/lib/docker/containers

daemonSetVolumeMounts:
  - name: varlog
    mountPath: /var/log
  - name: varlibdockercontainers
    mountPath: /var/lib/docker/containers
    readOnly: true
```

## VictoriaLogsの設定

VictoriaLogsも https://victoriametrics.github.io/helm-charts/ の victoria-logs-single チャートからインストールします。
なお、このチャートからfluent-bitもインストールできますが、他のクラスタにもfluent-bitをインストールするため分けました。

```yaml
printNotes: true

server:
  enabled: true
  name: server
  image:
    repository: victoriametrics/victoria-logs
    tag: "v0.26.1-victorialogs"
    pullPolicy: IfNotPresent
  # -- Data retention period in month
  retentionPeriod: 180d

  persistentVolume:
    enabled: true
    accessModes:
      - ReadWriteOnce
    storageClass: "trident"
    size: 50Gi

  resources:
    requests:
      cpu: 100m
      memory: 256Mi

  ingress:
    enabled: true
    hosts: 
      - name: vmlogs.example.com
        path: /
        port: http
    tls: []
    pathType: Prefix

  statefulSet:
    enabled: true
  terminationGracePeriodSeconds: 60
  serviceMonitor:
    enabled: true

fluent-bit:
  enabled: false
```

# LogsQLについて

マニュアルは[こちら](https://docs.victoriametrics.com/victorialogs/logsql/)

基本的にVictoriaLogsのログは以下の既定のフィールドを持っています。

| フィールド名 | 説明 |
| :---- | :---- |
| _time | ログタイムスタンプ |
| _stream | ログのStreamを形作るラベルのグループ |
| _msg | ログメッセージ本文 |

ログにはユーザやシステムで付けたラベルが付けられています。Kubernetes上の場合、fluent-bitが以下のようなラベルを付与してます。

| フィールド名 | 説明 |
| :---- | :---- |
| kubernetes_container_hash | コンテナハッシュ |
| kubernetes_container_image | コンテナイメージ名 |
| kubernetes_container_name | コンテナ名 |
| kubernetes_host | kubernetesホスト名 |
| kubernetes_namespace_name | 名前空間 |
| kubernetes_pod_id | podのID |
| kubernetes_pod_name | pod名 |

これらの情報に対して、クエリ言語であるLogsQLを通して検索を行います。
正直この年齢になって新しくログのQueryLanguage覚えるのもな…と思っていましたが、なかなかどうして単に検索するだけなら意外と直感的に使えました。

雑な全文検索をしたい場合は、以下のように検索すればいいです。なお、デフォルトで部分一致検索です。

```
検索したい言葉
```

コンテナ名で絞った上で検索したい場合は、以下のようにします。

```
kubernetes_container_name:"コンテナ名" 検索したい言葉
```

この検索では全ラベルをデータとして持ってくるため、絞るためには以下のようにします。パイプを使って処理を繋げていくことができる、流行りの言語になっています。

```
kubernetes_container_name:"コンテナ名" 検索したい言葉
| fields _time,kubernetes_container_name,kubernetes_pod_name,_msg
```