Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ื“ืขืจ ืึทืจื˜ื™ืงืœ ื•ื•ืขื˜ ื“ื™ืกืงื•ื˜ื™ืจืŸ ื“ื™ ืคึผืจื•ื™ืขืงื˜ nginx-log-collector, ื•ื•ืึธืก ื•ื•ืขื˜ ืœื™ื™ืขื ืขืŸ nginx ืœืึธื’ืก ืื•ืŸ ืฉื™ืงืŸ ื–ื™ื™ ืฆื• ื“ื™ ืงืœื™ืงื›ืึธื•ืกืข ืงื ื•ื™ืœ. ื™ื•ื–ืฉืึทื•ื•ืึทืœื™ ElasticSearch ืื™ื– ื’ืขื ื™ืฆื˜ ืคึฟืึทืจ ืœืึธื’ืก. ืงืœื™ืงื›ืึธื•ืกืข ืจื™ืงื•ื•ื™ื™ืขืจื– ื•ื•ื™ื™ื ื™ืงืขืจ ืจืขืกื•ืจืกืŸ (ื“ื™ืกืง ืคึผืœืึทืฅ, ื‘ืึทืจืึทืŸ, ืงืคึผื•). ืงืœื™ืงื›ืึธื•ืกืข ืจืขืงืึธืจื“ืก ื“ืึทื˜ืŸ ืคืึทืกื˜ืขืจ. ืงืœื™ืงื›ืึธื•ืกืข ืงืึทืžืคึผืจืขืกื™ื– ื“ืึทื˜ืŸ, ืžืื›ืŸ ื“ื™ ื“ืึทื˜ืŸ ืื•ื™ืฃ ื“ื™ืกืง ืืคื™ืœื• ืžืขืจ ืกืึธืœื™ื“. ื“ื™ ืึทื“ื•ื•ืึทื ื˜ื™ื“ื–ืฉื™ื– ืคื•ืŸ Clickhouse ื–ืขื ืขืŸ ืงืขื ื˜ื™ืง ืื™ืŸ 2 ืกืœื™ื™ื“ื– ืคื•ืŸ ื“ืขื ื‘ืึทืจื™ื›ื˜ ื•ื•ื™ VK ื™ื ืกืขืจืฅ ื“ืึทื˜ืŸ ืื™ืŸ ืงืœื™ืงื›ืึธื•ืกืข ืคึฟื•ืŸ ื˜ืขื ืก ืคื•ืŸ ื˜ื•ื™ื–ื ื˜ืขืจ ืคื•ืŸ ืกืขืจื•ื•ืขืจืก.

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืฆื• ื–ืขืŸ ืึทื ืึทืœื™ื˜ื™ืงืก ื‘ืื–ื™ืจื˜ ืื•ื™ืฃ ืœืึธื’ืก, ืžื™ืจ ืžืึทื›ืŸ ืึท ื“ืึทืฉื‘ืึธืจื“ ืคึฟืึทืจ Grafana.

ื•ื•ืขืจ ืขืก ื™ื– ืื™ื ื˜ืขืจืขืกื™ืจื˜, ื‘ืึทื’ืจื™ืกื•ื ื’ ืฆื• ืงืึทืฅ.

ื™ื ืกื˜ืึทืœื™ืจืŸ nginx, grafana ืื™ืŸ ื“ื™ ื ืึธืจืžืึทืœ ื•ื•ืขื’.

ื™ื ืกื˜ืึธืœื™ื ื’ ืึท ืงืœื™ืงื›ืึธื•ืกืข ืงื ื•ื™ืœ ื ื™ืฆืŸ ืึทื ืกื™ื‘ืœืข-ืคึผืœื™ื™ึทื‘ืึธืึธืง ืคึฟื•ืŸ ื“ืขื ื™ืก ืคึผืจืึธืกืงื•ืจื™ืŸ.

ืงืจื™ื™ื™ื˜ื™ื ื’ ื“ืึทื˜ืึทื‘ื™ื™ืกื™ื– ืื•ืŸ ื˜ื™ืฉืŸ ืื™ืŸ ืงืœื™ืงืงื”ืึธื•ืกืข

ืื™ืŸ ื“ืขื ื˜ืขืงืข ืกืงืœ ืงื•ื•ื™ืจื™ื– ืคึฟืึทืจ ืงืจื™ื™ื™ื˜ื™ื ื’ ื“ืึทื˜ืึทื‘ื™ื™ืกื™ื– ืื•ืŸ ื˜ื™ืฉืŸ ืคึฟืึทืจ nginx-log-collector ืื™ืŸ Clickhouse ื–ืขื ืขืŸ ื“ื™ืกืงืจื™ื™ื‘ื“.

ืžื™ืจ ืžืึทื›ืŸ ื™ืขื“ืขืจ ื‘ืงืฉื” ืื™ื™ื ืขืจ ื“ื•ืจืš ืื™ื™ื ืขืจ ืื•ื™ืฃ ื™ืขื“ืขืจ ืกืขืจื•ื•ืขืจ ืื™ืŸ ื“ื™ ืงืœื™ืงื›ืึธื•ืกืข ืงื ื•ื™ืœ.

ื•ื•ื™ื›ื˜ื™ืง ื˜ืึธืŸ. ืื™ืŸ ื“ืขื ืฉื•ืจื”, ืœืึธื’ืก_ืงืœื•ืกื˜ืขืจ ื“ืึทืจืฃ ื–ื™ื™ืŸ ืจื™ืคึผืœื™ื™ืกื˜ ืžื™ื˜ ื“ื™ื™ืŸ ืงื ื•ื™ืœ ื ืึธืžืขืŸ ืคื•ืŸ ื“ื™ ืงืœื™ืงื›ืึธื•ืกืข_ืจืขืžืึธื˜ืข_ืกืขืจื•ื•ืขืจืก.ืงืกืžืœ ื˜ืขืงืข ืฆื•ื•ื™ืฉืŸ "ืจื™ืžืึธื•ื˜_ืกืขืจื•ื•ืขืจืก" ืื•ืŸ "ืฉืึทืจื“".

ENGINE = Distributed('logs_cluster', 'nginx', 'access_log_shard', rand())

ื™ื ืกื˜ืึธืœื™ื ื’ ืื•ืŸ ืงืึทื ืคื™ื’ื™ืขืจ nginx-log-collector-rpm

Nginx-log-collector ื”ืื˜ ื ื™ืฉื˜ ืึท ืจืคึผื. ื“ืึธ https://github.com/patsevanton/nginx-log-collector-rpm ืฉืึทืคึฟืŸ ืจืคึผื ืคึฟืึทืจ ืขืก. rpm ื•ื•ืขื˜ ื–ื™ื™ืŸ ืงืึทืžืคึผื™ื™ืœื“ ืžื™ื˜ ืคืขื“ืึธืจืึท ืงืึธืคึผืจ

ื™ื ืกื˜ืึทืœื™ืจืŸ ื“ื™ rpm ืคึผืขืงืœ nginx-log-collector-rpm

yum -y install yum-plugin-copr
yum copr enable antonpatsev/nginx-log-collector-rpm
yum -y install nginx-log-collector
systemctl start nginx-log-collector

ืจืขื“ืึทื’ื™ืจืŸ ื“ื™ ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทืŸ /etc/nginx-log-collector/config.yaml:

  .......
  upload:
    table: nginx.access_log
    dsn: http://ip-ะฐะดั€ะตั-ะบะปะฐัั‚ะตั€ะฐ-clickhouse:8123/

- tag: "nginx_error:"
  format: error  # access | error
  buffer_size: 1048576
  upload:
    table: nginx.error_log
    dsn: http://ip-ะฐะดั€ะตั-ะบะปะฐัั‚ะตั€ะฐ-clickhouse:8123/

ื‘ืึทืฉื˜ืขื˜ื™ืงืŸ nginx

ืึทืœื’ืขืžื™ื™ื ืข nginx ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทืŸ:

user  nginx;
worker_processes  auto;

#error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    log_format avito_json escape=json
                     '{'
                     '"event_datetime": "$time_iso8601", '
                     '"server_name": "$server_name", '
                     '"remote_addr": "$remote_addr", '
                     '"remote_user": "$remote_user", '
                     '"http_x_real_ip": "$http_x_real_ip", '
                     '"status": "$status", '
                     '"scheme": "$scheme", '
                     '"request_method": "$request_method", '
                     '"request_uri": "$request_uri", '
                     '"server_protocol": "$server_protocol", '
                     '"body_bytes_sent": $body_bytes_sent, '
                     '"http_referer": "$http_referer", '
                     '"http_user_agent": "$http_user_agent", '
                     '"request_bytes": "$request_length", '
                     '"request_time": "$request_time", '
                     '"upstream_addr": "$upstream_addr", '
                     '"upstream_response_time": "$upstream_response_time", '
                     '"hostname": "$hostname", '
                     '"host": "$host"'
                     '}';

    access_log     syslog_server=unix:/var/run/nginx_log.sock,nohostname,tag=nginx avito_json; #ClickHouse
    error_log      syslog_server=unix:/var/run/nginx_log.sock,nohostname,tag=nginx_error; #ClickHouse

    #access_log  /var/log/nginx/access.log  main;

    proxy_ignore_client_abort on;
    sendfile        on;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
}

ืื™ื™ืŸ ื•ื•ื™ืจื˜ื•ืขืœ ื‘ืึทืœืขื‘ืึธืก:

vhost1.conf:

upstream backend {
    server ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-ั-stub_http_server:8080;
    server ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-ั-stub_http_server:8080;
    server ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-ั-stub_http_server:8080;
    server ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-ั-stub_http_server:8080;
    server ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-ั-stub_http_server:8080;
}

server {
    listen   80;
    server_name vhost1;
    location / {
        proxy_pass http://backend;
    }
}

ืœื™ื™ื’ ื•ื•ื™ืจื˜ื•ืึทืœ ืžื—ื ื•ืช ืฆื• ื“ื™ /etc/hosts ื˜ืขืงืข:

ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-ั-nginx vhost1

ื”ื˜ื˜ืคึผ ืกืขืจื•ื•ืขืจ ืขืžื•ืœืึทื˜ืึธืจ

ื•ื•ื™ ืึท ื”ื˜ื˜ืคึผ ืกืขืจื•ื•ืขืจ ืขืžื•ืœืึทื˜ืึธืจ ืžื™ืจ ื•ื•ืขืœืŸ ื ื•ืฆืŸ ื ืึธื“ืขื“ื–ืฉืก-ืฉื˜ื•ื‘-ืกืขืจื•ื•ืขืจ ืคื•ืŸ ืžืึทืงืกื™ื ืื™ื’ื ืึทื˜ืขื ืงืึธ

Nodejs-stub-server ื”ืื˜ ื ื™ืฉื˜ ืึท ืจืคึผื. ื“ืึธ https://github.com/patsevanton/nodejs-stub-server ืฉืึทืคึฟืŸ ืจืคึผื ืคึฟืึทืจ ืขืก. rpm ื•ื•ืขื˜ ื–ื™ื™ืŸ ืงืึทืžืคึผื™ื™ืœื“ ืžื™ื˜ ืคืขื“ืึธืจืึท ืงืึธืคึผืจ

ื™ื ืกื˜ืึทืœื™ืจืŸ nodejs-stub-server ืคึผืขืงืœ ืื•ื™ืฃ ืึทืคึผืกื˜ืจื™ื nginx ืจืคึผื

yum -y install yum-plugin-copr
yum copr enable antonpatsev/nodejs-stub-server
yum -y install stub_http_server
systemctl start stub_http_server

ื“ืจื•ืง ื˜ืขืกื˜ื™ื ื’

ืžื™ืจ ื“ื•ืจื›ืคื™ืจืŸ ื˜ืขืกื˜ื™ื ื’ ืžื™ื˜ ืึทืคึผืึทื˜ืฉื™ ื‘ืขื ื˜ืฉืžืึทืจืง.

ื™ื ืกื˜ืึทืœื™ืจืŸ ืขืก:

yum install -y httpd-tools

ืžื™ืจ ืึธื ื”ื™ื™ื‘ืŸ ื˜ืขืกื˜ื™ื ื’ ืžื™ื˜ ืึทืคึผืึทื˜ืฉื™ ื‘ืขื ื˜ืฉืžืึทืจืง ืคึฟื•ืŸ 5 ืคืึทืจืฉื™ื“ืขื ืข ืกืขืจื•ื•ืขืจืก:

while true; do ab -H "User-Agent: 1server" -c 10 -n 10 -t 10 http://vhost1/; sleep 1; done
while true; do ab -H "User-Agent: 2server" -c 10 -n 10 -t 10 http://vhost1/; sleep 1; done
while true; do ab -H "User-Agent: 3server" -c 10 -n 10 -t 10 http://vhost1/; sleep 1; done
while true; do ab -H "User-Agent: 4server" -c 10 -n 10 -t 10 http://vhost1/; sleep 1; done
while true; do ab -H "User-Agent: 5server" -c 10 -n 10 -t 10 http://vhost1/; sleep 1; done

ื‘ืึทืฉื˜ืขื˜ื™ืงืŸ ื’ืจืึทืคืึทื ืึท

ืื™ืจ ื•ื•ืขื˜ ื ื™ื˜ ื’ืขืคึฟื™ื ืขืŸ ืึท ื“ืึทืฉื‘ืึธืจื“ ืื•ื™ืฃ ื“ืขืจ ื‘ืึทืึทืžื˜ืขืจ Grafana ื•ื•ืขื‘ื–ื™ื™ื˜ืœ.

ื“ืขืจื™ื‘ืขืจ, ืžื™ืจ ื•ื•ืขืœืŸ ื˜ืึธืŸ ืขืก ืžื™ื˜ ื”ืึทื ื˜.

ืื™ืจ ืงืขื ืขืŸ ื’ืขืคึฟื™ื ืขืŸ ืžื™ื™ืŸ ื’ืขืจืื˜ืขื•ื•ืขื˜ ื“ืึทืฉื‘ืึธืจื“ ื“ืึธ.

ืื™ืจ ืื•ื™ืš ื“ืึทืจืคึฟืŸ ืฆื• ืฉืึทืคึฟืŸ ืึท ื˜ื™ืฉ ื‘ื™ื™ึทื˜ืขื•ื•ื“ื™ืง ืžื™ื˜ ื“ื™ ืื™ื ื”ืึทืœื˜ nginx.access_log.
Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืกื™ื ื’ืœืขืกื˜ืึทื˜ ื’ืึทื ืฅ ืจื™ืงื•ื•ืขืก:

SELECT
 1 as t,
 count(*) as c
 FROM $table
 WHERE $timeFilter GROUP BY t

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืกื™ื ื’ืœืขืกื˜ืึทื˜ ืคื™ื™ืœื“ ืจื™ืงื•ื•ืขืก:

SELECT
 1 as t,
 count(*) as c
 FROM $table
 WHERE $timeFilter AND status NOT IN (200, 201, 401) GROUP BY t

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืกื™ื ื’ืœืขืกื˜ืึทื˜ ืคื™ื™ืœื™ื ื’ ืคึผืจืึธืฆืขื ื˜:

SELECT
 1 as t, (sum(status = 500 or status = 499)/sum(status = 200 or status = 201 or status = 401))*100 FROM $table
 WHERE $timeFilter GROUP BY t

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืกื™ื ื’ืœืขืกื˜ืึทื˜ ื“ื•ืจื›ืฉื ื™ื˜ืœืขืš ืขื ื˜ืคืขืจ ืฆื™ื™ื˜:

SELECT
 1, avg(request_time) FROM $table
 WHERE $timeFilter GROUP BY 1

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืกื™ื ื’ืœืขืกื˜ืึทื˜ ืžืึทืงืก ืขื ื˜ืคืขืจ ืฆื™ื™ื˜:

SELECT
 1 as t, max(request_time) as c
 FROM $table
 WHERE $timeFilter GROUP BY t

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืฆื™ื™ืœืŸ ืกื˜ืึทื˜ื•ืก:

$columns(status, count(*) as c) from $table

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืฆื• ืจืขื–ื•ืœื˜ืึทื˜ ื“ืึทื˜ืŸ ื•ื•ื™ ืึท ืคึผื™ืจืึธื’, ืื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ื™ื ืกื˜ืึทืœื™ืจืŸ ื“ื™ ืคึผืœื•ื’ื™ืŸ ืื•ืŸ ืจื™ืกื˜ืึทืจื˜ ื’ืจืึทืคืึทื ืึท.

