Database ClickHouse untuk Manusia, atau Teknologi Alien

Aleksey Lizunov, Kepala Pusat Kompetensi Saluran Layanan Jarak Jauh Direktorat Teknologi Informasi MKB

Database ClickHouse untuk Manusia, atau Teknologi Alien

Sebagai alternatif tumpukan ELK (ElasticSearch, Logstash, Kibana), kami sedang melakukan penelitian tentang penggunaan database ClickHouse sebagai penyimpanan data untuk log.

Pada artikel ini, kami ingin berbicara tentang pengalaman kami menggunakan database ClickHouse dan hasil awal dari operasi percontohan. Perlu segera dicatat bahwa hasilnya sangat mengesankan.


Database ClickHouse untuk Manusia, atau Teknologi Alien

Selanjutnya, kami akan menjelaskan secara lebih rinci bagaimana sistem kami dikonfigurasi, dan terdiri dari komponen apa. Tapi sekarang saya ingin berbicara sedikit tentang database ini secara keseluruhan, dan mengapa perlu diperhatikan. Database ClickHouse adalah database kolumnar analitik berkinerja tinggi dari Yandex. Ini digunakan dalam layanan Yandex, awalnya ini adalah penyimpanan data utama untuk Yandex.Metrica. Sistem sumber terbuka, gratis. Dari sudut pandang pengembang, saya selalu bertanya-tanya bagaimana mereka menerapkannya, karena ada data yang sangat besar. Dan antarmuka pengguna Metrica sendiri sangat fleksibel dan cepat. Saat pertama kali mengenal database ini, kesannya adalah: “Akhirnya! Dibuat untuk orang-orang! Dimulai dari proses instalasi dan diakhiri dengan pengiriman request.

Basis data ini memiliki ambang masuk yang sangat rendah. Bahkan pengembang berketerampilan rata-rata dapat menginstal database ini dalam beberapa menit dan mulai menggunakannya. Semuanya bekerja dengan jelas. Bahkan orang yang baru mengenal Linux dapat menangani penginstalan dengan cepat dan melakukan operasi yang paling sederhana. Jika sebelumnya, dengan kata-kata Big Data, Hadoop, Google BigTable, HDFS, pengembang biasa memiliki gagasan bahwa sekitar beberapa terabyte, petabyte, beberapa manusia super terlibat dalam pengaturan dan pengembangan sistem ini, kemudian dengan munculnya ClickHouse database, kami mendapatkan alat sederhana dan mudah dipahami yang dapat digunakan untuk menyelesaikan berbagai tugas yang sebelumnya tidak dapat dicapai. Hanya membutuhkan satu mesin yang cukup rata-rata dan lima menit untuk menginstal. Artinya, kami mendapat database seperti, misalnya, MySql, tetapi hanya untuk menyimpan miliaran catatan! Pengarsip super tertentu dengan bahasa SQL. Ini seperti orang-orang yang menyerahkan senjata alien.

Tentang sistem logging kami

Untuk mengumpulkan informasi, file log IIS dari aplikasi web format standar digunakan (saat ini kami juga mem-parsing log aplikasi, tetapi tujuan utama pada tahap percontohan adalah untuk mengumpulkan log IIS).

Karena berbagai alasan, kami tidak dapat sepenuhnya meninggalkan tumpukan ELK, dan kami terus menggunakan komponen LogStash dan Filebeat, yang telah membuktikan diri dengan baik dan bekerja dengan cukup andal dan dapat diprediksi.

Skema penebangan umum ditunjukkan pada gambar di bawah ini:

Database ClickHouse untuk Manusia, atau Teknologi Alien

