Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

W artykule omówimy projekt nginx-log-collector, który będzie odczytywał logi nginx i wysyłał je do klastra Clickhouse. Zwykle do logów używa się ElasticSearch. Clickhouse wymaga mniej zasobów (przestrzeni dyskowej, RAM, CPU). Clickhouse szybciej zapisuje dane. Clickhouse kompresuje dane, co czyni je jeszcze bardziej kompaktowymi na dysku. Zalety Clickhouse są widoczne na dwóch slajdach z prezentacji. Jak VK wstawia dane do ClickHouse z dziesiątek tysięcy serwerów.

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Aby przeglądać analitykę logów, stworzymy dashboard dla Grafany.

Zainteresowanych zapraszam pod kat.

Instalujemy nginx, grafanę w standardowy sposób.

Instalujemy klaster Clickhouse za pomocą ansible-playbook od Denisa Proskurina.

Tworzenie bazy danych i tabel w Clickhouse

W tym pliku opisano zapytania SQL do tworzenia bazy danych i tabel dla nginx-log-collector w Clickhouse.

Każde zapytanie wykonujemy kolejno na każdym serwerze klastra Clickhouse.

Ważna uwaga. W tym wierszu logs_cluster należy zastąpić nazwą twojego klastra z pliku clickhouse_remote_servers.xml pomiędzy "remote_servers" a "shard".

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

Instalacja i konfiguracja nginx-log-collector-rpm

Nginx-log-collector nie ma rpm. Tutaj https://github.com/patsevanton/nginx-log-collector-rpm tworzymy dla niego rpm. Kompilujemy rpm za pomocą Fedora Copr

Instalujemy pakiet 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

Poprawiamy konfigurację /etc/nginx-log-collector/config.yaml:

  .......
  upload:
    table: nginx.access_log
    dsn: http://adres-ip-klastra-clickhouse:8123/

- tag: "nginx_error:"
  format: error  # access | error
  buffer_size: 1048576
  upload:
    table: nginx.error_log
    dsn: http://adres-ip-klastra-clickhouse:8123/

Konfiguracja nginx

Ogólna konfiguracja 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;
}

Wirtualny host jeden:

vhost1.conf:

upstream backend {
    server ip-adres-serwera-z-stub_http_server:8080;
    server ip-adres-serwera-z-stub_http_server:8080;
    server ip-adres-serwera-z-stub_http_server:8080;
    server ip-adres-serwera-z-stub_http_server:8080;
    server ip-adres-serwera-z-stub_http_server:8080;
}

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

Dodajemy do pliku /etc/hosts wirtualne hosty:

ip-adres-serwera-z-nginx vhost1

Emulator serwera HTTP

Jako emulator serwera HTTP użyjemy nodejs-stub-server od Maxim Ignatenko

Nodejs-stub-server nie posiada rpm. Tutaj https://github.com/patsevanton/nodejs-stub-server tworzymy dla niego rpm. Kompilujemy rpm za pomocą Fedora Copr

Instalujemy pakiet rpm nodejs-stub-server na upstream 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

Testowanie obciążenia

Testowanie przeprowadzamy za pomocą Apache benchmark.

Instalujemy go:

yum install -y httpd-tools

Uruchamiamy testowanie za pomocą Apache benchmark z 5 różnych serwerów:

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

Konfiguracja Grafana

Na oficjalnej stronie Grafana nie znajdziesz dashboardu.

Dlatego zrobimy go ręcznie.

Moje zapisane pulpit można znaleźć tutaj.

Musisz również utworzyć zmienną table z zawartością nginx.access_log.
Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Singlestat Łączne Żądania:

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

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Singlestat Nieudane Żądania:

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

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Singlestat Procent Niepowodzeń:

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 to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Singlestat Średni Czas Odpowiedzi:

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

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Singlestat Maksymalny Czas Odpowiedzi:

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

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Liczba Statusów:

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

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Aby wyświetlić dane jako wykres kołowy, należy zainstalować wtyczkę i zrestartować grafanę.

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

Wykres Kołowy TOP 5 Statusów:

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

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Kolejne zapytania podam bez zrzutów ekranu:

Liczba http_user_agent:

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

Dobra Stawka/Zła Stawka:

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

Czas Odpowiedzi:

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

Czas odpowiedzi upstream (czasu odpowiedzi 1. upstream):

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

Tabela Liczba Statusów dla wszystkich vhost:

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

Ogólny widok pulpitu

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Porównanie avg() i quantile()

avg()
Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse
quantile()
Nginx-log-collector to narzędzie od Avito do przesyłania logów nginx do Clickhouse

Wynik:

Mam nadzieję, że społeczność dołączy do rozwoju/testowania i używania nginx-log-collector.
I ktoś, kto wdroży nginx-log-collector, opowie, ile zaoszczędził miejsca na dysku, RAM-u, CPU.

Kanały Telegram:

Milisekundy:

Kto potrzebuje milisekund, niech napisze lub zagłosuje, proszę, w tym issue.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster