์„ธ์ƒ์—์„œ ๊ฐ€์žฅ ํŽธ๋ฆฌํ•œ ๋กœ๊ทธ ์กฐํšŒ ์ธํ„ฐํŽ˜์ด์Šค*๋ฅผ ๊ฐœ๋ฐœ ์ค‘์ž…๋‹ˆ๋‹ค.

์„ธ์ƒ์—์„œ ๊ฐ€์žฅ ํŽธ๋ฆฌํ•œ ๋กœ๊ทธ ์กฐํšŒ ์ธํ„ฐํŽ˜์ด์Šค*๋ฅผ ๊ฐœ๋ฐœ ์ค‘์ž…๋‹ˆ๋‹ค. ๋กœ๊ทธ๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด ์›น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด ๋ณธ ์ ์ด ์žˆ๋‹ค๋ฉด, ์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋ฒˆ๊ฑฐ๋กญ๊ณ  (์ข…์ข…) ๊ทธ๋‹ค์ง€ ํŽธ๋ฆฌํ•˜์ง€๋„ ์•Š๊ณ  ๋ฐ˜์‘๋„ ์ข‹์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„์ฐจ๋ ธ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ผ๋ถ€๋Š” ์ต์ˆ™ํ•ด์ง€๊ณ  ์ผ๋ถ€๋Š” ์™„์ „ํžˆ ๋”์ฐํ•˜์ง€๋งŒ ๋ชจ๋“  ๋ฌธ์ œ์˜ ์›์ธ์€ ๋กœ๊ทธ๋ฅผ ๋ณด๋Š” ์ž‘์—…์— ์ž˜๋ชป ์ ‘๊ทผํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. CLI(๋ช…๋ น์ค„ ์ธํ„ฐํŽ˜์ด์Šค)๊ฐ€ ์žˆ๋Š” ์›น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋” ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ tail, grep, awk ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์„ ๋งค์šฐ ํŽธ์•ˆํ•˜๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋กœ๊ทธ ์ž‘์—…์— ์ด์ƒ์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋Š” tail ๋ฐ grep๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ ๋งŽ์€ ์„œ๋ฒ„์—์„œ ์˜จ ๋กœ๊ทธ๋ฅผ ์ฝ๋Š” ๋ฐ์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ClickHouse์—์„œ ์ฝ์–ด๋ณด์„ธ์š”!

*habra ์‚ฌ์šฉ์ž์˜ ๊ฐœ์ธ์ ์ธ ์˜๊ฒฌ์— ๋”ฐ๋ฆ„ ๋‹น์‹ ์˜ ROCK

๋กœ๊ทธํด๋ฆฌ๋ฅผ ๋งŒ๋‚˜๋ณด์„ธ์š”

์ธํ„ฐํŽ˜์ด์Šค์˜ ์ด๋ฆ„์„ ์ •ํ•˜์ง€ ์•Š์•˜๊ณ  ์†”์งํžˆ ํ”„๋กœํ† ํƒ€์ž… ํ˜•ํƒœ๋กœ ์กด์žฌํ•˜์ง€๋งŒ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ฆ‰์‹œ ๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. https://github.com/YuriyNasretdinov/logscli (์„ ํƒํ•œ Go ์ฝ”๋“œ 350์ค„)

๊ธฐ๋Šฅ

