ClickHouse Database for Humans أو Alien Technologies

أليكسي ليزونوف ، رئيس مركز الكفاءة لقنوات الخدمة عن بعد في مديرية تكنولوجيا المعلومات في MKB

ClickHouse Database for Humans أو Alien Technologies

كبديل لمكدس ELK (ElasticSearch ، Logstash ، Kibana) ، نجري بحثًا حول استخدام قاعدة بيانات ClickHouse كمخزن بيانات للسجلات.

في هذا المقال ، نود أن نتحدث عن تجربتنا في استخدام قاعدة بيانات ClickHouse والنتائج الأولية للعملية التجريبية. وتجدر الإشارة على الفور إلى أن النتائج كانت رائعة.


ClickHouse Database for Humans أو Alien Technologies

بعد ذلك ، سنصف بمزيد من التفصيل كيفية تكوين نظامنا والمكونات التي يتكون منها. لكن الآن أود أن أتحدث قليلاً عن قاعدة البيانات هذه ككل ، ولماذا تستحق الاهتمام بها. قاعدة بيانات ClickHouse هي قاعدة بيانات عمودية تحليلية عالية الأداء من Yandex. يتم استخدامه في خدمات Yandex ، وهو في البداية مخزن البيانات الرئيسي لـ Yandex.Metrica. نظام مفتوح المصدر ، مجاني. من وجهة نظر مطور ، لطالما تساءلت كيف قاموا بتطبيقه ، لأن هناك بيانات ضخمة بشكل خيالي. وواجهة مستخدم Metrica نفسها مرنة وسريعة للغاية. عند التعارف الأول على قاعدة البيانات هذه ، كان الانطباع هو: "حسنًا ، أخيرًا! صنع للشعب! تبدأ من عملية التثبيت وتنتهي بإرسال الطلبات.

قاعدة البيانات هذه لديها عتبة دخول منخفضة للغاية. حتى المطور ذو المهارات المتوسطة يمكنه تثبيت قاعدة البيانات هذه في بضع دقائق والبدء في استخدامها. كل شيء يعمل بشكل واضح. حتى الأشخاص الجدد في Linux يمكنهم التعامل بسرعة مع التثبيت والقيام بأبسط العمليات. إذا كان في وقت سابق ، مع الكلمات Big Data و Hadoop و Google BigTable و HDFS ، كان لدى مطور عادي أفكار حول بعض تيرابايت ، بيتابايت ، أن بعض البشر الخارقين يشاركون في الإعدادات والتطوير لهذه الأنظمة ، ثم مع ظهور ClickHouse قاعدة البيانات ، لدينا أداة بسيطة ومفهومة يمكنك من خلالها حل مجموعة من المهام التي لم يكن من الممكن تحقيقها سابقًا. لا يستغرق الأمر سوى جهاز واحد متوسط ​​إلى حد ما وخمس دقائق للتثبيت. أي أننا حصلنا على قاعدة بيانات مثل MySql ، على سبيل المثال ، ولكن فقط لتخزين مليارات السجلات! مؤرشف فائق معين بلغة SQL. يبدو الأمر كما لو تم تسليم أسلحة كائنات فضائية للناس.

حول نظام التسجيل لدينا

لجمع المعلومات ، يتم استخدام ملفات سجل IIS لتطبيقات الويب ذات التنسيق القياسي (نحن أيضًا نقوم حاليًا بتحليل سجلات التطبيق ، ولكن الهدف الرئيسي في المرحلة التجريبية هو جمع سجلات IIS).

لأسباب مختلفة ، لم نتمكن من التخلي عن مكدس ELK تمامًا ، ونستمر في استخدام مكونات LogStash و Filebeat ، والتي أثبتت نفسها بشكل جيد وتعمل بشكل موثوق تمامًا ويمكن التنبؤ به.

يظهر مخطط التسجيل العام في الشكل أدناه:

ClickHouse Database for Humans أو Alien Technologies

ميزة كتابة البيانات إلى قاعدة بيانات ClickHouse هي إدراج السجلات على دفعات كبيرة (مرة واحدة في الثانية) بشكل غير متكرر. هذا ، على ما يبدو ، هو الجزء الأكثر "إشكالية" الذي تواجهه عندما واجهت العمل مع قاعدة بيانات ClickHouse لأول مرة: يصبح المخطط أكثر تعقيدًا بعض الشيء.
ساعد المكوِّن الإضافي لـ LogStash ، والذي يقوم بإدراج البيانات مباشرةً في ClickHouse ، كثيرًا هنا. يتم نشر هذا المكون على نفس الخادم مثل قاعدة البيانات نفسها. لذلك ، بشكل عام ، لا ينصح بالقيام بذلك ، ولكن من وجهة نظر عملية ، حتى لا يتم إنتاج خوادم منفصلة أثناء نشرها على نفس الخادم. لم نلاحظ أي حالات فشل أو تضارب في الموارد مع قاعدة البيانات. بالإضافة إلى ذلك ، تجدر الإشارة إلى أن البرنامج المساعد لديه آلية إعادة المحاولة في حالة حدوث أخطاء. وفي حالة وجود أخطاء ، يكتب البرنامج المساعد قرص مجموعة من البيانات التي لا يمكن إدراجها (تنسيق الملف مناسب: بعد التحرير ، يمكنك بسهولة إدخال الدُفعة المصححة باستخدام clickhouse-client).

يتم عرض قائمة كاملة بالبرامج المستخدمة في المخطط في الجدول:

قائمة البرامج المستخدمة

الاسم

وصف

رابط التوزيع

NGINX

عكس الوكيل لتقييد الوصول عن طريق المنافذ وتنظيم التفويض

حاليا لا تستخدم في المخطط

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

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

FileBeat

نقل سجلات الملفات.

https://www.elastic.co/downloads/beats/filebeat (مجموعة توزيع لنظام التشغيل Windows 64 بت).

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

لوغستاش

جامع السجلات.

تُستخدم لجمع السجلات من FileBeat ، وكذلك لتجميع السجلات من قائمة انتظار RabbitMQ (للخوادم الموجودة في DMZ.)

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

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

Logstash-output-clickhouse

البرنامج المساعد Loagstash لنقل السجلات إلى قاعدة بيانات ClickHouse على دفعات

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

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

/ usr / share / logstash / bin / logstash-plugin قم بتثبيت logstash-filter-prune

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

كليكهاوس

تخزين السجل 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

ملحوظة. بدءًا من أغسطس 2018 ، ظهرت إصدارات rpm "العادية" لـ RHEL في مستودع Yandex ، لذا يمكنك محاولة استخدامها. في وقت التثبيت ، كنا نستخدم الحزم التي أنشأتها Altinity.

جرافانا

تصور السجل. إعداد لوحات المعلومات

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos (64 Bit) - أحدث إصدار

مصدر بيانات ClickHouse لـ Grafana 4.6+

البرنامج المساعد لـ Grafana مع مصدر بيانات ClickHouse

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

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

لوغستاش

تسجيل الموجه من FileBeat إلى قائمة انتظار RabbitMQ.

ملحوظة. لسوء الحظ ، لا يحتوي FileBeat على إخراج مباشرة إلى RabbitMQ ، لذلك يلزم وجود رابط وسيط في شكل Logstash

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

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

RabbitMQ

قائمة انتظار الرسائل. هذا هو المخزن المؤقت للسجل في المنطقة المجردة من السلاح

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 (مطلوب لـ RabbitMQ)

وقت تشغيل Erlang. مطلوب لـ RabbitMQ للعمل

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

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

يتم تقديم تكوين الخادم مع قاعدة بيانات ClickHouse في الجدول التالي:

الاسم

قيمة

لاحظ

ترتيب

HDD: 40GB
مكبر الصوت ; يدعم
المعالج: Core 2 2GHz

من الضروري الانتباه إلى النصائح الخاصة بتشغيل قاعدة بيانات ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

برامج النظام العامة

نظام التشغيل: Red Hat Enterprise Linux Server (Maipo)

JRE (جافا 8)

 

كما ترى ، هذه محطة عمل عادية.

هيكل الجدول لتخزين السجلات كما يلي:

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;

نستخدم التقسيم الافتراضي (حسب الشهر) ودقة الفهرس. تتوافق جميع الحقول عمليًا مع إدخالات سجل IIS لتسجيل طلبات http. بشكل منفصل ، نلاحظ أن هناك حقولًا منفصلة لتخزين علامات utm (يتم تحليلها في مرحلة الإدراج في الجدول من حقل سلسلة الاستعلام).

أيضًا ، تمت إضافة العديد من حقول النظام إلى الجدول لتخزين معلومات حول الأنظمة والمكونات والخوادم. انظر الجدول أدناه للحصول على وصف لهذه الحقول. في جدول واحد ، نقوم بتخزين السجلات لعدة أنظمة.

الاسم

وصف

مثال

fld_app_name

اسم التطبيق / النظام
القيم الصالحة:

  • site1.domain.com موقع خارجي 1
  • site2.domain.com موقع خارجي 2
  • Internal-site1.domain.local موقع داخلي 1

site1.domain.com

fld_app_module

وحدة النظام
القيم الصالحة:

  • الويب - الموقع
  • svc - خدمة موقع الويب
  • intgr - خدمة ويب التكامل
  • bo - Admin (BackOffice)

الويب

fld_website_name

اسم الموقع في IIS

يمكن نشر العديد من الأنظمة على خادم واحد ، أو حتى عدة حالات لوحدة نظام واحدة

الويب الرئيسي

fld_server_name

اسم الخادم

web1.domain.com

fld_log_file_name

المسار إلى ملف السجل على الخادم

ج: inetpublogsLogFiles
W3SVC1u_ex190711.log

هذا يسمح لك ببناء الرسوم البيانية بكفاءة في Grafana. على سبيل المثال ، اعرض الطلبات من الواجهة الأمامية لنظام معين. هذا مشابه لعداد الموقع في Yandex.Metrica.

فيما يلي بعض الإحصائيات حول استخدام قاعدة البيانات لمدة شهرين.

عدد السجلات الموزعة حسب الأنظمة ومكوناتها

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

مقدار البيانات الموجودة على القرص

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.

درجة ضغط البيانات في الأعمدة

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.

وصف المكونات المستخدمة

FileBeat. نقل سجلات الملفات

يتتبع هذا المكون التغييرات التي تطرأ على ملفات السجل على القرص ويمرر المعلومات إلى LogStash. يتم تثبيته على جميع الخوادم حيث تتم كتابة ملفات السجل (عادةً IIS). يعمل في وضع الذيل (أي ينقل فقط السجلات المضافة إلى الملف). ولكن بشكل منفصل يمكن تهيئته لنقل الملفات بأكملها. هذا مفيد عندما تحتاج إلى تنزيل البيانات من الأشهر السابقة. فقط ضع ملف السجل في مجلد وسيقرأه بالكامل.

عند إيقاف الخدمة ، لم يعد يتم نقل البيانات إلى وحدة التخزين.

مثال على التكوين يبدو كالتالي:

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

لوغستاش. جامع السجلات

تم تصميم هذا المكون لتلقي إدخالات السجل من FileBeat (أو من خلال قائمة انتظار RabbitMQ) ، وتحليل الدفعات وإدخالها في قاعدة بيانات ClickHouse.

للإدراج في ClickHouse ، يتم استخدام المكون الإضافي Logstash-output-clickhouse. يحتوي المكون الإضافي Logstash على آلية إعادة محاولة الطلب ، ولكن مع الإغلاق المنتظم ، من الأفضل إيقاف الخدمة نفسها. عند التوقف ، سيتم تجميع الرسائل في قائمة انتظار RabbitMQ ، لذلك إذا كان التوقف لفترة طويلة ، فمن الأفضل إيقاف Filebeats على الخوادم. في مخطط حيث لا يتم استخدام RabbitMQ (على الشبكة المحلية ، يرسل Filebeat السجلات مباشرة إلى Logstash) ، يعمل Filebeats بشكل مقبول وآمن تمامًا ، لذلك بالنسبة لهم عدم توفر يمر الإخراج دون عواقب.

مثال على التكوين يبدو كالتالي:

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

خطوط الأنابيب

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

بيت النقر. تخزين السجل

يتم تخزين السجلات لجميع الأنظمة في جدول واحد (انظر في بداية المقال). الغرض منه هو تخزين معلومات حول الطلبات: جميع المعلمات متشابهة مع تنسيقات مختلفة ، مثل سجلات IIS و apache وسجلات nginx. بالنسبة لسجلات التطبيق ، التي يتم فيها ، على سبيل المثال ، تسجيل الأخطاء ورسائل المعلومات والتحذيرات ، سيتم تزويد جدول منفصل بالهيكل المناسب (حاليًا في مرحلة التصميم).

عند تصميم جدول ، من المهم جدًا اتخاذ قرار بشأن المفتاح الأساسي (الذي سيتم من خلاله فرز البيانات أثناء التخزين). تعتمد درجة ضغط البيانات وسرعة الاستعلام على هذا. في مثالنا ، المفتاح هو
ORDER BY (fld_app_name، fld_app_module، logdatetime)
أي حسب اسم النظام واسم مكون النظام وتاريخ الحدث. في البداية ، جاء تاريخ الحدث أولاً. بعد نقله إلى المكان الأخير ، بدأت الاستعلامات في العمل أسرع مرتين. سيتطلب تغيير المفتاح الأساسي إعادة إنشاء الجدول وإعادة تحميل البيانات بحيث يقوم ClickHouse بإعادة فرز البيانات الموجودة على القرص. هذه عملية صعبة ، لذا من الجيد التفكير كثيرًا فيما يجب تضمينه في مفتاح الفرز.

وتجدر الإشارة أيضًا إلى أن نوع البيانات LowCardinality ظهر نسبيًا في الإصدارات الحديثة. عند استخدامه ، يتم تقليل حجم البيانات المضغوطة بشكل كبير لتلك الحقول التي تحتوي على عدد قليل من العناصر الأساسية (خيارات قليلة).

الإصدار 19.6 قيد الاستخدام حاليًا ونخطط لمحاولة التحديث إلى أحدث إصدار. لديهم ميزات رائعة مثل Adaptive Granularity و Skipping indexes و DoubleDelta codec ، على سبيل المثال.

بشكل افتراضي ، أثناء التثبيت ، يتم تحديد مستوى التسجيل للتتبع. يتم تدوير السجلات وأرشفتها ، ولكن في نفس الوقت يتم توسيعها حتى غيغا بايت. إذا لم تكن هناك حاجة ، فيمكنك ضبط مستوى التحذير ، ثم يتم تقليل حجم السجل بشكل كبير. يتم ضبط إعداد التسجيل في ملف config.xml:

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

بعض الأوامر المفيدة

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

لوغستاش. تسجيل الموجه من FileBeat إلى قائمة انتظار RabbitMQ

يستخدم هذا المكون لتوجيه السجلات القادمة من FileBeat إلى قائمة انتظار RabbitMQ. هناك نقطتان هنا:

  1. لسوء الحظ ، لا يحتوي FileBeat على مكون إضافي للإخراج للكتابة مباشرة إلى RabbitMQ. وهذه الوظيفة ، بناءً على المشكلة الموجودة على github ، ليست مخططة للتنفيذ. يوجد مكون إضافي لكافكا ، لكن لسبب ما لا يمكننا استخدامه في المنزل.
  2. هناك متطلبات لجمع السجلات في المنطقة المجردة من السلاح. بناءً عليها ، يجب أولاً إضافة السجلات إلى قائمة الانتظار ثم يقوم LogStash بقراءة الإدخالات من قائمة الانتظار من الخارج.

لذلك ، بالنسبة للحالة التي توجد فيها الخوادم في DMZ ، يتعين على المرء استخدام مثل هذا المخطط المعقد قليلاً. مثال على التكوين يبدو كالتالي:

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

الأرنب قائمة انتظار الرسائل

يستخدم هذا المكون لتخزين إدخالات السجل مؤقتًا في DMZ. يتم التسجيل من خلال مجموعة من Filebeat → LogStash. تتم القراءة من خارج DMZ عبر LogStash. عند العمل من خلال RabboitMQ ، تتم معالجة حوالي 4 آلاف رسالة في الثانية.

يتم تكوين توجيه الرسائل حسب اسم النظام ، أي استنادًا إلى بيانات تكوين FileBeat. تنتقل جميع الرسائل إلى قائمة انتظار واحدة. إذا تم إيقاف خدمة قائمة الانتظار لسبب ما ، فلن يؤدي ذلك إلى فقد الرسائل: سيستقبل FileBeats أخطاء الاتصال ويوقف الإرسال مؤقتًا. وسيتلقى LogStash الذي يقرأ من قائمة الانتظار أيضًا أخطاء في الشبكة وينتظر استعادة الاتصال. في هذه الحالة ، لن تتم كتابة البيانات ، بالطبع ، في قاعدة البيانات.

تُستخدم الإرشادات التالية لإنشاء قوائم الانتظار وتكوينها:

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"

جرافانا. لوحات القيادة

يستخدم هذا المكون لتصور بيانات المراقبة. في هذه الحالة ، تحتاج إلى تثبيت مصدر بيانات ClickHouse للمكون الإضافي Grafana 4.6+. كان علينا تعديله قليلاً لتحسين كفاءة معالجة عوامل تصفية SQL على لوحة القيادة.

