İnsanlar veya Yabancı Teknolojiler için ClickHouse Veritabanı

ICB Bilgi Teknolojileri Direktörlüğü uzaktan hizmet kanalları yeterlilik merkezi başkanı Alexey Lizunov

İnsanlar veya Yabancı Teknolojiler için ClickHouse Veritabanı

ELK yığınına (ElasticSearch, Logstash, Kibana) alternatif olarak ClickHouse veritabanının loglar için veri deposu olarak kullanılması konusunda araştırmalar yürütüyoruz.

Bu yazıda ClickHouse veritabanını kullanma deneyimimizden ve pilot çalışmanın ön sonuçlarından bahsetmek istiyoruz. Sonuçların etkileyici olduğunu hemen belirtmekte fayda var.


İnsanlar veya Yabancı Teknolojiler için ClickHouse Veritabanı

Daha sonra sistemimizin nasıl yapılandırıldığını ve hangi bileşenlerden oluştuğunu daha ayrıntılı olarak açıklayacağız. Ama şimdi bir bütün olarak bu veritabanından ve neden dikkat etmeye değer olduğundan biraz bahsetmek istiyorum. ClickHouse veritabanı, Yandex'in yüksek performanslı analitik sütunlu veritabanıdır. Yandex hizmetlerinde kullanılan bu, başlangıçta Yandex.Metrica'nın ana veri depolama alanıdır. Açık kaynaklı sistem, ücretsiz. Bir geliştiricinin bakış açısından bakıldığında, bunu nasıl uyguladıklarını her zaman merak etmişimdir, çünkü inanılmaz derecede büyük veriler var. Metrica kullanıcı arayüzünün kendisi de oldukça esnektir ve hızlı çalışır. Bu veritabanıyla ilk tanıştığınızda şu izlenimi edinirsiniz: “Sonunda! “Halk için” yapıldı! Kurulum sürecinden istek göndermeye kadar.”

Bu veritabanının giriş engeli çok düşüktür. Ortalama bir geliştirici bile bu veritabanını birkaç dakika içinde kurup kullanmaya başlayabilir. Her şey sorunsuz çalışıyor. Linux'a yeni başlayan kişiler bile kurulumu hızlı bir şekilde halledebilir ve basit işlemleri yapabilir. Daha önce, Büyük Veri, Hadoop, Google BigTable, HDFS kelimelerini duyduğunda, ortalama bir geliştirici, bazı terabaytlardan, petabaytlardan bahsettiklerini, bazı süper insanların bu sistemlerin kurulmasına ve geliştirilmesine dahil olduğu fikrine kapılmıştı. ClickHouse veritabanının gelişiyle, daha önce ulaşılamayan bir dizi sorunu çözebileceğiniz basit, anlaşılır bir araca sahip olduk. Tek gereken oldukça ortalama bir makine ve kurulumu beş dakika. Yani, örneğin MySql gibi bir veritabanımız var, ancak yalnızca milyarlarca kaydı depolamak için! SQL diline sahip bir tür süper arşivleyici. Sanki insanlara uzaylı silahları verilmiş gibi.

Günlük toplama sistemimiz hakkında

Bilgi toplamak için standart formattaki web uygulamalarının IIS günlük dosyaları kullanılır (şu anda uygulama günlüklerinin ayrıştırılmasıyla da ilgileniyoruz, ancak pilot aşamada asıl amacımız IIS günlüklerini toplamaktır).

Çeşitli nedenlerden dolayı ELK stack'tan tamamen vazgeçemedik ve kendini kanıtlamış, oldukça güvenilir ve öngörülebilir şekilde çalışan LogStash ve Filebeat bileşenlerini kullanmaya devam ediyoruz.

Genel kayıt şeması aşağıdaki şekilde gösterilmektedir:

İnsanlar veya Yabancı Teknolojiler için ClickHouse Veritabanı