๋‚ด ๋ชฉํ‘œ๋Š” tail/grep์— ์ต์ˆ™ํ•œ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์นœ์ˆ™ํ•ด ๋ณด์ด๋Š” ์ธํ„ฐํŽ˜์ด์Šค, ์ฆ‰ ๋‹ค์Œ์„ ์ง€์›ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

  1. ํ•„ํ„ฐ๋ง ์—†์ด ๋ชจ๋“  ๋กœ๊ทธ๋ฅผ ๋ด…๋‹ˆ๋‹ค.
  2. ๊ณ ์ •๋œ ํ•˜์œ„ ๋ฌธ์ž์—ด(ํ”Œ๋ž˜๊ทธ)์ด ํฌํ•จ๋œ ํ–‰์„ ๊ทธ๋Œ€๋กœ ๋‘ก๋‹ˆ๋‹ค. -F ัƒ grep).
  3. ์ •๊ทœ์‹(ํ”Œ๋ž˜๊ทธ)๊ณผ ์ผ์น˜ํ•˜๋Š” ์ค„์„ ๋‚จ๊ฒจ์ฃผ์„ธ์š”. -E ัƒ grep).
  4. ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ€์žฅ ์ตœ๊ทผ ๋กœ๊ทธ๊ฐ€ ๋จผ์ € ๊ด€์‹ฌ ๋Œ€์ƒ์ด๋ฏ€๋กœ ๋ณด๊ธฐ๋Š” ์‹œ๊ฐ„ ์—ญ์ˆœ์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.
  5. ๊ฐ ์ค„ ์˜†์— ์ปจํ…์ŠคํŠธ ํ‘œ์‹œ(์˜ต์…˜ -A, -B ะธ -C ัƒ grep, ์ผ์น˜ํ•˜๋Š” ๊ฐ ์ค„ ์•ž, ๋’ค, ์ฃผ์œ„์— ๊ฐ๊ฐ N ์ค„์„ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค.
  6. ํ•„ํ„ฐ๋ง ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ์ˆ˜์‹  ๋กœ๊ทธ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ด…๋‹ˆ๋‹ค(๊ธฐ๋ณธ์ ์œผ๋กœ tail -f | grep).
  7. ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹ค์Œ๊ณผ ํ˜ธํ™˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. less, head, tail ๊ธฐํƒ€ - ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฒฐ๊ณผ๋Š” ๊ฐœ์ˆ˜ ์ œํ•œ ์—†์ด ๋ฐ˜ํ™˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋ผ์ธ ์ˆ˜์‹ ์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ํ•œ ๋ผ์ธ์€ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ธ์‡„๋ฉ๋‹ˆ๋‹ค. ์‹ ํ˜ธ SIGPIPE ๊ทธ๋“ค๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋กœ๊ทธ ์ŠคํŠธ๋ฆฌ๋ฐ์„ ์ž๋™์œผ๋กœ ์ค‘๋‹จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. tail, grep ๋ฐ ๊ธฐํƒ€ UNIX ์œ ํ‹ธ๋ฆฌํ‹ฐ.

ะ ะตะฐะปะธะทะฐั†ะธั

ClickHouse์— ๋กœ๊ทธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ์‹œ๋„ํ•ด ๋ณด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค ์—˜์—์Šค๋”” ะธ ์ƒˆ๋ผ ๊ณ ์–‘์ด ์ง‘๊ณผ ๋กœ๊ทธ ์ „๋‹ฌ์— ๊ด€ํ•œ ์ด ๋ฌธ์„œ.

๋จผ์ € ๊ธฐ๋ณธ ๊ตฌ์„ฑํ‘œ๋ฅผ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์‹œ๊ฐ„๋ณ„๋กœ ์ •๋ ฌ๋œ ๋กœ๊ทธ๋ฅผ ๋ฐ›๊ธฐ๋ฅผ ์›ํ•˜๋ฏ€๋กœ ๊ทธ๋ ‡๊ฒŒ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ๋…ผ๋ฆฌ์ ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๋งŽ๊ณ  ์œ ํ˜•์ด ๋ชจ๋‘ ๋™์ผํ•œ ๊ฒฝ์šฐ ๋กœ๊ทธ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ธฐ๋ณธ ํ‚ค์˜ ์ฒซ ๋ฒˆ์งธ ์—ด๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ” ๋Œ€์‹  ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ClickHouse์— ์‚ฝ์ž…(ํ•˜๋“œ ๋“œ๋ผ์ด๋ธŒ๊ฐ€ ์žˆ๋Š” ์„œ๋ฒ„์—์„œ๋Š” ์ดˆ๋‹น 1ํšŒ ์ดํ•˜๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค) ์ „์ฒด ์„œ๋ฒ„์— ๋Œ€ํ•ด).

