Cơ sở dữ liệu ClickHouse cho con người hoặc Công nghệ ngoài hành tinh

Alexey Lizunov, người đứng đầu trung tâm năng lực các kênh dịch vụ từ xa của Tổng cục Công nghệ thông tin ICB

Cơ sở dữ liệu ClickHouse cho con người hoặc Công nghệ ngoài hành tinh

Để thay thế cho ngăn xếp ELK (ElasticSearch, Logstash, Kibana), chúng tôi đang tiến hành nghiên cứu về cách sử dụng cơ sở dữ liệu ClickHouse làm nơi lưu trữ dữ liệu cho nhật ký.

Trong bài viết này, chúng tôi muốn nói về trải nghiệm của chúng tôi khi sử dụng cơ sở dữ liệu ClickHouse và kết quả sơ bộ từ hoạt động thí điểm. Điều đáng chú ý ngay là kết quả rất ấn tượng.


Cơ sở dữ liệu ClickHouse cho con người hoặc Công nghệ ngoài hành tinh

Tiếp theo, chúng tôi sẽ mô tả chi tiết hơn về cách hệ thống của chúng tôi được cấu hình và nó bao gồm những thành phần nào. Nhưng bây giờ tôi muốn nói một chút về toàn bộ cơ sở dữ liệu này và lý do tại sao nó đáng được chú ý. Cơ sở dữ liệu ClickHouse là cơ sở dữ liệu cột phân tích hiệu suất cao của Yandex. Được sử dụng trong các dịch vụ Yandex, ban đầu đây là nơi lưu trữ dữ liệu chính cho Yandex.Metrica. Hệ thống mã nguồn mở, miễn phí. Từ quan điểm của một nhà phát triển, tôi luôn tự hỏi họ đã triển khai điều này như thế nào, bởi vì có lượng dữ liệu cực kỳ lớn. Và bản thân giao diện người dùng Metrica rất linh hoạt và hoạt động nhanh chóng. Khi lần đầu tiên làm quen với cơ sở dữ liệu này, bạn sẽ có ấn tượng: “Cuối cùng thì! Làm “vì nhân dân”! Từ quá trình cài đặt đến gửi yêu cầu.”

Cơ sở dữ liệu này có rào cản gia nhập rất thấp. Ngay cả một nhà phát triển trung bình cũng có thể cài đặt cơ sở dữ liệu này trong vài phút và bắt đầu sử dụng nó. Mọi thứ đều hoạt động trơn tru. Ngay cả những người mới làm quen với Linux cũng có thể nhanh chóng xử lý việc cài đặt và thực hiện các thao tác đơn giản. Nếu trước đó, khi nghe đến những từ Big Data, Hadoop, Google BigTable, HDFS, các nhà phát triển bình thường đều có ý tưởng rằng họ đang nói về vài terabyte, petabyte, rằng một số siêu nhân đã tham gia thiết lập và phát triển cho các hệ thống này, thì với sự ra đời của cơ sở dữ liệu ClickHouse, chúng tôi có một công cụ đơn giản, dễ hiểu mà bạn có thể giải quyết một loạt vấn đề trước đây không thể giải quyết được. Tất cả chỉ cần một chiếc máy khá trung bình và năm phút để cài đặt. Nghĩa là, chúng tôi có một cơ sở dữ liệu chẳng hạn như MySql, nhưng chỉ để lưu trữ hàng tỷ bản ghi! Một loại siêu lưu trữ với ngôn ngữ SQL. Giống như con người được tặng vũ khí của người ngoài hành tinh vậy.

Giới thiệu về hệ thống thu thập nhật ký của chúng tôi

Để thu thập thông tin, chúng tôi sử dụng tệp nhật ký IIS của các ứng dụng web có định dạng chuẩn (hiện chúng tôi cũng đang tham gia phân tích nhật ký ứng dụng, nhưng mục tiêu chính của chúng tôi ở giai đoạn thử nghiệm là thu thập nhật ký IIS).

Chúng tôi không thể từ bỏ hoàn toàn ngăn xếp ELK vì nhiều lý do và chúng tôi tiếp tục sử dụng các thành phần LogStash và Filebeat, những thành phần này đã được chứng minh là tốt và hoạt động khá đáng tin cậy và có thể dự đoán được.

Sơ đồ ghi nhật ký chung được hiển thị trong hình dưới đây:

Cơ sở dữ liệu ClickHouse cho con người hoặc Công nghệ ngoài hành tinh

Một tính năng của việc ghi dữ liệu trong cơ sở dữ liệu ClickHouse là việc chèn các bản ghi không thường xuyên (một lần mỗi giây) theo lô lớn. Rõ ràng đây là phần “có vấn đề” nhất mà bạn gặp phải khi làm việc với cơ sở dữ liệu ClickHouse lần đầu tiên: sơ đồ trở nên phức tạp hơn một chút.
Plugin dành cho LogStash, chèn dữ liệu trực tiếp vào ClickHouse, đã giúp ích rất nhiều ở đây. Thành phần này được triển khai trên cùng một máy chủ với chính cơ sở dữ liệu. Vì vậy, nói chung, không nên làm điều này, nhưng từ quan điểm thực tế, để không tạo các máy chủ riêng biệt trong khi nó được triển khai trên cùng một máy chủ. Chúng tôi không quan sát thấy bất kỳ lỗi hoặc xung đột tài nguyên nào với cơ sở dữ liệu. Ngoài ra, cần lưu ý rằng plugin có cơ chế truy cập lại trong trường hợp xảy ra lỗi. Và trong trường hợp xảy ra lỗi, plugin sẽ ghi vào đĩa một lô dữ liệu không thể chèn được (định dạng tệp thuận tiện: sau khi chỉnh sửa, bạn có thể dễ dàng chèn lô đã sửa bằng clickhouse-client).

Danh sách đầy đủ các phần mềm được sử dụng trong chương trình được trình bày trong bảng:

Danh sách phần mềm sử dụng

tên

Описание

Liên kết phân phối

nginx

Proxy ngược để hạn chế quyền truy cập theo cổng và ủy quyền tổ chức

Hiện tại không được sử dụng trong chương trình

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

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

FileBeat

Chuyển nhật ký tập tin.

https://www.elastic.co/downloads/beats/filebeat (phân phối cho Windows 64bit).

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

Đăng nhậpStash

Người thu thập nhật ký.

Được sử dụng để thu thập nhật ký từ FileBeat, cũng như thu thập nhật ký từ hàng đợi RabbitMQ (đối với các máy chủ đặt trong DMZ.)

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

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

Logstash- đầu ra- clickhouse

Plugin Loagstash để chuyển nhật ký sang cơ sở dữ liệu ClickHouse theo đợt

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

/usr/share/logstash/bin/logstash-plugin cài đặt logstash-output-clickhouse

/usr/share/logstash/bin/logstash-plugin cài đặt logstash-filter-prune

/usr/share/logstash/bin/logstash-plugin cài đặt logstash-filter-multiline

ClickNhà

Lưu trữ nhật ký 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

Ghi chú. Bắt đầu từ tháng 2018 năm XNUMX, các bản dựng vòng/phút “bình thường” cho RHEL đã xuất hiện trong kho Yandex, vì vậy bạn có thể thử sử dụng chúng. Tại thời điểm cài đặt, chúng tôi đang sử dụng các gói do Altinity biên soạn.

grafana

Trực quan hóa nhật ký. Thiết lập bảng điều khiển

https://grafana.com/

https://grafana.com/grafana/download

Redhat & Centos(64 Bit) – phiên bản mới nhất

Nguồn dữ liệu ClickHouse cho Grafana 4.6+

Plugin cho Grafana với nguồn dữ liệu ClickHouse

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

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

