TL;DR

  • ์ถฉ๋Œํ•˜๋Š” ์—ฐ์‚ฐ์˜ ๋Œ€์ƒ๊ณผ ์ˆœ์„œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ locking, MVCC, OCC์˜ ์—ญํ•  ๊ตฌ๋ถ„
  • 2PL์˜ ๋ฝ ์œ ์ง€ ์‹œ๊ฐ„๊ณผ predicateยทrange๋ฅผ ํฌํ•จํ•œ ๋ฝ ๋ฒ”์œ„์˜ ๋ถ„๋ฆฌ
  • PostgreSQL์˜ ๋ฒ„์ „ ๊ฐ€์‹œ์„ฑ, ๋™์‹œ UPDATE์˜ ํ–‰ ๋ฝ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ OCC ๊ฒ€์ฆ์˜ ์กฐํ•ฉ

AI-assisted


1. ์ถฉ๋Œ์€ ์Œ์œผ๋กœ ๋‚˜๋‰œ๋‹ค

๊ฒฉ๋ฆฌ ์ˆ˜์ค€์€ ํ—ˆ์šฉํ•  ์ด์ƒ ํ˜„์ƒ์„ ์ •ํ•œ๋‹ค. ๋™์‹œ์„ฑ ์ œ์–ด๋Š” ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰์ด ๊ทธ ์กฐ๊ฑด์„ ์ง€ํ‚ค๋„๋ก ์กฐ์ •ํ•œ๋‹ค.

์ถฉ๋Œ์„ ํ–‰์œ„์ž ์Œ์œผ๋กœ ๋‚˜๋ˆˆ ๋’ค ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ์˜ ์ˆœ์„œ๋ฅผ ๊ตฌ๋ถ„ํ•œ๋‹ค.

1๋‹จ๊ณ„: ํ–‰์œ„์ž ๊ธฐ์ค€

ํ–‰์œ„์ž ์Œ์ถฉ๋Œ ์กฐ๊ฑด์ฒ˜๋ฆฌํ•  ๋ฌธ์ œ
reader โ†” reader๋‘˜ ๋‹ค ๊ฐ’์„ ๋ฐ”๊พธ์ง€ ์•Š์Œ์ผ๋ฐ˜์ ์ธ ๋ฐ์ดํ„ฐ ์ถฉ๋Œ ์—†์Œ
reader โ†” writer์ฝ๋Š” ๋™์•ˆ ๊ฐ’์ด๋‚˜ ๋Œ€์ƒ ์ง‘ํ•ฉ์ด ๋ฐ”๋€œdirty read, non-repeatable read, phantom
writer โ†” writer๊ฐ™์€ ๊ฐ’์„ ํ•จ๊ป˜ ๊ฐฑ์‹ ํ•จlost update, dirty write

์ฝ๊ธฐ๋ผ๋ฆฌ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š์œผ๋ฏ€๋กœ ์ผ๋ฐ˜์ ์ธ ์ฝ๊ธฐยท์“ฐ๊ธฐ ์ถฉ๋Œ์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ๋™์‹œ์„ฑ ์ œ์–ด๋Š” ์ฃผ๋กœ readerโ†”writer์™€ writerโ†”writer ์‚ฌ์ด์˜ ์ˆœ์„œ๋ฅผ ๋‹ค๋ฃฌ๋‹ค.

2๋‹จ๊ณ„: ์–ด๋А ์ชฝ์ด ๋จผ์ €์ธ๊ฐ€

readerโ†”writer๋Š” ์—ฐ์‚ฐ ์ˆœ์„œ์— ๋”ฐ๋ผ ๋‚˜ํƒ€๋‚˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค.

์—ฐ์‚ฐ ์ˆœ์„œ์กฐ๊ฑด์ด์ƒ ํ˜„์ƒ
write โ†’ readT2๊ฐ€ T1์˜ ๋ฏธ์ปค๋ฐ‹ ๊ฐ’์„ ์ฝ์Œdirty read
read โ†’ writeT1์ด ์ฝ์€ ํ–‰์ด๋‚˜ ์กฐ๊ฑด ๋ฒ”์œ„๋ฅผ T2๊ฐ€ ๋ฐ”๊พธ๊ณ  T1์ด ๋‹ค์‹œ ์ฝ์Œnon-repeatable read, phantom
write โ†’ write๋‘˜์ด ๊ฐ™์€ ์ด์ „ ๊ฐ’์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐฑ์‹ ํ•˜๊ณ  ํ•œ์ชฝ ๊ฒฐ๊ณผ๊ฐ€ ๋ฎ์ž„lost update

๊ฒฉ๋ฆฌ ์ˆ˜์ค€๊ณผ ์ด์ƒ ํ˜„์ƒ

  • Read Committed๋Š” dirty read๋ฅผ ๋ง‰๋Š”๋‹ค
  • Repeatable Read๋Š” ๊ฐ™์€ ํ–‰์„ ๋‹ค์‹œ ์ฝ์„ ๋•Œ ๊ฐ’์ด ๋ฐ”๋€Œ๋Š” non-repeatable read๋ฅผ ๋ง‰๋Š”๋‹ค
  • Serializable์€ ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ ์–ด๋–ค ์ง๋ ฌ ์‹คํ–‰๊ณผ ๊ฐ™๋„๋ก ์ œํ•œํ•œ๋‹ค
  • DBMS๋งˆ๋‹ค ๊ฐ™์€ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ํ—ˆ์šฉํ•˜๋Š” ์„ธ๋ถ€ ํ˜„์ƒ์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค

์ˆ˜๋‹จ๋งˆ๋‹ค ๋งก๋Š” ์—ญํ• ์ด ๋‹ค๋ฅด๋‹ค

๊ฐ ์ˆ˜๋‹จ์˜ ์—ญํ• ์€ ์ถฉ๋Œํ•˜๋Š” ์—ฐ์‚ฐ์˜ ๋Œ€๊ธฐ, ์ฝ์„ ๋ฒ„์ „์˜ ์„ ํƒ, ๋ณ€๊ฒฝ์˜ ๊ฒ€์ฆ์œผ๋กœ ๋‚˜๋‰œ๋‹ค.

์ˆ˜๋‹จ์ฃผ๋œ ์—ญํ• ์ถฉ๋Œ ์ฒ˜๋ฆฌ ์œ„์น˜
locking์ถฉ๋Œํ•˜๋Š” ์—ฐ์‚ฐ์„ ๋Œ€๊ธฐ์‹œ์ผœ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ์ •ํ•จ์—ฐ์‚ฐ ์ „์ด๋‚˜ ์‹คํ–‰ ์ค‘
๋‹ค์ค‘ ๋ฒ„์ „ ์ €์žฅ์ฝ๋Š” ์ชฝ์— ํ•„์š”ํ•œ ์˜› ๋ฒ„์ „์„ ๋ณด์กดํ•จ์ฝ๊ธฐ ์‹œ์ ์˜ ๊ฐ€์‹œ์„ฑ ํŒ์ •
OCC์ž‘์—… ๋’ค ์ฝ์€ ๊ฐ’์ด๋‚˜ ๊ธฐ์ค€ ๋ฒ„์ „์ด ๋ฐ”๋€Œ์—ˆ๋Š”์ง€ ๊ฒ€์ฆํ•จ๋ฐ˜์˜ ์ง์ „

๊ฐ™์€ ํ–‰์˜ ์˜› ๋ฒ„์ „๊ณผ ์ƒˆ ๋ฒ„์ „์„ ๋ณด๊ด€ํ•ด๋„ ์–ด๋–ค ๋ฒ„์ „์„ ์ฝ์„์ง€, ๋‘ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ์ˆ˜์ •ํ•˜๋ฉด ์–ด๋А ์ชฝ์„ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•˜๊ฑฐ๋‚˜ ์‹คํŒจ์‹œํ‚ฌ์ง€๋Š” ๋”ฐ๋กœ ์ •ํ•ด์•ผ ํ•œ๋‹ค. MVCC ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋ฒ„์ „ ๊ด€๋ฆฌ์— ์ด๋Ÿฐ ๊ทœ์น™์„ ๊ฒฐํ•ฉํ•œ๋‹ค.

PostgreSQL์—์„œ A๊ฐ€ ์ž”์•ก์„ 1000์—์„œ 900์œผ๋กœ ๋ฐ”๊พธ๊ณ  ์•„์ง ์ปค๋ฐ‹ํ•˜์ง€ ์•Š์•˜๋‹ค๊ณ  ํ•˜์ž.

  • B๊ฐ€ ์ž”์•ก์„ ์กฐํšŒ: ์ผ๋ฐ˜ SELECT๋Š” A์˜ ๋ฏธ์ปค๋ฐ‹ ๊ฐ’ 900์„ ์ฝ์ง€ ์•Š๋Š”๋‹ค. B์˜ ์Šค๋ƒ…์ƒท์— ๋ณด์ด๋Š” ์ด์ „ ๋ฒ„์ „์ด 1000์ด๋ฉด A์˜ ์ปค๋ฐ‹์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  1000์„ ์ฝ๋Š”๋‹ค
  • B๋„ ๊ฐ™์€ ์ž”์•ก์„ ๋ณ€๊ฒฝ: B์˜ UPDATE๋Š” A์˜ ํŠธ๋žœ์žญ์…˜์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. A๊ฐ€ ์ปค๋ฐ‹ํ•˜๋ฉด Read Committed์—์„œ๋Š” ๋ณ€๊ฒฝ๋œ ํ–‰์ด WHERE ์กฐ๊ฑด์— ์—ฌ์ „ํžˆ ๋งž์œผ๋ฉด ๊ทธ ํ–‰์„ ๊ฐฑ์‹ ํ•œ๋‹ค. Repeatable Read์—์„œ๋Š” B์˜ ์Šค๋ƒ…์ƒท ์ดํ›„ A๊ฐ€ ๋ณ€๊ฒฝํ•œ ํ–‰์ด๋ฉด ์˜ค๋ฅ˜๋กœ ์ค‘๋‹จ๋œ๋‹ค

