Nëse keni përdorur ndonjëherë ndërfaqe në internet për të parë regjistrat, atëherë me siguri keni vënë re se si, si rregull, këto ndërfaqe janë të rënda dhe (shpesh) jo shumë të përshtatshme dhe të përgjegjshme. Disa me të cilat mund të mësoheni, disa janë absolutisht të tmerrshme, por mua më duket se arsyeja për të gjitha problemet është se ne po i afrohemi detyrës së shikimit të regjistrave gabimisht: ne po përpiqemi të krijojmë një ndërfaqe në internet ku CLI (linja e komandës ndërfaqja) funksionon më mirë. Unë personalisht jam shumë rehat duke punuar me tail, grep, awk dhe të tjera, dhe për këtë arsye për mua ndërfaqja ideale për të punuar me logs do të ishte diçka e ngjashme me tail dhe grep, por që mund të përdoret gjithashtu për të lexuar regjistrat që vinin nga shumë serverë. Kjo është, sigurisht, lexoni ato nga ClickHouse!
*sipas mendimit personal të përdoruesit të habra
Njihuni me logscli
Unë nuk dola me një emër për ndërfaqen time, dhe, për të qenë i sinqertë, ai ekziston më tepër në formën e një prototipi, por nëse doni të shihni menjëherë kodin burimor, atëherë jeni të mirëpritur:
Aftësitë
Qëllimi im ishte të krijoja një ndërfaqe që do t'u dukej e njohur për ata që janë mësuar me bisht/grep, domethënë të mbështeste gjërat e mëposhtme:
- Shikoni të gjitha regjistrat, pa filtrim.
- Lini linjat që përmbajnë një nënvarg fiks (flamur
-F
уgrep
). - Lini rreshta që përputhen me shprehjen e rregullt (flamur
-E
уgrep
). - Si parazgjedhje, shikimi është në rend të kundërt kronologjik, pasi regjistrat më të fundit zakonisht janë me interes fillimisht.
- Trego kontekstin pranë çdo rreshti (opsionet
-A
,-B
и-C
уgrep
, duke shtypur N rreshta para, pas dhe rreth çdo rreshti që përputhet, përkatësisht). - Shikoni regjistrat hyrës në kohë reale, me ose pa filtrim (në thelb
tail -f | grep
). - Ndërfaqja duhet të jetë e pajtueshme me
less
,head
,tail
dhe të tjerët - si parazgjedhje, rezultatet duhet të kthehen pa kufizime në numrin e tyre; linjat printohen si një transmetim për sa kohë që përdoruesi është i interesuar t'i marrë ato; sinjalSIGPIPE
duhet të ndërpresin në heshtje transmetimin e regjistrave, ashtu siç bëjnë atatail
,grep
dhe shërbime të tjera të UNIX.
Zbatimi
Unë do të supozoj se ju tashmë dini disi se si të dorëzoni regjistrat në ClickHouse. Nëse jo, unë rekomandoj ta provoni
Së pari ju duhet të vendosni për skemën bazë. Meqenëse zakonisht dëshironi të merrni regjistra të renditur sipas kohës, duket logjike t'i ruani ato në këtë mënyrë. Nëse ka shumë kategori regjistrash dhe të gjitha janë të të njëjtit lloj, atëherë mund të bëni një kategori regjistrash si kolona e parë e çelësit kryesor - kjo do t'ju lejojë të keni një tabelë në vend të disa, gjë që do të jetë një plus i madh kur duke futur në ClickHouse (në serverët me hard disk, rekomandohet të futni të dhëna jo më shumë se ~ 1 herë në sekondë për të gjithë serverin).
Kjo do të thotë, ne kemi nevojë përafërsisht skemën e mëposhtme të tabelës:
CREATE TABLE logs(
category LowCardinality(String), -- категория логов (опционально)
time DateTime, -- время события
millis UInt16, -- миллисекунды (могут быть и микросекунды, и т.д.): рекомендуется хранить, если событий много, чтобы было легче различать события между собой
..., -- ваши собственные поля, например имя сервера, уровень логирования, и так далее
message String -- текст сообщения
) ENGINE=MergeTree()
ORDER BY (category, time, millis)
Fatkeqësisht, nuk munda të gjeja menjëherë ndonjë burim të hapur me regjistra realistë që mund të kapja dhe shkarkoja, kështu që e mora këtë si shembull
udhëzime për ngarkimin e komenteve të Amazon në ClickHouse
Le të krijojmë një tabelë:
CREATE TABLE amazon(
review_date Date,
time DateTime DEFAULT toDateTime(toUInt32(review_date) * 86400 + rand() % 86400),
millis UInt16 DEFAULT rand() % 1000,
marketplace LowCardinality(String),
customer_id Int64,
review_id String,
product_id LowCardinality(String),
product_parent Int64,
product_title String,
product_category LowCardinality(String),
star_rating UInt8,
helpful_votes UInt32,
total_votes UInt32,
vine FixedString(1),
verified_purchase FixedString(1),
review_headline String,
review_body String
)
ENGINE=MergeTree()
ORDER BY (time, millis)
SETTINGS index_granularity=8192
Në grupin e të dhënave të Amazon ka vetëm një datë për një rishikim, por nuk ka kohë të saktë, kështu që le t'i plotësojmë këto të dhëna me një rast.
Ju nuk duhet të shkarkoni të gjithë skedarët tsv dhe të kufizoni veten në ~ 10-20 të parët në mënyrë që të merrni një grup mjaft të madh të dhënash që nuk do të përshtaten në 16 GB RAM. Për të ngarkuar skedarët TSV përdora komandën e mëposhtme:
for i in *.tsv; do
echo $i;
tail -n +2 $i | pv |
clickhouse-client --input_format_allow_errors_ratio 0.5 --query='INSERT INTO amazon(marketplace,customer_id,review_id,product_id,product_parent,product_title,product_category,star_rating,helpful_votes,total_votes,vine,verified_purchase,review_headline,review_body,review_date) FORMAT TabSeparated'
done
Në një disk standard të qëndrueshëm (i cili është një HDD) në Google Cloud me një madhësi prej 1000 GB (e mora këtë madhësi kryesisht në mënyrë që shpejtësia të ishte pak më e lartë, megjithëse ndoshta një SSD e madhësisë së kërkuar do të ishte më e lirë) ngarkimi shpejtësia ishte afërsisht ~ 75 MB/sek në 4 bërthama.
- Duhet të bëj një rezervim që punoj në Google, por kam përdorur një llogari personale dhe ky artikull nuk ka të bëjë fare me punën time në kompani
Unë do të prodhoj të gjitha ilustrimet me këtë grup të dhënash të veçantë, pasi kjo është gjithçka që kisha në dorë.
Trego progresin e skanimit të të dhënave
Meqenëse në ClickHouse ne do të përdorim një skanim të plotë në një tabelë me regjistra dhe ky operacion mund të marrë një sasi të konsiderueshme kohe dhe mund të mos japë rezultate për një kohë të gjatë nëse gjenden pak ndeshje, këshillohet që të jeni në gjendje të tregoni ecuria e pyetjes derisa të merren rreshtat e parë me rezultatin. Për ta bërë këtë, ekziston një parametër në ndërfaqen HTTP që ju lejon të dërgoni përparimin në titujt HTTP: send_progress_in_http_headers=1
. Fatkeqësisht, biblioteka standarde Go nuk mund t'i lexojë titujt ashtu siç merren, por ndërfaqja HTTP 1.0 (për të mos u ngatërruar me 1.1!) mbështetet nga ClickHouse, kështu që ju mund të hapni një lidhje të papërpunuar TCP me ClickHouse dhe ta dërgoni atje GET /?query=... HTTP/1.0nn
dhe merrni titujt dhe trupin e përgjigjes pa asnjë ikje ose enkriptim, kështu që në këtë rast nuk kemi nevojë as të përdorim bibliotekën standarde.
Transmetimi i regjistrave nga ClickHouse
ClickHouse ka pasur optimizim për pyetjet me ORDER BY për një kohë relativisht të gjatë (që nga viti 2019?), kështu që një pyetje si
SELECT time, millis, message
FROM logs
WHERE message LIKE '%something%'
ORDER BY time DESC, millis DESC
Menjëherë do të fillojë të kthejë linjat që kanë nënvargun "diçka" në mesazhin e tyre, pa pritur që skanimi të përfundojë.
Gjithashtu, do të ishte shumë i përshtatshëm nëse vetë ClickHouse do ta anulonte kërkesën kur lidhja me të u mbyll, por kjo nuk është sjellja e paracaktuar. Anulimi automatik i kërkesës mund të aktivizohet duke përdorur opsionin cancel_http_readonly_queries_on_client_close=1
.
Trajtimi i saktë i SIGPIPE në Go
Kur ekzekutoni, le të themi, komandën some_cmd | head -n 10
, saktësisht si komanda some_cmd
ndalon ekzekutimin kur head
zbriten 10 rreshta? Përgjigja është e thjeshtë: kur head
përfundon, tubi mbyllet dhe stdout i komandës some_cmd fillon të tregojë, me kusht, "në askund". Kur some_cmd
përpiqet të shkruajë në një tub të mbyllur,
Në Go kjo ndodh gjithashtu si parazgjedhje, por mbajtësi i sinjalit SIGPIPE gjithashtu printon "sinjal: SIGPIPE" ose një mesazh të ngjashëm në fund, dhe për të pastruar këtë mesazh, thjesht duhet ta trajtojmë vetë SIGPIPE ashtu siç duam, domethënë në heshtje. dalje:
ch := make(chan os.Signal)
signal.Notify(ch, syscall.SIGPIPE)
go func() {
<-ch
os.Exit(0)
}()
Trego kontekstin e mesazhit
Shpesh ju dëshironi të shihni kontekstin në të cilin ndodhi ndonjë gabim (për shembull, cila kërkesë shkaktoi panik, ose cilat probleme të lidhura ishin të dukshme përpara përplasjes) dhe në grep
Kjo bëhet duke përdorur opsionet -A, -B dhe -C, të cilat tregojnë numrin e caktuar të rreshtave përkatësisht pas, para dhe rreth mesazhit.
Fatkeqësisht, nuk kam gjetur një mënyrë të thjeshtë për të bërë të njëjtën gjë në ClickHouse, kështu që për të shfaqur kontekstin, një kërkesë shtesë si kjo dërgohet në secilën rresht të rezultatit (detajet varen nga renditja dhe nëse konteksti shfaqet më parë ose pas):
SELECT time,millis,review_body FROM amazon
WHERE (time = 'ВРЕМЯ_СОБЫТИЯ' AND millis < МИЛЛИСЕКУНДЫ_СОБЫТИЯ) OR (time < 'ВРЕМЯ_СОБЫТИЯ')
ORDER BY time DESC, millis DESC
LIMIT КОЛИЧЕСТВО_СТРОК_КОНТЕКСТА
SETTINGS max_threads=1
Meqenëse kërkesa dërgohet pothuajse menjëherë pasi ClickHouse të kthejë linjën përkatëse, ajo përfundon në cache dhe në përgjithësi kërkesa ekzekutohet mjaft shpejt dhe konsumon pak CPU (zakonisht kërkesa merr rreth ~6 ms në makinën time virtuale).
Shfaq mesazhe të reja në kohë reale
Për të shfaqur mesazhet hyrëse në (pothuajse) kohë reale, ne thjesht e ekzekutojmë kërkesën një herë në disa sekonda, duke kujtuar vulën e fundit kohore që kemi hasur më parë.
Shembuj të komandave
Si duken komandat tipike logscli në praktikë?
Nëse keni shkarkuar grupin e të dhënave të Amazon që përmenda në fillim të artikullit, mund të ekzekutoni komandat e mëposhtme:
# Показать строки, где встречается слово walmart
$ logscli -F 'walmart' | less
# Показать самые свежие 10 строк, где встречается "terrible"
$ logscli -F terrible -limit 10
# То же самое без -limit:
$ logscli -F terrible | head -n 10
# Показать все строки, подходящие под /times [0-9]/, написанные для vine и у которых высокий рейтинг
$ logscli -E 'times [0-9]' -where="vine='Y' AND star_rating>4" | less
# Показать все строки со словом "panic" и 3 строки контекста вокруг
$ logscli -F 'panic' -C 3 | less
# Непрерывно показывать новые строки со словом "5-star"
$ logscli -F '5-star' -tailf
Referencat
Kodi i shërbimeve (pa dokumentacion) është i disponueshëm në github në
Burimi: www.habr.com