Fitur penulisan data ke database ClickHouse adalah penyisipan record yang jarang (sekali per detik) dalam batch besar. Ini, tampaknya, adalah bagian paling "bermasalah" yang Anda temui saat pertama kali bekerja dengan database ClickHouse: skemanya menjadi sedikit lebih rumit.
Plugin untuk LogStash, yang langsung memasukkan data ke ClickHouse, sangat membantu di sini. Komponen ini digunakan di server yang sama dengan database itu sendiri. Jadi, secara umum, tidak disarankan untuk melakukannya, tetapi dari sudut pandang praktis, agar tidak menghasilkan server terpisah saat digunakan di server yang sama. Kami tidak mengamati adanya kegagalan atau konflik sumber daya dengan database. Selain itu, perlu diperhatikan bahwa plugin memiliki mekanisme coba ulang jika terjadi kesalahan. Dan jika terjadi kesalahan, plugin menulis ke disk kumpulan data yang tidak dapat dimasukkan (format file nyaman: setelah mengedit, Anda dapat dengan mudah memasukkan kumpulan yang diperbaiki menggunakan klien clickhouse).

Daftar lengkap perangkat lunak yang digunakan dalam skema disajikan dalam tabel:

Daftar perangkat lunak yang digunakan

Nama

Описание

Tautan distribusi

nginx

Reverse-proxy untuk membatasi akses oleh port dan mengatur otorisasi

Saat ini tidak digunakan dalam skema

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

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

FileBeat

Transfer file log.

https://www.elastic.co/downloads/beats/filebeat (kit distribusi untuk Windows 64bit).

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

logstash

Pengumpul kayu.

Digunakan untuk mengumpulkan log dari FileBeat, serta mengumpulkan log dari antrian RabbitMQ (untuk server yang ada di DMZ.)

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

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

Logstash-output-clickhouse

Plugin Loagstash untuk mentransfer log ke database ClickHouse secara berkelompok

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

/usr/share/logstash/bin/logstash-plugin instal logstash-output-clickhouse

/usr/share/logstash/bin/logstash-plugin instal logstash-filter-prune

/usr/share/logstash/bin/logstash-plugin instal logstash-filter-multiline

KlikRumah

Penyimpanan log 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

Catatan. Mulai Agustus 2018, build rpm "normal" untuk RHEL muncul di repositori Yandex, jadi Anda dapat mencoba menggunakannya. Pada saat penginstalan, kami menggunakan paket yang dibuat oleh Altinity.

grafana

Visualisasi log. Menyiapkan dasbor

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos(64 Bit) - versi terbaru

Sumber data ClickHouse untuk Grafana 4.6+

Plugin untuk Grafana dengan sumber data ClickHouse

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

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

logstash

Log router dari antrian FileBeat ke RabbitMQ.

Catatan. Sayangnya, FileBeat tidak memiliki keluaran langsung ke RabbitMQ, jadi diperlukan tautan perantara dalam bentuk Logstash

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

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

RabbitMQ

antrian pesan. Ini adalah buffer log di 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 Runtime (Diperlukan untuk RabbitMQ)

Waktu proses Erlang. Diperlukan agar RabbitMQ berfungsi

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

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

Konfigurasi server dengan database ClickHouse disajikan pada tabel berikut:

Nama

Nilai

Catatan

Konfigurasi

HDD: 40GB
RAM: 8GB
Prosesor: Core 2 2Ghz

Penting untuk memperhatikan tips untuk mengoperasikan database ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

perangkat lunak sistem umum

OS: Red Hat Enterprise Linux Server (Maipo)

JRE (Jawa 8)

 

Seperti yang Anda lihat, ini adalah workstation biasa.

Struktur tabel untuk menyimpan log adalah sebagai berikut:

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;

Kami menggunakan partisi default (berdasarkan bulan) dan perincian indeks. Semua bidang secara praktis sesuai dengan entri log IIS untuk mencatat permintaan http. Secara terpisah, kami mencatat bahwa ada bidang terpisah untuk menyimpan utm-tag (diuraikan pada tahap penyisipan ke dalam tabel dari bidang string kueri).

Juga, beberapa bidang sistem telah ditambahkan ke tabel untuk menyimpan informasi tentang sistem, komponen, server. Lihat tabel di bawah untuk deskripsi bidang ini. Dalam satu tabel, kami menyimpan log untuk beberapa sistem.