์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ์˜ ๋ฝ: ํ…Œ์ด๋ธ”๊ณผ ํ–‰์˜ ๊ตฌ๋ถ„

  • ์ผ๋ฐ˜ ์กฐํšŒ: SELECT๋Š” ํ…Œ์ด๋ธ” ์ˆ˜์ค€์˜ ACCESS SHARE ๋ฝ์„ ์žก๋Š”๋‹ค. ์ด ๋ฝ์€ ํ…Œ์ด๋ธ” ์‚ญ์ œ ๊ฐ™์€ ์ž‘์—…๊ณผ ์ถฉ๋Œํ•˜์ง€๋งŒ UPDATE์˜ ํ…Œ์ด๋ธ” ๋ฝ๊ณผ๋Š” ํ•จ๊ป˜ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค
  • ํ–‰ ๋ณ€๊ฒฝ: UPDATE๋Š” ๋ณ€๊ฒฝํ•˜๋Š” ํ–‰์—๋„ ๋ฝ์„ ์žก๋Š”๋‹ค. ์ผ๋ฐ˜ SELECT๋Š” ์ด ํ–‰ ๋ฝ์„ ์š”์ฒญํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์กฐํšŒ์™€ ๋ณ€๊ฒฝ์€ ์„œ๋กœ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ๊ฐ™์€ ํ–‰์„ ๋ณ€๊ฒฝํ•˜๋ ค๋Š” ๋‹ค๋ฅธ UPDATE๋Š” ๊ธฐ๋‹ค๋ฆฐ๋‹ค
  • ์ž ๊ธˆ ์กฐํšŒ: SELECT FOR UPDATE์ฒ˜๋Ÿผ ๋ช…์‹œ์ ์œผ๋กœ ํ–‰ ๋ฝ์„ ์š”์ฒญํ•˜๋Š” ์กฐํšŒ๋Š” ์ผ๋ฐ˜ SELECT์™€ ๋‹ฌ๋ฆฌ ๋Œ€๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค

2. ๋น„๊ด€์ : ๋ฝ์œผ๋กœ ๋ง‰๋Š”๋‹ค

์‚ฌ์šฉ์ž๋“ค์ด ๋™์‹œ์— ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •

๋น„๊ด€์  ๋ฐฉ์‹์€ ์—ฐ์‚ฐ ์ „์— ๋ฝ์„ ์žก์•„ ๊ฐ™์€ ๋Œ€์ƒ์˜ ์ถฉ๋Œํ•˜๋Š” ์—ฐ์‚ฐ์„ ๋Œ€๊ธฐ์‹œํ‚จ๋‹ค.

  • ๊ณต์œ  ๋ฝ(shared, S): ์ฝ์„ ๋•Œ ์žก๋Š”๋‹ค. ์—ฌ๋Ÿฌ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ์žก์„ ์ˆ˜ ์žˆ๋‹ค
  • ๋ฐฐํƒ€ ๋ฝ(exclusive, X): ์“ธ ๋•Œ ์žก๋Š”๋‹ค. ํ•˜๋‚˜๋งŒ ์žก์„ ์ˆ˜ ์žˆ๊ณ  ๊ฐ™์€ ๋Œ€์ƒ์˜ ๊ณต์œ  ๋ฝ๊ณผ๋„ ๊ณต์กดํ•˜์ง€ ๋ชปํ•œ๋‹ค
๋ณด์œ  ์ค‘ \ ์š”์ฒญS ์š”์ฒญX ์š”์ฒญ
S ๋ณด์œ ํ—ˆ์šฉ๋Œ€๊ธฐ
X ๋ณด์œ ๋Œ€๊ธฐ๋Œ€๊ธฐ

๊ฐ™์€ ๋Œ€์ƒ์˜ S/X๋ฝ์ด ์ถฉ๋Œํ•˜๋ฉด ์š”์ฒญํ•œ ์—ฐ์‚ฐ์ด ๋Œ€๊ธฐํ•œ๋‹ค. ์ด ํ˜ธํ™˜์„ฑ ๊ทœ์น™์— ๋ฝ์„ ์œ ์ง€ํ•˜๋Š” ์‹œ๊ฐ„๊ณผ ์ž ๊ทธ๋Š” ๋ฒ”์œ„๋ฅผ ๋”ํ•ด์•ผ ์›ํ•˜๋Š” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๋ฝ์˜ ๋‹จ์œ„: ํ–‰๋ถ€ํ„ฐ ํ…Œ์ด๋ธ”๊นŒ์ง€

  • ํ–‰ ๋ฝ์€ ์„œ๋กœ ๋‹ค๋ฅธ ํ–‰์˜ ์ž‘์—…์„ ํ•จ๊ป˜ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฝ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋น„์šฉ์ด ๋“ ๋‹ค
  • ์ผ๋ถ€ DBMS๋Š” ๋งŽ์€ ํ–‰ ๋ฝ์„ ํŽ˜์ด์ง€๋‚˜ ํ…Œ์ด๋ธ” ๋ฝ์œผ๋กœ ์Šน๊ธ‰ํ•œ๋‹ค
  • PostgreSQL์€ ํ–‰ ๋ฝ ์ •๋ณด๋ฅผ ํŠœํ”Œ ํ—ค๋”์— ๊ธฐ๋กํ•˜๋ฉฐ ํ–‰ ๋ฝ ์ˆ˜๊ฐ€ ๋Š˜์–ด๋„ ํ…Œ์ด๋ธ” ๋ฝ์œผ๋กœ ์Šน๊ธ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค
  • PostgreSQL์˜ ๋ฝ ์ข…๋ฅ˜๋Š” ํ…Œ์ด๋ธ” ๋‹จ์œ„์™€ ํ–‰ ๋‹จ์œ„๋กœ ๋‚˜๋‰œ๋‹ค

2PL: ๋ฝ์„ ์–ธ์ œ ๋†“๋А๋ƒ

๋ฝ ํ˜ธํ™˜์„ฑ๋งŒ์œผ๋กœ๋Š” ์ง๋ ฌ์„ฑ์„ ๋ณด์žฅํ•˜์ง€ ๋ชปํ•œ๋‹ค. ๋ฝ์„ ์žก์•˜๋‹ค ๋ฐ”๋กœ ๋†“๋Š” ์ž‘์—…์„ ๋ฐ˜๋ณตํ•˜๋ฉด ๊ฐœ๋ณ„ ์ถฉ๋Œ์€ ๊ฒน์น˜์ง€ ์•Š์•„๋„ ์ „์ฒด ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ ์ง๋ ฌ ์‹คํ–‰๊ณผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค.

๋‘ ๊ฐ’์„ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ ๋ณต์‚ฌํ•˜๋Š” ์˜ˆ๋ฅผ ๋ณธ๋‹ค. ์ดˆ๊ธฐ๊ฐ’์€ A=1, B=2๋‹ค.

  • T1: A๋ฅผ ์ฝ์–ด B์— ์“ด๋‹ค
  • T2: B๋ฅผ ์ฝ์–ด A์— ์“ด๋‹ค

๋‘ ํŠธ๋žœ์žญ์…˜์„ ํ•˜๋‚˜์”ฉ ์‹คํ–‰ํ•˜๋ฉด ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋‹ค.

์ง๋ ฌ ์ˆœ์„œ์‹คํ–‰๊ฒฐ๊ณผ
T1 โ†’ T2B=1๋กœ ๋ฐ”๊พผ ๋’ค T2๊ฐ€ B๋ฅผ ์ฝ์–ด A=1๋กœ ๋ณ€๊ฒฝA=1, B=1
T2 โ†’ T1A=2๋กœ ๋ฐ”๊พผ ๋’ค T1์ด A๋ฅผ ์ฝ์–ด B=2๋กœ ๋ณ€๊ฒฝA=2, B=2

๋ฝ์„ ๋งค ์—ฐ์‚ฐ ์งํ›„ ํ•ด์ œํ•˜๋ฉฐ ๊ต์ฐจ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค.

T1  S(A) r(A)=1 ํ•ด์ œ
T2                    S(B) r(B)=2 ํ•ด์ œ
T1                                     X(B) w(B)=1 ํ•ด์ œ
T2                                                      X(A) w(A)=2 ํ•ด์ œ
 
๊ฒฐ๊ณผ   A=2, B=1

๋‘ ํŠธ๋žœ์žญ์…˜์€ ๋ชจ๋‘ ์ƒ๋Œ€๊ฐ€ ์“ฐ๊ธฐ ์ „์˜ ๊ฐ’์„ ์ฝ์–ด ๊ณ„์‚ฐํ–ˆ๋‹ค. A์˜ ์ถฉ๋Œ ์ˆœ์„œ๋Š” T1โ†’T2์ด๊ณ  B์˜ ์ถฉ๋Œ ์ˆœ์„œ๋Š” T2โ†’T1์ด๋ฏ€๋กœ ํ•˜๋‚˜์˜ ์ง๋ ฌ ์ˆœ์„œ๋กœ ์„ค๋ช…ํ•  ์ˆ˜ ์—†๋‹ค.

