VectorをClickHouseと統合する
生産アプリケーションにおけるリアルタイムなログ分析は非常に重要です。ClickHouseがログデータの保存と分析に優れているかどうか考えたことはありませんか?ClickHouseにログインフラストラクチャを移行したUberの経験をぜひご確認ください。
このガイドでは、人気のデータパイプラインVectorを使用して、Nginxログファイルを監視し、それをClickHouseに送信する方法を説明します。以下の手順は、任意のタイプのログファイルを監視する際にも同様です。ClickHouseが稼働しており、Vectorがインストールされていることを前提とします(ただし、まだ起動する必要はありません)。
1. データベースとテーブルを作成する
ログイベントを保存するためのテーブルを定義しましょう。
新しいデータベースnginxdbを作成します:
CREATE DATABASE IF NOT EXISTS nginxdb
初めに、ログイベント全体を1つの文字列として挿入します。これは分析するには最適な形式ではありませんが、Materialized Viewを使用してこの部分を以下で改善します。
CREATE TABLE IF NOT EXISTS nginxdb.access_logs (
message String
)
ENGINE = MergeTree()
ORDER BY tuple()Note主キーはまだ必要ないため、ORDER BYはtuple()に設定しています。
2. Nginxを設定する
Nginxについて詳しく説明することは避けたいところですが、詳細を省略したくもないので、Nginxのログ設定に必要な詳細を提供します。
以下の
access_log
プロパティは、combined形式でログを/var/log/nginx/my_access.logに送信します。この設定はnginx.confファイルのhttp
セクションに入力します:http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/my_access.log combined;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}nginx.confを修正した場合は、Nginxを再起動してください。
ウェブサーバーでページを訪問して、アクセスログにいくつかのログイベントを生成します。combined形式のログは次の形式を持ちます:
192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://localhost/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
192.168.208.1 - - [12/Oct/2021:03:31:49 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
3. Vectorを設定する
Vectorは、ログ、メトリクス、トレース(ソースと呼ばれます)を収集、変換、およびルーティングし、多くの異なるベンダー(シンクと呼ばれます)に送信します。ClickHouseとの即時対応性も組み込まれています。ソースとシンクは、vector.tomlという名前の設定ファイルで定義されます。
以下のvector.tomlは、my_access.logの末尾を監視するタイプがfileのsourceを定義し、上記で定義されたaccess_logsテーブルをsinkとしても定義しています:
[sources.nginx_logs]
type = "file"
include = [ "/var/log/nginx/my_access.log" ]
read_from = "end"
[sinks.clickhouse]
type = "clickhouse"
inputs = ["nginx_logs"]
endpoint = "http://clickhouse-server:8123"
database = "nginxdb"
table = "access_logs"
skip_unknown_fields = true上記の設定を使用してVectorを起動します。ソースとシンクの定義についてさらに詳しい情報を知りたい場合は、Vectorのドキュメントをご覧ください。
アクセスログがClickHouseに挿入されていることを確認します。以下のクエリを実行し、テーブルにアクセスログが表示されるはずです:
SELECT * FROM nginxdb.access_logs
4. ログを解析する
ClickHouseにログが保存されているのは素晴らしいことですが、各イベントを単独の文字列として保存していると、データの分析があまりできません。Materialized Viewを利用してログイベントを解析する方法を見てみましょう。
Materialized View(MVと略します)は、既存のテーブルに基づいた新しいテーブルで、既存のテーブルに挿入されたデータがMaterialized Viewにも自動的に反映されます。access_logs内のログイベントの解析された表現を含むMVを定義する方法を見てみましょう。次のように表現します:
192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
ClickHouseには文字列を解析するためのさまざまな関数が用意されていますが、まずはsplitByWhitespaceを見てみましょう。これは、空白によって文字列を解析し、各トークンを配列で返します。次のコマンドを実行してみてください:
SELECT splitByWhitespace('192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')
レスポンスがかなり理想に近いことに気づくでしょう!一部の文字列には余分な文字が含まれており、ユーザーエージェント(ブラウザの詳細)は解析されていませんが、それは次のステップで解決します:
["192.168.208.1","-","-","[12/Oct/2021:15:32:43","+0000]","\"GET","/","HTTP/1.1\"","304","0","\"-\"","\"Mozilla/5.0","(Macintosh;","Intel","Mac","OS","X","10_15_7)","AppleWebKit/537.36","(KHTML,","like","Gecko)","Chrome/93.0.4577.63","Safari/537.36\""]
splitByWhitespaceに似て、splitByRegexp関数は正規表現に基づいて文字列を配列に分割します。以下のコマンドを実行してみてください。2つの文字列が返されます。
SELECT splitByRegexp('\S \d+ "([^"]*)"', '192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')
ログから正常に解析されたユーザーエージェントが2番目の文字列として返されます:
["192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] \"GET / HTTP/1.1\" 30"," \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36\""]
最終的なCREATE MATERIALIZED VIEWコマンドを見る前に、データをクリーンアップするために使用されるいくつかの関数を見てみましょう。例えば、RequestMethodは不要なダブルクォート付きの"GETとなっています。以下のtrim関数を実行してください。これによりダブルクォートが削除されます:
SELECT trim(LEADING '"' FROM '"GET')
時間文字列には先頭に角括弧が付いており、ClickHouseが日付に変換できる形式にはなっていません。しかし、コロン(:)をカンマ(,)に変更すると、きちんと解析されます:
SELECT parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM '[12/Oct/2021:15:32:43'), ':', ' '))
これでMaterialized Viewを定義する準備が整いました。定義にはPOPULATEが含まれており、既存のaccess_logs内の行がすぐに処理され挿入されます。以下のSQL文を実行してください:
CREATE MATERIALIZED VIEW nginxdb.access_logs_view
(
RemoteAddr String,
Client String,
RemoteUser String,
TimeLocal DateTime,
RequestMethod String,
Request String,
HttpVersion String,
Status Int32,
BytesSent Int64,
UserAgent String
)
ENGINE = MergeTree()
ORDER BY RemoteAddr
POPULATE AS
WITH
splitByWhitespace(message) as split,
splitByRegexp('\S \d+ "([^"]*)"', message) as referer
SELECT
split[1] AS RemoteAddr,
split[2] AS Client,
split[3] AS RemoteUser,
parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM split[4]), ':', ' ')) AS TimeLocal,
trim(LEADING '"' FROM split[6]) AS RequestMethod,
split[7] AS Request,
trim(TRAILING '"' FROM split[8]) AS HttpVersion,
split[9] AS Status,
split[10] AS BytesSent,
trim(BOTH '"' from referer[2]) AS UserAgent
FROM
(SELECT message FROM nginxdb.access_logs)これがうまくいったかどうか確認しましょう。アクセスログがきちんとカラムに解析されているはずです:
SELECT * FROM nginxdb.access_logs_view
Note上記のレッスンではデータを2つのテーブルに保存しましたが、最初のnginxdb.access_logsテーブルをNullテーブルエンジンに変更することで、解析されたデータはnginxdb.access_logs_viewテーブルに入りますが、生のデータはテーブルに保存されません。
まとめ: 簡単なインストールと迅速な設定だけでVectorを使用すると、NginxサーバーからClickHouse内のテーブルにログを送信できます。巧妙なMaterialized Viewを使用することで、これらのログをカラムに解析し、分析を容易に行うことができます。