ClickHouse veritabanına veri kaydetmenin bir özelliği, kayıtların büyük gruplar halinde nadiren (saniyede bir kez) eklenmesidir. Görünüşe göre bu, ClickHouse veritabanıyla ilk kez çalışırken karşılaştığınız en "sorunlu" kısımdır: şema biraz daha karmaşık hale gelir.
Verileri doğrudan ClickHouse'a ekleyen LogStash eklentisi burada çok yardımcı oldu. Bu bileşen veritabanının kendisiyle aynı sunucuya konuşlandırılır. Bu nedenle, genel olarak konuşursak, aynı sunucuya dağıtılırken ayrı sunucular oluşturmamak için pratik açıdan bunu yapmanız önerilmez. Veritabanında herhangi bir arıza veya kaynak çakışması gözlemlemedik. Ayrıca eklentinin hata durumunda yeniden yönlendirme mekanizmasına sahip olduğunu da belirtelim. Ve hata durumunda eklenti, eklenemeyen bir veri kümesini diske yazar (dosya formatı uygundur: düzenlemeden sonra, clickhouse-client'ı kullanarak düzeltilmiş grubu kolayca ekleyebilirsiniz).

Şemada kullanılan yazılımların tam listesi tabloda sunulmaktadır:

Kullanılan yazılımların listesi

isim

Açıklama

Dağıtıma bağlantı

nginx

Bağlantı noktasına göre erişimi kısıtlamak ve yetkilendirmeyi düzenlemek için ters proxy

Şu anda şemada kullanılmıyor

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

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

DosyaBeat

Dosya günlüklerinin aktarımı.

https://www.elastic.co/downloads/beats/filebeat (Windows 64bit için dağıtım).

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

GünlükStash

Günlük toplayıcı.

FileBeat'ten günlük toplamak ve RabbitMQ kuyruğundan (DMZ'de bulunan sunucular için) günlükleri toplamak için kullanılır.

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

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

Logstash- çıktı- clickhouse

Günlükleri ClickHouse veritabanına toplu olarak aktarmak için Loagstash eklentisi

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

/usr/share/logstash/bin/logstash-plugin logstash-output-clickhouse'u kurun

/usr/share/logstash/bin/logstash-plugin logstash-filter-prune'u yükle

/usr/share/logstash/bin/logstash-plugin logstash-filter-multiline'ı yükle

Tıklama Evi

Günlük depolama 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

Not. Ağustos 2018'den itibaren, RHEL için "normal" rpm yapıları Yandex deposunda göründü, böylece bunları kullanmayı deneyebilirsiniz. Kurulum sırasında Altinity tarafından derlenen paketleri kullanıyorduk.

grafana

Günlüklerin görselleştirilmesi. Gösterge tablolarını ayarlama

https://grafana.com/

https://grafana.com/grafana/download

Redhat ve Centos(64 Bit) – en son sürüm

Grafana 4.6+ için ClickHouse veri kaynağı

ClickHouse veri kaynağına sahip Grafana eklentisi

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

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

GünlükStash

Yönlendiriciyi FileBeat'ten RabbitMQ kuyruğuna kaydedin.

Not. Ne yazık ki FileBeat'in doğrudan RabbitMQ'ya çıkışı yok, bu nedenle Logstash biçiminde bir ara bağlantı gerekiyor

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

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

RabbitMQ

Mesaj kuyruğu. Bu, DMZ'deki günlük girişlerinin arabelleğidir

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 Çalışma Zamanı (RabitMQ için gerekli)

Erlang çalışma zamanı. RabbitMQ'nun çalışması için gereklidir

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

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

ClickHouse veritabanıyla sunucu yapılandırması aşağıdaki tabloda sunulmaktadır:

isim

Değer

Dikkat

Yapılandırma

HDD: 40GB
RAM: 8GB
İşlemci: Core 2 2Ghz

ClickHouse veritabanının kullanımına ilişkin ipuçlarına dikkat etmelisiniz (https://clickhouse.yandex/docs/ru/operations/tips/)

Sistem çapında yazılım

İşletim Sistemi: Red Hat Enterprise Linux Sunucusu (Maipo)

JRE (Java 8)

 

Gördüğünüz gibi bu normal bir iş istasyonu.

Günlüklerin saklanmasına ilişkin tablonun yapısı aşağıdaki gibidir:

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;

Bölümlendirme (aylık) ve dizin ayrıntı düzeyi için varsayılan değerleri kullanırız. Tüm alanlar pratik olarak http isteklerini kaydetmek için IIS günlük girişlerine karşılık gelir. Ayrı olarak, utm etiketlerini depolamak için ayrı alanlar olduğunu not ediyoruz (bunlar sorgu dizesi alanından tabloya ekleme aşamasında ayrıştırılır).

Ayrıca sistemler, bileşenler ve sunucular hakkındaki bilgileri depolamak için tabloya çeşitli sistem alanları eklenmiştir. Bu alanların açıklaması için aşağıdaki tabloya bakın. Tek bir tabloda birden fazla sistemin günlüklerini saklıyoruz.

isim

Açıklama

Örnek

fld_app_name

Uygulama/sistem adı
Geçerli değerler:

  • site1.domain.com Harici site 1
  • site2.domain.com Harici site 2
  • internal-site1.domain.local Dahili site 1

site1.domain.com

fld_app_module

Sistem modülü
Geçerli değerler:

  • web - Web sitesi
  • svc — Web sitesi web hizmeti
  • ingr - Web entegrasyon hizmeti
  • bo — Yönetici (BackOffice)

fld_website_name

IIS'de site adı

Bir sunucuya birden fazla sistem, hatta bir sistem modülünün birden fazla örneğine yerleştirilebilir

web ana

fld_sunucu_adı

Sunucu adı

web1.domain.com

fld_log_file_name

Sunucudaki günlük dosyasının yolu

Gönderen:inetpublogsLogFiles
W3SVC1u_ex190711.log

Bu, Grafana'da verimli bir şekilde grafikler oluşturmanıza olanak tanır. Örneğin, belirli bir sistemin ön ucundan gelen istekleri görüntüleyin. Bu, Yandex.Metrica'daki site sayacına benzer.

İşte iki ay boyunca veritabanı kullanımına ilişkin bazı istatistikler.

Sistem ve bileşene göre kayıt sayısı

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

Disk veri hacmi

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.

Sütun veri sıkıştırma oranı

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.

Kullanılan bileşenlerin açıklaması

FileBeat. Dosya günlüklerini aktarma

Bu bileşen, diskteki günlük dosyalarındaki değişiklikleri izler ve bilgileri LogStash'e aktarır. Günlük dosyalarının yazıldığı tüm sunuculara (genellikle IIS) yüklenir. Kuyruk modunda çalışır (yani dosyaya yalnızca eklenen kayıtları aktarır). Ancak tüm dosyaları aktarmak için ayrı ayrı yapılandırabilirsiniz. Bu, önceki aylara ait verileri indirmeniz gerektiğinde kullanışlıdır. Günlük dosyasını bir klasöre koymanız yeterlidir; tamamen okuyacaktır.

Hizmet durduğunda verilerin depolama birimine aktarımı da durdurulur.

Örnek bir konfigürasyon şuna benzer:

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. Günlük Toplayıcı

Bu bileşen, FileBeat'ten (veya bir RabbitMQ kuyruğu aracılığıyla) günlük kayıtlarını almak, bunları ayrıştırmak ve toplu olarak ClickHouse veritabanına eklemek için tasarlanmıştır.

ClickHouse'a eklemek için Logstash-output-clickhouse eklentisini kullanın. Logstash eklentisinin istekleri yeniden izlemek için bir mekanizması vardır, ancak düzenli bir kapatma sırasında hizmetin kendisini durdurmak daha iyidir. Durdurulduğunda mesajlar RabbitMQ kuyruğunda birikir, bu nedenle durma uzun sürüyorsa, sunuculardaki Filebeats'i durdurmak daha iyidir. RabbitMQ'nun kullanılmadığı bir şemada (yerel ağdaki Filebeat, günlükleri doğrudan Logstash'a gönderir), Filebeats oldukça kabul edilebilir ve güvenli çalışır, dolayısıyla çıktının bulunmamasının onlar için hiçbir sonucu yoktur.

Örnek bir konfigürasyon şuna benzer:

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

boru hatları.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. Günlük depolama

Tüm sistemlerin günlükleri tek bir tabloya kaydedilir (makalenin başına bakın). İsteklerle ilgili bilgileri depolamak için tasarlanmıştır: IIS günlükleri, apache ve nginx günlükleri gibi tüm parametreler farklı formatlar için benzerdir. Örneğin hataların, bilgi mesajlarının, uyarıların kaydedildiği uygulama günlükleri için uygun yapıya sahip ayrı bir tablo sağlanacaktır (şu anda tasarım aşamasındadır).

