人間またはエイリアンテクノロジーの ClickHouse データベース

MKB 情報技術総局リモート サービス チャネル コンピテンス センター所長、Aleksey Lizunov 氏

人間またはエイリアンテクノロジーの ClickHouse データベース

ELK スタック (ElasticSearch、Logstash、Kibana) の代替として、ClickHouse データベースをログのデータ ストアとして使用する研究を行っています。

この記事では、ClickHouse データベースの使用経験とパイロット運用の暫定結果についてお話したいと思います。 結果が印象的であったことにすぐに注目してください。


人間またはエイリアンテクノロジーの ClickHouse データベース

次に、システムがどのように構成され、どのようなコンポーネントで構成されているかについて詳しく説明します。 ここで、このデータベース全体について、そしてなぜ注目する価値があるのか​​について少しお話したいと思います。 ClickHouse データベースは、Yandex の高性能分析カラム型データベースです。 これは Yandex サービスで使用され、当初は Yandex.Metrica のメイン データ ストレージでした。 オープンソース システム、無料。 開発者の観点から見ると、途方もないビッグデータがあるので、どうやって実装したのかいつも不思議に思っていました。 また、Metrica のユーザー インターフェイス自体は非常に柔軟で高速です。 このデータベースを初めて知ったときの印象は次のとおりです。 人々のために作られました! インストールプロセスから始まり、リクエストの送信で終わります。

このデータベースのエントリしきい値は非常に低いです。 平均的なスキルを持つ開発者でも、このデータベースを数分でインストールして使用を開始できます。 すべてが明確に機能します。 Linux を初めて使用する人でも、インストールと最も簡単な操作をすぐに実行できます。 以前は、ビッグ データ、Hadoop、Google BigTable、HDFS という言葉を聞いて、普通の開発者がそれが数テラバイト、ペタバイト程度であり、これらのシステムの設定や開発には超人が関与しているのではないかという考えを持っていたとしたら、ClickHouse データベースの出現により、以前は達成できなかった範囲のタスクを解決できる、シンプルでわかりやすいツールを手に入れることができました。 インストールにはごく平均的なマシン XNUMX 台と XNUMX 分しかかかりません。 つまり、たとえば MySql のようなデータベースを入手しましたが、それは数十億のレコードを保存するためだけにすぎませんでした。 SQL言語を扱うとあるスーパーアーカイバ。 人類がエイリアンの武器を渡されたようなものだ。

ロギングシステムについて

情報収集には、標準形式の Web アプリケーションの IIS ログ ファイルが使用されます (現在、アプリケーション ログも解析中ですが、パイロット段階の主な目的は IIS ログを収集することです)。

さまざまな理由から、私たちは ELK スタックを完全に放棄することができず、LogStash コンポーネントと Filebeat コンポーネントを引き続き使用しています。これらのコンポーネントは十分に実証されており、非常に信頼性が高く、予測どおりに動作します。

一般的なログ記録スキームを次の図に示します。

人間またはエイリアンテクノロジーの ClickHouse データベース

ClickHouse データベースにデータを書き込む機能の XNUMX つは、大規模なバッチでレコードが頻繁に (XNUMX 秒に XNUMX 回) 挿入されることです。 どうやら、これは、ClickHouse データベースの操作を初めて経験するときに遭遇する最も「問題のある」部分です。スキームは少し複雑になります。
ここでは、ClickHouse にデータを直接挿入する LogStash のプラグインが非常に役立ちました。 このコンポーネントは、データベース自体と同じサーバーにデプロイされます。 したがって、一般的には、これを行うことはお勧めしませんが、同じサーバー上にデプロイされている間に別のサーバーが作成されないようにするための実用的な観点からです。 データベースとの障害やリソースの競合は観察されませんでした。 さらに、プラグインにはエラーが発生した場合の再試行メカニズムがあることに注意してください。 また、エラーが発生した場合、プラグインは挿入できなかったデータのバッチをディスクに書き込みます (このファイル形式は便利です。編集後、clickhouse-client を使用して修正したバッチを簡単に挿入できます)。

このスキームで使用されるソフトウェアの完全なリストを表に示します。

使用ソフト一覧

名前

説明

配布リンク

nginxの

リバースプロキシでポートごとにアクセスを制限し、認可を整理する

現在、このスキームでは使用されていません

https://nginx.org/ru/download.html

https://nginx.org/download/nginx-1.16.0.tar.gz

ファイルビート

ファイルログの転送。

https://www.elastic.co/downloads/beats/filebeat (Windows 64 ビット用の配布キット)。

https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.3.0-windows-x86_64.zip

ログスタッシュ

ログコレクター。

FileBeat からのログの収集と、(DMZ 内にあるサーバーの) RabbitMQ キューからのログの収集に使用されます。