Nama

Описание

Contoh

fld_app_name

Nama aplikasi/sistem
Nilai yang valid:

  • site1.domain.com Situs eksternal 1
  • site2.domain.com Situs eksternal 2
  • internal-site1.domain.local Situs internal 1

situs1.domain.com

fld_app_module

Modul sistem
Nilai yang valid:

  • web - Situs web
  • svc - Layanan situs web
  • intgr - Layanan Web Integrasi
  • bo - Admin (BackOffice)

jaringan

fld_nama_situs web

Nama situs di IIS

Beberapa sistem dapat digunakan pada satu server, atau bahkan beberapa instance dari satu modul sistem

web utama

fld_server_name

Nama server

web1.domain.com

fld_log_file_name

Jalur ke file log di server

C:inetpublogsLogFiles
W3SVC1u_ex190711.log

Ini memungkinkan Anda membuat grafik secara efisien di Grafana. Misalnya, lihat permintaan dari frontend sistem tertentu. Ini mirip dengan penghitung situs di Yandex.Metrica.

Berikut adalah beberapa statistik penggunaan database selama dua bulan.

Jumlah rekaman yang dipecah berdasarkan sistem dan komponennya

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.)

Jumlah data pada disk

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.

Tingkat kompresi data dalam kolom

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.

Deskripsi komponen yang digunakan

FileBeat. Mentransfer log file

Komponen ini melacak perubahan pada file log pada disk dan meneruskan informasi ke LogStash. Diinstal di semua server tempat file log ditulis (biasanya IIS). Bekerja dalam mode ekor (yaitu hanya mentransfer catatan yang ditambahkan ke file). Tetapi secara terpisah dapat dikonfigurasi untuk mentransfer seluruh file. Ini berguna saat Anda perlu mengunduh data dari bulan sebelumnya. Letakkan saja file log di folder dan itu akan membacanya secara keseluruhan.

Saat layanan dihentikan, data tidak lagi ditransfer lebih jauh ke penyimpanan.

Contoh konfigurasi terlihat seperti ini:

filebeat.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: ~

logstash. Kolektor Log

Komponen ini dirancang untuk menerima entri log dari FileBeat (atau melalui antrian RabbitMQ), mem-parsing dan memasukkan kumpulan ke dalam database ClickHouse.

Untuk dimasukkan ke dalam ClickHouse, plugin Logstash-output-clickhouse digunakan. Plugin Logstash memiliki mekanisme coba ulang kueri, tetapi dengan penghentian reguler, lebih baik menghentikan layanan itu sendiri. Saat dihentikan, pesan akan terakumulasi dalam antrian RabbitMQ, jadi jika penghentiannya lama, lebih baik hentikan Filebeats di server. Dalam skema di mana RabbitMQ tidak digunakan (Filebeat langsung mengirimkan log ke Logstash di jaringan lokal), Filebeats bekerja dengan cukup dapat diterima dan aman, sehingga bagi mereka tidak tersedianya keluaran tanpa konsekuensi.

Contoh konfigurasi terlihat seperti ini:

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"
        }
    }
 
}

pipa.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"

clickhouse. Penyimpanan log

Log untuk semua sistem disimpan dalam satu tabel (lihat di awal artikel). Ini dimaksudkan untuk menyimpan informasi tentang permintaan: semua parameter serupa untuk format yang berbeda, seperti log IIS, log apache, dan nginx. Untuk log aplikasi, di mana, misalnya, kesalahan, pesan informasi, peringatan dicatat, tabel terpisah akan disediakan dengan struktur yang sesuai (saat ini dalam tahap desain).