على سبيل المثال ، نستخدم المتغيرات ، وإذا لم يتم تعيينها في حقل المرشح ، فنحن نرغب في عدم إنشاء شرط في WHERE من النموذج (uriStem = »AND uriStem! =»). في هذه الحالة ، سيقرأ ClickHouse عمود uriStem. بشكل عام ، جربنا خيارات مختلفة وقمنا في النهاية بتصحيح المكون الإضافي (الماكرو valueIfEmpty $) بحيث في حالة وجود قيمة فارغة ، فإنه يُرجع 1 ، دون ذكر العمود نفسه.

والآن يمكنك استخدام هذا الاستعلام للرسم البياني

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

الذي يترجم إلى SQL هذا (لاحظ أنه تم تحويل حقول uriStem الفارغة إلى 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

اختتام

أصبح ظهور قاعدة بيانات ClickHouse حدثًا بارزًا في السوق. كان من الصعب أن نتخيل أننا ، مجانًا تمامًا ، في لحظة تسلحنا بأداة قوية وعملية للعمل مع البيانات الضخمة. بالطبع ، مع الاحتياجات المتزايدة (على سبيل المثال ، التجزئة والنسخ المتماثل إلى خوادم متعددة) ، سيصبح المخطط أكثر تعقيدًا. ولكن في الانطباعات الأولى ، فإن العمل باستخدام قاعدة البيانات هذه أمر ممتع للغاية. يمكن ملاحظة أن المنتج مصنوع "للناس".

مقارنةً بـ ElasticSearch ، فإن تكلفة تخزين السجلات ومعالجتها تقدر بخمس إلى عشر مرات. بعبارة أخرى ، إذا كان علينا إعداد مجموعة من عدة آلات بالنسبة للكمية الحالية من البيانات ، فعند استخدام ClickHouse ، تكفي آلة واحدة منخفضة الطاقة بالنسبة لنا. نعم ، بالطبع ، يحتوي ElasticSearch أيضًا على آليات لضغط البيانات على القرص وميزات أخرى يمكن أن تقلل بشكل كبير من استهلاك الموارد ، ولكن بالمقارنة مع ClickHouse ، سيكون هذا أكثر تكلفة.

بدون أي تحسينات خاصة من جانبنا ، في الإعدادات الافتراضية ، يعمل تحميل البيانات والاختيار من قاعدة البيانات بسرعة مذهلة. ليس لدينا الكثير من البيانات حتى الآن (حوالي 200 مليون سجل) ، لكن الخادم نفسه ضعيف. يمكننا استخدام هذه الأداة في المستقبل لأغراض أخرى لا تتعلق بتخزين السجلات. على سبيل المثال ، للتحليلات الشاملة ، في مجال الأمن ، التعلم الآلي.

في النهاية ، القليل عن الإيجابيات والسلبيات.

سلبيات

  1. تحميل السجلات على دفعات كبيرة. من ناحية ، هذه ميزة ، ولكن لا يزال يتعين عليك استخدام مكونات إضافية لتخزين السجلات مؤقتًا. هذه المهمة ليست دائما سهلة ، لكنها لا تزال قابلة للحل. وأود تبسيط المخطط.
  2. غالبًا ما تتعطل بعض الوظائف الغريبة أو الميزات الجديدة في الإصدارات الجديدة. هذا يسبب القلق ، مما يقلل من الرغبة في الترقية إلى إصدار جديد. على سبيل المثال ، يعد محرك طاولة كافكا ميزة مفيدة للغاية تسمح لك بقراءة الأحداث مباشرة من كافكا ، دون تنفيذ المستهلكين. ولكن بناءً على عدد المشكلات الموجودة على github ، ما زلنا حريصين على عدم استخدام هذا المحرك في الإنتاج. ومع ذلك ، إذا لم تقم بإيماءات مفاجئة للجانب واستخدمت الوظيفة الرئيسية ، فستعمل بثبات.

الايجابيات

  1. لا تبطئ.
  2. عتبة الدخول المنخفضة.
  3. المصدر المفتوح.
  4. حر.
  5. المقاييس جيدة (التجزئة / النسخ المتماثل خارج الصندوق)
  6. المدرجة في سجل البرامج الروسية التي أوصت بها وزارة الاتصالات.
  7. وجود دعم رسمي من شركة Yandex.

المصدر: www.habr.com

إضافة تعليق