https://www.elastic.co/products/logstash

https://artifacts.elastic.co/downloads/logstash/logstash-7.0.1.rpm

Logstash 出力クリックハウス

ログを ClickHouse データベースにバッチで転送するための Loagstash プラグイン

https://github.com/mikechris/logstash-output-clickhouse

/usr/share/logstash/bin/logstash-plugin logstash-output-clickhouse をインストールします

/usr/share/logstash/bin/logstash-plugin logstash-filter-prune をインストールします

/usr/share/logstash/bin/logstash-plugin logstash-filter-multiline をインストールします

クリックハウス

ログストレージ https://clickhouse.yandex/docs/ru/

https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-server-19.5.3.8-1.el7.x86_64.rpm

https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-client-19.5.3.8-1.el7.x86_64.rpm

ノート。 2018 年 XNUMX 月以降、RHEL 用の「通常の」 rpm ビルドが Yandex リポジトリに登場したので、それらを使用してみることができます。 インストール時には、Altinity によって構築されたパッケージを使用していました。

グラファナ

ログの可視化。 ダッシュボードのセットアップ

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos(64 ビット) - 最新バージョン

Grafana 4.6 以降の ClickHouse データソース

ClickHouse データ ソースを使用した Grafana 用プラグイン

https://grafana.com/plugins/vertamedia-clickhouse-datasource

https://grafana.com/api/plugins/vertamedia-clickhouse-datasource/versions/1.8.1/download

ログスタッシュ

FileBeat から RabbitMQ キューへのログルーター。

ノート。 残念ながら、FileBeat には RabbitMQ への直接出力がないため、Logstash 形式の中間リンクが必要です。

https://www.elastic.co/products/logstash

https://artifacts.elastic.co/downloads/logstash/logstash-7.0.1.rpm

RabbitMQの

メッセージキュー。 これはDMZ内のログバッファです

https://www.rabbitmq.com/download.html

https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.14/rabbitmq-server-3.7.14-1.el7.noarch.rpm

Erlang ランタイム (RabbitMQ に必要)

Erlang ランタイム。 RabbitMQ が動作するために必要です

http://www.erlang.org/download.html

https://www.rabbitmq.com/install-rpm.html#install-erlang http://www.erlang.org/downloads/21.3

ClickHouse データベースを使用したサーバー構成を次の表に示します。

名前

注意

設定

HDD:40GB
RAM:8GB
プロセッサー: Core 2 2Ghz

ClickHouseデータベースを運用する際の注意点(https://clickhouse.yandex/docs/ru/operations/tips/)

システムソフトウェア全般

OS:Red Hat Enterprise Linux Server(Maipo)

JRE (Java 8)

 

ご覧のとおり、これは普通のワークステーションです。

ログを保存するテーブルの構造は次のとおりです。

log_web.sql

CREATE TABLE log_web (
  logdate Date,
  logdatetime DateTime CODEC(Delta, LZ4HC),
   
  fld_log_file_name LowCardinality( String ),
  fld_server_name LowCardinality( String ),
  fld_app_name LowCardinality( String ),
  fld_app_module LowCardinality( String ),
  fld_website_name LowCardinality( String ),
 
  serverIP LowCardinality( String ),
  method LowCardinality( String ),
  uriStem String,
  uriQuery String,
  port UInt32,
  username LowCardinality( String ),
  clientIP String,
  clientRealIP String,
  userAgent String,
  referer String,
  response String,
  subresponse String,
  win32response String,
  timetaken UInt64
   
  , uriQuery__utm_medium String
  , uriQuery__utm_source String
  , uriQuery__utm_campaign String
  , uriQuery__utm_term String
  , uriQuery__utm_content String
  , uriQuery__yclid String
  , uriQuery__region String
 
) Engine = MergeTree()
PARTITION BY toYYYYMM(logdate)
ORDER BY (fld_app_name, fld_app_module, logdatetime)
SETTINGS index_granularity = 8192;

デフォルトのパーティション分割 (月ごと) とインデックスの粒度を使用します。 すべてのフィールドは、実質的に http 要求を記録するための IIS ログ エントリに対応します。 これとは別に、utm タグを保存するための別のフィールドがあることに注意してください (クエリ文字列フィールドからテーブルに挿入する段階で解析されます)。

また、システム、コンポーネント、サーバーに関する情報を保存するために、いくつかのシステム フィールドがテーブルに追加されました。 これらのフィールドの説明については、以下の表を参照してください。 XNUMX つのテーブルに、複数のシステムのログを保存します。

名前

説明

fld_app_name

アプリケーション/システム名
有効な値:

  • site1.domain.com 外部サイト 1
  • site2.domain.com 外部サイト 2
  • Internal-site1.domain.local 内部サイト 1

site1.domain.com

fld_app_module

システムモジュール
有効な値:

  • ウェブ - ウェブサイト
  • svc - Web サイト サービス
  • intgr - 統合 Web サービス
  • bo - 管理者 (バックオフィス)

ウェブ

fld_ウェブサイト名

IIS のサイト名

複数のシステムを XNUMX 台のサーバーに配置することも、XNUMX つのシステム モジュールの複数のインスタンスを配置することもできます

ウェブメイン

fld_サーバー名

サーバー名

web1.domain.com

fld_log_file_name

サーバー上のログ ファイルへのパス

C:inetpublogsログファイル
W3SVC1u_ex190711.log

これにより、Grafana でグラフを効率的に構築できるようになります。 たとえば、特定のシステムのフロントエンドからのリクエストを表示します。 これは、Yandex.Metrica のサイトカウンターに似ています。

ここでは、XNUMX か月間のデータベースの使用に関する統計をいくつか示します。

システムとそのコンポーネントごとに分類されたレコードの数

SELECT
    fld_app_name,
    fld_app_module,
    count(fld_app_name) AS rows_count
FROM log_web
GROUP BY
    fld_app_name,
    fld_app_module
    WITH TOTALS
ORDER BY
    fld_app_name ASC,
    rows_count DESC
 
┌─fld_app_name─────┬─fld_app_module─┬─rows_count─┐
│ site1.domain.ru  │ web            │     131441 │
│ site2.domain.ru  │ web            │    1751081 │
│ site3.domain.ru  │ web            │  106887543 │
│ site3.domain.ru  │ svc            │   44908603 │
│ site3.domain.ru  │ intgr          │    9813911 │
│ site4.domain.ru  │ web            │     772095 │
│ site5.domain.ru  │ web            │   17037221 │
│ site5.domain.ru  │ intgr          │     838559 │
│ site5.domain.ru  │ bo             │       7404 │
│ site6.domain.ru  │ web            │     595877 │
│ site7.domain.ru  │ web            │   27778858 │
└──────────────────┴────────────────┴────────────┘
 
Totals:
┌─fld_app_name─┬─fld_app_module─┬─rows_count─┐
│              │                │  210522593 │
└──────────────┴────────────────┴────────────┘
 
11 rows in set. Elapsed: 4.874 sec. Processed 210.52 million rows, 421.67 MB (43.19 million rows/s., 86.51 MB/s.)

ディスク上のデータ量

SELECT
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed,
    sum(rows) AS total_rows
FROM system.parts
WHERE table = 'log_web'
 
┌─uncompressed─┬─compressed─┬─total_rows─┐
│ 54.50 GiB    │ 4.86 GiB   │  211427094 │
└──────────────┴────────────┴────────────┘
 
1 rows in set. Elapsed: 0.035 sec.

列のデータ圧縮の程度

SELECT
    name,
    formatReadableSize(data_uncompressed_bytes) AS uncompressed,
    formatReadableSize(data_compressed_bytes) AS compressed,
    data_uncompressed_bytes / data_compressed_bytes AS compress_ratio
FROM system.columns
WHERE table = 'log_web'
 
┌─name───────────────────┬─uncompressed─┬─compressed─┬─────compress_ratio─┐
│ logdate                │ 401.53 MiB   │ 1.80 MiB   │ 223.16665968777315 │
│ logdatetime            │ 803.06 MiB   │ 35.91 MiB  │ 22.363966401202305 │
│ fld_log_file_name      │ 220.66 MiB   │ 2.60 MiB   │  84.99905736932571 │
│ fld_server_name        │ 201.54 MiB   │ 50.63 MiB  │  3.980924816977078 │
│ fld_app_name           │ 201.17 MiB   │ 969.17 KiB │ 212.55518183686877 │
│ fld_app_module         │ 201.17 MiB   │ 968.60 KiB │ 212.67805817411906 │
│ fld_website_name       │ 201.54 MiB   │ 1.24 MiB   │  162.7204926761546 │
│ serverIP               │ 201.54 MiB   │ 50.25 MiB  │  4.010824061219731 │
│ method                 │ 201.53 MiB   │ 43.64 MiB  │  4.617721053304486 │
│ uriStem                │ 5.13 GiB     │ 832.51 MiB │  6.311522291936919 │
│ uriQuery               │ 2.58 GiB     │ 501.06 MiB │  5.269731450124478 │
│ port                   │ 803.06 MiB   │ 3.98 MiB   │ 201.91673864241824 │
│ username               │ 318.08 MiB   │ 26.93 MiB  │ 11.812513794583598 │
│ clientIP               │ 2.35 GiB     │ 82.59 MiB  │ 29.132328640073343 │
│ clientRealIP           │ 2.49 GiB     │ 465.05 MiB │  5.478382297052563 │
│ userAgent              │ 18.34 GiB    │ 764.08 MiB │  24.57905114484208 │
│ referer                │ 14.71 GiB    │ 1.37 GiB   │ 10.736792723669906 │
│ response               │ 803.06 MiB   │ 83.81 MiB  │  9.582334090987247 │
│ subresponse            │ 399.87 MiB   │ 1.83 MiB   │  218.4831068635027 │
│ win32response          │ 407.86 MiB   │ 7.41 MiB   │ 55.050315514606815 │
│ timetaken              │ 1.57 GiB     │ 402.06 MiB │ 3.9947395692010637 │
│ uriQuery__utm_medium   │ 208.17 MiB   │ 12.29 MiB  │ 16.936148912472955 │
│ uriQuery__utm_source   │ 215.18 MiB   │ 13.00 MiB  │ 16.548367623199912 │
│ uriQuery__utm_campaign │ 381.46 MiB   │ 37.94 MiB  │ 10.055156353418509 │
│ uriQuery__utm_term     │ 231.82 MiB   │ 10.78 MiB  │ 21.502540454070672 │
│ uriQuery__utm_content  │ 441.34 MiB   │ 87.60 MiB  │  5.038260760449327 │
│ uriQuery__yclid        │ 216.88 MiB   │ 16.58 MiB  │  13.07721335008116 │
│ uriQuery__region       │ 204.35 MiB   │ 9.49 MiB   │  21.52661903446796 │
└────────────────────────┴──────────────┴────────────┴────────────────────┘
 
28 rows in set. Elapsed: 0.005 sec.

使用コンポーネントの説明

ファイルビート。 ファイルログの転送

このコンポーネントは、ディスク上のログ ファイルへの変更を追跡し、情報を LogStash に渡します。 ログ ファイルが書き込まれるすべてのサーバー (通常は IIS) にインストールされます。 末尾モードで動作します (つまり、追加されたレコードのみをファイルに転送します)。 ただし、ファイル全体を転送するように個別に設定できます。 これは、前月のデータをダウンロードする必要がある場合に便利です。 ログ ファイルをフォルダーに置くだけで、ログ ファイル全体が読み取られます。

サービスが停止されると、データはそれ以上ストレージに転送されなくなります。

構成例は次のようになります。

ファイルビート.yml

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - C:/inetpub/logs/LogFiles/W3SVC1/*.log
  exclude_files: ['.gz$','.zip$']
  tail_files: true
  ignore_older: 24h
  fields:
    fld_server_name: "site1.domain.ru"
    fld_app_name: "site1.domain.ru"
    fld_app_module: "web"
    fld_website_name: "web-main"
 
- type: log
  enabled: true
  paths:
    - C:/inetpub/logs/LogFiles/__Import/access_log-*
  exclude_files: ['.gz$','.zip$']
  tail_files: false
  fields:
    fld_server_name: "site2.domain.ru"
    fld_app_name: "site2.domain.ru"
    fld_app_module: "web"
    fld_website_name: "web-main"
    fld_logformat: "logformat__apache"
 
 
filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false
  reload.period: 2s
 
output.logstash:
  hosts: ["log.domain.com:5044"]
 
  ssl.enabled: true
  ssl.certificate_authorities: ["C:/filebeat/certs/ca.pem", "C:/filebeat/certs/ca-issuing.pem"]
  ssl.certificate: "C:/filebeat/certs/site1.domain.ru.cer"
  ssl.key: "C:/filebeat/certs/site1.domain.ru.key"
 
#================================ Processors =====================================
 
processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~

ログスタッシュ。 ログコレクター

このコンポーネントは、FileBeat から (または RabbitMQ キューを通じて) ログ エントリを受信し、解析してバッチを ClickHouse データベースに挿入するように設計されています。

ClickHouse への挿入には、Logstash-output-clickhouse プラグインが使用されます。 Logstash プラグインにはリクエストの再試行メカニズムがありますが、定期的にシャットダウンする場合は、サービス自体を停止することをお勧めします。 停止するとRabbitMQキューにメッセージが溜まってしまうため、長時間停止する場合はサーバー上のFilebeatsを停止した方がよいでしょう。 RabbitMQ が使用されないスキーム (ローカル ネットワーク上では、Filebeat がログを Logstash に直接送信します) では、Filebeat は非常に許容範囲内で安全に動作するため、出力が利用できないことは影響を受けません。

構成例は次のようになります。

log_web__filebeat_clickhouse.conf

input {
 
    beats {
        port => 5044
        type => 'iis'
        ssl => true
        ssl_certificate_authorities => ["/etc/logstash/certs/ca.cer", "/etc/logstash/certs/ca-issuing.cer"]
        ssl_certificate => "/etc/logstash/certs/server.cer"
        ssl_key => "/etc/logstash/certs/server-pkcs8.key"
        ssl_verify_mode => "peer"
 
            add_field => {
                "fld_server_name" => "%{[fields][fld_server_name]}"
                "fld_app_name" => "%{[fields][fld_app_name]}"
                "fld_app_module" => "%{[fields][fld_app_module]}"
                "fld_website_name" => "%{[fields][fld_website_name]}"
                "fld_log_file_name" => "%{source}"
                "fld_logformat" => "%{[fields][fld_logformat]}"
            }
    }
 
    rabbitmq {
        host => "queue.domain.com"
        port => 5671
        user => "q-reader"
        password => "password"
        queue => "web_log"
        heartbeat => 30
        durable => true
        ssl => true
        #ssl_certificate_path => "/etc/logstash/certs/server.p12"
        #ssl_certificate_password => "password"
 
        add_field => {
            "fld_server_name" => "%{[fields][fld_server_name]}"
            "fld_app_name" => "%{[fields][fld_app_name]}"
            "fld_app_module" => "%{[fields][fld_app_module]}"
            "fld_website_name" => "%{[fields][fld_website_name]}"
            "fld_log_file_name" => "%{source}"
            "fld_logformat" => "%{[fields][fld_logformat]}"
        }
    }
 
}
 
filter { 
 
      if [message] =~ "^#" {
        drop {}
      }
 
      if [fld_logformat] == "logformat__iis_with_xrealip" {
     
          grok {
            match => ["message", "%{TIMESTAMP_ISO8601:log_timestamp} %{IP:serverIP} %{WORD:method} %{NOTSPACE:uriStem} %{NOTSPACE:uriQuery} %{NUMBER:port} %{NOTSPACE:username} %{IPORHOST:clientIP} %{NOTSPACE:userAgent} %{NOTSPACE:referer} %{NUMBER:response} %{NUMBER:subresponse} %{NUMBER:win32response} %{NUMBER:timetaken} %{NOTSPACE:xrealIP} %{NOTSPACE:xforwarderfor}"]
          }
      } else {
   
          grok {
             match => ["message", "%{TIMESTAMP_ISO8601:log_timestamp} %{IP:serverIP} %{WORD:method} %{NOTSPACE:uriStem} %{NOTSPACE:uriQuery} %{NUMBER:port} %{NOTSPACE:username} %{IPORHOST:clientIP} %{NOTSPACE:userAgent} %{NOTSPACE:referer} %{NUMBER:response} %{NUMBER:subresponse} %{NUMBER:win32response} %{NUMBER:timetaken}"]
          }
 
      }
 
      date {
        match => [ "log_timestamp", "YYYY-MM-dd HH:mm:ss" ]
          timezone => "Etc/UTC"
        remove_field => [ "log_timestamp", "@timestamp" ]
        target => [ "log_timestamp2" ]
      }
 
        ruby {
            code => "tstamp = event.get('log_timestamp2').to_i
                        event.set('logdatetime', Time.at(tstamp).strftime('%Y-%m-%d %H:%M:%S'))
                        event.set('logdate', Time.at(tstamp).strftime('%Y-%m-%d'))"
        }
 
      if [bytesSent] {
        ruby {
          code => "event['kilobytesSent'] = event['bytesSent'].to_i / 1024.0"
        }
      }
 
 
      if [bytesReceived] {
        ruby {
          code => "event['kilobytesReceived'] = event['bytesReceived'].to_i / 1024.0"
        }
      }
 
   
        ruby {
            code => "event.set('clientRealIP', event.get('clientIP'))"
        }
        if [xrealIP] {
            ruby {
                code => "event.set('clientRealIP', event.get('xrealIP'))"
            }
        }
        if [xforwarderfor] {
            ruby {
                code => "event.set('clientRealIP', event.get('xforwarderfor'))"
            }
        }
 
      mutate {
        convert => ["bytesSent", "integer"]
        convert => ["bytesReceived", "integer"]
        convert => ["timetaken", "integer"] 
        convert => ["port", "integer"]
 
        add_field => {
            "clientHostname" => "%{clientIP}"
        }
      }
 
        useragent {
            source=> "useragent"
            prefix=> "browser"
        }
 
        kv {
            source => "uriQuery"
            prefix => "uriQuery__"
            allow_duplicate_values => false
            field_split => "&"
            include_keys => [ "utm_medium", "utm_source", "utm_campaign", "utm_term", "utm_content", "yclid", "region" ]
        }
 
        mutate {
            join => { "uriQuery__utm_source" => "," }
            join => { "uriQuery__utm_medium" => "," }
            join => { "uriQuery__utm_campaign" => "," }
            join => { "uriQuery__utm_term" => "," }
            join => { "uriQuery__utm_content" => "," }
            join => { "uriQuery__yclid" => "," }
            join => { "uriQuery__region" => "," }
        }
 
}
 
output { 
  #stdout {codec => rubydebug}
    clickhouse {
      headers => ["Authorization", "Basic abcdsfks..."]
      http_hosts => ["http://127.0.0.1:8123"]
      save_dir => "/etc/logstash/tmp"
      table => "log_web"
      request_tolerance => 1
      flush_size => 10000
      idle_flush_time => 1
        mutations => {
            "fld_log_file_name" => "fld_log_file_name"
            "fld_server_name" => "fld_server_name"
            "fld_app_name" => "fld_app_name"
            "fld_app_module" => "fld_app_module"
            "fld_website_name" => "fld_website_name"
 
            "logdatetime" => "logdatetime"
            "logdate" => "logdate"
            "serverIP" => "serverIP"
            "method" => "method"
            "uriStem" => "uriStem"
            "uriQuery" => "uriQuery"
            "port" => "port"
            "username" => "username"
            "clientIP" => "clientIP"
            "clientRealIP" => "clientRealIP"
            "userAgent" => "userAgent"
            "referer" => "referer"
            "response" => "response"
            "subresponse" => "subresponse"
            "win32response" => "win32response"
            "timetaken" => "timetaken"
             
            "uriQuery__utm_medium" => "uriQuery__utm_medium"
            "uriQuery__utm_source" => "uriQuery__utm_source"
            "uriQuery__utm_campaign" => "uriQuery__utm_campaign"
            "uriQuery__utm_term" => "uriQuery__utm_term"
            "uriQuery__utm_content" => "uriQuery__utm_content"
            "uriQuery__yclid" => "uriQuery__yclid"
            "uriQuery__region" => "uriQuery__region"
        }
    }
 
}

パイプライン.yml

# This file is where you define your pipelines. You can define multiple.
# For more information on multiple pipelines, see the documentation:
#   https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html
 
- pipeline.id: log_web__filebeat_clickhouse
  path.config: "/etc/logstash/log_web__filebeat_clickhouse.conf"

クリックハウス。 ログストレージ

すべてのシステムのログは XNUMX つのテーブルに保存されます (記事の冒頭を参照)。 これは、リクエストに関する情報を保存することを目的としています。すべてのパラメーターは、IIS ログ、Apache、nginx ログなどのさまざまな形式で類似しています。 エラー、情報メッセージ、警告などが記録されるアプリケーション ログについては、適切な構造を備えた別のテーブルが提供されます (現在設計段階)。

テーブルを設計するときは、主キー (格納中にデータを並べ替えるためのキー) を決定することが非常に重要です。 データ圧縮の程度とクエリ速度はこれに依存します。 この例では、キーは次のとおりです。
ORDER BY (fld_app_name、fld_app_module、logdatetime)
つまり、システムの名前、システム コンポーネントの名前、およびイベントの日付によって決まります。 当初は開催日が先だった。 これを最後の場所に移動した後、クエリは約 XNUMX 倍の速度で動作するようになりました。 主キーを変更するには、ClickHouse がディスク上のデータを再ソートできるように、テーブルを再作成してデータを再ロードする必要があります。 これは重い操作なので、ソートキーに何を含めるかについてよく考えることをお勧めします。

LowCardinality データ型は比較的最近のバージョンで登場したことにも注意してください。 これを使用すると、カーディナリティが低い (オプションが少ない) フィールドの圧縮データのサイズが大幅に削減されます。

現在バージョン 19.6 が使用されていますが、最新バージョンへの更新を試みる予定です。 たとえば、Adaptive Granularity、Skipping Index、DoubleDelta コーデックなどの素晴らしい機能を備えています。

デフォルトでは、インストール時にログ レベルがトレースに設定されます。 ログはローテーションおよびアーカイブされますが、同時に最大 XNUMX GB まで拡張されます。 必要がない場合は、警告レベルを設定すると、ログのサイズが大幅に削減されます。 ログ設定は config.xml ファイルで設定されます。

<!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger. h#L105 -->
<level>warning</level>

いくつかの便利なコマンド

Поскольку оригинальные пакеты установки собираются по Debian, то для других версий Linux необходимо использовать пакеты собранные компанией Altinity.
 
Вот по этой ссылке есть инструкции с ссылками на их репозиторий: https://www.altinity.com/blog/2017/12/18/logstash-with-clickhouse
sudo yum search clickhouse-server
sudo yum install clickhouse-server.noarch
  
1. проверка статуса
sudo systemctl status clickhouse-server
 
2. остановка сервера
sudo systemctl stop clickhouse-server
 
3. запуск сервера
sudo systemctl start clickhouse-server
 
Запуск для выполнения запросов в многострочном режиме (выполнение после знака ";")
clickhouse-client --multiline
clickhouse-client --multiline --host 127.0.0.1 --password pa55w0rd
clickhouse-client --multiline --host 127.0.0.1 --port 9440 --secure --user default --password pa55w0rd
 
Плагин кликлауза для логстеш в случае ошибки в одной строке сохраняет всю пачку в файл /tmp/log_web_failed.json
Можно вручную исправить этот файл и попробовать залить его в БД вручную:
clickhouse-client --host 127.0.0.1 --password password --query="INSERT INTO log_web FORMAT JSONEachRow" < /tmp/log_web_failed__fixed.json
 
sudo mv /etc/logstash/tmp/log_web_failed.json /etc/logstash/tmp/log_web_failed__fixed.json
sudo chown user_dev /etc/logstash/tmp/log_web_failed__fixed.json
sudo clickhouse-client --host 127.0.0.1 --password password --query="INSERT INTO log_web FORMAT JSONEachRow" < /etc/logstash/tmp/log_web_failed__fixed.json
sudo mv /etc/logstash/tmp/log_web_failed__fixed.json /etc/logstash/tmp/log_web_failed__fixed_.json
 
выход из командной строки
quit;
## Настройка TLS
https://www.altinity.com/blog/2019/3/5/clickhouse-networking-part-2
 
openssl s_client -connect log.domain.com:9440 < /dev/null

ログスタッシュ。 FileBeat から RabbitMQ キューへのログルーター

このコンポーネントは、FileBeat からのログを RabbitMQ キューにルーティングするために使用されます。 ここでのポイントは XNUMX つあります。

  1. 残念ながら、FileBeat には RabbitMQ に直接書き込むための出力プラグインがありません。 そして、そのような機能は、github の問題から判断すると、実装される予定はありません。 Kafka用のプラグインがあるのですが、なぜか我が家では使えません。
  2. DMZ でログを収集するには要件があります。 これらに基づいて、まずログをキューに追加し、次に LogStash が外部からキューからエントリを読み取る必要があります。

したがって、このような少し複雑なスキームを使用する必要があるのは、サーバーが DMZ 内に配置されている場合です。 構成例は次のようになります。

iis_w3c_logs__filebeat_rabbitmq.conf

input {
 
    beats {
        port => 5044
        type => 'iis'
        ssl => true
        ssl_certificate_authorities => ["/etc/pki/tls/certs/app/ca.pem", "/etc/pki/tls/certs/app/ca-issuing.pem"]
        ssl_certificate => "/etc/pki/tls/certs/app/queue.domain.com.cer"
        ssl_key => "/etc/pki/tls/certs/app/queue.domain.com-pkcs8.key"
        ssl_verify_mode => "peer"
    }
 
}
 
output { 
  #stdout {codec => rubydebug}
 
    rabbitmq {
        host => "127.0.0.1"
        port => 5672
        exchange => "monitor.direct"
        exchange_type => "direct"
        key => "%{[fields][fld_app_name]}"
        user => "q-writer"
        password => "password"
        ssl => false
    }
}

ラビットMQ。 メッセージキュー

このコンポーネントは、DMZ でログ エントリをバッファリングするために使用されます。 記録は一連の Filebeat → LogStash を通じて行われます。 読み取りは、LogStash を介して DMZ の外側から行われます。 RabboitMQ を介して動作する場合、4 秒あたり約 XNUMX のメッセージが処理されます。

メッセージ ルーティングはシステム名によって、つまり FileBeat 構成データに基づいて構成されます。 すべてのメッセージは XNUMX つのキューに入れられます。 何らかの理由でキュー サービスが停止しても、メッセージが失われることはありません。FileBeats は接続エラーを受け取り、送信を一時的に停止します。 また、キューから読み取る LogStash もネットワーク エラーを受け取り、接続が復元されるまで待機します。 この場合、当然のことながら、データはデータベースに書き込まれなくなります。

キューを作成および構成するには、次の手順を使用します。

sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin declare exchange --vhost=/ name=monitor.direct type=direct sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin declare queue --vhost=/ name=web_log durable=true
sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin --vhost="/" declare binding source="monitor.direct" destination_type="queue" destination="web_log" routing_key="site1.domain.ru"
sudo /usr/local/bin/rabbitmqadmin/rabbitmqadmin --vhost="/" declare binding source="monitor.direct" destination_type="queue" destination="web_log" routing_key="site2.domain.ru"

グラファナ。 ダッシュボード

このコンポーネントは、監視データを視覚化するために使用されます。 この場合、Grafana 4.6+ プラグイン用の ClickHouse データソースをインストールする必要があります。 ダッシュボードでの SQL フィルターの処理効率を向上させるために、少し調整する必要がありました。

たとえば、変数を使用しますが、変数がフィルター フィールドに設定されていない場合は、フォーム ( uriStem = » AND uriStem != » ) の WHERE で条件を生成しないようにします。 この場合、ClickHouse は uriStem 列を読み取ります。 一般に、さまざまなオプションを試し、最終的にプラグイン ($valueIfEmpty マクロ) を修正して、空の値の場合に列自体には言及せずに 1 を返すようにしました。

これで、このクエリをグラフに使用できるようになりました

$columns(response, count(*) c) from $table where $adhoc
and $valueIfEmpty($fld_app_name, 1, fld_app_name = '$fld_app_name')
and $valueIfEmpty($fld_app_module, 1, fld_app_module = '$fld_app_module') and $valueIfEmpty($fld_server_name, 1, fld_server_name = '$fld_server_name') and $valueIfEmpty($uriStem, 1, uriStem like '%$uriStem%')
and $valueIfEmpty($clientRealIP, 1, clientRealIP = '$clientRealIP')

これは次の SQL に変換されます (空の uriStem フィールドは 1 に変換されていることに注意してください)

SELECT
t,
groupArray((response, c)) AS groupArr
FROM (
SELECT
(intDiv(toUInt32(logdatetime), 60) * 60) * 1000 AS t, response,
count(*) AS c FROM default.log_web
WHERE (logdate >= toDate(1565061982)) AND (logdatetime >= toDateTime(1565061982)) AND 1 AND (fld_app_name = 'site1.domain.ru') AND (fld_app_module = 'web') AND 1 AND 1 AND 1
GROUP BY
t, response
ORDER BY
t ASC,
response ASC
)
GROUP BY t ORDER BY t ASC

まとめ

ClickHouse データベースの登場は、市場における画期的な出来事になりました。 完全に無料で、ビッグデータを扱うための強力で実用的なツールを瞬時に手に入れることができるとは想像もつきませんでした。 もちろん、ニーズが増加するにつれて (たとえば、複数のサーバーへのシャーディングやレプリケーション)、スキームはより複雑になります。 しかし、第一印象では、このデータベースの操作は非常に快適です。 「人のために」作られていることがわかります。

ElasticSearch と比較して、ログの保存と処理のコストは XNUMX ~ XNUMX 分の XNUMX に削減されると推定されています。 言い換えれば、現在のデータ量に対して複数のマシンのクラスターをセットアップする必要がある場合、ClickHouse を使用する場合は、XNUMX 台の低電力マシンで十分です。 はい、もちろん、ElasticSearch には、リソース消費を大幅に削減できるディスク上のデータ圧縮メカニズムやその他の機能もありますが、ClickHouse と比較すると、より高価になります。

特別な最適化を行わなくても、デフォルト設定では、データのロードとデータベースからの選択が驚くべき速度で機能します。 データはまだ多くありません (約 200 億レコード) が、サーバー自体が弱いです。 将来的には、ログの保存に関係しない他の目的でもこのツールを使用できるようになります。 たとえば、セキュリティや機械学習の分野におけるエンドツーエンド分析の場合です。

最後にメリットとデメリットについて少し触れておきます。

コンズ

  1. レコードを大きなバッチでロードします。 一方で、これは機能ですが、レコードをバッファリングするには追加のコンポーネントを使用する必要があります。 この課題は必ずしも簡単ではありませんが、それでも解決可能です。 そして、スキームを簡素化したいと考えています。
  2. 一部の珍しい機能や新機能は、新しいバージョンでは機能しなくなることがよくあります。 これにより懸念が生じ、新しいバージョンにアップグレードする意欲が減退します。 たとえば、Kafka テーブル エンジンは、コンシューマーを実装せずに、Kafka からイベントを直接読み取ることができる非常に便利な機能です。 しかし、github 上の Issue の数から判断すると、私たちはこのエンジンを運用環境で使用しないように依然として注意しています。 ただし、突然横にジェスチャーをせずにメイン機能を使用する場合は、安定して動作します。

プロたち

  1. 減速しません。
  2. エントリのしきい値が低い。
  3. オープンソース。
  4. 無料。
  5. 優れた拡張性 (すぐに使えるシャーディング/レプリケーション)
  6. 通信省が推奨するロシアのソフトウェアの登録に含まれています。
  7. Yandexからの公式サポートの存在。

出所: habr.com

コメントを追加します