Saat mendesain tabel, sangat penting untuk memutuskan kunci utama (yang akan digunakan untuk mengurutkan data selama penyimpanan). Tingkat kompresi data dan kecepatan kueri bergantung pada ini. Dalam contoh kita, kuncinya adalah
DIPESAN BERDASARKAN (fld_app_name, fld_app_module, waktu log)
Yaitu, dengan nama sistem, nama komponen sistem, dan tanggal kejadian. Awalnya, tanggal acara didahulukan. Setelah memindahkannya ke tempat terakhir, kueri mulai bekerja dua kali lebih cepat. Mengubah kunci utama akan membutuhkan pembuatan ulang tabel dan memuat ulang data sehingga ClickHouse mengurutkan ulang data pada disk. Ini adalah operasi yang berat, jadi merupakan ide bagus untuk memikirkan banyak hal tentang apa yang harus disertakan dalam kunci pengurutan.

Perlu juga dicatat bahwa tipe data LowCardinality telah muncul secara relatif di versi terbaru. Saat menggunakannya, ukuran data terkompresi berkurang drastis untuk bidang yang memiliki kardinalitas rendah (beberapa pilihan).

Versi 19.6 sedang digunakan dan kami berencana untuk mencoba memperbarui ke versi terbaru. Mereka memiliki fitur luar biasa seperti Adaptive Granularity, Skipping indexs dan codec DoubleDelta, misalnya.

Secara default, selama penginstalan, level logging diatur ke pelacakan. Log diputar dan diarsipkan, tetapi pada saat yang sama mereka berkembang hingga satu gigabyte. Jika tidak perlu, maka Anda dapat mengatur level peringatan, kemudian ukuran log berkurang drastis. Pengaturan logging diatur dalam file config.xml:

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

Beberapa perintah yang berguna

Поскольку оригинальные пакеты установки собираются по 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

logstash. Log router dari antrian FileBeat ke RabbitMQ

Komponen ini digunakan untuk merutekan log yang berasal dari FileBeat ke antrean RabbitMQ. Ada dua poin di sini:

  1. Sayangnya, FileBeat tidak memiliki plugin keluaran untuk menulis langsung ke RabbitMQ. Dan fungsionalitas seperti itu, dilihat dari masalah di github mereka, tidak direncanakan untuk diterapkan. Ada plugin untuk Kafka, tapi entah kenapa kami tidak bisa menggunakannya di rumah.
  2. Ada persyaratan untuk mengumpulkan log di DMZ. Berdasarkan mereka, log pertama-tama harus ditambahkan ke antrian dan kemudian LogStash membaca entri dari antrian dari luar.

Oleh karena itu, untuk kasus di mana server berada di DMZ, seseorang harus menggunakan skema yang sedikit rumit. Contoh konfigurasi terlihat seperti ini:

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
    }
}

RabbitMQ. antrian pesan

Komponen ini digunakan untuk menyangga entri log di DMZ. Perekaman dilakukan melalui kumpulan Filebeat → LogStash. Pembacaan dilakukan dari luar DMZ melalui LogStash. Saat beroperasi melalui RabboitMQ, sekitar 4 ribu pesan per detik diproses.

Perutean pesan dikonfigurasi berdasarkan nama sistem, yaitu berdasarkan data konfigurasi FileBeat. Semua pesan masuk ke satu antrean. Jika karena alasan tertentu layanan antrian dihentikan, ini tidak akan menyebabkan hilangnya pesan: FileBeats akan menerima kesalahan koneksi dan untuk sementara menangguhkan pengiriman. Dan LogStash yang membaca dari antrian juga akan menerima kesalahan jaringan dan menunggu koneksi dipulihkan. Dalam hal ini, data tentunya tidak akan lagi ditulis ke database.

Instruksi berikut digunakan untuk membuat dan mengonfigurasi antrean:

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. Dasbor

Komponen ini digunakan untuk memvisualisasikan data pemantauan. Dalam hal ini, Anda perlu menginstal sumber data ClickHouse untuk plugin Grafana 4.6+. Kami harus mengubahnya sedikit untuk meningkatkan efisiensi pemrosesan filter SQL di dasbor.