2PL(two-phase locking)์€ ๋ฝ ํš๋“๊ณผ ํ•ด์ œ ์ˆœ์„œ๋ฅผ ์ œํ•œํ•œ๋‹ค.

  • Expanding phase: ๋ฝ์„ ํš๋“๋งŒ ํ•˜๊ณ  ํ•ด์ œํ•˜์ง€ ์•Š๋Š”๋‹ค
  • Shrinking phase: ๋ฝ์„ ํ•ด์ œ๋งŒ ํ•˜๊ณ  ์ƒˆ ๋ฝ์„ ํš๋“ํ•˜์ง€ ์•Š๋Š”๋‹ค

ํ•œ ๋ฒˆ์ด๋ผ๋„ ๋ฝ์„ ํ•ด์ œํ•œ ๋’ค์—๋Š” ์ƒˆ ๋ฝ์„ ํš๋“ํ•  ์ˆ˜ ์—†๋‹ค. ์œ„ ์˜ˆ์‹œ์—์„œ ๋‘ ํŠธ๋žœ์žญ์…˜์ด ํ•„์š”ํ•œ S๋ฝ์„ ๊ณ„์† ๋ณด์œ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒํ˜ธ ๋Œ€๊ธฐ๊ฐ€ ์ƒ๊ธด๋‹ค.

T1  S(A) ํš๋“ โ†’ r(A) โ†’ X(B) ์š”์ฒญ ยทยทยท ๋Œ€๊ธฐ      B๋Š” T2๊ฐ€ S๋ฝ ๋ณด์œ  ์ค‘
T2  S(B) ํš๋“ โ†’ r(B) โ†’ X(A) ์š”์ฒญ ยทยทยท ๋Œ€๊ธฐ      A๋Š” T1์ด S๋ฝ ๋ณด์œ  ์ค‘

DBMS๋Š” ์ด ์ˆœํ™˜์„ ๋ฐ๋“œ๋ฝ์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ํ•œ์ชฝ ํŠธ๋žœ์žญ์…˜์„ ์ค‘๋‹จํ•œ๋‹ค. ์ค‘๋‹จ๋œ ์ž‘์—…์„ ๋‹ค์‹œ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ํŠธ๋žœ์žญ์…˜์„ ์žฌ์‹œ๋„ํ•œ๋‹ค.

๋ฝ ํ˜ธํ™˜์„ฑ๊ณผ 2PL์˜ ์—ญํ• 

  • S/X ํ˜ธํ™˜์„ฑ: ๊ฐ™์€ ๋…ผ๋ฆฌ์  ๋Œ€์ƒ์˜ ์ถฉ๋Œํ•˜๋Š” ์—ฐ์‚ฐ์„ ๋Œ€๊ธฐ์‹œํ‚จ๋‹ค
  • 2๋‹จ๊ณ„ ๊ทœ์น™: ๊ด€๋ จ ๋…ผ๋ฆฌ์  ๋Œ€์ƒ์„ ๋ชจ๋‘ ์ž ๊ทผ ์Šค์ผ€์ค„์„ conflict serializableํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค
  • ์ ์šฉ ์ฃผ์ฒด: ๊ฐ ํŠธ๋žœ์žญ์…˜์ด ์ž์‹ ์ด ํš๋“ํ•˜๊ณ  ํ•ด์ œํ•˜๋Š” ๋ฝ์— ๊ทœ์น™์„ ์ ์šฉํ•œ๋‹ค
  • ๋ฐ๋“œ๋ฝ: 2PL๋„ ์„œ๋กœ ๋‹ค๋ฅธ ์ˆœ์„œ๋กœ ๋ฝ์„ ์žก์œผ๋ฉด ์ˆœํ™˜์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค

์ฃผ์˜: ๋ฐ๋“œ๋ฝ ์ฒ˜๋ฆฌ

  • T1์ด A๋ฅผ ์žก๊ณ  B๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ T2๊ฐ€ B๋ฅผ ์žก๊ณ  A๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉด ๋‘˜ ๋‹ค ์ƒ๋Œ€๊ฐ€ ๋ฝ์„ ํ•ด์ œํ•˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค
  • DBMS๋Š” ๋Œ€๊ธฐ ๊ทธ๋ž˜ํ”„์˜ ์ˆœํ™˜์„ ์ฐพ์•„ ํ•œ์ชฝ ํŠธ๋žœ์žญ์…˜์„ ์ค‘๋‹จํ•œ๋‹ค
  • ์ž์›์„ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์ž ๊ทธ๋ฉด ์ด ํ˜•ํƒœ์˜ ์ˆœํ™˜์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ณ„์ขŒ ์ด์ฒด๋ผ๋ฉด id๊ฐ€ ์ž‘์€ ๊ณ„์ขŒ๋ถ€ํ„ฐ ์ž ๊ทผ๋‹ค
  • PostgreSQL์€ deadlock_timeout ์ดํ›„ ๋ฐ๋“œ๋ฝ ๊ฒ€์‚ฌ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค
     ํš๋“ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ํ•ด์ œ
                     โ”‚
  Expanding phase    โ”‚     Shrinking phase
                     โ”‚
                  lock point

Lock point๋Š” ํŠธ๋žœ์žญ์…˜์ด ๋งˆ์ง€๋ง‰ ๋ฝ์„ ํš๋“ํ•œ ์‹œ์ ์ด๋‹ค. ๊ฐ ํŠธ๋žœ์žญ์…˜์˜ lock point ์ˆœ์„œ๋กœ ์ง๋ ฌ ์ˆœ์„œ๋ฅผ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ด€๋ จ๋œ ๋ชจ๋“  ๋…ผ๋ฆฌ์  ๋Œ€์ƒ์— ํ˜ธํ™˜ ๋ฝ์„ ์ ์šฉํ•œ 2PL ์Šค์ผ€์ค„์€ conflict serializableํ•˜๋‹ค.

ํ–‰ ๋ฝ๊ณผ phantom

์ถฉ๋Œ๊ฐ™์€ ํ–‰์— ๊ฑด ๋ฝ์˜ ์ฒ˜๋ฆฌ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•œ ๋ฒ”์œ„
write โ†’ writeX๋ฝ๋ผ๋ฆฌ ์ถฉ๋Œํ•ด ๋’ค์ชฝ์ด ๋Œ€๊ธฐ๊ฐ™์€ ํ–‰
write โ†’ readX๋ฝ๊ณผ S๋ฝ์ด ์ถฉ๋Œํ•ด ์ฝ๋Š” ์ชฝ์ด ๋Œ€๊ธฐ๊ฐ™์€ ํ–‰
read โ†’ writeS๋ฝ๊ณผ X๋ฝ์ด ์ถฉ๋Œํ•ด ์“ฐ๋Š” ์ชฝ์ด ๋Œ€๊ธฐ๊ฐ™์€ ํ–‰ ๋˜๋Š” ์กฐ๊ฑด ๋ฒ”์œ„

S๋ฝ์„ ๊ณ„์† ๋ณด์œ ํ•˜๋ฉด ๊ฐ™์€ ํ–‰์˜ ๊ฐ’์ด ๋ฐ”๋€Œ๋Š” ๊ฒƒ์„ ๋ง‰๋Š”๋‹ค. S๋ฝ์„ ํ•ด์ œํ•œ ๋’ค ๊ฐ™์€ ํ–‰์„ ๋‹ค์‹œ ์ฝ์œผ๋ ค๋ฉด ์ƒˆ S๋ฝ์ด ํ•„์š”ํ•˜์ง€๋งŒ shrinking phase์—์„œ๋Š” ์ƒˆ ๋ฝ์„ ํš๋“ํ•  ์ˆ˜ ์—†๋‹ค.

์กฐ๊ฑด์— ๋งž๋Š” ํ–‰ ์ง‘ํ•ฉ์„ ๋‹ค์‹œ ์ฝ๋Š” ๊ฒฝ์šฐ์—๋Š” ๊ธฐ์กด ํ–‰์˜ ๋ฝ๋งŒ์œผ๋กœ ๋ถ€์กฑํ•˜๋‹ค.

T1  SELECT count(*) WHERE age > 30   โ†’ 10๊ฑด. ๊ธฐ์กด 10ํ–‰์— S๋ฝ
T2  INSERT age = 35                  โ†’ ๊ธฐ์กด ํ–‰ ๋ฝ๊ณผ ์ถฉ๋Œํ•˜์ง€ ์•Š์Œ
T1  SELECT count(*) WHERE age > 30   โ†’ 11๊ฑด

T1์ด ๊ธฐ์กด ํ–‰์˜ S๋ฝ์„ ๊ณ„์† ๋ณด์œ ํ•ด๋„ ์ƒˆ ํ–‰์ด ์กฐ๊ฑด ๋ฒ”์œ„์— ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ํ–‰ ๋ฝ๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ์ด phantom์„ ๋ง‰์ง€ ๋ชปํ•œ๋‹ค.

phantom ๋ฐฉ์ง€: ์กฐ๊ฑด ๋ฒ”์œ„์˜ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ

  • predicate lock: ์กฐ๊ฑด์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ๋…ผ๋ฆฌ์  ์ง‘ํ•ฉ์„ ์ž ๊ทผ๋‹ค
  • index range lock: ์ธ๋ฑ์Šค ๊ฐ’ ์‚ฌ์ด์˜ ๋ฒ”์œ„๋ฅผ ์ž ๊ทผ๋‹ค. MySQL InnoDB์˜ gap lock์ด ์ด ๋ฐฉ์‹์— ์†ํ•œ๋‹ค
  • SSI: ์ฝ์€ ๋ฒ”์œ„๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์œ„ํ—˜ํ•œ ์ฝ๊ธฐยท์“ฐ๊ธฐ ์˜์กด์„ ๊ฐ์ง€ํ•œ๋‹ค. PostgreSQL Serializable์ด ์ด ๋ฐฉ์‹์„ ์“ด๋‹ค
  • ๊ตฌ๋ถ„ ๊ธฐ์ค€: 2PL ๋ณ€ํ˜•์€ ๋ฝ์˜ ์œ ์ง€ ์‹œ๊ฐ„์„ ์ •ํ•œ๋‹ค. phantom ๋ฐฉ์ง€๋Š” ์–ด๋–ค ๋…ผ๋ฆฌ์  ๋ฒ”์œ„๊นŒ์ง€ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€์— ๋‹ฌ๋ ค ์žˆ๋‹ค

2PL ๋ณ€ํ˜•

๋ณ€ํ˜•๋ฝ ํš๋“ยทํ•ด์ œ ๊ทœ์น™์ง๋ ฌ์„ฑ๋ฐ๋“œ๋ฝ๋ณต๊ตฌ ํŠน์„ฑ
๊ธฐ๋ณธ 2PLlock point ์ดํ›„conflict serializable์ƒ๊ธธ ์ˆ˜ ์žˆ์Œrecoverable์„ ๋ณด์žฅํ•˜์ง€ ์•Š์Œ
Conservative 2PLํ•„์š”ํ•œ ๋ฝ์„ ์ž‘์—… ์ „์— ๋ชจ๋‘ ํš๋“conflict serializable๋ฝ ํš๋“ ์ˆœํ™˜ ์—†์Œํ•ด์ œ ๊ทœ์น™์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง
Strict 2PL (S2PL)X๋ฝ์„ ์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€ ์œ ์ง€conflict serializable์ƒ๊ธธ ์ˆ˜ ์žˆ์Œstrict
Strong Strict 2PL (SS2PL)S๋ฝ๊ณผ X๋ฝ์„ ์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€ ์œ ์ง€conflict serializable์ƒ๊ธธ ์ˆ˜ ์žˆ์Œstrict

recoverable๊ณผ strict

  • recoverable: ์ฝ์€ ๊ฐ’์„ ๋งŒ๋“  ํŠธ๋žœ์žญ์…˜์ด ๋จผ์ € ์ปค๋ฐ‹ํ•œ ๋’ค ์ด๋ฅผ ์ฝ์€ ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹ํ•œ๋‹ค
  • cascadeless: ์ปค๋ฐ‹ํ•œ ๊ฐ’๋งŒ ์ฝ์–ด ์—ฐ์‡„ ๋กค๋ฐฑ์„ ํ”ผํ•œ๋‹ค
  • strict: ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์˜ ๋ฏธ์ปค๋ฐ‹ ๊ฐ’์„ ์ฝ๊ฑฐ๋‚˜ ๋ฎ์–ด์“ฐ์ง€ ์•Š๋Š”๋‹ค
  • ํฌํ•จ ๊ด€๊ณ„๋Š” strict โ†’ cascadeless โ†’ recoverable์ด๋‹ค
  • Conservative 2PL: ์ž‘์—… ์ „์— ํ•„์š”ํ•œ ๋ฝ ์ง‘ํ•ฉ์„ ์•Œ์•„์•ผ ํ•œ๋‹ค. ์‹คํ–‰ ์ค‘ ํ•„์š”ํ•œ ๋Œ€์ƒ์ด ๋‹ฌ๋ผ์ง€๋Š” ์ž‘์—…์—๋Š” ์ ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค
  • Strict 2PL: X๋ฝ์„ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€ํ•ด ๋ฏธ์ปค๋ฐ‹ ๊ฐ’์„ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์ฝ๊ฑฐ๋‚˜ ๋ฎ์–ด์“ฐ์ง€ ๋ชปํ•˜๊ฒŒ ํ•œ๋‹ค
  • Strong Strict 2PL: S๋ฝ๊ณผ X๋ฝ์„ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€ํ•œ๋‹ค. ์ปค๋ฐ‹ ์ˆœ์„œ๊ฐ€ serialization order์™€ ์ผ์น˜ํ•œ๋‹ค

PostgreSQL์˜ SELECT ... FOR UPDATE๊ฐ€ ํš๋“ํ•œ ํ–‰ ๋ฝ์€ ํŠธ๋žœ์žญ์…˜์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์œ ์ง€๋œ๋‹ค.

BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;   -- ํ–‰ ๋ฝ ํš๋“
UPDATE accounts SET balance = 500 WHERE id = 1;
COMMIT;                                            -- ํ–‰ ๋ฝ ํ•ด์ œ

๋ฝ ๊ธฐ๋ฐ˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€

๋‹ค์Œ ํ‘œ๋Š” Berenson ๋“ฑ์˜ ๋…ผ๋ฌธ์˜ ๋ฝ ๊ธฐ๋ฐ˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€ ๋ชจ๋ธ์ด๋‹ค.

๊ฒฉ๋ฆฌ ์ˆ˜์ค€write lockdata-item read lockpredicate read lock๋ฐฉ์ง€ํ•˜๋Š” ํ˜„์ƒ
Read Uncommitted์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€์—†์Œ์—†์Œdirty write
Read Committed์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€์ฝ๋Š” ๋™์•ˆ์ฝ๋Š” ๋™์•ˆdirty read
Repeatable Read์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€์ฝ๋Š” ๋™์•ˆnon-repeatable read
Serializable์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€์ปค๋ฐ‹ยท๋กค๋ฐฑ๊นŒ์ง€phantom์„ ํฌํ•จํ•œ ๋น„์ง๋ ฌ ์‹คํ–‰

์ด ๋ชจ๋ธ์—์„œ Repeatable Read์™€ Serializable์˜ ์ฐจ์ด๋Š” predicate read lock์„ ์œ ์ง€ํ•˜๋Š” ์‹œ๊ฐ„์ด๋‹ค. ์‹ค์ œ DBMS์˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์€ MVCC, ๋ฝ, ์˜์กด ์ถ”์ ์„ ์กฐํ•ฉํ•ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.


3. MVCC: ์ฝ๊ธฐ๋ฅผ ๋ง‰์ง€ ์•Š๋Š”๋‹ค

MVCC(Multiversion Concurrency Control)๋Š” ์ฝ๋Š” ์ชฝ์— ํ•„์š”ํ•œ ์˜› ๋ฒ„์ „์„ ๋ณด์กดํ•˜๊ณ  ์Šค๋ƒ…์ƒท์— ๋งž๋Š” ๋ฒ„์ „์„ ์„ ํƒํ•œ๋‹ค. ๋ฒ„์ „์„ ์ €์žฅํ•˜๋Š” ๋ฌผ๋ฆฌ ๋ฐฉ์‹์€ DBMS๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค.

PostgreSQL์€ UPDATEํ•  ๋•Œ ์˜› ํŠœํ”Œ์„ ๋‚จ๊ธฐ๊ณ  ์ƒˆ ํŠœํ”Œ์„ ๋งŒ๋“ ๋‹ค.

๋ฒ„์ „balance์ƒํƒœ
๋ฒ„์ „ 11000T10์ด ๋งŒ๋“ค๊ณ  T20์ด ๊ฐฑ์‹  ๋Œ€์ƒ์œผ๋กœ ํ‘œ์‹œ
๋ฒ„์ „ 2500T20์ด ์ƒˆ๋กœ ๋งŒ๋“ฆ

์ฝ๋Š” ์ชฝ์€ ์ฟผ๋ฆฌ์˜ ์Šค๋ƒ…์ƒท์— ๋ณด์ด๋Š” ๋ฒ„์ „์„ ๊ณ ๋ฅธ๋‹ค. PostgreSQL Read Committed๋Š” ๋ฌธ์žฅ๋งˆ๋‹ค ์ƒˆ ์Šค๋ƒ…์ƒท์„ ์‚ฌ์šฉํ•œ๋‹ค. Repeatable Read์™€ Serializable์€ BEGIN ๋’ค ์ฒซ ์กฐํšŒยท๋ณ€๊ฒฝ ๋ฌธ์žฅ์—์„œ ์–ป์€ ์Šค๋ƒ…์ƒท์„ ํŠธ๋žœ์žญ์…˜ ๋™์•ˆ ์‚ฌ์šฉํ•œ๋‹ค.

์ผ๋ฐ˜ ์กฐํšŒ์™€ ๊ฐฑ์‹ ์€ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋ณดํ†ต ์„œ๋กœ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

PostgreSQL์˜ ๊ตฌํ˜„

