did_story

[Database] ๋™์‹œ์„ฑ ์ œ์–ด(Concurrency Control) - MVCC ๋ณธ๋ฌธ

BackEnd๐Ÿƒ/DB & SQL

[Database] ๋™์‹œ์„ฑ ์ œ์–ด(Concurrency Control) - MVCC

์–ด์ œ์‹œ์ž‘ 2025. 7. 14. 14:56
์—ฌ๋Ÿฌ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜์—ฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ณ  ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ• (๋™์‹œ์— ์ž‘์šฉํ•˜๋Š” ๋‹ค์ค‘ ํŠธ๋žœ์žญ์…˜์˜ ์ƒํ˜ธ๊ฐ„์„ญ ์ž‘์šฉ์—์„œ Database๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ๊ฒƒ) ์„ ๋™์‹œ์„ฑ ์ œ์–ด(Concurrency Control) ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ข…๋ฅ˜๋Š” ์–ด๋–ค ๊ฒƒ์ด ์žˆ์„๊นŒ?! ์ง€๊ธˆ๋ถ€ํ„ฐ ๊ทธ๊ฒƒ์„ ์•Œ์•„๋ณด๋Ÿฌ ๋– ๋‚˜๋ด…์‹œ๋‹ค.

์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์ค‘ ๋ฒ„์ „ ๋™์‹œ์„ฑ ์ œ์–ด (MVCC, Multi-Version Concurrency Control)๊ณผ ์ž ๊ธˆ ๊ธฐ๋ฐ˜ ๋™์‹œ์„ฑ ์ œ์–ด (Lock-based Concurrency Control)์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ด์ œ ํ•˜๋‚˜ํ•˜๋‚˜ ์ž์„ธํ•˜๊ฒŒ ์•Œ์•„๋ณผ๊นŒ์š”??

1. ๋™์‹œ์„ฑ ์ œ์–ด์˜ ๋ชฉ์ 

์ •์˜: ์—ฌ๋Ÿฌ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•ด๋„ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ๊ณผ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•˜๋ฉด์„œ, ์„ฑ๋Šฅ๊ณผ ํšจ์œจ์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๋ชฉ์ ์ž…๋‹ˆ๋‹ค.
    1. ๋ถ„์‹ค๋œ ๊ฐฑ์‹ (Lost Update)
      • ๋ฌธ์ œ ์ƒํ™ฉ: ๋‘ ํŠธ๋žœ์žญ์…˜์ด ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์ˆ˜์ •ํ•œ ํ›„ ์ €์žฅํ•˜๋ฉด, ๋จผ์ € ์ €์žฅ๋œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์ค‘ ์ €์žฅ์œผ๋กœ ๋ฎ์—ฌ์ง.
        • T1: A = 100 ์ฝ์Œ → A = A+10 → ์ €์žฅ
        • T2: A = 100 ์ฝ์Œ → A = A+20 → ์ €์žฅ
          → ๊ฒฐ๊ณผ: A=120 (T1์˜ 10์€ ์‚ฌ๋ผ์ง)
    2. ๋ชจ์ˆœ์„ฑ(Inconsistency)
      • ๋ฌธ์ œ ์ƒํ™ฉ: ๋‘ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ์‹คํ–‰๋˜์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ถˆ์ผ์น˜ํ•˜๊ฑฐ๋‚˜ ์˜ค๋ฅ˜ ์ƒํƒœ์— ๋น ์ง€๋Š” ๊ฒฝ์šฐ.
        • T1์€ ์ž”๊ณ ๋ฅผ ์ฐจ๊ฐํ•˜๊ณ , T2๋Š” ๋™์‹œ์— ์ฐจ๊ฐํ•˜์—ฌ ์ตœ์ข… ์ž”๊ณ ๊ฐ€ ์ž˜๋ชป๋จ
    3. ์—ฐ์‡„๋ณต๊ท€(Cascading Rollback)
      • ๋ฌธ์ œ ์ƒํ™ฉ: ํ•œ ํŠธ๋žœ์žญ์…˜์ด ์‹คํŒจํ•˜์—ฌ ๋กค๋ฐฑ๋˜๋ฉด, ๊ทธ ํŠธ๋žœ์žญ์…˜ ๊ฒฐ๊ณผ๋ฅผ ์ฐธ์กฐํ•œ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜๋„ ์—ฐ์‡„์ ์œผ๋กœ ๋กค๋ฐฑ๋˜๋Š” ์ƒํ™ฉ.
        • T1์ด A๊ฐ’์„ ๋ณ€๊ฒฝ (์ปค๋ฐ‹ ์•ˆ๋จ)
        • T2๊ฐ€ A๋ฅผ ์ฐธ์กฐ → T1 ์‹คํŒจ๋กœ ๋กค๋ฐฑ
        • T2๋„ ์˜ํ–ฅ์„ ๋ฐ›์•„ ๋กค๋ฐฑ
    4. ๋น„์™„๋ฃŒ ์˜์กด์„ฑ(Uncommitted Dependency)
      • ๋ฌธ์ œ ์ƒํ™ฉ: ์ปค๋ฐ‹๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ(์ž ์ •๊ฐ’)๋ฅผ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์ฝ๊ณ , ๊ทธ ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ.
        • T1์ด A=500 → 600์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ์ง€๋งŒ ์•„์ง ์ปค๋ฐ‹ ์•ˆ ๋จ
        • T2๊ฐ€ A=600 ์‚ฌ์šฉ
        • T1์ด ๋กค๋ฐฑ → T2๋Š” ์ž˜๋ชป๋œ A ์‚ฌ์šฉ