Misalnya, kami menggunakan variabel, dan jika variabel tersebut tidak disetel di bidang filter, maka kami ingin variabel tersebut tidak menghasilkan kondisi dalam bentuk WHERE ( uriStem = » AND uriStem != » ). Dalam hal ini, ClickHouse akan membaca kolom uriStem. Secara umum, kami mencoba opsi yang berbeda dan akhirnya mengoreksi plugin (makro $valueIfEmpty) sehingga dalam kasus nilai kosong ia mengembalikan 1, tanpa menyebutkan kolom itu sendiri.

Dan sekarang Anda dapat menggunakan kueri ini untuk grafik

$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')

yang diterjemahkan ke SQL ini (perhatikan bahwa bidang uriStem kosong telah diubah menjadi hanya 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

Kesimpulan

Munculnya database ClickHouse telah menjadi peristiwa penting di pasar. Sulit membayangkan bahwa, sepenuhnya gratis, dalam sekejap kami dipersenjatai dengan alat yang ampuh dan praktis untuk bekerja dengan data besar. Tentunya dengan meningkatnya kebutuhan (misalnya sharding dan replikasi ke beberapa server), skemanya akan menjadi lebih rumit. Namun kesan pertama, bekerja dengan database ini sangat menyenangkan. Dapat dilihat bahwa produk tersebut dibuat "untuk orang".

Dibandingkan dengan ElasticSearch, biaya penyimpanan dan pemrosesan log diperkirakan berkurang lima hingga sepuluh kali lipat. Dengan kata lain, jika untuk jumlah data saat ini kita harus menyiapkan cluster dari beberapa mesin, maka saat menggunakan ClickHouse, satu mesin berdaya rendah sudah cukup bagi kita. Ya, tentu saja, ElasticSearch juga memiliki mekanisme kompresi data dalam disk dan fitur lain yang dapat mengurangi konsumsi sumber daya secara signifikan, tetapi dibandingkan dengan ClickHouse, ini akan lebih mahal.

Tanpa pengoptimalan khusus apa pun dari pihak kami, pada pengaturan default, memuat data dan memilih dari database bekerja dengan kecepatan luar biasa. Kami belum memiliki banyak data (sekitar 200 juta catatan), tetapi servernya sendiri lemah. Kami dapat menggunakan alat ini di masa mendatang untuk tujuan lain yang tidak terkait dengan penyimpanan log. Misalnya untuk analitik ujung ke ujung, di bidang keamanan, pembelajaran mesin.

Pada akhirnya, sedikit tentang pro dan kontra.

Kontra

  1. Memuat catatan dalam batch besar. Di satu sisi, ini adalah fitur, tetapi Anda masih harus menggunakan komponen tambahan untuk menyangga catatan. Tugas ini tidak selalu mudah, tetapi masih bisa diselesaikan. Dan saya ingin menyederhanakan skema.
  2. Beberapa fungsi eksotis atau fitur baru sering kali rusak di versi baru. Ini menimbulkan kekhawatiran, mengurangi keinginan untuk meningkatkan ke versi baru. Misalnya, mesin tabel Kafka adalah fitur yang sangat berguna yang memungkinkan Anda membaca langsung acara dari Kafka, tanpa mengimplementasikan konsumen. Namun dilihat dari banyaknya Masalah di github, kami tetap berhati-hati untuk tidak menggunakan mesin ini dalam produksi. Namun, jika Anda tidak membuat gerakan tiba-tiba ke samping dan menggunakan fungsi utama, maka fungsi tersebut akan bekerja dengan stabil.

Kelebihan:

  1. Tidak melambat.
  2. Ambang masuk rendah.
  3. Sumber terbuka.
  4. Gratis.
  5. Berskala dengan baik (sharding/replikasi di luar kotak)
  6. Termasuk dalam daftar perangkat lunak Rusia yang direkomendasikan oleh Kementerian Komunikasi.
  7. Kehadiran dukungan resmi dari Yandex.

Sumber: www.habr.com

Tambah komentar