אלכסי ליזונוב, ראש מרכז הכשירות לערוצי שירות מרוחקים של מינהלת טכנולוגיות המידע של ה-MKB

כחלופה למחסנית ELK (ElasticSearch, Logstash, Kibana), אנו עורכים מחקר על השימוש במסד הנתונים של ClickHouse כמאגר נתונים עבור יומנים.
במאמר זה נרצה לדבר על הניסיון שלנו בשימוש במסד הנתונים של ClickHouse ועל התוצאות הראשוניות של פעולת הפיילוט. יש לציין מיד שהתוצאות היו מרשימות.

לאחר מכן, נתאר ביתר פירוט כיצד המערכת שלנו מוגדרת ומאילו רכיבים היא מורכבת. אבל עכשיו אני רוצה לדבר קצת על מסד הנתונים הזה בכללותו, ולמה כדאי לשים לב אליו. מסד הנתונים של ClickHouse הוא מסד נתונים עמודות אנליטי בעל ביצועים גבוהים מבית Yandex. הוא משמש בשירותי Yandex, בתחילה זהו אחסון הנתונים העיקרי עבור Yandex.Metrica. מערכת קוד פתוח, בחינם. מנקודת מבט של מפתח, תמיד תהיתי איך הם יישמו את זה, כי יש נתונים גדולים להפליא. וממשק המשתמש של Metrica עצמו מאוד גמיש ומהיר. בהיכרות ראשונה עם מאגר זה, הרושם הוא: "טוב, סוף סוף! נוצר עבור האנשים! החל מתהליך ההתקנה וכלה בשליחת בקשות.
למסד הנתונים הזה יש מחסום כניסה נמוך מאוד. אפילו מפתח עם מיומנות ממוצעת יכול להתקין אותו ולהתחיל להשתמש בו תוך מספר דקות. הכל עובד בצורה חלקה. אפילו אנשים חדשים בו. Linux, יכול להתמודד עם התקנה ופעולות פשוטות די מהר. בעוד שבעבר, המילים Big Data, Hadoop, Google BigTable ו-HDFS היו גורמות למפתח הממוצע לדמיין טרה-בייט ופטה-בייט של נתונים, ושכמה בני-על היו אחראים על התצורה והפיתוח של מערכות אלו, עם הופעתו של מסד הנתונים ClickHouse, יש לנו כעת כלי פשוט ואינטואיטיבי שיכול לפתור מגוון בעיות שלא היו ניתנות להשגה בעבר. כל מה שצריך זה מכונה אחת ממוצעת למדי וחמש דקות להתקנה. במילים אחרות, כעת יש לנו מסד נתונים כמו, נניח, MySQL, אבל לאחסון מיליארדי רשומות! סוג של סופר-ארכיון עם שפת SQL. זה כאילו בני אדם קיבלו נשק חייזרים.
על מערכת הרישום שלנו
כדי לאסוף מידע, נעשה שימוש בקובצי יומן IIS של יישומי אינטרנט בפורמט סטנדרטי (אנחנו גם מנתחים כעת יומני יישומים, אך המטרה העיקרית בשלב הפיילוט היא איסוף יומני IIS).
מסיבות שונות, לא יכולנו לנטוש לחלוטין את מחסנית ה-ELK, ואנו ממשיכים להשתמש ברכיבי LogStash ו-Filebeat, שהוכיחו את עצמם היטב ועובדים בצורה די אמינה וצפויה.
סכימת הרישום הכללית מוצגת באיור שלהלן:

תכונה של כתיבת נתונים למסד הנתונים של ClickHouse היא הכנסה נדירה (פעם בשנייה) של רשומות באצוות גדולות. זה, ככל הנראה, החלק הכי "בעייתי" שאתה נתקל בו כשאתה מתנסה בעבודה עם מסד הנתונים של ClickHouse: הסכימה הופכת קצת יותר מסובכת.
התוסף ל-LogStash, שמכניס נתונים ישירות ל-ClickHouse, עזר כאן מאוד. רכיב זה פרוס על אותו שרת כמו מסד הנתונים עצמו. אז באופן כללי, לא מומלץ לעשות את זה, אלא מבחינה מעשית, כדי לא לייצר שרתים נפרדים בזמן שהוא פרוס על אותו שרת. לא ראינו כשלים או התנגשויות משאבים עם מסד הנתונים. בנוסף, יש לציין כי לתוסף יש מנגנון ניסיון חוזר במקרה של שגיאות. ובמקרה של שגיאות, התוסף כותב לדיסק אצווה של נתונים שלא ניתן היה להכניס (פורמט הקובץ נוח: לאחר העריכה ניתן להכניס בקלות את האצווה המתוקנת באמצעות clickhouse-client).
רשימה מלאה של תוכנות המשמשות בסכימה מוצגת בטבלה:
רשימת התוכנות שבהן נעשה שימוש
שם
תיאור
קישור להפצה
nginx
פרוקסי הפוך להגבלת גישה לפי יציאות ולארגון הרשאות
כרגע לא בשימוש בתכנית
FileBeat
העברת יומני קבצים.
(הפצה עבור Windows 64 ביט).
logstash
אספן בולי עץ.
משמש לאיסוף יומנים מ-FileBeat, כמו גם לאיסוף יומנים מהתור של RabbitMQ (עבור שרתים שנמצאים ב-DMZ.)
Logstash-output-clickhouse
תוסף Loagstash להעברת יומנים למסד הנתונים של ClickHouse באצוות
/usr/share/logstash/bin/logstash-plugin התקנת logstash-output-clickhouse
/usr/share/logstash/bin/logstash-plugin התקנת logstash-filter-prune
/usr/share/logstash/bin/logstash-plugin התקנת logstash-filter-multiline
קליקהאוס
אחסון יומנים
הערה. החל מאוגוסט 2018, בניית סל"ד "רגילה" עבור RHEL הופיעו במאגר Yandex, כך שתוכל לנסות להשתמש בהם. בזמן ההתקנה, השתמשנו בחבילות שנבנו על ידי Altinity.
גרפנה
הדמיית יומן. הגדרת לוחות מחוונים
רדהאט ו Centos(64 ביט) – הגרסה האחרונה
מקור נתונים של ClickHouse עבור Grafana 4.6+
תוסף עבור Grafana עם מקור נתונים ClickHouse
logstash
התחבר לנתב מ-FileBeat לתור RabbitMQ.
הערה. לרוע המזל FileBeat אינו מפלט ישירות ל-RabbitMQ, ולכן נדרש קישור ביניים בצורה של Logstash
RabbitMQ
תור הודעות. זהו מאגר היומן ב-DMZ
זמן ריצה של Erlang (נדרש עבור RabbitMQ)
זמן ריצה של ארלנג. נדרש עבור RabbitMQ לעבוד
תצורת השרת עם מסד הנתונים של ClickHouse מוצגת בטבלה הבאה:
שם
ערך
שים לב
תְצוּרָה
דיסק קשיח: 40GB
זיכרון RAM: 8GB
מעבד: Core 2 2Ghz
יש לשים לב לעצות להפעלת מסד הנתונים של ClickHouse ()
תוכנת מערכת כללית
מערכת הפעלה: רד האט אנטרפרייז Linux שרת (מאיפו)
JRE (Java 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 - Integration Web Service
- bo - Admin (BackOffice)
אינטרנט
fld_website_name
שם האתר ב-IIS
ניתן לפרוס מספר מערכות בשרת אחד, או אפילו מספר מופעים של מודול מערכת אחד
ראשי אינטרנט
fld_server_name
שם שרת
web1.domain.com
fld_log_file_name
נתיב לקובץ היומן בשרת
C:inetpublogsLogFiles
W3SVC1u_ex190711.log
זה מאפשר לך לבנות ביעילות גרפים בגרפאנה. לדוגמה, הצג בקשות מהחזית של מערכת מסוימת. זה דומה למונה האתרים ב-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: ~logstash. אספן יומנים
רכיב זה נועד לקבל רשומות יומן מ-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"
}
}
}pipelines.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"בית קליק. אחסון יומנים
היומנים של כל המערכות מאוחסנים בטבלה אחת (ראה בתחילת המאמר). הוא נועד לאחסן מידע על בקשות: כל הפרמטרים דומים עבור פורמטים שונים, כגון יומני IIS, apache ו-nginx. עבור יומני יישומים, בהם נרשמות, למשל, שגיאות, הודעות מידע, אזהרות, תינתן טבלה נפרדת עם המבנה המתאים (כרגע בשלב התכנון).
בעת עיצוב טבלה, חשוב מאוד להחליט על המפתח הראשי (על פיו ימוינו הנתונים במהלך האחסון). מידת דחיסת הנתונים ומהירות השאילתה תלויים בכך. בדוגמה שלנו, המפתח הוא
ORDER BY (fld_app_name, fld_app_module, logdatetime)
כלומר לפי שם המערכת, שם רכיב המערכת ותאריך האירוע. בתחילה, תאריך האירוע הגיע ראשון. לאחר העברתו למקום האחרון, השאילתות החלו לעבוד בערך פי שניים מהר יותר. שינוי המפתח הראשי ידרוש יצירה מחדש של הטבלה וטעינה מחדש של הנתונים כך ש-ClickHouse ימיין מחדש את הנתונים בדיסק. מדובר בפעולה כבדה ולכן כדאי לחשוב הרבה מה צריך לכלול במפתח המיון.
יש לציין גם שסוג הנתונים LowCardinality הופיע יחסית בגרסאות האחרונות. בעת השימוש בו, גודל הנתונים הדחוסים מצטמצם באופן דרסטי עבור אותם שדות בעלי קרדינליות נמוכה (אפשרויות מעטות).
גרסה 19.6 נמצאת כעת בשימוש ואנו מתכננים לנסות לעדכן לגרסה העדכנית ביותר. יש להם תכונות נפלאות כמו Adaptive Granularity, דילוג על מדדי ו-DoubleDelta, למשל.
כברירת מחדל, במהלך ההתקנה, רמת הרישום מוגדרת למעקב. היומנים מסובבים ומאוחסנים בארכיון, אך במקביל הם מתרחבים עד לגיגה-בייט. אם אין צורך, אז אתה יכול להגדיר את רמת האזהרה, ואז גודל היומן מצטמצם באופן דרסטי. הגדרת הרישום מוגדרת בקובץ 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/nulllogstash. התחבר לנתב מ-FileBeat לתור RabbitMQ
רכיב זה משמש לניתוב יומנים המגיעים מ-FileBeat לתור RabbitMQ. יש כאן שתי נקודות:
- לרוע המזל, ל-FileBeat אין תוסף פלט לכתיבה ישירות ל-RabbitMQ. ופונקציונליות כזו, אם לשפוט לפי הנושא ב-github שלהם, לא מתוכננת ליישום. יש תוסף לקפקא, אבל משום מה אנחנו לא יכולים להשתמש בו בבית.
- ישנן דרישות לאיסוף יומנים ב-DMZ. בהתבסס עליהם, תחילה יש להוסיף את היומנים לתור ולאחר מכן 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
}
}RabbitMQ. תור הודעות
רכיב זה משמש לאגירת ערכי יומן ב-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 מיליון רשומות), אבל השרת עצמו חלש. נוכל להשתמש בכלי זה בעתיד למטרות אחרות שאינן קשורות לאחסון יומנים. לדוגמה, עבור אנליטיקה מקצה לקצה, בתחום האבטחה, למידת מכונה.
בסוף, קצת על היתרונות והחסרונות.
חסרונות
- טעינת רשומות בקבוצות גדולות. מצד אחד, זו תכונה, אבל אתה עדיין צריך להשתמש ברכיבים נוספים לאגירת רשומות. משימה זו לא תמיד קלה, אך עדיין ניתנת לפתרון. ואני רוצה לפשט את התוכנית.
- פונקציונליות אקזוטית מסוימת או תכונות חדשות נשברות לעתים קרובות בגרסאות חדשות. זה מעורר דאגה, ומפחית את הרצון לשדרג לגרסה חדשה. לדוגמה, מנוע השולחן של קפקא הוא תכונה שימושית מאוד המאפשרת לקרוא אירועים מקפקא ישירות, מבלי ליישם צרכנים. אבל אם לשפוט לפי מספר הבעיות ב-github, אנחנו עדיין נזהרים לא להשתמש במנוע הזה בייצור. עם זאת, אם אתה לא עושה מחוות פתאומיות לצד ומשתמש בפונקציונליות העיקרית, אז זה עובד ביציבות.
Pros
- לא מאט.
- סף כניסה נמוך.
- קוד פתוח
- חינם.
- קנה מידה טוב (ריסוק/שכפול מחוץ לקופסה)
- כלול בפנקס התוכנות הרוסיות המומלצות על ידי משרד התקשורת.
- נוכחות של תמיכה רשמית מ- Yandex.
מקור: www.habr.com