์ฆ‰, ๋Œ€๋žต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ…Œ์ด๋ธ” ๊ตฌ์„ฑํ‘œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

CREATE TABLE logs(
    category LowCardinality(String), -- ะบะฐั‚ะตะณะพั€ะธั ะปะพะณะพะฒ (ะพะฟั†ะธะพะฝะฐะปัŒะฝะพ)
    time DateTime, -- ะฒั€ะตะผั ัะพะฑั‹ั‚ะธั
    millis UInt16, -- ะผะธะปะปะธัะตะบัƒะฝะดั‹ (ะผะพะณัƒั‚ ะฑั‹ั‚ัŒ ะธ ะผะธะบั€ะพัะตะบัƒะฝะดั‹, ะธ ั‚.ะด.): ั€ะตะบะพะผะตะฝะดัƒะตั‚ัั ั…ั€ะฐะฝะธั‚ัŒ, ะตัะปะธ ัะพะฑั‹ั‚ะธะน ะผะฝะพะณะพ, ั‡ั‚ะพะฑั‹ ะฑั‹ะปะพ ะปะตะณั‡ะต ั€ะฐะทะปะธั‡ะฐั‚ัŒ ัะพะฑั‹ั‚ะธั ะผะตะถะดัƒ ัะพะฑะพะน
    ..., -- ะฒะฐัˆะธ ัะพะฑัั‚ะฒะตะฝะฝั‹ะต ะฟะพะปั, ะฝะฐะฟั€ะธะผะตั€ ะธะผั ัะตั€ะฒะตั€ะฐ, ัƒั€ะพะฒะตะฝัŒ ะปะพะณะธั€ะพะฒะฐะฝะธั, ะธ ั‚ะฐะบ ะดะฐะปะตะต
    message String -- ั‚ะตะบัั‚ ัะพะพะฑั‰ะตะฝะธั
) ENGINE=MergeTree()
ORDER BY (category, time, millis)

์•„์‰ฝ๊ฒŒ๋„ ์ œ๊ฐ€ ์žก์•„์„œ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ํ˜„์‹ค์ ์ธ ๋กœ๊ทธ๊ฐ€ ์žˆ๋Š” ์˜คํ”ˆ ์†Œ์Šค๋ฅผ ์ฆ‰์‹œ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์˜ˆ๋กœ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. 2015๋…„ ์ด์ „ Amazon ์ œํ’ˆ ๋ฆฌ๋ทฐ. ๋ฌผ๋ก  ๊ทธ ๊ตฌ์กฐ๋Š” ํ…์ŠคํŠธ ๋กœ๊ทธ์˜ ๊ตฌ์กฐ์™€ ์ •ํ™•ํžˆ ๋™์ผํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์„ค๋ช… ๋ชฉ์ ์œผ๋กœ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ClickHouse์— Amazon ๋ฆฌ๋ทฐ๋ฅผ ์—…๋กœ๋“œํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ง€์นจ

ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

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

Amazon ๋ฐ์ดํ„ฐ์„ธํŠธ์—๋Š” ๊ฒ€ํ†  ๋‚ ์งœ๋งŒ ์žˆ๊ณ  ์ •ํ™•ํ•œ ์‹œ๊ฐ„์€ ์—†์œผ๋ฏ€๋กœ ์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋žœ๋ˆ์œผ๋กœ ์ฑ„์›Œ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

10GB RAM์— ๋งž์ง€ ์•Š๋Š” ์ƒ๋‹นํžˆ ํฐ ๋ฐ์ดํ„ฐ ์„ธํŠธ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๋ชจ๋“  tsv ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ์ฒ˜์Œ ~20-16์œผ๋กœ ์ œํ•œํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. TSV ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

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

ํฌ๊ธฐ๊ฐ€ 1000GB์ธ Google Cloud์˜ ํ‘œ์ค€ ์˜๊ตฌ ๋””์Šคํฌ(HDD)์—์„œ(ํ•„์š”ํ•œ ํฌ๊ธฐ์˜ SSD๊ฐ€ ๋” ์ €๋ ดํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์†๋„๋ฅผ ์กฐ๊ธˆ ๋” ๋†’์ด๊ธฐ ์œ„ํ•ด ์ฃผ๋กœ ์ด ํฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค) ์†๋„๋Š” 75๊ฐœ ์ฝ”์–ด์—์„œ ์•ฝ 4MB/์ดˆ์˜€์Šต๋‹ˆ๋‹ค.

  • ๊ตฌ๊ธ€์—์„œ ์ผํ•œ๋‹ค๊ณ  ์˜ˆ์•ฝ์„ ํ•ด์•ผ ํ•˜๋Š”๋ฐ ๊ฐœ์ธ ๊ณ„์ •์„ ์‚ฌ์šฉํ–ˆ๊ณ  ์ด ๊ธ€์€ ํšŒ์‚ฌ ์—…๋ฌด์™€๋Š” ์•„๋ฌด๋Ÿฐ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ „๋ถ€์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ์ด ํŠน์ • ๋ฐ์ดํ„ฐ์„ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ์ผ๋Ÿฌ์ŠคํŠธ๋ ˆ์ด์…˜์„ ์ œ์ž‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ์Šค์บ” ์ง„ํ–‰ ์ƒํ™ฉ ํ‘œ์‹œ

ClickHouse์—์„œ๋Š” ๋กœ๊ทธ๊ฐ€ ์žˆ๋Š” ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด ์ „์ฒด ์Šค์บ”์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ฏ€๋กœ ์ด ์ž‘์—…์€ ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ผ์น˜ํ•˜๋Š” ํ•ญ๋ชฉ์ด ๊ฑฐ์˜ ์—†์œผ๋ฉด ์˜ค๋žœ ์‹œ๊ฐ„ ๋™์•ˆ ๊ฒฐ๊ณผ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋‹ค์Œ์„ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๊ฐ€ ์žˆ๋Š” ์ฒซ ๋ฒˆ์งธ ํ–‰์ด ์ˆ˜์‹ ๋  ๋•Œ๊นŒ์ง€ ์ฟผ๋ฆฌ๊ฐ€ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด HTTP ํ—ค๋”์— ์ง„ํ–‰ ์ƒํ™ฉ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ HTTP ์ธํ„ฐํŽ˜์ด์Šค์— ์žˆ์Šต๋‹ˆ๋‹ค. send_progress_in_http_headers=1. ๋ถˆํ–‰ํ•˜๊ฒŒ๋„ ํ‘œ์ค€ Go ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ˆ˜์‹ ๋œ ํ—ค๋”๋ฅผ ์ฝ์„ ์ˆ˜ ์—†์ง€๋งŒ ClickHouse๋Š” HTTP 1.0 ์ธํ„ฐํŽ˜์ด์Šค(1.1๊ณผ ํ˜ผ๋™ํ•˜์ง€ ๋งˆ์„ธ์š”!)๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ ClickHouse์— ๋Œ€ํ•œ ์›์‹œ TCP ์—ฐ๊ฒฐ์„ ์—ด๊ณ  ๊ฑฐ๊ธฐ๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. GET /?query=... HTTP/1.0nn ์ด์Šค์ผ€์ดํ”„๋‚˜ ์•”ํ˜ธํ™” ์—†์ด ์‘๋‹ต ํ—ค๋”์™€ ๋ณธ๋ฌธ์„ ์ˆ˜์‹ ํ•˜๋ฏ€๋กœ ์ด ๊ฒฝ์šฐ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”์กฐ์ฐจ ์—†์Šต๋‹ˆ๋‹ค.

ClickHouse์—์„œ ๋กœ๊ทธ ์ŠคํŠธ๋ฆฌ๋ฐ

ClickHouse๋Š” ๋น„๊ต์  ์˜ค๋žœ ๊ธฐ๊ฐ„(2019๋…„?) ๋™์•ˆ ORDER BY๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ๋ฅผ ์ตœ์ ํ™”ํ•ด ์™”์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฟผ๋ฆฌ๋Š”

SELECT time, millis, message
FROM logs
WHERE message LIKE '%something%'
ORDER BY time DESC, millis DESC

์Šค์บ”์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋ฉ”์‹œ์ง€์— ํ•˜์œ„ ๋ฌธ์ž์—ด "something"์ด ์žˆ๋Š” ์ค„์„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์—ฐ๊ฒฐ์ด ๋Š์–ด์กŒ์„ ๋•Œ ClickHouse ์ž์ฒด์—์„œ ์š”์ฒญ์„ ์ทจ์†Œํ•˜๋ฉด ๋งค์šฐ ํŽธ๋ฆฌํ•˜์ง€๋งŒ ์ด๋Š” ๊ธฐ๋ณธ ๋™์ž‘์ด ์•„๋‹™๋‹ˆ๋‹ค. ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™ ์š”์ฒญ ์ทจ์†Œ๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. cancel_http_readonly_queries_on_client_close=1.

Go์—์„œ SIGPIPE์˜ ์˜ฌ๋ฐ”๋ฅธ ์ฒ˜๋ฆฌ

๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด some_cmd | head -n 10, ์ •ํ™•ํžˆ ๋ช…๋ น์ด ์–ด๋–ป๊ฒŒ some_cmd ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ ์‹คํ–‰์„ ์ค‘์ง€ํ•ฉ๋‹ˆ๋‹ค. head 10์ค„์„ ๋บ๋‚˜? ๋Œ€๋‹ต์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์–ธ์ œ head ๋๋‚˜๊ณ  ํŒŒ์ดํ”„๊ฐ€ ๋‹ซํžˆ๊ณ  some_cmd ๋ช…๋ น์˜ stdout์ด ์กฐ๊ฑด๋ถ€๋กœ "์•„๋ฌด๋ฐ๋„"๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์–ธ์ œ some_cmd ๋‹ซํžŒ ํŒŒ์ดํ”„์— ์“ฐ๊ธฐ๋ฅผ ์‹œ๋„ํ•˜๊ณ , ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ์ž๋™์œผ๋กœ ์ข…๋ฃŒํ•˜๋Š” SIGPIPE ์‹ ํ˜ธ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค..

Go์—์„œ๋„ ์ด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐœ์ƒํ•˜์ง€๋งŒ SIGPIPE ์‹ ํ˜ธ ์ฒ˜๋ฆฌ๊ธฐ๋Š” ๋์— "signal: SIGPIPE" ๋˜๋Š” ์œ ์‚ฌํ•œ ๋ฉ”์‹œ์ง€๋„ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์‹œ์ง€๋ฅผ ์ง€์šฐ๋ ค๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ์ฆ‰ ์ž๋™์œผ๋กœ SIGPIPE๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ถœ๊ตฌ:

ch := make(chan os.Signal)
signal.Notify(ch, syscall.SIGPIPE)
go func() {
    <-ch
    os.Exit(0)
}()

๋ฉ”์‹œ์ง€ ์ปจํ…์ŠคํŠธ ํ‘œ์‹œ

์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ์ปจํ…์ŠคํŠธ(์˜ˆ: ์–ด๋–ค ์š”์ฒญ์œผ๋กœ ์ธํ•ด ํŒจ๋‹‰์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€, ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๊ธฐ ์ „์— ์–ด๋–ค ๊ด€๋ จ ๋ฌธ์ œ๊ฐ€ ํ‘œ์‹œ๋˜์—ˆ๋Š”์ง€ ๋“ฑ)๋ฅผ ํ™•์ธํ•˜๋ ค๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. grep ์ด๋Š” ๊ฐ๊ฐ ๋ฉ”์‹œ์ง€ ๋’ค, ์•ž, ์ฃผ์œ„์— ์ง€์ •๋œ ํ–‰ ์ˆ˜๋ฅผ ํ‘œ์‹œํ•˜๋Š” -A, -B ๋ฐ -C ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