2. MVCC (Multi-Version Concurrency Control)

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

MVCC ์˜ ํŠน์ง•

ํŠน์ง•  
Snapshot Isolation ๊ฐ ํŠธ๋žœ์žญ์…˜์€ ์‹œ์ž‘ ์‹œ์ ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ณ ์ •๋œ ์Šค๋ƒ…์ƒท์„ ์ฝ์Šต๋‹ˆ๋‹ค. ์ดํ›„ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์•„, ์ผ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Non-blocking Read ์ฝ๊ธฐ ์ž‘์—…์€ ์“ฐ๊ธฐ ์ž‘์—…์„ ๋ง‰์ง€ ์•Š๊ณ , ์“ฐ๊ธฐ ์ž‘์—…๋„ ์ฝ๊ธฐ ์ž‘์—…์— ๋ฐฉํ•ด๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋™์‹œ์„ฑ์ด ๋†’์•„์ง€๊ณ , ๋ฝ ๊ฒฝํ•ฉ์ด ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.
ํŠธ๋žœ์žญ์…˜ ๋‚ด ์ฝ๊ธฐ ์ผ๊ด€์„ฑ ๋ณด์žฅ ํŠธ๋žœ์žญ์…˜์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ๋™์ผํ•œ ์งˆ์˜ ๊ฒฐ๊ณผ๋Š” ํ•ญ์ƒ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ, Read Committed ์ˆ˜์ค€์—์„œ๋Š” ์ปค๋ฐ‹๋œ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ˜์˜๋˜์–ด ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

PostgreSQL์—์„œ MVCC ์˜ ์ž‘์—… ๋ฐฉ์‹ ์˜ˆ์ œ

https://vladmihalcea.com/how-does-mvcc-multi-version-concurrency-control-work/
https://vladmihalcea.com/how-does-mvcc-multi-version-concurrency-control-work/

  1. Alice์™€ Bob์€ ๋ชจ๋‘ ์ƒˆ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ณ , txid_current() PostgreSQL ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜ ID๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. Alice๊ฐ€ ์ƒˆ ๊ธ€ ํ–‰์„ ์‚ฝ์ž…ํ•˜๋ฉด xmin ์—ด ๊ฐ’์ด Alice์˜ ํŠธ๋žœ์žญ์…˜ ID๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
  3. ๊ธฐ๋ณธ ์ฝ๊ธฐ ์ปค๋ฐ‹ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์—์„œ, Bob์€ ์•จ๋ฆฌ์Šค๊ฐ€ ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•  ๋•Œ๊นŒ์ง€ ์•จ๋ฆฌ์Šค๊ฐ€ ์ƒˆ๋กœ ์‚ฝ์ž…ํ•œ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  4. Alice๊ฐ€ ์ปค๋ฐ‹ํ•œ ํ›„, Bob์€ ์ด์ œ Alice๊ฐ€ ์ƒˆ๋กœ ์‚ฝ์ž…ํ•œ ํ–‰์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

⇒ ์ฆ‰ ์ด์ฒ˜๋Ÿผ MVCC๋Š” ๊ฐ ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘๋  ๋•Œ, ๊ทธ ์‹œ์ ์˜ ์Šค๋ƒ…์ƒท(Snapshot)์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ์Šค๋ƒ…์ƒท์€ ๋‹ค์Œ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค:

  • ์ฝ๊ธฐ ์ผ๊ด€์„ฑ (Read Consistency): ํŠธ๋žœ์žญ์…˜์€ ์ž์‹ ์ด ์‹œ์ž‘๋œ ์‹œ์ ์˜ ๋ฐ์ดํ„ฐ ๋ฒ„์ „๋งŒ ๋ณผ ์ˆ˜ ์žˆ๊ณ , ์ดํ›„ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•ด๋„ ๊ทธ ํŠธ๋žœ์žญ์…˜์—๋Š” ์˜ํ–ฅ ์—†์Œ.
  • ์“ฐ๊ธฐ ์ถฉ๋Œ ์ตœ์†Œํ™”: ๊ฐ ํŠธ๋žœ์žญ์…˜์€ ์ž์‹ ๋งŒ์˜ ๋ฒ„์ „์—์„œ ์ž‘์—…ํ•˜๋ฉฐ, ์ปค๋ฐ‹ ์‹œ์ ์—๋งŒ ์ถฉ๋Œ์„ ์ฒดํฌํ•จ.