๊ฐ ํŠœํ”Œ์—๋Š” ํŠธ๋žœ์žญ์…˜ ID๋ฅผ ๊ธฐ๋กํ•˜๋Š” ํ•„๋“œ๊ฐ€ ์žˆ๋‹ค.

  • xmin: ์ด ๋ฒ„์ „์„ ๋งŒ๋“  ํŠธ๋žœ์žญ์…˜ ID
  • xmax: ์ด ๋ฒ„์ „์„ ์ง€์šฐ๊ฑฐ๋‚˜ ์ž ๊ทผ ํŠธ๋žœ์žญ์…˜ ID. ์•„๋ฌด๋„ ์†๋Œ€์ง€ ์•Š์•˜์œผ๋ฉด 0
SELECT xmin, xmax, * FROM accounts WHERE id = 1;

SQL ๋ฌธ์žฅ๋งˆ๋‹ค xmin๊ณผ xmax์— ๊ธฐ๋กํ•˜๋Š” ๊ฐ’์ด ๋‹ค๋ฅด๋‹ค.

๋ฌธ์žฅxminxmax
INSERT์ƒˆ ํŠœํ”Œ์— ์ž๊ธฐ XID๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Œ
UPDATE์ƒˆ ํŠœํ”Œ์— ์ž๊ธฐ XID์˜› ํŠœํ”Œ์— ์ž๊ธฐ XID
DELETE๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Œ์˜› ํŠœํ”Œ์— ์ž๊ธฐ XID
SELECT ... FOR UPDATE๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Œ์ž ๊ธˆ ์ •๋ณด๋ฅผ ๊ธฐ๋ก

INSERT๋Š” ์ƒˆ ํŠœํ”Œ์„ ๋งŒ๋“ ๋‹ค. PostgreSQL์˜ UPDATE๋Š” ์˜› ํŠœํ”Œ์— xmax๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์ƒˆ ๊ฐ’์„ ๊ฐ€์ง„ ํŠœํ”Œ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

์ฃผ์˜: xmax์™€ ๊ฐ€์‹œ์„ฑ

  • PostgreSQL system columns์€ ๋ณด์ด๋Š” ํŠœํ”Œ์˜ xmax๋„ 0์ด ์•„๋‹ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์„ค๋ช…ํ•œ๋‹ค
  • xmax์˜ ํŠธ๋žœ์žญ์…˜์ด ์•„์ง ์ปค๋ฐ‹ํ•˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๋กค๋ฐฑํ–ˆ์„ ์ˆ˜ ์žˆ๋‹ค
  • ํ–‰ ์‚ญ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ํ–‰ ์ž ๊ธˆ์„ ๊ธฐ๋กํ•œ ๊ฐ’์ผ ์ˆ˜ ์žˆ๋‹ค
  • ๊ฐ€์‹œ์„ฑ์€ xmax์˜ ๊ฐ’๋งŒ์œผ๋กœ ์ •ํ•˜์ง€ ์•Š๊ณ  ํŠธ๋žœ์žญ์…˜ ์ƒํƒœ์™€ ์Šค๋ƒ…์ƒท์„ ํ•จ๊ป˜ ํ™•์ธํ•œ๋‹ค

ํ–‰ ๋ฝ ์ •๋ณด์˜ ์ €์žฅ ์œ„์น˜

  • PostgreSQL์€ ํ–‰ ๋ฝ ์ •๋ณด๋ฅผ ํŠœํ”Œ ํ—ค๋”์˜ t_xmax์— ๊ธฐ๋กํ•œ๋‹ค
  • ์‚ญ์ œ์™€ ์ž ๊ธˆ์€ t_infomask ๋“ฑ์˜ ์ƒํƒœ ๋น„ํŠธ๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค
  • SELECT ... FOR UPDATE๋„ ๋Œ€์ƒ ํŠœํ”Œ์— ์ž ๊ธˆ ์ •๋ณด๋ฅผ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ๋‹ค
  • PostgreSQL์€ ํ–‰ ๋ฝ ์ˆ˜๊ฐ€ ๋Š˜์–ด๋„ ํ…Œ์ด๋ธ” ๋ฝ์œผ๋กœ ์Šน๊ธ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค
ํŠœํ”Œ ํ•„๋“œ์™€ ํŠธ๋žœ์žญ์…˜ ์ƒํƒœ

ํŠœํ”Œ์˜ xmin๊ณผ xmax๋Š” SQL ๋ฌธ์žฅ์„ ์‹คํ–‰ํ•  ๋•Œ ๊ธฐ๋ก๋œ๋‹ค.

BEGIN;
UPDATE accounts SET balance = 500 WHERE id = 1;
-- ์˜› ํŠœํ”Œ์˜ xmax์™€ ์ƒˆ ํŠœํ”Œ์˜ xmin์— ํ˜„์žฌ XID๊ฐ€ ๊ธฐ๋ก๋œ๋‹ค
COMMIT;

pg_xact๋Š” ํŠธ๋žœ์žญ์…˜์˜ ์ปค๋ฐ‹ ์ƒํƒœ๋ฅผ ์ €์žฅํ•œ๋‹ค. PostgreSQL์€ ์ปค๋ฐ‹ํ•  ๋•Œ ์ˆ˜์ •ํ•œ ํŠœํ”Œ๋งˆ๋‹ค ์ปค๋ฐ‹ ์—ฌ๋ถ€๋ฅผ ๋‹ค์‹œ ๊ธฐ๋กํ•˜์ง€ ์•Š๊ณ  ํŠธ๋žœ์žญ์…˜ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ€์‹œ์„ฑ์„ ํŒ์ •ํ•œ๋‹ค. ์ปค๋ฐ‹๊ณผ ๋กค๋ฐฑ์˜ ์ „์ฒด ๋น„์šฉ์—๋Š” WAL ๊ธฐ๋ก๊ณผ ๋ฝยท์ž์› ์ •๋ฆฌ ๋น„์šฉ๋„ ํฌํ•จ๋œ๋‹ค.

์œ„์น˜์ €์žฅ ๋‚ด์šฉ๊ธฐ๋ก ์‹œ์ 
ํŠœํ”Œ์˜ xminยทxmaxํŠœํ”Œ์„ ๋งŒ๋“  XID์™€ ์‚ญ์ œยท์ž ๊ธˆํ•œ XID๋ฌธ์žฅ ์‹คํ–‰ ์ค‘
pg_xactํŠธ๋žœ์žญ์…˜์˜ ์ปค๋ฐ‹ ์ƒํƒœ์ปค๋ฐ‹ยท๋กค๋ฐฑ ์ฒ˜๋ฆฌ ์ค‘

๋กค๋ฐฑํ•œ ํŠธ๋žœ์žญ์…˜์ด ๋งŒ๋“  ํŠœํ”Œ์€ ์กฐํšŒ ๋Œ€์ƒ์—์„œ ์ œ์™ธ๋˜๊ณ  VACUUM์œผ๋กœ ํšŒ์ˆ˜๋œ๋‹ค. InnoDB๋Š” undo log๋ฅผ ์—ญ์ˆœ์œผ๋กœ ์ ์šฉํ•ด ๋ณ€๊ฒฝ์„ ๋˜๋Œ๋ฆฐ๋‹ค.

hint bit: ์ฝ๊ธฐ๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค

  • ๊ฐ€์‹œ์„ฑ์„ ํ™•์ธํ•œ backend๋Š” ํŠธ๋žœ์žญ์…˜ ์ƒํƒœ๋ฅผ ํŠœํ”Œ์˜ hint bit์— ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ๋‹ค
  • hint bit๋ฅผ ๊ธฐ๋กํ•˜๋ฉด ์กฐํšŒ ์ค‘์—๋„ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€๊ฐ€ dirty ์ƒํƒœ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค
  • ๋ฐ์ดํ„ฐ checksum์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ wal_log_hints=on์ด๋ฉด checkpoint ์ดํ›„ ํŽ˜์ด์ง€์˜ ์ฒซ ๋ณ€๊ฒฝ์—์„œ full-page image๊ฐ€ WAL์— ๊ธฐ๋ก๋  ์ˆ˜ ์žˆ๋‹ค
  • ์กฐํšŒ ์‹œ๊ฐ„์—๋Š” hint bit ๊ธฐ๋ก ๋น„์šฉ ์™ธ์— ์บ์‹œ ์ƒํƒœ์™€ ๋™์‹œ์— ์‹คํ–‰ ์ค‘์ธ ์ž‘์—…๋„ ์˜ํ–ฅ์„ ์ค€๋‹ค

์ฃผ์˜: dead tuple๊ณผ VACUUM

  • ๋”๋Š” ๋ณด์ด์ง€ ์•Š๋Š” ์˜› ๋ฒ„์ „์„ dead tuple์ด๋ผ๊ณ  ํ•œ๋‹ค. ํšŒ์ˆ˜ํ•˜์ง€ ์•Š์œผ๋ฉด ๋””์Šคํฌ๋ฅผ ์ฐจ์ง€ํ•˜๊ณ  ์Šค์บ” ๋น„์šฉ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค
  • VACUUM์ด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ณต๊ฐ„์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค
  • ์˜ค๋ž˜ ์œ ์ง€ํ•œ ์Šค๋ƒ…์ƒท์— ํ•„์š”ํ•œ ์˜› ๋ฒ„์ „์€ VACUUM์ด ํšŒ์ˆ˜ํ•  ์ˆ˜ ์—†๋‹ค
  • ๋ถ€ํ’€์Œ์€ ์‹ค์ œ ํฌ๊ธฐ์™€ ์˜ˆ์ƒ ํฌ๊ธฐ๋ฅผ ๋น„๊ตํ•ด ํ™•์ธํ•œ๋‹ค. ํ•„์š”ํ•œ ๊ฒฝ์šฐ VACUUM FULL์ด๋‚˜ ํ…Œ์ด๋ธ” ์žฌ์ž‘์„ฑ์„ ๊ฒ€ํ† ํ•œ๋‹ค
  • ์ฐธ๊ณ  : https://techblog.woowahan.com/9478/ (PostgreSQL MVCC, Vacuum์— ๋Œ€ํ•ด ์ •๋ฆฌ๋œ ๋งค์šฐ ์ข‹์€ ๊ธ€)