Bir tablo tasarlarken birincil anahtara (verilerin depolama sırasında sıralanacağı) karar vermek çok önemlidir. Veri sıkıştırma derecesi ve sorgu hızı buna bağlıdır. Örneğimizde anahtar
SİPARİŞ BY (fld_app_name, fld_app_module, logdatetime)
Yani sistemin adına, sistem bileşeninin adına ve olayın tarihine göre. Başlangıçta olayın tarihi ilk sırada geliyordu. Son yere taşındıktan sonra sorgular yaklaşık iki kat daha hızlı çalışmaya başladı. Birincil anahtarı değiştirmek, ClickHouse'un diskteki verileri yeniden sıralayabilmesi için tablonun yeniden oluşturulmasını ve verilerin yeniden yüklenmesini gerektirecektir. Bu zor bir işlemdir, bu nedenle sıralama anahtarına nelerin dahil edilmesi gerektiği konusunda önceden dikkatlice düşünmeniz önerilir.

LowCardinality veri türünün nispeten yeni sürümlerde ortaya çıktığı da unutulmamalıdır. Bunu kullanırken, düşük kardinaliteye sahip alanlar (birkaç seçenek) için sıkıştırılmış verilerin boyutu keskin bir şekilde azalır.

Şu anda 19.6 sürümünü kullanıyoruz ve en son sürüme güncellemeyi denemeyi planlıyoruz. Örneğin Uyarlanabilir Parçalılık, Atlama endeksleri ve DoubleDelta codec bileşeni gibi harika özelliklere sahiptirler.

Varsayılan olarak, kurulum sırasında konfigürasyon günlük kaydı düzeyi izleme olarak ayarlanmıştır. Günlükler döndürülür ve arşivlenir, ancak aynı zamanda bir gigabayta kadar genişlerler. Gerek yoksa seviyeyi uyarı olarak ayarlayabilirsiniz, ardından günlük boyutu keskin bir şekilde azalacaktır. Günlük ayarları config.xml dosyasında belirtilmiştir:

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

Bazı yararlı komutlar

Поскольку оригинальные пакеты установки собираются по 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. Yönlendiriciyi FileBeat'ten RabbitMQ kuyruğuna kaydedin

Bu bileşen, FileBeat'ten gelen günlükleri RabbitMQ kuyruğuna yönlendirmek için kullanılır. Burada iki nokta var:

  1. Ne yazık ki FileBeat'in doğrudan RabbitMQ'ya yazmak için bir çıktı eklentisi yok. Ve github'larındaki gönderiye bakılırsa bu tür bir işlevselliğin uygulanması planlanmamıştır. Kafka için bir eklenti var ama bazı nedenlerden dolayı onu kendimiz kullanamıyoruz.
  2. DMZ'de günlüklerin toplanmasına yönelik gereksinimler vardır. Bunlara dayanarak, günlüklerin önce kuyruğa alınması gerekir ve ardından LogStash kuyruktaki kayıtları harici olarak okur.

Bu nedenle, özellikle DMZ'de bulunan sunucular için, bu kadar biraz karmaşık bir şemanın kullanılması gereklidir. Örnek bir konfigürasyon şuna benzer:

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

TavşanMQ. Mesaj Sırası

Bu bileşen DMZ'deki günlük girişlerini ara belleğe almak için kullanılır. Kayıt, Filebeat → LogStash bağlantısı aracılığıyla yapılır. Okuma LogStash aracılığıyla DMZ dışından yapılır. RabbitMQ üzerinden çalışırken saniyede yaklaşık 4 bin mesaj işleniyor.

Mesaj yönlendirme, sistem adına göre, yani FileBeat yapılandırma verilerine göre yapılandırılır. Tüm mesajlar tek bir sıraya girer. Herhangi bir nedenle sıraya alma hizmeti durdurulursa, bu durum mesaj kaybına neden olmaz: FileBeats bağlantı hataları alır ve gönderimi geçici olarak durdurur. Sıradan okuyan LogStash da ağ hataları alacak ve bağlantının yeniden kurulmasını bekleyecektir. Bu durumda elbette veriler artık veritabanına yazılmayacaktır.

Kuyrukları oluşturmak ve yapılandırmak için aşağıdaki talimatlar kullanılır:

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. Gösterge tabloları