๋ถˆํ–‰ํžˆ๋„ ClickHouse์—์„œ๋Š” ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์‰ฌ์šด ๋ฐฉ๋ฒ•์„ ์ฐพ์ง€ ๋ชปํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ปจํ…์ŠคํŠธ๋ฅผ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ์ด์™€ ๊ฐ™์€ ์ถ”๊ฐ€ ์š”์ฒญ์ด ๊ฒฐ๊ณผ์˜ ๊ฐ ์ค„์— ์ „์†ก๋ฉ๋‹ˆ๋‹ค(์„ธ๋ถ€ ์‚ฌํ•ญ์€ ์ •๋ ฌ ๋ฐ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ด์ „์— ํ‘œ์‹œ๋˜๋Š”์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‹ค๋ฆ„). ๋˜๋Š” ์ดํ›„):

SELECT time,millis,review_body FROM amazon
WHERE (time = 'ะ’ะ ะ•ะœะฏ_ะกะžะ‘ะซะขะ˜ะฏ' AND millis < ะœะ˜ะ›ะ›ะ˜ะกะ•ะšะฃะะ”ะซ_ะกะžะ‘ะซะขะ˜ะฏ) OR (time < 'ะ’ะ ะ•ะœะฏ_ะกะžะ‘ะซะขะ˜ะฏ')
ORDER BY time DESC, millis DESC
LIMIT ะšะžะ›ะ˜ะงะ•ะกะขะ’ะž_ะกะขะ ะžะš_ะšะžะะขะ•ะšะกะขะ
SETTINGS max_threads=1

ClickHouse๊ฐ€ ํ•ด๋‹น ๋ผ์ธ์„ ๋ฐ˜ํ™˜ํ•œ ํ›„ ๊ฑฐ์˜ ์ฆ‰์‹œ ์š”์ฒญ์ด ์ „์†ก๋˜๋ฏ€๋กœ ๊ฒฐ๊ตญ ์บ์‹œ์— ์ €์žฅ๋˜๊ณ  ์ผ๋ฐ˜์ ์œผ๋กœ ์š”์ฒญ์€ ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์‹คํ–‰๋˜๊ณ  ์•ฝ๊ฐ„์˜ CPU๋ฅผ ์†Œ๋ชจํ•ฉ๋‹ˆ๋‹ค(๋ณดํ†ต ๊ฐ€์ƒ ๋จธ์‹ ์—์„œ ์š”์ฒญ์€ ์•ฝ 6ms ์ •๋„ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค).

์ƒˆ ๋ฉ”์‹œ์ง€๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ‘œ์‹œ

๋“ค์–ด์˜ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ (๊ฑฐ์˜) ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ์ด์ „์— ์ ‘ํ–ˆ๋˜ ๋งˆ์ง€๋ง‰ ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ๊ธฐ์–ตํ•˜๋ฉด์„œ ๋ช‡ ์ดˆ๋งˆ๋‹ค ํ•œ ๋ฒˆ์”ฉ ์š”์ฒญ์„ ์‹คํ–‰ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋ช…๋ น ์˜ˆ

์ผ๋ฐ˜์ ์ธ logcli ๋ช…๋ น์€ ์‹ค์ œ๋กœ ์–ด๋–ค ๋ชจ์Šต์ž…๋‹ˆ๊นŒ?

๊ธฐ์‚ฌ ์‹œ์ž‘ ๋ถ€๋ถ„์—์„œ ์–ธ๊ธ‰ํ•œ Amazon ๋ฐ์ดํ„ฐ ์„ธํŠธ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•œ ๊ฒฝ์šฐ ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# ะŸะพะบะฐะทะฐั‚ัŒ ัั‚ั€ะพะบะธ, ะณะดะต ะฒัั‚ั€ะตั‡ะฐะตั‚ัั ัะปะพะฒะพ 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

์ฐธ์กฐ

์œ ํ‹ธ๋ฆฌํ‹ฐ ์ฝ”๋“œ(๋ฌธ์„œ ์ œ์™ธ)๋Š” github์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/YuriyNasretdinov/logscli. ClickHouse๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋กœ๊ทธ๋ฅผ ๋ณด๊ธฐ ์œ„ํ•œ ์ฝ˜์†” ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•œ ๋‚ด ์•„์ด๋””์–ด์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์ƒ๊ฐ์„ ๋“ฃ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€