grafana-cli plugins install grafana-piechart-panel
service grafana-server restart

ืคึผื™ืจืึธื’ ืฉืคึผื™ืฅ 5 ืกื˜ืึทื˜ื•ืก:

SELECT
    1, /* fake timestamp value */
    status,
    sum(status) AS Reqs
FROM $table
WHERE $timeFilter
GROUP BY status
ORDER BY Reqs desc
LIMIT 5

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ื•ื•ื™ื™ึทื˜ืขืจ ืื™ืš ื•ื•ืขืœ ื’ืขื‘ืŸ ืจื™ืงื•ื•ืขืก ืึธืŸ ืกืงืจืขืขื ืฉืึธืฅ:

ืฆื™ื™ืœืŸ http_user_agent:

$columns(http_user_agent, count(*) c) FROM $table

GoodRate/BadRate:

$rate(countIf(status = 200) AS good, countIf(status != 200) AS bad) FROM $table

ืขื ื˜ืคืขืจ ืฆื™ื™ื˜:

$rate(avg(request_time) as request_time) FROM $table

ืึทืคึผืกื˜ืจื™ื ืขื ื˜ืคืขืจ ืฆื™ื™ื˜ (1st ืึทืคึผืกื˜ืจื™ื ืขื ื˜ืคืขืจ ืฆื™ื™ื˜):

$rate(avg(arrayElement(upstream_response_time,1)) as upstream_response_time) FROM $table

ื˜ืึทื‘ืœืข ื’ืจืืฃ ืกื˜ืึทื˜ื•ืก ืคึฟืึทืจ ืึทืœืข ื•ื•ื”ืึธืกื˜:

$columns(status, count(*) as c) from $table

ืึทืœื’ืขืžื™ื™ื ืข ืžื™ื™ื ื•ื ื’ ืคื•ืŸ ื“ื™ ื“ืึทืฉื‘ืึธืจื“

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืคืึทืจื’ืœื™ื™ึทืš ืคื•ืŸ ืึทื•ื•ื’ () ืื•ืŸ ืงื•ื•ืึทื ื˜ื™ืœ ()

avg()
Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse
ืงื•ื•ืึทื ื˜ื™ืœ ()
Nginx-log-collector ื ื•ืฆืŸ ืคื•ืŸ Avito ืคึฟืึทืจ ืฉื™ืงืŸ nginx ืœืึธื’ืก ืฆื• Clickhouse

ืžืกืงื ื:

ืื™ืš ื”ืึธืคึฟืŸ ื“ื™ ืงื”ืœ ืื™ื– ื™ื ื•ื•ืึทืœื•ื•ื“ ืื™ืŸ ื“ืขื•ื•ืขืœืึธืคึผื™ื ื’ / ื˜ืขืกื˜ื™ื ื’ ืื•ืŸ ื ื™ืฆืŸ nginx-log-collector.
ืื•ืŸ ื•ื•ืขืŸ ืขืžืขืฆืขืจ ื™ืžืคึผืœืึทืžืึทื ืฅ nginx-log-collector, ื–ื™ื™ ื•ื•ืขืœืŸ ื–ืึธื’ืŸ ืื™ืจ ื•ื•ื™ ืคื™ืœ ื“ื™ืกืง, ื‘ืึทืจืึทืŸ ืื•ืŸ ืงืคึผื• ื–ื™ื™ ื’ืขืจืื˜ืขื•ื•ืขื˜.

ื˜ืขืœืขื’ืจืึทื ื˜ืฉืึทื ืึทืœื–:

ืžื™ืœื™ืกืขืงื•ื ื“ืŸ:

ืฆื• ื•ื•ืขืžืขืŸ ืžื™ืœื™ืกืขืงืึทื ื“ื– ืขื ื™ืŸ, ื‘ื™ื˜ืข ืฉืจื™ื™ึทื‘ืŸ ืึธื“ืขืจ ืฉื˜ื™ืžืขืŸ ืื™ืŸ ื“ืขื ืึทืจื•ื™ืกื’ืขื‘ืŸ.

ืžืงื•ืจ: www.habr.com

ืœื™ื™ื’ืŸ ืึท ื‘ืึทืžืขืจืงื•ื ื’