Đăng nhậpStash

Ghi nhật ký bộ định tuyến từ hàng đợi FileBeat sang RabbitMQ.

Ghi chú. Rất tiếc là FileBeat không có đầu ra trực tiếp tới RabbitMQ nên cần có một liên kết trung gian ở dạng Logstash

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

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

ThỏMQ

Hàng đợi tin nhắn. Đây là bộ đệm chứa các mục nhật ký trong 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

Thời gian chạy Erlang (Bắt buộc đối với RabbitMQ)

Thời gian chạy Erlang. Cần thiết để RabbitMQ hoạt động

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

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

Cấu hình máy chủ với cơ sở dữ liệu ClickHouse được trình bày trong bảng sau:

tên

Giá trị

Ghi

Cấu hình

HDD: 40GB
RAM: 8GB
Bộ xử lý: Core 2 2GHz

Bạn nên chú ý đến các mẹo sử dụng cơ sở dữ liệu ClickHouse (https://clickhouse.yandex/docs/ru/operations/tips/)

Phần mềm toàn hệ thống

Hệ điều hành: Máy chủ Linux doanh nghiệp Red Hat (Maipo)

JRE (Java 8)

 

Như bạn có thể thấy, đây là một máy trạm thông thường.

Cấu trúc của bảng lưu trữ log như sau:

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;

Chúng tôi sử dụng các giá trị mặc định để phân vùng (hàng tháng) và mức độ chi tiết của chỉ mục. Tất cả các trường thực tế đều tương ứng với các mục nhật ký IIS để ghi lại các yêu cầu http. Riêng biệt, chúng tôi lưu ý rằng có các trường riêng biệt để lưu trữ thẻ utm (chúng được phân tích cú pháp ở giai đoạn chèn vào bảng từ trường chuỗi truy vấn).

Ngoài ra, một số trường hệ thống đã được thêm vào bảng để lưu trữ thông tin về hệ thống, thành phần và máy chủ. Để biết mô tả về các trường này, hãy xem bảng bên dưới. Trong một bảng, chúng tôi lưu trữ nhật ký cho một số hệ thống.

tên

Описание

Ví dụ

fld_app_name

Tên ứng dụng/hệ thống
Giá trị hợp lệ:

  • site1.domain.com Trang web bên ngoài 1
  • site2.domain.com Trang web bên ngoài 2
  • nội bộ-site1.domain.local Trang web nội bộ 1

site1.domain.com

fld_app_module

Mô-đun hệ thống
Giá trị hợp lệ:

  • web - Trang web
  • svc — Dịch vụ web trang web
  • intgr - Dịch vụ tích hợp web
  • bo — Quản trị viên (BackOffice)

web

fld_website_name

Tên trang web trong IIS

Một số hệ thống có thể được triển khai trên một máy chủ hoặc thậm chí một số phiên bản của một mô-đun hệ thống

web chính

fld_server_name

Tên máy chủ

web1.domain.com

fld_log_file_name

Đường dẫn đến tệp nhật ký trên máy chủ

Từ:inetpublogsLogFiles
W3SVC1u_ex190711.log

Điều này cho phép bạn xây dựng biểu đồ trong Grafana một cách hiệu quả. Ví dụ: xem các yêu cầu từ giao diện người dùng của một hệ thống cụ thể. Điều này tương tự với bộ đếm trang web trong Yandex.Metrica.

Dưới đây là một số thống kê về việc sử dụng cơ sở dữ liệu trong hai tháng.

Số lượng bản ghi theo hệ thống và thành phần

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

Khối lượng dữ liệu đĩa

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.

Tỷ lệ nén dữ liệu cột

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.

Mô tả các thành phần được sử dụng

FileBeat. Chuyển nhật ký tập tin

Thành phần này giám sát các thay đổi đối với tệp nhật ký trên đĩa và chuyển thông tin tới LogStash. Được cài đặt trên tất cả các máy chủ nơi tệp nhật ký được ghi (thường là IIS). Hoạt động ở chế độ đuôi (tức là nó chỉ chuyển các bản ghi đã thêm vào tệp). Nhưng bạn có thể cấu hình riêng nó để chuyển toàn bộ tập tin. Điều này thuận tiện khi bạn cần tải dữ liệu của các tháng trước. Chỉ cần đặt tệp nhật ký vào một thư mục và nó sẽ đọc toàn bộ.

Khi dịch vụ dừng, dữ liệu sẽ ngừng được truyền tiếp vào bộ lưu trữ.

Một cấu hình ví dụ trông như thế này:

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. Trình thu thập nhật ký

Thành phần này được thiết kế để nhận các bản ghi nhật ký từ FileBeat (hoặc thông qua hàng đợi RabbitMQ), phân tích cú pháp và chèn chúng theo đợt vào cơ sở dữ liệu ClickHouse.

Để chèn vào ClickHouse, hãy sử dụng plugin Logstash-output-clickhouse. Plugin Logstash có cơ chế truy xuất các yêu cầu, nhưng trong quá trình tắt máy thường xuyên, tốt hơn hết bạn nên dừng dịch vụ đó. Khi dừng, các tin nhắn sẽ tích lũy trong hàng đợi RabbitMQ, vì vậy nếu thời gian dừng kéo dài thì tốt hơn hết bạn nên dừng Filebeats trên máy chủ. Trong sơ đồ không sử dụng RabbitMQ (trên mạng cục bộ Filebeat gửi trực tiếp nhật ký tới Logstash), Filebeats hoạt động khá chấp nhận được và an toàn, do đó, việc không có đầu ra không có hậu quả đối với chúng.

Một cấu hình ví dụ trông như thế này:

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

đường ống.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. Lưu trữ nhật ký

Nhật ký của tất cả các hệ thống được lưu trong một bảng (xem ở đầu bài viết). Nó được thiết kế để lưu trữ thông tin về các yêu cầu: tất cả các tham số đều giống nhau ở các định dạng khác nhau, ví dụ: nhật ký IIS, nhật ký apache và nginx. Đối với nhật ký ứng dụng, chẳng hạn như ghi lại lỗi, thông báo thông tin, cảnh báo, một bảng riêng sẽ được cung cấp với cấu trúc phù hợp (hiện đang ở giai đoạn thiết kế).

Khi thiết kế bảng, việc quyết định khóa chính (theo đó dữ liệu sẽ được sắp xếp trong quá trình lưu trữ) là rất quan trọng. Mức độ nén dữ liệu và tốc độ truy vấn phụ thuộc vào điều này. Trong ví dụ của chúng tôi, chìa khóa là
ĐẶT HÀNG THEO (fld_app_name, fld_app_module, logdatetime)
Tức là theo tên của hệ thống, tên của thành phần hệ thống và ngày xảy ra sự kiện. Ban đầu, ngày diễn ra sự kiện được đặt lên hàng đầu. Sau khi di chuyển nó đến vị trí cuối cùng, các truy vấn bắt đầu hoạt động nhanh hơn khoảng gấp đôi. Việc thay đổi khóa chính sẽ yêu cầu tạo lại bảng và tải lại dữ liệu để ClickHouse sắp xếp lại dữ liệu trên đĩa. Đây là một thao tác khó, vì vậy nên suy nghĩ kỹ trước về những gì cần đưa vào khóa sắp xếp.

Cũng cần lưu ý rằng kiểu dữ liệu LowCardinality xuất hiện trong các phiên bản tương đối gần đây. Khi sử dụng nó, kích thước của dữ liệu nén sẽ giảm mạnh đối với những trường có lượng số thấp (một vài tùy chọn).

Chúng tôi hiện đang sử dụng phiên bản 19.6 và chúng tôi dự định sẽ thử cập nhật lên phiên bản mới nhất. Ví dụ: chúng có các tính năng tuyệt vời như Độ chi tiết thích ứng, Bỏ qua chỉ mục và codec DoubleDelta.

Theo mặc định, trong quá trình cài đặt, mức ghi cấu hình được đặt thành theo dõi. Nhật ký được xoay và lưu trữ, nhưng đồng thời chúng mở rộng lên tới gigabyte. Nếu không có nhu cầu thì bạn có thể đặt mức cảnh báo, khi đó kích thước nhật ký sẽ giảm mạnh. Cài đặt ghi nhật ký được chỉ định trong tệp config.xml:

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

Một số lệnh hữu ích

Поскольку оригинальные пакеты установки собираются по 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. Đăng nhập bộ định tuyến từ hàng đợi FileBeat sang RabbitMQ

Thành phần này được sử dụng để định tuyến các nhật ký đến từ FileBeat đến hàng đợi RabbitMQ. Có hai điểm ở đây:

  1. Thật không may, FileBeat không có plugin đầu ra để ghi trực tiếp vào RabbitMQ. Và chức năng như vậy, theo đánh giá của bài đăng trên github của họ, không có kế hoạch triển khai. Có một plugin dành cho Kafka, nhưng vì một số lý do nhất định, chúng tôi không thể tự sử dụng nó.
  2. Có các yêu cầu để thu thập nhật ký trong DMZ. Dựa trên chúng, trước tiên các nhật ký phải được xếp hàng đợi và sau đó LogStash đọc các bản ghi từ hàng đợi ra bên ngoài.

Do đó, đặc biệt đối với trường hợp máy chủ đặt trong DMZ, cần phải sử dụng sơ đồ hơi phức tạp như vậy. Một cấu hình ví dụ trông như thế này:

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

ThỏMQ. Hàng đợi tin nhắn

Thành phần này được sử dụng để đệm các mục nhật ký trong DMZ. Việc ghi được thực hiện thông qua liên kết Filebeat → LogStash. Việc đọc được thực hiện từ bên ngoài DMZ thông qua LogStash. Khi hoạt động thông qua RabbitMQ, khoảng 4 nghìn tin nhắn mỗi giây được xử lý.

Định tuyến tin nhắn được định cấu hình theo tên hệ thống, tức là dựa trên dữ liệu cấu hình FileBeat. Tất cả tin nhắn đi vào một hàng đợi. Nếu vì lý do nào đó mà dịch vụ xếp hàng bị dừng, điều này sẽ không dẫn đến mất tin nhắn: FileBeats sẽ nhận được lỗi kết nối và sẽ tạm thời ngừng gửi. Và LogStash đọc từ hàng đợi cũng sẽ nhận lỗi mạng và chờ kết nối được khôi phục. Tất nhiên, trong trường hợp này, dữ liệu sẽ không được ghi vào cơ sở dữ liệu nữa.

Các hướng dẫn sau được sử dụng để tạo và định cấu hình hàng đợi:

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. Trang tổng quan

Thành phần này được sử dụng để trực quan hóa dữ liệu giám sát. Trong trường hợp này, bạn cần cài đặt nguồn dữ liệu ClickHouse cho plugin Grafana 4.6+. Chúng tôi đã phải điều chỉnh nó một chút để cải thiện hiệu quả xử lý các bộ lọc SQL trên trang tổng quan.

Ví dụ: chúng tôi sử dụng các biến và nếu chúng không được chỉ định trong trường bộ lọc thì chúng tôi muốn nó không tạo điều kiện ở WHERE của biểu mẫu ( uriStem = "AND uriStem != "). Trong trường hợp này, ClickHouse sẽ đọc cột uriStem. Vì vậy, chúng tôi đã thử các tùy chọn khác nhau và cuối cùng đã sửa plugin (macro $valueIfEmpty) để trả về 1 trong trường hợp giá trị trống mà không đề cập đến chính cột đó.

Và bây giờ bạn có thể sử dụng truy vấn này cho biểu đồ

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

được chuyển đổi sang SQL như thế này (lưu ý rằng các trường uriStem trống được chuyển đổi thành chỉ 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

Kết luận

Sự xuất hiện của cơ sở dữ liệu ClickHouse đã trở thành một sự kiện mang tính bước ngoặt trên thị trường. Thật khó để tưởng tượng rằng ngay lập tức, hoàn toàn miễn phí, chúng ta lại được trang bị một công cụ mạnh mẽ và thiết thực để làm việc với dữ liệu lớn. Tất nhiên, khi nhu cầu tăng lên (ví dụ: phân chia và sao chép sang nhiều máy chủ), kế hoạch sẽ trở nên phức tạp hơn. Nhưng theo ấn tượng đầu tiên, làm việc với cơ sở dữ liệu này rất dễ chịu. Rõ ràng là sản phẩm được làm ra “vì con người”.

So với ElasticSearch, chi phí lưu trữ và xử lý nhật ký, theo ước tính sơ bộ, giảm từ 5 đến 10 lần. Nói cách khác, nếu với khối lượng dữ liệu hiện tại chúng ta phải thiết lập một cụm gồm nhiều máy thì khi sử dụng ClickHouse chúng ta chỉ cần một máy có công suất thấp. Có, tất nhiên, ElasticSearch cũng có cơ chế nén dữ liệu trên đĩa và các tính năng khác có thể giảm đáng kể mức tiêu thụ tài nguyên, nhưng so với ClickHouse thì điều này sẽ đòi hỏi chi phí cao hơn.

Không có bất kỳ tối ưu hóa đặc biệt nào từ phía chúng tôi, với cài đặt mặc định, việc tải dữ liệu và truy xuất dữ liệu từ cơ sở dữ liệu hoạt động với tốc độ đáng kinh ngạc. Chúng tôi chưa có nhiều dữ liệu (khoảng 200 triệu bản ghi), nhưng bản thân máy chủ thì yếu. Chúng tôi có thể sử dụng công cụ này trong tương lai cho các mục đích khác không liên quan đến việc lưu trữ nhật ký. Ví dụ: đối với phân tích từ đầu đến cuối, trong lĩnh vực bảo mật, học máy.

Cuối cùng, một chút về ưu và nhược điểm.

Nhược điểm

  1. Đang tải hồ sơ theo lô lớn. Một mặt, đây là một tính năng nhưng bạn vẫn phải sử dụng các thành phần bổ sung để đệm các bản ghi. Nhiệm vụ này không phải lúc nào cũng đơn giản nhưng vẫn có thể giải quyết được. Và tôi muốn đơn giản hóa sơ đồ này.
  2. Một số chức năng kỳ lạ hoặc tính năng mới thường bị hỏng trong các phiên bản mới. Điều này gây lo ngại, làm giảm mong muốn nâng cấp lên phiên bản mới. Ví dụ: công cụ bảng Kafka là một tính năng rất hữu ích cho phép bạn đọc trực tiếp các sự kiện từ Kafka mà không cần triển khai người tiêu dùng. Nhưng xét theo số lượng Vấn đề trên Github, chúng tôi vẫn cảnh giác khi sử dụng công cụ này trong sản xuất. Tuy nhiên, nếu bạn không thực hiện các chuyển động đột ngột sang một bên và sử dụng các chức năng cơ bản thì nó sẽ hoạt động ổn định.

Ưu điểm

  1. Không chậm lại.
  2. Ngưỡng đầu vào thấp.
  3. Mã nguồn mở.
  4. Miễn phí.
  5. Có thể mở rộng (sharding/sao chép sẵn dùng)
  6. Bao gồm trong sổ đăng ký phần mềm tiếng Nga do Bộ Truyền thông khuyến nghị.
  7. Có sẵn hỗ trợ chính thức từ Yandex.

Nguồn: www.habr.com

Thêm một lời nhận xét