readerโ†”writer ์ถฉ๋Œ

๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๋งŒ๋“  ๋ฒ„์ „์„ ์ฝ์„ ๋•Œ๋Š” ์Šค๋ƒ…์ƒท์— ๋ณด์ด๋Š” ์ปค๋ฐ‹ ์ƒํƒœ์™€ xminยทxmax๋ฅผ ํ•จ๊ป˜ ํ™•์ธํ•œ๋‹ค. ์ž์‹ ์˜ ํŠธ๋žœ์žญ์…˜์ด ๋งŒ๋“  ๋ฏธ์ปค๋ฐ‹ ๋ณ€๊ฒฝ์€ ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

write โ†’ read: T20์ด ์“ฐ๋Š” ๋™์•ˆ T21์ด ์ฝ๋Š” ๊ฒฝ์šฐ๋‹ค. ์ดˆ๊ธฐ๊ฐ’ balance = 1000์€ T10์ด ๋งŒ๋“  ๋ฒ„์ „์ด๋‹ค.

T20 (์“ฐ๋Š” ์ชฝ)                  T21 (์ฝ๋Š” ์ชฝ)
-----------------------------  -----------------------------
BEGIN
UPDATE balance = 500
                               BEGIN
                               SELECT balance  --> 1000
ROLLBACK
                               SELECT balance  --> 1000

UPDATE ์งํ›„ ํ–‰์€ ๋‹ค์Œ ์ƒํƒœ๋‹ค.

๋ฒ„์ „xminxmaxbalance์ƒํƒœ
๋ฒ„์ „ 110201000T20์ด ๊ฐฑ์‹  ๋Œ€์ƒ์œผ๋กœ ํ‘œ์‹œํ–ˆ์œผ๋‚˜ ๋ฏธ์ปค๋ฐ‹
๋ฒ„์ „ 220-500T20์ด ๋งŒ๋“ค์—ˆ์œผ๋‚˜ ๋ฏธ์ปค๋ฐ‹

T21์€ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์˜ ๋ฏธ์ปค๋ฐ‹ ๋ฒ„์ „ 2๋ฅผ ๊ฑด๋„ˆ๋›ด๋‹ค. ๋ฒ„์ „ 1์˜ xmax=20๋„ ๋ฏธ์ปค๋ฐ‹์ด๋ฏ€๋กœ ๋ฒ„์ „ 1์„ ์•„์ง ์‚ญ์ œ๋˜์ง€ ์•Š์€ ๊ฒƒ์œผ๋กœ ํŒ์ •ํ•˜๊ณ  1000์„ ์ฝ๋Š”๋‹ค. T20์ด ๋กค๋ฐฑํ•˜๋ฉด ๋ฒ„์ „ 2๋Š” ์ดํ›„ VACUUM์˜ ํšŒ์ˆ˜ ๋Œ€์ƒ์ด ๋œ๋‹ค.

read โ†’ write: T30์ด Repeatable Read์—์„œ ์ฝ๋Š” ๋™์•ˆ T31์ด ์“ฐ๋Š” ๊ฒฝ์šฐ๋‹ค.

T30 (์ฝ๋Š” ์ชฝ, RR)              T31 (์“ฐ๋Š” ์ชฝ)
-----------------------------  -----------------------------
BEGIN
SELECT balance  --> 1000
                               BEGIN
                               UPDATE balance = 500
                               COMMIT
SELECT balance  --> 1000
COMMIT
SELECT balance  --> 500

T30์€ ์ฒซ SELECT์—์„œ ์Šค๋ƒ…์ƒท์„ ์–ป๋Š”๋‹ค. ๊ทธ ๋’ค T31์ด ๋งŒ๋“ค๊ณ  ์ปค๋ฐ‹ํ•œ ๋ฒ„์ „์€ T30์˜ ์Šค๋ƒ…์ƒท์— ๋ณด์ด์ง€ ์•Š์œผ๋ฏ€๋กœ T30์˜ ๋‘ ๋ฒˆ์งธ SELECT๋„ 1000์„ ์ฝ๋Š”๋‹ค.

์ถฉ๋Œ๋ฝ ๊ธฐ๋ฐ˜ ์ฝ๊ธฐMVCC ์ฝ๊ธฐ
write โ†’ read์ฝ๋Š” ์ชฝ์ด ๊ฐ™์€ ๋Œ€์ƒ์˜ X๋ฝ ์•ž์—์„œ ๋Œ€๊ธฐ๋ณด์ด๋Š” ์˜› ๋ฒ„์ „์„ ์ฝ์Œ
read โ†’ write์“ฐ๋Š” ์ชฝ์ด ๊ฐ™์€ ๋Œ€์ƒ์˜ S๋ฝ ์•ž์—์„œ ๋Œ€๊ธฐ์ƒˆ ๋ฒ„์ „์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ

PostgreSQL์˜ ์Šค๋ƒ…์ƒท ์‹œ์ 

  • Read Committed: ๋ฌธ์žฅ๋งˆ๋‹ค ์ƒˆ ์Šค๋ƒ…์ƒท์„ ์‚ฌ์šฉํ•œ๋‹ค. ์œ„ ์˜ˆ์‹œ๋ผ๋ฉด T30์˜ ๋‘ ๋ฒˆ์งธ SELECT๊ฐ€ 500์„ ์ฝ๋Š”๋‹ค
  • Repeatable Read: BEGIN ๋’ค ์ฒซ ์กฐํšŒยท๋ณ€๊ฒฝ ๋ฌธ์žฅ์—์„œ ์–ป์€ ์Šค๋ƒ…์ƒท์„ ํŠธ๋žœ์žญ์…˜ ๋™์•ˆ ์‚ฌ์šฉํ•œ๋‹ค
  • Serializable: Repeatable Read์™€ ๊ฐ™์€ ์Šค๋ƒ…์ƒท ๊ทœ์น™์— SSI์˜ ์˜์กด ์ถ”์ ์„ ๋”ํ•œ๋‹ค
  • PostgreSQL์—์„œ๋Š” ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์˜ ๋ฏธ์ปค๋ฐ‹ ๋ณ€๊ฒฝ์„ ์ฝ์ง€ ์•Š๋Š”๋‹ค

psql ์ฐฝ ๋‘ ๊ฐœ๋กœ ์žฌํ˜„

-- ์ฐฝ 1
BEGIN;
UPDATE accounts SET balance = 500 WHERE id = 1;   -- ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๊ณ  ๋‘”๋‹ค
 
-- ์ฐฝ 2
SELECT balance FROM accounts WHERE id = 1;        -- ์ฆ‰์‹œ ์‘๋‹ต. ์˜› ๊ฐ’
SELECT xmin, xmax, balance FROM accounts WHERE id = 1;
  • ์ฐฝ 2๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•œ๋‹ค
  • SELECT ... FOR UPDATE๋กœ ๋ฐ”๊พธ๋ฉด ์กฐํšŒํ•œ ํ–‰์„ ์ž ๊ทธ๋ฏ€๋กœ ์•ž์„  ๊ฐฑ์‹ ์˜ ํ–‰ ๋ฝ์ด ํ•ด์ œ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค

writerโ†”writer ์ถฉ๋Œ : PostgreSQL์˜ ๋™์‹œ UPDATE

๋‹ค์ค‘ ๋ฒ„์ „ ์ €์žฅ๋งŒ์œผ๋กœ๋Š” ๋‘ ๊ฐฑ์‹ ์˜ ์ˆœ์„œ๋ฅผ ์ •ํ•˜์ง€ ๋ชปํ•œ๋‹ค.

T40                            T41
-----------------------------  -----------------------------
BEGIN
UPDATE balance = 500
                               BEGIN
                               UPDATE balance = 300
                                 ... ๋Œ€๊ธฐ ...
COMMIT
                               (์žฌ๊ฐœ)

PostgreSQL์˜ ๋‘ ๋ฒˆ์งธ UPDATE๋Š” ๊ฐ™์€ ํ–‰์˜ ๋ฝ์ด ํ•ด์ œ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. Read Committed์—์„œ๋Š” ๋Œ€๊ธฐ ๋’ค ๊ฒ€์ƒ‰ ์กฐ๊ฑด์„ ๋‹ค์‹œ ํ‰๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ณ  Repeatable Read์—์„œ๋Š” ๋™์‹œ ๋ณ€๊ฒฝ ๋•Œ๋ฌธ์— serialization failure๊ฐ€ ๋‚  ์ˆ˜ ์žˆ๋‹ค.

DBMS๋ณ„ ์˜› ๋ฒ„์ „ ์ €์žฅ ์œ„์น˜

