๐Ÿคฆโ€โ™‚๏ธ "๋‹น์—ฐํ•œ ๊ฑธ ์ง€ํ‚ค๋Š” ๊ฒŒ ์ด๋ ‡๊ฒŒ ์–ด๋ ค์šด๊ฐ€" EC2 ํ™˜๊ฒฝ์—์„œ DuckDB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋น„์Šค์—์„œ Collector writer๊ฐ€ ๊ฐ„ํ—์ ์œผ๋กœ ๋ฝ ํš๋“์— ์‹คํŒจํ–ˆ๋‹ค. ์—๋Ÿฌ๋Š” ์ด๊ฑฐ์˜€๋‹ค. Could not set lock on file "analytics.db": Conflicting lock is held in PID 0 โ€œ๋ฆฌ์†Œ์Šค๋Š” ์“ฐ๊ณ  ๋‚˜๋ฉด ๋‹ซ์•„์•ผ ํ•œ๋‹ค.โ€ ๋„ˆ๋ฌด ๋‹น์—ฐํ•œ ์–˜๊ธฐ๋ผ ํ•œ ๊ตฐ๋ฐ์—์„œ ๋†“์ณค์„ ๊ฑฐ๋ผ๊ณ ๋Š” ์ฒ˜์Œ์—” ์ƒ๊ฐ๋„ ๋ชป ํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ฒฐ๊ตญ ๐Ÿ˜… ๐Ÿงฑ "์ด๋ฏธ ๋‹ค ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ" ๊ตฌ์กฐ๋Š” ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹จ์ˆœํ•˜๊ฒŒ ์žก์•˜๋‹ค. Writer 1๋ช…, Reader N๋ช…. Collector ํ•˜๋‚˜๋งŒ DuckDB์— ์“ฐ๊ณ , Detector์™€ API๋Š” read_only=True๋กœ๋งŒ ์ ‘๊ทผํ–ˆ๋‹ค. ๋Œ€์‹œ๋ณด๋“œ๋Š” React + Vite๊ณ , ๋ฐ์ดํ„ฐ๋Š” API๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๋‚ด๋ ค์ฃผ๊ธฐ ๋•Œ๋ฌธ์— DuckDB์— ์ง์ ‘ ๋ถ™๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์•„๋‹ˆ์—ˆ๋‹ค. Collector์™€ API๋Š” DuckDB ์—ฐ๊ฒฐ์„ ์—ด๊ณ  ๋‚˜๋ฉด ํ•ญ์ƒ ๋‹ซ๋„๋ก ๊ตฌํ˜„ํ•ด ๋‘” ์ƒํƒœ์˜€๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ก ์ƒ์œผ๋กœ๋Š” ๋‹ค ๋ง‰์•„ ๋‘” ๊ตฌ์กฐ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ๐Ÿ” "์–ด๋””์„œ ๋ฝ์ด ๊ฑธ๋ฆฐ ๊ฑด์ง€" ์—๋Ÿฌ ๋ฉ”์‹œ์ง€์— ์ฐํžŒ PID 0 ๋•Œ๋ฌธ์— ์ฒ˜์Œ์—” โ€œ์ด๋ฏธ ์ฃฝ์€ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋‚จ๊ธด stale lockโ€ ์ชฝ์œผ๋กœ๋งŒ ์ƒ๊ฐํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ดˆ๋ฐ˜์—๋Š” close() ๋ฌธ์ œ์ผ ๊ฑฐ๋ผ๊ณ  ๋ฐ”๋กœ ์—ฐ๊ฒฐํ•˜์ง€ ๋ชปํ–ˆ๋‹ค. ๊ฐ€๋Šฅ์„ฑ์„ ์„ธ ๊ฐ€์ง€๋กœ ๋‚˜๋ˆด๋‹ค. ํ•˜๋‚˜๋Š” stale lock, ํ•˜๋‚˜๋Š” ์—ฐ๊ฒฐ ๋ˆ„์ˆ˜, ํ•˜๋‚˜๋Š” reader์™€ writer ์ ‘๊ทผ ํƒ€์ด๋ฐ ๋ฌธ์ œ. ๊ทธ๋ž˜์„œ ํ•˜๋‚˜์”ฉ ํ™•์ธํ–ˆ๋‹ค. ๋จผ์ € Detector ์ฝ”๋“œ๋ถ€ํ„ฐ ๋ดค๋‹ค. detect_spikes()์—์„œ DuckDB read_only ์—ฐ๊ฒฐ์„ ์—ฐ ๋’ค, ๋ฐ์ดํ„ฐ๊ฐ€ ๋ถ€์กฑํ•˜๋ฉด early return ํ•˜๋Š” ๊ฒฝ๋กœ๊ฐ€ ์žˆ์—ˆ๊ณ  ๊ทธ ๊ฒฝ๋กœ์—์„œ๋Š” close()๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์•˜๋‹ค. ๊ทธ๋‹ค์Œ ๋กœ๊ทธ ํƒ€์ž„๋ผ์ธ์„ ๋‹ค์‹œ ๋ดค๋‹ค. ์žฌ์‹œ์ž‘ ์งํ›„์—๋Š” ์‹คํŒจํ•˜๊ณ , ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์„ฑ๊ณตํ•˜๋Š” ํŒจํ„ด์ด์—ˆ๋‹ค. ์ผ์‹œ์ ์ธ ๋ฝ์ด๊ฑฐ๋‚˜, ์—ฐ๊ฒฐ์ด ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉฐ ์ •๋ฆฌ๋˜๋Š” ์ƒํ™ฉ๊ณผ ๋งž์•„๋–จ์–ด์กŒ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ์žฌ์‹œ์ž‘ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ”๋ดค๋‹ค. detector์™€ api๋ฅผ ๋จผ์ € ๋‚ด๋ฆฌ๊ณ , collector๋ฅผ ๋‚˜์ค‘์— ์˜ฌ๋ฆฌ์ž ๋ฐ”๋กœ ํ•ด๊ฒฐ๋๋‹ค. ๊ธฐ์กด reader ์—ฐ๊ฒฐ์„ ๋จผ์ € ์ •๋ฆฌํ•ด์•ผ writer๊ฐ€ ๋ฝ์„ ์žก์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒŒ ๋ช…ํ™•ํ•ด์กŒ๋‹ค. ๐Ÿงฉ ๊ฒฐ๋ก  ํž˜ ๋น ์ง€๊ฒŒ๋„ ์›์ธ์€ ๋ณต์žกํ•˜์ง€ ์•Š์•˜๋‹ค. ๋‹ซํžˆ์ง€ ์•Š์€ reader ์—ฐ๊ฒฐ, ์ด์ „ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋‚จ๊ธด stale lock, ์—ฌ๋Ÿฌ reader๊ฐ€ ๊ฐ™์€ ํŒŒ์ผ์„ ๋™์‹œ์— ๋ถ™๋“ค๊ณ  ์žˆ๋˜ ์ƒํ™ฉ. ์ด ์„ธ ๊ฐ€์ง€๊ฐ€ ๊ฒน์ณค๋‹ค. ๐Ÿ”ง 1์ฐจ ํ•ด๊ฒฐ detector์™€ api๋ฅผ ๋จผ์ € ์žฌ์‹œ์ž‘ํ•˜๊ณ , dashboard๋Š” ์ž ์‹œ ๋‚ด๋ ค๋‘๊ณ , collector๋ฅผ ์žฌ์‹œ์ž‘ํ•œ ๋’ค ๋‹ค์‹œ dashboard๋ฅผ ์˜ฌ๋ ธ๋‹ค. DB์— ๋ถ™์–ด ์žˆ๋˜ ์—ฐ๊ฒฐ์„ ์ „๋ถ€ ๋Š๊ณ  writer๋งŒ ๊นจ๋—ํ•œ ์ƒํƒœ์—์„œ ๋‹ค์‹œ ๋ถ™์ธ๋‹ค. ์ด๊ฒŒ ๋์ด์—ˆ๋‹ค. ๐Ÿ›  ๊ทผ๋ณธ ํ•ด๊ฒฐ Detector ์ชฝ DuckDB ์ ‘๊ทผ์„ ์ „๋ถ€ try/finally๋กœ ๊ฐ์ŒŒ๋‹ค. early return์ด๋‚˜ ์ฟผ๋ฆฌ ๋„์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋‚˜๋„ reader๊ฐ€ DB๋ฅผ ์˜ค๋ž˜ ๋ถ™๋“ค๊ณ  ์žˆ์ง€ ์•Š๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค. Collector ์ชฝ์—๋Š” ๋ฝ ๊ด€๋ จ ์˜ˆ์™ธ๋งŒ ๊ณจ๋ผ exponential backoff๋ฅผ 3ํšŒ๊นŒ์ง€๋งŒ ๋‘์—ˆ๋‹ค. ์†”์งํžˆ ๋ฝ ์˜ˆ์™ธ๋ฅผ ์ง์ ‘ ๋‹ค๋ค„๋ณธ ๊ฑด ์ด๋ฒˆ์ด ์ฒ˜์Œ์ด์—ˆ๋‹ค. ์ˆœ๊ฐ„์ ์ธ ๊ฒฝํ•ฉ์ด๋‚˜ stale lock์€ ์žฌ์‹œ๋„๋กœ ํก์ˆ˜ํ•  ํ•„์š”๊ฐ€ ์žˆ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  runbook.md์— DuckDB ๋ฝ ์ถฉ๋Œ ์‹œ ์กฐ์น˜ ์ ˆ์ฐจ๋ฅผ ๋”ฐ๋กœ ์ •๋ฆฌํ•ด ๋‘์—ˆ๋‹ค. OLAP ์šฉ์œผ๋กœ DuckDB, OLTP ์šฉ์œผ๋กœ Postgres๋ฅผ ์“ฐ๊ณ  ์žˆ์–ด์„œ ๋ฌธ์ œ๊ฐ€ ๋‚œ๋‹ค๋ฉด DB ๊ฐ„ ์ถฉ๋Œ์ด๊ฑฐ๋‚˜ Postgres ์ชฝ์ผ ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์—ˆ๋‹ค. ์ •์ž‘ ๋ฐœ๋ชฉ์„ ์žก์€ ๊ฑด ํŒŒ์ผ ๊ธฐ๋ฐ˜ DB ์ชฝ์ด์—ˆ๋‹ค. ๐ŸŽฏ ์ •๋ฆฌ ๊ธฐ๋ณธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ ๊ฒƒ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋ณด๊ฒŒ ๋๋‹ค. ์›์ธ์€ ํ•˜๋‚˜๋ผ๊ณ  ๋‹จ์ • ์ง€์œผ๋ฉด ์•ˆ ๋œ๋‹ค๋Š” ๊ฒƒ๋„. ๊ทธ๋ฆฌ๊ณ  ๊ตฌ์กฐ์ƒ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ๋Š” ๋ถ„๋ช…ํžˆ ์กด์žฌํ•œ๋‹ค๋Š” ๊ฒƒ. ์ค‘์š”ํ•œ ๊ฑด, ๊ทธ ์—๋Ÿฌ๋ฅผ โ€œ์–ด์ฉ” ์ˆ˜ ์—†๋Š” ๊ฒƒโ€์œผ๋กœ ๋„˜๊ธฐ์ง€ ์•Š๊ณ  ์šด์˜์—์„œ ๊ด€๋ฆฌ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋กœ ๋งŒ๋“œ๋Š” ์žฅ์น˜๋ฅผ ๋‘๋Š” ๊ฒƒ. ๐Ÿ’ข
์ฝ˜ํ…์ธ ๋ฅผ ๋” ์ฝ๊ณ  ์‹ถ๋‹ค๋ฉด?
์›ํ‹ฐ๋“œ์— ๊ฐ€์ž…ํ•ด ์ฃผ์„ธ์š”.
๋กœ๊ทธ์ธ ํ›„ ๋ชจ๋“  ๊ธ€์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ใƒป๋Œ“๊ธ€ 1