Bu bileşen izleme verilerini görselleştirmek için kullanılır. Bu durumda Grafana 4.6+ eklentisi için ClickHouse veri kaynağını yüklemeniz gerekir. Kontrol panelinde SQL filtrelerinin işlenmesinin verimliliğini artırmak için biraz değişiklik yapmak zorunda kaldık.

Örneğin, değişkenleri kullanırız ve eğer bunlar filtre alanında belirtilmemişse, formun NEREDE kısmında bir koşul oluşturmamasını isteriz ( uriStem = "AND uriStem != "). Bu durumda ClickHouse uriStem sütununu okuyacaktır. Bu nedenle, farklı seçenekleri denedik ve sonunda eklentiyi ($valueIfEmpty makrosu), sütunun kendisinden bahsetmeden, boş bir değer durumunda 1 değerini döndürecek şekilde düzelttik.

Artık grafik için bu sorguyu kullanabilirsiniz

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

bu şekilde SQL'e dönüştürülür (boş uriStem alanlarının yalnızca 1'e dönüştürüldüğünü unutmayın)

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

Sonuç

ClickHouse veritabanının ortaya çıkışı piyasada bir dönüm noktası haline geldi. Bir anda, tamamen ücretsiz olarak, büyük verilerle çalışmak için güçlü ve pratik bir araçla donatıldığımızı hayal etmek zordu. Elbette ihtiyaçlar arttıkça (örneğin, parçalama ve birden fazla sunucuya kopyalama) şema daha karmaşık hale gelecektir. Ancak ilk izlenimlere göre bu veritabanıyla çalışmak çok keyifli. Ürünün “insanlar için” üretildiği açıktır.

ElasticSearch ile karşılaştırıldığında, ön tahminlere göre günlüklerin saklanması ve işlenmesi maliyeti beş ila on kat azalır. Başka bir deyişle, mevcut veri hacmi için birkaç makineden oluşan bir küme oluşturmamız gerekiyorsa, ClickHouse'u kullanırken yalnızca bir düşük güçlü makineye ihtiyacımız var. Evet, elbette ElasticSearch ayrıca disk üzerinde veri sıkıştırma mekanizmalarına ve kaynak tüketimini önemli ölçüde azaltabilecek diğer özelliklere de sahiptir, ancak ClickHouse ile karşılaştırıldığında bu daha fazla maliyet gerektirecektir.

Tarafımızdan herhangi bir özel optimizasyon yapılmadan, varsayılan ayarlarla, veri yükleme ve veri tabanından veri alma inanılmaz bir hızda çalışır. Henüz çok fazla verimiz yok (yaklaşık 200 milyon kayıt), ancak sunucunun kendisi zayıf. Bu aracı gelecekte günlüklerin saklanmasıyla ilgili olmayan başka amaçlar için de kullanabiliriz. Örneğin güvenlik alanında uçtan uca analitik için makine öğrenimi.

Sonunda, artıları ve eksileri hakkında biraz.

Eksileri

  1. Kayıtları büyük gruplar halinde yükleme. Bir yandan bu bir özelliktir, ancak yine de kayıtları ara belleğe almak için ek bileşenler kullanmanız gerekir. Bu görev her zaman basit değildir ancak yine de çözülebilir. Ve planı basitleştirmek istiyorum.
  2. Bazı egzotik işlevler veya yeni özellikler sıklıkla yeni sürümlerde bozulur. Bu durum endişeleri artırıyor ve yeni bir sürüme yükseltme isteğini azaltıyor. Örneğin Kafka tablo motoru, tüketicileri uygulamadan olayları doğrudan Kafka'dan okumanıza olanak tanıyan çok kullanışlı bir özelliktir. Ancak Github'daki Sorunların sayısına bakılırsa, bu motoru üretimde kullanma konusunda hâlâ ihtiyatlıyız. Ancak yana doğru ani hareketler yapmazsanız ve temel işlevleri kullanmazsanız stabil çalışır.

Avantajları:

  1. Yavaşlamaz.
  2. Düşük giriş eşiği.
  3. Açık kaynak
  4. Özgür.
  5. Ölçeklenebilir (parçalama/kullanıma hazır çoğaltma)
  6. İletişim Bakanlığı tarafından önerilen Rus yazılımlarının kaydına dahil edilmiştir.
  7. Yandex'den resmi desteğin varlığı.

Kaynak: habr.com

Yorum ekle