DBMS์ตœ์‹  ๋ฒ„์ „์˜› ๋ฒ„์ „
PostgreSQL์ƒˆ ํŠœํ”Œ์„ ํ…Œ์ด๋ธ”์— ์ถ”๊ฐ€์˜› ํŠœํ”Œ์„ ํ…Œ์ด๋ธ”์— ์œ ์ง€
MySQL InnoDBํ˜„์žฌ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐฑ์‹ undo log์— ๊ธฐ๋ก
Oracleํ˜„์žฌ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐฑ์‹ undo segment์— ๊ธฐ๋ก

InnoDB์™€ Oracle์€ undo ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•ด ์Šค๋ƒ…์ƒท์— ํ•„์š”ํ•œ ์˜› ๋ฒ„์ „์„ ์žฌ๊ตฌ์„ฑํ•œ๋‹ค. PostgreSQL์€ ํ…Œ์ด๋ธ” ์•ˆ์˜ ์—ฌ๋Ÿฌ ํŠœํ”Œ ๋ฒ„์ „์—์„œ ๊ฐ€์‹œ์„ฑ ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ’์„ ๊ณ ๋ฅธ๋‹ค.


4. ๋‚™๊ด€์ : ์ž‘์—… ๋’ค ๊ฒ€์ฆํ•œ๋‹ค

์‚ฌ์šฉ์ž๋“ค์ด ๋™์‹œ์— ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ ์„ ๊ฒƒ์œผ๋กœ ๊ฐ€์ •

Kung๊ณผ Robinson์˜ OCC(Optimistic Concurrency Control)๋Š” ํŠธ๋žœ์žญ์…˜ ์ž‘์—… ์ค‘ ๊ณต์œ  ๋ฐ์ดํ„ฐ์— ๋ฝ์„ ๊ฑธ์ง€ ์•Š๊ณ  ๋ฐ˜์˜ ์ „์— ์ถฉ๋Œ์„ ๊ฒ€์ฆํ•œ๋‹ค.

  1. ์ฝ๊ธฐ ๋‹จ๊ณ„: ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ๊ณ„์‚ฐํ•œ๋‹ค. ๊ฒฐ๊ณผ๋Š” ๋กœ์ปฌ์— ๋‘”๋‹ค
  2. ๊ฒ€์ฆ ๋‹จ๊ณ„: ์ฝ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ์‚ฌ์ด ๋‹ค๋ฅธ ์ž‘์—…๊ณผ ์ถฉ๋Œํ–ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค
  3. ์“ฐ๊ธฐ ๋‹จ๊ณ„: ๊ฒ€์ฆ์— ์„ฑ๊ณตํ•˜๋ฉด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜์˜ํ•œ๋‹ค

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋ฒ„์ „ ์ปฌ๋Ÿผ๊ณผ ์กฐ๊ฑด๋ถ€ UPDATE๋กœ ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

-- ์ฝ์„ ๋•Œ ๋ฒ„์ „๋„ ํ•จ๊ป˜ ๊ฐ€์ ธ์˜จ๋‹ค
SELECT balance, version FROM accounts WHERE id = 1;   -- version = 3
 
-- ๋ฐ˜์˜ํ•  ๋•Œ ์ฝ์—ˆ๋˜ ๋ฒ„์ „์ด ์œ ์ง€๋๋Š”์ง€ ํ™•์ธํ•œ๋‹ค
UPDATE accounts SET balance = 500, version = 4
WHERE id = 1 AND version = 3;
-- ์˜ํ–ฅ๋ฐ›์€ ํ–‰์ด 0์ด๋ฉด version์ด ๋ฐ”๋€Œ์—ˆ๊ฑฐ๋‚˜ ๋Œ€์ƒ ํ–‰์ด ์—†๋‹ค

์ด SQL์„ PostgreSQL์—์„œ ์‹คํ–‰ํ•˜๋ฉด UPDATE ์ž์ฒด๋Š” ํ…Œ์ด๋ธ” ๋ฝ๊ณผ ํ–‰ ๋ฝ์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋™์‹œ์— ๊ฐ™์€ ํ–‰์„ ๊ฐฑ์‹ ํ•˜๋ฉด ๋Œ€๊ธฐํ•œ ๋’ค version = 3 ์กฐ๊ฑด์„ ๋‹ค์‹œ ํ‰๊ฐ€ํ•ด ์˜ํ–ฅ๋ฐ›์€ ํ–‰์ด 0์ด ๋  ์ˆ˜ ์žˆ๋‹ค. ํ˜ธ์ถœ์ž๋Š” ํ–‰ ์ˆ˜๋ฅผ ํ™•์ธํ•˜๊ณ  ์žฌ์‹œ๋„ํ•˜๊ฑฐ๋‚˜ ์ถฉ๋Œ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

ORM์—์„œ๋Š” ์ด๋ฅผ ๋‚™๊ด€์  ์ž ๊ธˆ์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. Hibernate์™€ JPA์˜ @Version์€ ๊ฐ™์€ ํ˜•ํƒœ์˜ ์กฐ๊ฑด๋ถ€ ๊ฐฑ์‹ ์„ ๋งŒ๋“ ๋‹ค.

CAS: ๊ฐ’์„ ๋น„๊ตํ•œ ๋’ค ๋ณ€๊ฒฝ

  • compare-and-swap์€ ํ˜„์žฌ ๊ฐ’์ด ์˜ˆ์ƒ๊ฐ’๊ณผ ๊ฐ™์„ ๋•Œ๋งŒ ์ƒˆ ๊ฐ’์œผ๋กœ ๋ฐ”๊พธ๋Š” ์›์ž์  ์—ฐ์‚ฐ์ด๋‹ค
  • CPU์˜ CMPXCHG, SQL์˜ ์กฐ๊ฑด๋ถ€ UPDATE, HTTP์˜ If-Match๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๊ณ„์ธต์—์„œ ๊ฐ™์€ ๋น„๊ต ํ›„ ๋ณ€๊ฒฝ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค
  • ์œ„ SQL์€ ๊ฐ’ ๋Œ€์‹  version์„ ๋น„๊ต ์กฐ๊ฑด์œผ๋กœ ์“ด๋‹ค

์ฃผ์˜: ์กฐ๊ฑด๋ถ€ ๊ฐฑ์‹ ์˜ ์‹คํŒจ ์ฒ˜๋ฆฌ

  • ์˜ํ–ฅ๋ฐ›์€ ํ–‰์ด 0์ด๋ฉด ๊ฐฑ์‹ ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š์•˜๋‹ค
  • ํ–‰ ์ˆ˜๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š์œผ๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํŒจํ•œ ๊ฐฑ์‹ ์„ ์„ฑ๊ณต์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์žฌ์‹œ๋„ ์—ฌ๋ถ€์™€ ํšŸ์ˆ˜๋Š” ์ž‘์—…์˜ ๋ฉฑ๋“ฑ์„ฑ, ์ถฉ๋Œ ๋นˆ๋„, ์‚ฌ์šฉ์ž ์‘๋‹ต ์ •์ฑ…์„ ๊ธฐ์ค€์œผ๋กœ ์ •ํ•œ๋‹ค
  • ๋ฒ„์ „ ์ปฌ๋Ÿผ ๋ฐฉ์‹์„ lock-based DB์—์„œ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค๋ฅธ ๋ฝ๊ณผ์˜ ๋Œ€๊ธฐ๋‚˜ multi-resource deadlock์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค

5. ์‹ค์ œ ์‹œ์Šคํ…œ์˜ ์กฐํ•ฉ

์‹ค์ œ ๊ตฌํ˜„์€ ๋ฒ„์ „ ๊ฐ€์‹œ์„ฑ, ๋ฝ, ์ถฉ๋Œ ๊ฒ€์ฆ์„ ์šฉ๋„์— ๋”ฐ๋ผ ์กฐํ•ฉํ•œ๋‹ค.

PostgreSQL

์ถฉ๋Œ๊ธฐ๋ณธ ์ฒ˜๋ฆฌ
reader โ†” writer์ผ๋ฐ˜ SELECT๋Š” row lock ์—†์ด ์Šค๋ƒ…์ƒท์— ๋ณด์ด๋Š” ๋ฒ„์ „์„ ์ฝ์Œ
writer โ†” writer๊ฐ™์€ ํ–‰์˜ ๋’ค์ชฝ UPDATE๊ฐ€ ํ–‰ ๋ฝ์—์„œ ๋Œ€๊ธฐํ•œ ๋’ค ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์— ๋งž๊ฒŒ ์ฒ˜๋ฆฌ๋จ

์ผ๋ฐ˜ SELECT๋„ ACCESS SHARE relation lock์€ ํš๋“ํ•œ๋‹ค. ์ด ๋ฝ์€ ์ผ๋ฐ˜์ ์ธ UPDATE์˜ relation lock๊ณผ ํ˜ธํ™˜๋˜๋ฏ€๋กœ readerโ†”writer ๋Œ€๊ธฐ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.

๊ฒฉ๋ฆฌ ์ˆ˜์ค€PostgreSQL์˜ ์ถ”๊ฐ€ ๊ทœ์น™
Read Committed (๊ธฐ๋ณธ)๋ฌธ์žฅ๋งˆ๋‹ค ์ƒˆ ์Šค๋ƒ…์ƒท์„ ์‚ฌ์šฉ
Repeatable Read์ฒซ ์กฐํšŒยท๋ณ€๊ฒฝ ๋ฌธ์žฅ์—์„œ ์–ป์€ ์Šค๋ƒ…์ƒท์„ ํŠธ๋žœ์žญ์…˜ ๋™์•ˆ ์‚ฌ์šฉ
Serializable๊ฐ™์€ ์Šค๋ƒ…์ƒท ๊ทœ์น™์— SSI ์˜์กด ์ถ”์ ์„ ์ถ”๊ฐ€

