Ako ste ikad koristili web sučelja za pregled zapisa, onda ste vjerojatno primijetili kako su ta sučelja u pravilu glomazna i (često) ne baš zgodna i osjetljiva. Na neke se možete naviknuti, neki su apsolutno užasni, ali čini mi se da je razlog svih problema to što neispravno pristupamo zadatku pregledavanja zapisa: pokušavamo stvoriti web sučelje gdje CLI (sučelje naredbenog retka) radi bolje. Meni osobno je vrlo ugodno raditi s tail, grep, awk i drugima, pa bi za mene idealno sučelje za rad s zapisima bilo nešto slično tail i grep-u, ali koje bi se također moglo koristiti za čitanje zapisa koji dolaze s mnogih poslužitelja. To je, naravno, pročitajte ih iz ClickHouse!
*prema osobnom mišljenju korisnika habre
Upoznajte logscli
Nisam smislio ime za svoje sučelje i, da budem iskren, radije postoji u obliku prototipa, ali ako želite odmah vidjeti izvorni kod, onda ste dobrodošli:
Sposobnosti
Moj cilj je bio napraviti sučelje koje će djelovati poznato onima koji su navikli na tail/grep, odnosno podržavati sljedeće stvari:
- Pogledajte sve zapisnike, bez filtriranja.
- Ostavite retke koji sadrže fiksni podniz (zastavica
-F
уgrep
). - Ostavite retke koji odgovaraju regularnom izrazu (zastavica
-E
уgrep
). - Prema zadanim postavkama, pregled je obrnutim kronološkim redoslijedom, budući da su najnoviji zapisnici obično prvi od interesa.
- Prikaži kontekst pored svakog retka (opcije
-A
,-B
и-C
уgrep
, ispisivanjem N redaka prije, iza i oko svakog odgovarajućeg retka). - Pregledajte dolazne zapisnike u stvarnom vremenu, sa ili bez filtriranja (u suštini
tail -f | grep
). - Sučelje mora biti kompatibilno s
less
,head
,tail
i ostali - prema zadanim postavkama, rezultati bi se trebali vratiti bez ograničenja njihovog broja; linije se ispisuju kao tok sve dok je korisnik zainteresiran za njihov prijem; signalSIGPIPE
trebali tiho prekinuti strujanje dnevnika, baš kao što to činetail
,grep
i druge UNIX pomoćne programe.
Provedba
Pretpostavljam da već nekako znate kako isporučiti zapise ClickHouseu. Ako ne, preporučam isprobati
Prvo morate odlučiti o osnovnoj shemi. Budući da obično želite primati zapise razvrstane po vremenu, čini se logičnim pohraniti ih na taj način. Ako postoji mnogo kategorija dnevnika i sve su iste vrste, tada možete napraviti kategoriju dnevnika kao prvi stupac primarnog ključa - to će vam omogućiti da imate jednu tablicu umjesto nekoliko, što će biti veliki plus kada umetanje u ClickHouse (na poslužiteljima s tvrdim diskovima preporuča se unos podataka ne više od ~1 puta u sekundi za cijeli server).
Odnosno, trebamo otprilike sljedeću shemu tablice:
CREATE TABLE logs(
category LowCardinality(String), -- категория логов (опционально)
time DateTime, -- время события
millis UInt16, -- миллисекунды (могут быть и микросекунды, и т.д.): рекомендуется хранить, если событий много, чтобы было легче различать события между собой
..., -- ваши собственные поля, например имя сервера, уровень логирования, и так далее
message String -- текст сообщения
) ENGINE=MergeTree()
ORDER BY (category, time, millis)
Nažalost, nisam mogao odmah pronaći otvorene izvore s realističnim zapisima koje bih mogao zgrabiti i preuzeti, pa sam ovo uzeo kao primjer
upute za učitavanje recenzija Amazona na ClickHouse
Kreirajmo tablicu:
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
U Amazonovom skupu podataka postoji samo datum za recenziju, ali ne postoji točno vrijeme, pa popunimo ove podatke nasumično.
Ne morate preuzeti sve tsv datoteke i ograničiti se na prvih ~10-20 kako biste dobili prilično velik skup podataka koji neće stati u 16 GB RAM-a. Za prijenos TSV datoteka koristio sam sljedeću naredbu:
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
Na standardni trajni disk (što je HDD) u Google Cloudu veličine 1000 GB (uzeo sam ovu veličinu uglavnom da bi brzina bila malo veća, iako bi možda SSD potrebne veličine bio jeftiniji) upload brzina je bila otprilike ~ 75 MB/s na 4 jezgre.
- Moram napomenuti da radim u Googleu, ali koristio sam osobni račun i ovaj članak nema nikakve veze s mojim radom u tvrtki
Napravit ću sve ilustracije s ovim određenim skupom podataka, budući da je to sve što sam imao pri ruci.
Prikaži napredak skeniranja podataka
Budući da ćemo u ClickHouseu koristiti potpuno skeniranje na tablici s zapisnicima, a ova operacija može potrajati dosta vremena i možda neće dati nikakve rezultate dulje vrijeme ako se pronađe malo podudaranja, preporučljivo je moći prikazati napredak upita dok se ne prime prvi redci s rezultatom. Da biste to učinili, u HTTP sučelju postoji parametar koji vam omogućuje slanje napretka u HTTP zaglavljima: send_progress_in_http_headers=1
. Nažalost, standardna Go knjižnica ne može čitati zaglavlja kako su primljena, ali HTTP 1.0 sučelje (ne smije se brkati s 1.1!) podržava ClickHouse, tako da možete otvoriti neobrađenu TCP vezu na ClickHouse i poslati je tamo GET /?query=... HTTP/1.0nn
i primiti zaglavlja i tijelo odgovora bez ikakvog bježanja ili enkripcije, tako da u ovom slučaju čak ne trebamo koristiti standardnu biblioteku.
Streaming zapisa iz ClickHousea
ClickHouse već relativno dugo (od 2019?) ima optimizaciju za upite s ORDER BY, pa upit poput
SELECT time, millis, message
FROM logs
WHERE message LIKE '%something%'
ORDER BY time DESC, millis DESC
Odmah će početi vraćati retke koji imaju podniz "nešto" u svojoj poruci, bez čekanja da skeniranje završi.
Također, bilo bi vrlo zgodno da sam ClickHouse poništi zahtjev kada se prekine veza s njim, ali to nije zadano ponašanje. Opcijom se može omogućiti automatsko otkazivanje zahtjeva cancel_http_readonly_queries_on_client_close=1
.
Ispravno rukovanje SIGPIPE u Go
Kada izvršite, recimo, naredbu some_cmd | head -n 10
, točno kako naredba some_cmd
zaustavlja izvršenje kada head
oduzeto 10 redaka? Odgovor je jednostavan: kada head
završava, cijev se zatvara, a stdout naredbe some_cmd počinje usmjeravati, uvjetno, "nigdje". Kada some_cmd
pokušava pisati u zatvorenu cijev,
U Go-u se to također događa prema zadanim postavkama, ali rukovatelj signala SIGPIPE također ispisuje "signal: SIGPIPE" ili sličnu poruku na kraju, a da bismo izbrisali ovu poruku, samo trebamo sami rukovati SIGPIPE-om onako kako želimo, to jest, samo tiho Izlaz:
ch := make(chan os.Signal)
signal.Notify(ch, syscall.SIGPIPE)
go func() {
<-ch
os.Exit(0)
}()
Prikaži kontekst poruke
Često želite vidjeti kontekst u kojem se dogodila neka pogreška (na primjer, koji je zahtjev izazvao paniku ili koji su povezani problemi bili vidljivi prije rušenja), a u grep
To se radi korištenjem opcija -A, -B i -C, koje prikazuju određeni broj redaka iza, prije i oko poruke.
Nažalost, nisam pronašao jednostavan način da to isto učinim u ClickHouseu, tako da se za prikaz konteksta šalje dodatni zahtjev kao što je ovaj u svaki redak rezultata (pojedinosti ovise o sortiranju i je li kontekst prikazan prije ili poslije):
SELECT time,millis,review_body FROM amazon
WHERE (time = 'ВРЕМЯ_СОБЫТИЯ' AND millis < МИЛЛИСЕКУНДЫ_СОБЫТИЯ) OR (time < 'ВРЕМЯ_СОБЫТИЯ')
ORDER BY time DESC, millis DESC
LIMIT КОЛИЧЕСТВО_СТРОК_КОНТЕКСТА
SETTINGS max_threads=1
Budući da se zahtjev šalje gotovo odmah nakon što ClickHouse vrati odgovarajuću liniju, on završava u predmemoriji i općenito se zahtjev izvršava prilično brzo i troši malo CPU-a (obično zahtjev traje oko ~6 ms na mom virtualnom računalu).
Prikaži nove poruke u stvarnom vremenu
Kako bismo prikazali dolazne poruke u (gotovo) stvarnom vremenu, jednostavno izvršavamo zahtjev jednom svakih nekoliko sekundi, prisjećajući se zadnje vremenske oznake na koju smo prije naišli.
Primjeri naredbi
Kako tipične logscli naredbe izgledaju u praksi?
Ako ste preuzeli skup podataka Amazona koji sam spomenuo na početku članka, možete pokrenuti sljedeće naredbe:
# Показать строки, где встречается слово 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
reference
Kôd pomoćnog programa (bez dokumentacije) dostupan je na githubu na
Izvor: www.habr.com