MySQL์—์„œ์˜ MVCC(Multi-Version Concurrency Controll)

MySQL์˜ InnoDB์—์„œ๋Š” Undo Log๋ฅผ ํ™œ์šฉํ•ด MVCC ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋ณด์ž.

CREATE TABLE member (
    id INT NOT NULL,
    name VARCHAR(20) NOT NULL,
    area VARCHAR(100) NOT NULL,
    PRIMARY KEY(m_id),
    INDEX idx_area(area)
)

INSERT INTO member(id, name, area) VALUES (1, "Dohyun", "Pohang");

์ด๋Ÿฌ๋ฉด ๋ฐ์ดํ„ฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ์™€ ๋””์Šคํฌ์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ๋™์ผํ•˜๊ฒŒ ์ €์žฅ์ด ๋œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹œ์ž‘ํ•œ๋‹ค๊ณ  ๊ฐ€์กํ•ด๋ณด์ž,

UPDATE member SET area = "Seoul" WHERE id = 1;

 

ํ•ด๋‹น Updata ๋ฌธ์„ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ๋Š” ์‚ฌ์ง„๊ณผ ๊ฐ™๋‹ค. ๋จผ์ € COMMIT ์‹คํ–‰ ์—ฌ๋ถ€์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ InnoDB ๋ฒ„ํผ ํ’€์€ ์ƒˆ๋กœ์šด ๊ฐ’์œผ๋กœ ๊ฐฑ์‹ ๋˜๊ณ , Undo Log์—๋Š” ๋ณ€๊ฒฝ ์ „์— ๊ฐ’๋งŒ ๋ณต์‚ฌ๋œ๋‹ค. InnoDB ๋ฒ„ํผ ํ’€์˜ ๋‚ด์šฉ์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด์„œ ๋””์Šคํฌ์— ๊ธฐ๋ก์ด ๋œ๋‹ค. ํ•˜์ง€๋งŒ ๋ฐ˜์˜ ์—ฌ๋ถ€๋Š” ์‹œ์ ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ,

SELECT * FROM member WHERE id = 1; 

ํ•˜๊ฒŒ ๋˜๋ฉด,

- READ_UNCOMMITTED์—์„œ๋Š” ๋ฒ„ํผ ํ’€์˜ ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ → Dirty Read ๋ฐœ์ƒ
- READ_COMMITTED ์ด์ƒ(REPEATABLE_READ, SERIALIZABLE)Undo Log ๊ธฐ๋ฐ˜์œผ๋กœ ์ปค๋ฐ‹ ์ „ ๋ฐ์ดํ„ฐ ๋ณต์›
- Undo Log๋Š” ์ฐธ์กฐ๋˜์ง€ ์•Š์œผ๋ฉด ์‚ญ์ œ๊ฐ€ ๋˜์–ด ์ง‘๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ ๋‹ค์Œ์€ ์ž ๊ธˆ ๊ธฐ๋ฐ˜ ๋™์‹œ์„ฑ ์ œ์–ด (Lock-based Concurrency Control)์— ๋Œ€ํ•ด์„œ ๋ฐฐ์›Œ๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค!

 

๋‹ค์Œ ๊ธ€์ด ๊ถ๊ธˆํ•˜๋‹ค๋ฉด?

2025.07.15 - [BackEnd๐Ÿƒ/DB & SQL] - [Database] ๋™์‹œ์„ฑ ์ œ์–ด(Concurrency Control) - Locking

 

[Database] ๋™์‹œ์„ฑ ์ œ์–ด(Concurrency Control) - Locking

์•ž์„  ๊ธ€์„ ์ฝ๊ณ  ์˜จ ๋‹น์‹ , ๋™์‹œ์„ฑ ์ œ์–ด์— ๋Œ€ํ•ด์„œ ์กฐ๊ธˆ์€ ๋ฐฐ์›Œ๋ณด์•˜์„ ๊ฒƒ์ด๋‹ค. ์ด์ œ ๋‹ค์Œ ์ œ์–ด ๋ฐฉ๋ฒ•์ธ Locking์— ๋Œ€ํ•ด์„œ ๊ฐ™์ด ์•Œ์•„๋ด…์‹œ๋‹ค~!LockingLocking์€ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์ด ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋Š” ๋™์•ˆ,

didcheck.tistory.com