์œ„ ํ‘œ์˜ ์ถ•์€ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋‹ค. ์•ž ํ‘œ์˜ ์ถ•์€ ์ถฉ๋Œ ์Œ์ด๋‹ค.

SSI์˜ SIReadLock

  • ์ด๋ฆ„์— lock์ด ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์„ ๋Œ€๊ธฐ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค
  • PostgreSQL์€ ์ฝ์€ ๋ฒ”์œ„์™€ ์ฝ๊ธฐยท์“ฐ๊ธฐ ์˜์กด์„ ์ถ”์ ํ•˜๋Š” ํ‘œ์‹์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค
  • ์œ„ํ—˜ํ•œ ์˜์กด ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง€ํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜ ํ•˜๋‚˜๋ฅผ serialization failure๋กœ ์ค‘๋‹จํ•œ๋‹ค
  • ํ˜ธ์ถœ์ž๋Š” ์ค‘๋‹จ๋œ ์ž‘์—…์„ ์žฌ์‹œ๋„ํ•˜๊ฑฐ๋‚˜ ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค

๊ฐ์ฒด ์Šคํ† ๋ฆฌ์ง€ ์œ„์˜ ํ…Œ์ด๋ธ” ํฌ๋งท

ํ…Œ์ด๋ธ” ํฌ๋งท์€ ๊ฐ์ฒด ์Šคํ† ๋ฆฌ์ง€์— ์Šค๋ƒ…์ƒท ์„ ํƒ๊ณผ ๋™์‹œ ์ปค๋ฐ‹ ๊ฒ€์ฆ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ๋‹ค์Œ ํ‘œ๋Š” ๊ฐ ํฌ๋งท์˜ ์Šค๋ƒ…์ƒท ์„ ํƒ๊ณผ ๋™์‹œ ์“ฐ๊ธฐ ์ฒ˜๋ฆฌ ์˜ˆ์‹œ๋‹ค.

ํฌ๋งทreaderโ†”writerwriterโ†”writer์˜ ๋Œ€ํ‘œ ์ฒ˜๋ฆฌ
Iceberg์ปค๋ฐ‹๋œ ์Šค๋ƒ…์ƒท์„ ์„ ํƒ์นดํƒˆ๋กœ๊ทธ์—์„œ ํ˜„์žฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํฌ์ธํ„ฐ๋ฅผ ์กฐ๊ฑด๋ถ€ ๊ต์ฒด
Delta Lake๋ฒ„์ „๋ณ„ transaction log๋ฅผ ์ฝ์Œ๋‹ค์Œ ๋กœ๊ทธ ๋ฒ„์ „ ์ปค๋ฐ‹์„ ๊ฒ€์ฆํ•˜๊ณ  ์ถฉ๋Œ ์‹œ ์ž‘์—…์— ๋”ฐ๋ผ ์žฌ์‹œ๋„
Hudiํƒ€์ž„๋ผ์ธ์˜ ์™„๋ฃŒ๋œ instant๋ฅผ ์ฝ์Œmulti-writer OCC ๋ชจ๋“œ์—์„œ lock provider์™€ ์ถฉ๋Œ ๊ฒ€์ฆ์„ ์‚ฌ์šฉ

Hudi์—์„œ ํ•œ ํ”„๋กœ์„ธ์Šค์˜ writer์™€ async table service๋ฅผ ์กฐ์ •ํ•  ๋•Œ๋Š” InProcessLockProvider๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ตฌํ˜„๊ณผ ์šด์˜ ์„ค์ •์€ ํ…Œ์ด๋ธ” ํฌ๋งท์—์„œ ๋‹ค๋ฃฌ๋‹ค.


6. ์„ ํƒ ๊ธฐ์ค€

๋น„๊ด€์  ๋ฐฉ์‹๊ณผ ๋‚™๊ด€์  ๋ฐฉ์‹์€ ์ถฉ๋Œ ๋นˆ๋„์™€ ์ถฉ๋Œ ๋’ค ์ฒ˜๋ฆฌ ๋น„์šฉ์„ ํ•จ๊ป˜ ๋น„๊ตํ•œ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฒ„์ „ ์ปฌ๋Ÿผ OCC๋„ DB ๋‚ด๋ถ€์—์„œ๋Š” ๋ฝ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋‘ ๋ฐฉ์‹์„ ๋ฝ์˜ ์œ ๋ฌด๋งŒ์œผ๋กœ ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค.

๋น„๊ต ํ•ญ๋ชฉ๋น„๊ด€์  ๋ฐฉ์‹๋‚™๊ด€์  ๋ฐฉ์‹
์ˆœ์„œ๋ฅผ ์ •ํ•˜๋Š” ์‹œ์ ์ž‘์—… ์ „์ด๋‚˜ ์‹คํ–‰ ์ค‘๊ฒฐ๊ณผ ๋ฐ˜์˜ ์ „ ๊ฒ€์ฆ ์‹œ์ 
์ถฉ๋Œ ์ฒ˜๋ฆฌ๋Œ€๊ธฐํ•˜๊ฑฐ๋‚˜ ํŠธ๋žœ์žญ์…˜ ์ค‘๋‹จ๊ฒ€์ฆ ์‹คํŒจ ํ›„ ์ž‘์—…๋ณ„ ์ •์ฑ… ์ ์šฉ
ํ‰์ƒ์‹œ ๋น„์šฉ๋ฝ ํš๋“๊ณผ ๊ด€๋ฆฌ๋ฒ„์ „ยท๊ฒ€์ฆ ์ •๋ณด ๊ด€๋ฆฌ
์‹คํŒจ ๊ฐ€๋Šฅ์„ฑ๋ฐ๋“œ๋ฝ, timeout, serialization failure ๋“ฑ๊ฒ€์ฆ ์‹คํŒจ, starvation, DB ๋ฝ ๊ด€๋ จ ์‹คํŒจ ๋“ฑ
์žฌ์ฒ˜๋ฆฌ ๋น„์šฉ์ค‘๋‹จ๋œ ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„๊ฒ€์ฆ ์ „์— ์ˆ˜ํ–‰ํ•œ ๊ณ„์‚ฐ๊ณผ I/O ๋ฒ”์œ„
  • ๊ฐ™์€ ํ–‰์˜ ๊ฐฑ์‹ ์ด ์ž์ฃผ ๊ฒน์น˜๋Š” ์ž‘์—…: ์žฌ์‹œ๋„ ๋น„์šฉ๊ณผ ๋ฝ ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ ์ธก์ •ํ•ด ๋น„๊ด€์  ๋ฐฉ์‹์„ ์šฐ์„  ๊ฒ€ํ† ํ•œ๋‹ค
  • ๊ฐฑ์‹  ๋Œ€์ƒ์ด ๋„“๊ฒŒ ๋ถ„์‚ฐ๋œ ์ž‘์—…: ์ถฉ๋Œ์ด ๋“œ๋ฌผ๊ณ  ์žฌ๊ณ„์‚ฐ์ด ์ €๋ ดํ•˜๋ฉด ๋‚™๊ด€์  ๊ฒ€์ฆ์„ ์šฐ์„  ๊ฒ€ํ† ํ•œ๋‹ค
  • ์ฝ๊ธฐ๊ฐ€ ๋งŽ์€ ์›Œํฌ๋กœ๋“œ: MVCC๋Š” readerโ†”writer ๋Œ€๊ธฐ๋ฅผ ์ค„์ด์ง€๋งŒ ์“ฐ๊ธฐ ์ถฉ๋Œ๊ณผ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์˜ ๋ฌธ์ œ๋Š” ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค
  • ์กฐ๊ฑด์„ ์ฝ๊ณ  ์—ฌ๋Ÿฌ ํ–‰์„ ๊ฐฑ์‹ ํ•˜๋Š” ์ž‘์—…: ๊ฐœ๋ณ„ ํ–‰ ์ถฉ๋Œ๊ณผ ํ•จ๊ป˜ predicate ๋ฒ”์œ„์˜ ์ผ๊ด€์„ฑ์ด ํ•„์š”ํ•œ์ง€ ํ™•์ธํ•œ๋‹ค

์„ ํƒํ•  ๋•Œ๋Š” ์ถฉ๋Œ๋ฅ , ํ‰๊ท ยท์ตœ๋Œ€ ๋Œ€๊ธฐ ์‹œ๊ฐ„, ์žฌ์‹œ๋„ ํšŸ์ˆ˜, ํ•œ ๋ฒˆ์˜ ์žฌ์ฒ˜๋ฆฌ ๋ฒ”์œ„๋ฅผ ์ธก์ •ํ•œ๋‹ค. ๊ฐ™์€ ์ถฉ๋Œ๋ฅ ์ด์–ด๋„ ๊ฒ€์ฆ ์ „์— ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฑฐ๋‚˜ ๊ณ„์‚ฐํ–ˆ๋‹ค๋ฉด ์žฌ์ฒ˜๋ฆฌ ๋น„์šฉ์ด ์ปค์ง„๋‹ค.