[DB] ์ข์์ ์ - ๋์์ฑ ์ด์์ ํด๊ฒฐ ์ ๋ต : ๋น๊ด์ ๋ฝ, ๋๊ด์ ๋ฝ, ๋น๋๊ธฐ ์ฒ๋ฆฌ
by Dongwoongkim์ ํ์ฑ๊ณผ ์ฑ๋ฅ์ ํธ๋ ์ด๋ ์คํ ๊ด๊ณ์ด๋ค. ๋ฌด๊ฒฐ์ฑ์ ๋์ด๊ธฐ ์ํด ๋ฝ์ ๊ฐํ๊ฒ ๊ฑธ๋ฉด ์ฑ๋ฅ์ด ํฌ์๋๊ณ , ๋ฐ๋๋ก ์ฑ๋ฅ ์ต์ ํ์ ์ง์คํ๋ฉด ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ด ๊นจ์ง ์ ์๋ ๋ฆฌ์คํฌ๊ฐ ๋ฐ์ํ๋ค. ๊ฐ๋ฐ์์ ์ญํ ์ ์๋น์ค ์ํฉ์ ๋ง๋ ์ ์ ํ ๊ท ํ์ ์ ์ฐพ๋ ๊ฒ์ด๋ค.
์ด๋น ์์ฒ ๊ฑด์ ์์ฒญ์ด ์์์ง๋ '์ข์์' ๊ธฐ๋ฅ์ ๋ฐ์ดํฐ ์ ์ค ์์ด ์ฒ๋ฆฌํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น? ํต์ฌ์ ๊ฒฐ๊ตญ ๋์์ฑ ์ ์ด์ ์๋ค. ๋ช ์์ ์ธ ๋ ์ฝ๋ ๋ฝ์ผ๋ก ๋ฐ์ดํฐ์ ์ ํฉ์ฑ์ ๋ณด์ฅํ๋ ๋น๊ด์ ๋ฝ๊ณผ, ๋ฝ ์์ด ์์คํ ์ ์ฒ๋ฆฌ๋์ ๊ทน๋ํํ๋ ๋๊ด์ ๋ฝ์ ๊ฐ๊ฐ ๊ตฌํํ๋ฉด์ ๋ ๋ฐฉ์์ ์ฐจ์ด๋ฅผ ๋น๊ตํ๋ฉฐ, ์๋น์ค ์ํฉ์ ๋ง๋ ์ต์ ์ ์ ํ์ง๋ฅผ ์ฐพ์๊ฐ๋ ๊ณผ์ ์ ์ ๋ฆฌํด ๋ณด๋ ค ํ๋ค.
๋จผ์ ์ข์์ ์์ ๋ํ ๋ฐ์ดํฐ์ ํน์ฑ์ ์ดํดํด ๋ณด์.
์ฒซ ๋ฒ์งธ๋ก, ‘์ข์์ ์’ ๋ฐ์ดํฐ๋ ์๋์ ๊ฐ์ด ๋น๊ต์ ๋จ์ํ๊ฒ ์ฒ๋ฆฌ๋๊ธฐ ๋๋ฌธ์ ์ฐ๊ธฐ ํธ๋ํฝ์ ๊ทธ๋ ๊ฒ ํฌ์ง ์๋ค.
1. ์ฌ์ฉ์๊ฐ ๊ฒ์๊ธ์ ์กฐํํ๊ณ , ์ข์์๋ฅผ ํด๋ฆญํ๋ค.
2. ํด๋น ๊ฒ์๋ฌผ์ ์ข์์ ์๊ฐ 1 ์ฆ๊ฐํ๋ค.
๋ ๋ฒ์งธ๋ก, ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ด ์ค์ํ๋ค. 100๋ช ์ด ์ข์์ ๋ฒํผ์ ๋๋ ๋ค๋ฉด, ์ข์์ ์๋ 100์ผ๋ก ํ์๋์ด์ผ ํ๋ค. ์๋์ฒ๋ผ ๊ฑฐ์ ๋์ผํ ์์ ์์ ๋ ํธ๋์ญ์ ์ด ์คํ๋๋ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค.
| ์๊ฐ | ํธ๋์ญ์ A (์ฌ์ฉ์ A) | ํธ๋์ญ์ B (์ฌ์ฉ์ B) | DB ์ํ (like_count) |
| T1 | ๊ฒ์๊ธ 100๋ฒ ์กฐํ (๊ฐ: 10) | 10 | |
| T2 | ๊ฒ์๊ธ 100๋ฒ ์กฐํ (๊ฐ: 10) | 10 | |
| T3 | 10 + 1 = 11 ๊ณ์ฐ | 10 | |
| T4 | 11๋ก ์ ๋ฐ์ดํธ ์คํ(Commit) | 11 | |
| T5 | 10 + 1 = 11 ๊ณ์ฐ | 11 | |
| T6 | 11๋ก ์ ๋ฐ์ดํธ ์คํ(Commit) | 11 |
์ด๋ฐ ํน์ฑ์ ๊ฐ์ง ์ข์์ ์ ๋ฐ์ดํฐ๋ฅผ ์ผ๊ด๋๊ฒ ๊ด๋ฆฌํ๋ ค๋ฉด ์ด๋ป๊ฒ ํ๋ฉด ์ข์๊น?
๊ฐ์ฅ ์ฝ๊ฒ ์๊ฐํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก๋ ๊ฒ์๊ธ ํ ์ด๋ธ์์ ์ข์์ ์์ ๋ํ ์ปฌ๋ผ์ ์ถ๊ฐํ๊ณ ์ข์์๋ฅผ ๋๋ฅผ ๋ ํด๋น ๋ ์ฝ๋์ ๋ฝ์ ๊ฑธ๊ณ ์์ ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. ์ฆ, ๊ฒ์๊ธ ํ ์ด๋ธ์ ์ข์์ ์ ์ปฌ๋ผ์ ์ถ๊ฐํ๊ณ , ์ข์์๊ฐ ์์ฑ๋๊ฑฐ๋ ์ญ์ ๋ ๋๋ง๋ค ํด๋น ์ปฌ๋ผ์ ์ ๋ฐ์ดํธํ๋ ๋ฐฉ์์ ์ฌ์ฉํ ์ ์๋ค. ๊ทธ๋ฌ๋ ์ด์ฒ๋ผ ๊ฒ์๊ธ ํ ์ด๋ธ์์ ์ง์ ์ข์์ ์๋ฅผ ๊ด๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
- ์ฒซ ๋ฒ์งธ๋ ๋ ์ฝ๋ ๋ฝ(Record Lock)์ผ๋ก ์ธํ ์ฑ๋ฅ ์ ํ๋ค.
- ๊ฒ์๊ธ๊ณผ ์ข์์๋ ์๋ช ์ฃผ๊ธฐ์ ํธ๋ํฝ์ ์ฑ๊ฒฉ์ด ์์ ํ ๋ค๋ฅด๋ค. ๊ฒ์๊ธ์ ์์ฑ์์ ์ํด ๊ฐ๋ ์์ ๋์ง๋ง, ์ข์์๋ ๊ธ์ ์กฐํํ๋ ์๋ง์ ์ฌ์ฉ์์ ์ํด ์ค์๊ฐ์ผ๋ก ์ฐ๊ธฐ ์์ ์ด ๋ฐ์ํ๋ค. ๋ง์ฝ ๊ฒ์๊ธ ํ ์ด๋ธ์ ์ข์์ ์นด์ดํธ๊ฐ ํฌํจ๋์ด ์๋ค๋ฉด, ์ด๋น ์์ฒ ๊ฑด์ ์ข์์ ์์ฒญ์ด ๋ฐ์ํ ๋๋ง๋ค ํด๋น ๊ฒ์๊ธ ๋ ์ฝ๋์ ๋ฝ์ด ๊ฑธ๋ฆฐ๋ค. ์ด๋ก ์ธํด ์ข์์์ ๋ฌด๊ดํ ๋ณธ๋ฌธ ์กฐํ๋ ๋๊ธ ์์ฑ์ ์๋ํ๋ ์ฌ์ฉ์๊น์ง ๋ฝ์ด ํด์ ๋ ๋๊น์ง ๋๊ธฐํ๊ฒ ๋์ด ์์คํ ์ ์ฒด์ ์ฑ๋ฅ์ด ์ ํ๋๋ค.
- ๋ ๋ฒ์งธ๋ ๋ถ์ฐ ํธ๋์ญ์
์ฒ๋ฆฌ์ ๋ณต์ก์ฑ์ด๋ค. ์ข์์ ๋ด์ญ ์ ์ฅ๊ณผ ์นด์ดํธ ์
๋ฐ์ดํธ๊ฐ ์๋ก ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๋ง์ดํฌ๋ก์๋น์ค์์ ์ผ์ด๋ ๊ฒฝ์ฐ, ๋ ์์
์ ์์์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํ ๋ถ์ฐ ํธ๋์ญ์
์ค๊ณ๊ฐ ํ์ํ๋ฉฐ ์ด๋ ์์คํ
์ ๋ณต์ก๋๋ฅผ ํฌ๊ฒ ๋์ด๊ฒ ๋๋ค.
- ๋จ์ผ DB๋ฅผ ์ธ ๋๋ ์ข์์ ๋ด์ญ์ ์ ์ฅํ๊ณ (A), ๊ฒ์๊ธ์ ์ข์์ ์๋ฅผ +1 ํ๋(B) ์์ ์ ํ๋์ ํธ๋์ญ์ ์ผ๋ก ๋ฌถ๊ธฐ ์ฝ๋ค. ํ์ง๋ง ์๋น์ค๊ฐ ๋ถ๋ฆฌ๋ ๋ถ์ฐ ํ๊ฒฝ์์๋ A๋ ์ข์์ ์๋น์ค DB์, B๋ ๊ฒ์๊ธ ์๋น์ค DB์ ์์นํ๊ฒ ๋๋ค.
- ๋ง์ฝ ์ข์์ ๋ด์ญ์ ์ ์ฅ๋๋๋ฐ(A ์ฑ๊ณต), ๋คํธ์ํฌ ๋ฌธ์ ๋ก ๊ฒ์๊ธ ์๋น์ค์ ์นด์ดํธ ์ ๋ฐ์ดํธ๊ฐ ์คํจํ๋ฉด(B ์คํจ)? ์ค์ ์ข์์๋ ๋๋ ธ๋๋ฐ ์ซ์๋ ์ ์ฌ๋ผ๊ฐ๋ ๋ฐ์ดํฐ ๋ถ์ผ์น๊ฐ ๋ฐ์ํ๋ค.
- ์ด๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด 2PC(2-Phase Commit)๋ Saga ํจํด ๊ฐ์ ๋ณต์กํ ๊ธฐ๋ฒ์ ๋์ ํด์ผ ํ๋ค. ์ด๋ ๊ฐ๋ฐ ๋์ด๋๋ฅผ ๋์ผ ๋ฟ๋ง ์๋๋ผ ์์คํ ์ ์ฒด ์ฑ๋ฅ์ ๊น์๋จน๋ ์ฃผ๋ฒ์ด ๋๋ค.
- ์ธ ๋ฒ์งธ๋ก, ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ ์ธก๋ฉด์์ ์ด ์ค๊ณ๋ ์ ์ ํ์ง ์๋ค.
- ์ข์์๋ผ๋ ํ์์ ์ฃผ์ธ์ '์ข์์ ์๋น์ค'๋ค. ๊ทธ๋ฐ๋ฐ ์ข์์ ๊ฐ์๋ผ๋ ๋ฐ์ดํฐ๋ฅผ '๊ฒ์๊ธ ์๋น์ค'๊ฐ ๋ค๊ณ ์์ผ๋ฉด, ๊ฒ์๊ธ ์๋น์ค๋ ์๊ธฐ ์ฑ ์๋ ์๋ '์ข์์' ๋๋ฌธ์ ๊ณ์ํด์ DB ์์ (Update) ์์ฒญ์ ๋ฐ์์ผ ํ๋ค.
- ๊ฒ์๊ธ ์๋น์ค๋ฅผ ์์ ํ๊ฑฐ๋ ๋ฐฐํฌํ ๋ ์ข์์ ๋ก์ง์ ์ ๊ฒฝ ์จ์ผ ํ๊ณ , ๋ฐ๋์ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง๋ค. ์๋น์ค ๊ฐ์ ๊ฒฐํฉ๋๊ฐ ๋์์ ธ์ ๋์ค์ ์๋น์ค๋ฅผ ํ์ฅํ๊ฑฐ๋ ๋ณ๊ฒฝํ๊ธฐ๊ฐ ๋งค์ฐ ํ๋ค์ด์ง๋ค.
- ๋ค ๋ฒ์งธ๋ก ๋ฆฌ์์ค ๊ฒฝํฉ์ ๋ถ๊ท ํ์ด๋ค.
- ์ฐ์์ธ์ด๋ ์ ๋ช ์ธํ๋ฃจ์ธ์์ ๊ฒ์๊ธ์ ์ด๋น ์์ฒ ๋ช ์ ์ฌ์ฉ์๊ฐ ์ข์์๋ฅผ ๋๋ฅธ๋ค.
- ์ด๋๋ง๋ค ๊ฒ์๊ธ ํ ์ด๋ธ์ ํน์ ํ์ ๋ ์ฝ๋ ๋ฝ(๋น๊ด์ ๋ฝ)์ด ๊ฑธ๋ฆฐ๋ค.
- ์ด๋ ์ข์์๋ฅผ ๋๋ฅด๋ ์ฌ๋๋ง ๋๊ธฐํ๋ ๊ฒ ์๋๋ผ, ๋จ์ํ ๊ฒ์๊ธ ๋ณธ๋ฌธ์ ์ฝ์ผ๋ ค๋ ์ฌ๋์ด๋ ๋๊ธ์ ๋ฌ๋ ค๋ ์ฌ๋๊น์ง ๊ฒ์๊ธ ํ ์ด๋ธ์ ๊ฑธ๋ฆฐ ๋ฝ ๋๋ฌธ์ ๋๊ธฐํ๊ฑฐ๋ ์ฑ๋ฅ ์ ํ๋ฅผ ๊ฒช๊ฒ ๋๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก, ์ข์์ ์๋ ์์ฃผ ๋ณํ๋ ๋ฐ์ดํฐ์ด๋ฏ๋ก, ์ด๋ฅผ ๊ฒ์๊ธ์ด๋ผ๋ ๋ฌด๊ฑฐ์ด ๋ณธ์ฒด์ ๋ถ๋ฆฌํ์ฌ ๋ณ๋์ ์๋น์ค์์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ๋ถ์ฐ ํ๊ฒฝ์ ํ์ฅ์ฑ๊ณผ ์ฑ๋ฅ ๋ฉด์์ ํจ์ฌ ์ ๋ฆฌํ๋ค.
0. Record Lock
๋ ์ฝ๋ ๋ฝ์ ํ ์ด๋ธ์ ํ ๋ฐ์ดํฐ์ ๋ํ ์ ๊ธ์ ๊ฑฐ๋ ๊ฒ์ ๋งํ๋ค.
๋ ์ฝ๋ ๋ฝ์ ํตํด ์ฌ๋ฌ ๋ช ์ ์ฌ์ฉ์๊ฐ ๋์์ ๋ ์ฝ๋๋ฅผ ์์ ํ๊ณ ์กฐํํ๋ ๋์ ๋ฐ์ดํฐ์ ๋ฌด๊ฒฐ์ฑ, ๊ฒฝ์ ์ํ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
1. ๋ฐ์ดํฐ์ ๋ฌด๊ฒฐ์ฑ (Data Integrity)
๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ ๋ฐ์ดํฐ๊ฐ ์ ํ์ฑ, ์ผ๊ด์ฑ, ์ ํจ์ฑ์ ์ ์งํ๋ ๊ฒ์ ๋งํ๋ค. ์ฆ, ์ด๋ค ์ํฉ์์๋ ๋ฐ์ดํฐ๊ฐ ์ค์ผ๋์ง ์๊ณ ๋ฏฟ์ ์ ์๋ ์ํ์ฌ์ผ ํ๋ค๋ ๋ป์ด๋ค.
๋์์ฑ ์ ์ด ์ธก๋ฉด์์ ๋ฌด๊ฒฐ์ฑ์ด ๊นจ์ง๋ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ์ผ๊ด์ฑ ๊ฒฐ์ฌ: ์์ ์ค์ธ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ์ฝ์ด๊ฐ ๋ ๋ฐ์ํ๋ ๋ถ์ผ์น ํ์์ด๋ค.
- ๋ฐ์ดํฐ ์์ค: ์ฌ๋ฌ ์ฌ์ฉ์๊ฐ ๋์์ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ์ฌ ํ ๋ช ์ ์์ ์ฌํญ์ด ์ฌ๋ผ์ง๋ ๊ฒฝ์ฐ๋ค.
2. ๊ฒฝ์ ์ํ (Race Condition)
๊ฒฝ์ ์ํ๋ ๋ ๊ฐ ์ด์์ ํ๋ก์ธ์ค๊ฐ ๊ณต์ ์์์ ๋์์ ์ ๊ทผํ์ฌ ๊ทธ ์คํ ๊ฒฐ๊ณผ๊ฐ ์ ๊ทผ ์์์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ํ์์ ๋งํ๋ค.
๋ํ์ ์ธ ์์์ธ ๊ฐฑ์ ์์ค(Lost Update) ์๋๋ฆฌ์ค๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ์ฌ๊ณ ๊ฐ 10๊ฐ์ธ ์ํ์ ์ฌ์ฉ์ A์ B๊ฐ ๋์์ ์กฐํํ์ฌ ๋ ๋ค 10๊ฐ๋ก ํ์ธํ๋ค.
- ์ฌ์ฉ์ A๊ฐ 1๊ฐ๋ฅผ ๋นผ์ 9๋ก ์ ์ฅํ๋ค.
- ์ฌ์ฉ์ B๋ ์์ ์ด ํ์ธํ๋ 10์ ๊ธฐ์ค์ผ๋ก 1๊ฐ๋ฅผ ๋นผ์ 9๋ก ์ ์ฅํ๋ค.
- ์ค์ ๋ก๋ 2๊ฐ๊ฐ ํ๋ ธ์ผ๋ ์ฌ๊ณ ๋ 8์ด ์๋ 9๊ฐ ๋์ด ๋ฐ์ดํฐ๊ฐ ํ์ด์ง๊ฒ ๋๋ค.
3. ๋ ์ฝ๋ ๋ฝ์ ํด๊ฒฐ ๋ฐฉ์
๋ ์ฝ๋ ๋ฝ์ ํน์ ํ(Row)์ ๋ํด ์ฌ์ฉ๊ถ์ ์ ์ ํ๋ ๋ฐฉ์์ด๋ค.
- ๋ฐฐํ์ ๋ฝ: ์ฌ์ฉ์ A๊ฐ ์์ ์ค์ผ ๋ ๋ค๋ฅธ ์ฌ์ฉ์์ ์ ๊ทผ์ ์ฐจ๋จํ๋ค.
- ์์ฐจ ์ฒ๋ฆฌ: ๋์ค์ ์จ ์ฌ์ฉ์๋ ์์ ์์ ์ด ๋๋ ๋๊น์ง ๋๊ธฐํด์ผ ํ๋ฏ๋ก ๊ฒฝ์ ์ํ๊ฐ ๋ฌผ๋ฆฌ์ ์ผ๋ก ๋ฐฉ์ง๋๋ค.
- ๋ฌด๊ฒฐ์ฑ ๋ณด์ฅ: ๋ชจ๋ ์์ ์ด ์์ฐจ์ ์ผ๋ก ์ด๋ฃจ์ด์ง๋ฏ๋ก ์ต์ข ์ ์ผ๋ก ๋ฐ์ดํฐ์ ์ ํ์ฑ์ด ์ ์ง๋๋ค.
์์ฝํ์๋ฉด ๋ ์ฝ๋ ๋ฝ์ ํ๋ก์ธ์ค ๊ฐ์ ์ค ์ธ์ฐ๊ธฐ๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ์ค์ผ๋๋ ๊ฒ์ ๋ง๋ ํต์ฌ์ ์ธ ์ฅ์น๋ค.
- SELECT … FOR UPDATE ๊ตฌ๋ฌธ์ ํตํด ์กฐํ๋ ๋ ์ฝ๋๋ค์ ๋ํด ๋ฐฐํ์ ๋ฝ์ ๊ฐ์ ธ๊ฐ ์ ์๋ค.
| ๋จ๊ณ | ํธ๋์ญ์ A (์ฌ์ฉ์ A) | ํธ๋์ญ์ B (์ฌ์ฉ์ B) | DB (like_count) | |
| 1 | SELECT ... FOR UPDATE (10 ์ฝ์) | 10 | A๊ฐ ๋ฝ ์ ์ | |
| 2 | SELECT ... FOR UPDATE ์๋ | 10 | B๋ ๋๊ธฐ(Waiting) | |
| 3 | 10 + 1 = 11 ๊ณ์ฐ ๋ฐ UPDATE | 11 | ||
| 4 | COMMIT (๋ฝ ํด์ ) | 11 | ||
| 5 | SELECT ์ฑ๊ณต (๊ฐฑ์ ๋ 11 ์ฝ์) | 11 | B๊ฐ ๋ฝ์ ํ๋ํ๊ณ ์ฝ์ | |
| 6 | 11 + 1 = 12 ๊ณ์ฐ ๋ฐ UPDATE | 12 |
๋ ์ฝ๋ ๋ฝ์ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ์ง๋ง, ์๋ชป ์ฌ์ฉํ๋ฉด ์์คํ ์ ์ฒด์ ์ฑ๋ฅ๊ณผ ์์ ์ฑ์ ๋จ์ด๋จ๋ฆฌ๋ ์ฌ๋ฌ ๋จ์ ์ด ์กด์ฌํ๋ค.
1. Record Lock์ ๋จ์
1. ์ฑ๋ฅ ์ ํ ๋ฐ ์ฒ๋ฆฌ๋ ๊ฐ์
๊ฐ์ฅ ์ง์ ์ ์ธ ๋จ์ ์ ์์คํ ์ ๋ณ๋ ฌ ์ฒ๋ฆฌ ๋ฅ๋ ฅ์ด ๋จ์ด์ง๋ค๋ ๊ฒ์ด๋ค.
- ์ง๋ ฌํ ๋ฐ์: ์ฌ๋ฌ ์ฌ์ฉ์๊ฐ ๋์์ ์์ ํ ์ ์๋ ํ๊ฒฝ์์๋ ๋ถ๊ตฌํ๊ณ , ๋ฝ์ด ๊ฑธ๋ฆฐ ๋์์๋ ๋ค๋ฅธ ์ฌ์ฉ์๋ค์ด ๋๊ธฐํด์ผ ํ๋ค. ์ด๋ ์๋ต ์๊ฐ์ ๋ฆ์ถ๊ณ ์ด๋น ์ฒ๋ฆฌ ๊ฐ๋ฅํ ํธ๋์ญ์ ์๋ฅผ ์ค์ธ๋ค.
- ๋๊ธฐ์ด ์ ์ฒด: ํน์ ์ธ๊ธฐ ์๋ ๋ ์ฝ๋(์: ์ด๋ฒคํธ ์ํ ์ฌ๊ณ )์ ๋ฝ์ด ์ง์ค๋๋ฉด, ์๋ง์ ํธ๋์ญ์ ์ด ์ค์ ์๊ฒ ๋์ด ์์คํ ์ ์ฒด๊ฐ ๋๋ ค์ง๋ ๋ณ๋ชฉ ํ์์ด ๋ฐ์ํ๋ค.
2. ๋ฐ๋๋ฝ (Deadlock, ๊ต์ฐฉ ์ํ)
๋ ๊ฐ ์ด์์ ํธ๋์ญ์ ์ด ์๋ก๊ฐ ๊ฐ์ง ๋ฝ์ ํด์ ํ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ๋ฌดํ ๋๊ธฐ์ ๋น ์ง๋ ์ํฉ์ด๋ค.
- ์์: ํธ๋์ญ์ A๊ฐ 1๋ฒ ๋ ์ฝ๋๋ฅผ ์ก๊ณ 2๋ฒ์ ์์ฒญํ๋๋ฐ, ๋์์ ํธ๋์ญ์ B๊ฐ 2๋ฒ ๋ ์ฝ๋๋ฅผ ์ก๊ณ 1๋ฒ์ ์์ฒญํ๋ฉด ๋ ์์ ๋ชจ๋ ์์ํ ๋ฉ์ถ๋ค.
- ๊ฒฐ๊ณผ: DB ์์ง์ด ์ด๋ฅผ ๊ฐ์งํ์ฌ ๊ฐ์ ๋ก ํ๋๋ฅผ ์ข ๋ฃ(Rollback)์ํค์ง๋ง, ์ด ๊ณผ์ ์์ ์ฌ์ฉ์ ๊ฒฝํ์ด ์ ํ๋๊ณ ์ถ๊ฐ์ ์ธ ์์ธ ์ฒ๋ฆฌ ๋ก์ง์ด ํ์ํ๋ค.
3. ๋ฝ ์์ค์ปฌ๋ ์ด์ ๋ฐ ๋ฒ์ ๋ฌธ์
๋ฝ์ ๊ฑฐ๋ ๊ณผ์ ์์ ์์๋ณด๋ค ํฐ ๋ฒ์๊ฐ ์ ๊ธธ ์ ์๋ค.
- ํ ์ด๋ธ ํ ์ค์บ: WHERE ์กฐ๊ฑด์ ์ธ๋ฑ์ค๊ฐ ๊ฑธ๋ ค ์์ง ์์ผ๋ฉด, DB๋ ์ด๋ค ๋ ์ฝ๋๋ฅผ ์ ๊ธ์ง ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ํ ์ด๋ธ ์ ์ฒด๋ฅผ ํ์ผ๋ฉฐ ๋ชจ๋ ํ์ ๋ฝ์ ๊ฑธ๊ฑฐ๋ ํ ์ด๋ธ ๋ฝ์ ์ํจ๋ค.
- ์๋์น ์์ ์ฐจ๋จ: ๋๋ ํ ํ๋๋ง ์์ ํ๋ ค๊ณ ํ๋๋ฐ, ์ธ๋ฑ์ค ๋ฌธ์ ๋ก ์ธํด ์๋ฑํ ๋ ์ฝ๋๋ค๊น์ง ์์ ์ด ๋ถ๊ฐ๋ฅํด์ง๋ ์ํฉ์ด ๋ฐ์ํ ์ ์๋ค.
4. ์ปค๋ฅ์ ๊ณ ๊ฐ (Connection Pool Starvation)
๋ฝ์ ํ๋ํ๊ธฐ ์ํด ๋๊ธฐํ๋ ์๊ฐ์ด ๊ธธ์ด์ง๋ฉด ํด๋น ์์ฒญ์ ์ฒ๋ฆฌํ๋ DB ์ปค๋ฅ์ ์ด ๊ณ์ ์ ์ ๋ ์ํ๋ก ๋จ๋๋ค.
- ๋๊ธฐํ๋ ํธ๋์ญ์ ์ด ๋ง์์ง๋ฉด ์ฌ์ฉ ๊ฐ๋ฅํ ์ปค๋ฅ์ ํ์ด ๋ฐ๋ฅ๋์, ๋ฝ๊ณผ ์๊ด์๋ ๋ค๋ฅธ ๋จ์ ์กฐํ ์๋น์ค๋ค๊น์ง ๋ชจ๋ ๋จนํต์ด ๋๋ ์ฐ์ ์ฅ์ ๋ก ์ด์ด์ง ์ ์๋ค.
5. ๊ด๋ฆฌ ๋ฐ ์ค๊ณ์ ๋ณต์ก๋ ์ฆ๊ฐ
๋ฝ์ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด ๊ฐ๋ฐ์๊ฐ ๊ณ ๋ คํด์ผ ํ ๊ฒ์ด ๋ง์์ง๋ค.
- ํธ๋์ญ์ ์ ์ต๋ํ ์งง๊ฒ ์ ์งํด์ผ ํ๊ณ , ๋ฝ์ ๊ฑฐ๋ ์์๋ฅผ ๋ชจ๋ ๋ก์ง์์ ํต์ผํด์ผ ๋ฐ๋๋ฝ์ ํผํ ์ ์๋ค.
- ์๋น์ค๊ฐ ์ปค์ง์๋ก ์ด๋ค ๋ก์ง์์ ๋ฝ์ ์ก๊ณ ์๋์ง ์ถ์ ํ๊ณ ๋๋ฒ๊น ํ๊ธฐ๊ฐ ๋งค์ฐ ๊น๋ค๋ก์์ง๋ค.
2. ํด๊ฒฐ ๋ฐฉ์
์ด๋ฌํ ๋จ์ ์ ๋ณด์ํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ ์ ๋ต์ ์์ด์ ์ฌ์ฉํ ์ ์๋ค.
- ๋๊ด์ ๋ฝ(Optimistic Lock): ๋ฝ์ ์ง์ ๊ฑธ์ง ์๊ณ ๋ฒ์ ๋ฒํธ ๋ฑ์ ํตํด ์ถฉ๋ ์ฌ๋ถ๋ง ํ์ธํ๋ค. (์ถฉ๋์ด ์ ์ ๊ฒฝ์ฐ ์ ๋ฆฌ)
- Redis ๋ฑ์ ์บ์ ์ฌ์ฉ: DB๊น์ง ์ค๊ธฐ ์ ์ ๋ถ์ฐ ๋ฝ์ ํตํด ์ฒ๋ฆฌ ์๋๋ฅผ ๋์ธ๋ค.
- ์งง์ ํธ๋์ญ์ : ๋ฝ์ ์ก๋ ์๊ฐ์ ์ต์ํํ๋๋ก ๋ก์ง์ ๋ถ๋ฆฌํ๋ค.
๋๊ด์ ๋ฝ๊ณผ ๋น๊ด์ ๋ฝ์ ์ฌ์ฉํ์ฌ ์ข์์ ์๋น์ค๋ฅผ ๊ฒ์๊ธ ์๋น์ค์ ๋ถ๋ฆฌํ์ฌ ๊ตฌํํด ๋ณด์.
- ํ
์ด๋ธ ์ค๊ณ : ๋จผ์ ๋ถ์ฐ ํธ๋์ญ์
ํ๊ฒฝ ๋ด์์, ์ข์์ ์ ์๋น์ค๋ ๊ฒ์๊ธ๊ณผ 1 : 1 ๋๋ ์๋น์ค์ด๊ธฐ ๋๋ฌธ์ ์ค๋ ํค๋ ๊ฒ์๊ธ ์์ด๋์ธ ArticleId๋ฅผ ์ฌ์ฉํ๋ค.
- article_id : ๊ธฐ๋ณธ ํค์ด์ ์ค๋ ํค(Shard Key)๋ก ์ฌ์ฉํ๋ค.
- like_count : ์ค์ ์ข์์ ์๋ฅผ ์ ์ฅํ๋ค.
- version : ๋๊ด์ ๋ฝ์ ์ํ ๋ฒ์ ๊ด๋ฆฌ ์ปฌ๋ผ์ด๋ค.
CREATE TABLE `article_like_count` (
`article_id` bigint NOT NULL,
`like_count` bigint NOT NULL,
`version` bigint NOT NULL,
PRIMARY KEY (`article_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
โ ๋น๊ด์ ๋ฝ (Pessimistic Lock)
๋ฐ์ดํฐ ์ถฉ๋์ด ๋ฐ์ํ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํ๊ณ , ๋ฝ์ ๊ฑธ์ด ๋ค๋ฅธ ํธ๋์ญ์ ์ ์ ๊ทผ์ ์ฐจ๋จํ๋ ๋ฐฉ์์ด๋ค.
- ๋ฐฉ๋ฒ 1 (์ง์ ์ ๋ฐ์ดํธ): update ... set like_count = like_count + 1 ์ฟผ๋ฆฌ๋ฅผ ๋ฐ๋ก ์คํํ๋ค. ๋ฝ ์ ์ ์๊ฐ์ด ์งง์ ํจ์จ์ ์ด๋ค. ์์ ์์ ์ ๋ฝ์ ๊ฑฐ๋ ๋ฐฉ์์ด๋ค.
@Query(
value = "update article_like_count set like_count = like_count + 1 where article_id = :articleId",
nativeQuery = true
)
@Modifying
int increase(@Param("articleId") Long articleId);
/**
* update ๊ตฌ๋ฌธ
*/
@Transactional
public void likePessimisticLock1(Long articleId, Long userId) {
int result = articleLikeCountRepository.increase(articleId);
if (result == 0) {
articleLikeCountRepository.save(
ArticleLikeCount.init(articleId, 1L)
);
}
}
- ๋ฐฉ๋ฒ 2 (์กฐํ ํ ์ ๋ฐ์ดํธ): SELECT ... FOR UPDATE๋ก ๋จผ์ ๋ฝ์ ์ก๊ณ ์กฐํํ ๋ค, ์ ํ๋ฆฌ์ผ์ด์ ์์ ๊ณ์ฐ๋ ๊ฐ์ UPDATE ํ๋ค. ๋ฝ์ ์กฐํ ์์ ๋ถํฐ ์ ์ ํ๋ฏ๋ก ๋น๊ต์ ๋ฝ ์ ์ ์๊ฐ์ด ๊ธธ๋ค. JPA ํ๊ฒฝ์์๋ ๋ ํฌ์งํ ๋ฆฌ ๋ฉ์๋์@Lock(LockModeType.PESSIMISTIC_WRITE) ์ด๋ ธํ ์ด์ ์ ์ ์ธํ์ฌ ๊ฐ๋จํ ๊ตฌํํ ์ ์๋ค.
@Query(
value = "update article_like_count set like_count = like_count + 1 where article_id = :articleId",
nativeQuery = true
)
@Modifying
int increase(@Param("articleId") Long articleId);
/**
* update ๊ตฌ๋ฌธ
*/
@Transactional
public void likePessimisticLock1(Long articleId, Long userId) {
int result = articleLikeCountRepository.increase(articleId);
if (result == 0) {
articleLikeCountRepository.save(
ArticleLikeCount.init(articleId, 1L)
);
}
}
โก ๋๊ด์ ๋ฝ (Optimistic Lock)
์ถฉ๋์ด ๊ฑฐ์ ์๋ค ๊ฐ์ ํ๊ณ , ๋ฝ ๋์ ๋ฒ์ (Version) ๊ด๋ฆฌ๋ฅผ ํตํด ์ ํฉ์ฑ์ ์ ์งํ๋ ๋ฐฉ์์ด๋ค.
- ๋์ ์๋ฆฌ: ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ๋ ๋ฒ์ ๋ฒํธ๋ฅผ ํจ๊ป ๊ฐ์ ธ์ค๊ณ , ์์ ํ ๋ WHERE version = ํ์ฌ๋ฒ์ ์กฐ๊ฑด์ ๊ฑด๋ค. ์ฑ๊ณตํ๋ฉด ๋ฒ์ ์ ์ฌ๋ฆฌ๊ณ , ์คํจํ๋ฉด ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ์ด๋ฏธ ์์ ํ ๊ฒ์ผ๋ก ํ๋จํด ๋กค๋ฐฑํ๋ค.
- ํน์ง: DB ๋ฝ์ ์ก์ง ์์ ์ฑ๋ฅ์ ์ ๋ฆฌํ์ง๋ง, ์ถฉ๋ ๋ฐ์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ํ์ฒ๋ฆฌ(์ฌ์๋ ๋ฑ)๊ฐ ํ์ํ๋ค. JPA์์๋ @Version ์ด๋ ธํ ์ด์ ์ผ๋ก ๊ฐ๋จํ ๊ตฌํ ๊ฐ๋ฅํ๋ค.
- ์๋ ์ฝ๋์์๋ increase() ์์ ์ ์ํฐํฐ์ ๋ณ๊ฒฝ์ด ๋ฐ์ํ๊ณ , ์ด๋ฅผ ๊ฐ์งํ์ฌ WHERE ์กฐ๊ฑด์ ์ํด version์ด ์ด ์ ๋ฒ์ ์ธ์ง ๊ฒ์ฌํ์ฌ UPDTAE๋ฅผ ์ํํ๋ค.
- ๋ค๋ง ๋ฒ์ ์ถฉ๋ ๋ฐ์ ์ ์์ธ ์ฒ๋ฆฌํ ์ง, ์ฌ์๋ ๋ก์ง์ ํตํด ์ฒ๋ฆฌํ ๊ฒ์ธ์ง์ ๋ํ ์ถ๊ฐ์ ์ธ ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค. ๋๊ด์ ๋ฝ์ ๋ฐ์ดํฐ์ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ ๋ฟ,
/**
* optimistic Lock - ๋ณ๊ฒฝ ์์ (increase() ์ํ ์์ )์์ version ์ฒดํฌํด์ update
* UPDATE article_like_count SET like_count = ?, version = ? (์ ๋ฒ์ ) WHERE article_id = ? AND version = ? (๊ธฐ์กด ๋ฒ์ )
*/
@Transactional
public void likeOptimisticLock(Long articleId, Long userId) {
ArticleLikeCount articleLikeCount = articleLikeCountRepository.findById(articleId)
.orElseGet(() -> ArticleLikeCount.init(articleId, 0L));
articleLikeCount.increase(); // dirty check
// articleLikeCountRepository.save(articleLikeCount);
}
โข ๋น๋๊ธฐ ์์ฐจ ์ฒ๋ฆฌ
์์ฒญ์ ๋๊ธฐ์ด(Queue)์ ๋ฃ๊ณ ๋ณ๋ ์ค๋ ๋์์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ด๋ค.
- ๊ตฌํ ์๋ฆฌ: ์ฌ์ฉ์์ ์์ฒญ(Producer)๊ณผ ์ค์ DB ๋ฐ์(Consumer)์ ์์ ํ ๋ถ๋ฆฌํ๋ค.
- ํ(Queue)๋ฅผ ํตํด ์์ฒญ์ ์ผ๋ ฌ๋ก ์ค ์ธ์ฐ๊ธฐ ๋๋ฌธ์, DB ๋ ๋ฒจ์ ๋ณต์กํ ๋ฝ ์์ด๋ ์ ํฉ์ฑ์ ์ ์งํ ์ ์๋ค.
- ์ฅ์
- ๋น ๋ฅธ ์ฐ๊ธฐ ์๋: DB ํธ๋์ญ์ ์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ฉ๋ชจ๋ฆฌ(Redis)์ ์ฐ๊ณ ๋ฐ๋ก ์๋ตํ๋ฏ๋ก ์ฌ์ฉ์ ์ฒด๊ฐ ์๋๊ฐ ๋งค์ฐ ๋น ๋ฅด๋ค.
- ๋ถํ ์กฐ์ : ๊ฐ์๊ธฐ ์ข์์๊ฐ ๋ช๋ง ๊ฐ๊ฐ ๋ชฐ๋ ค๋ DB๊ฐ ํฐ์ง์ง ์๊ณ ํ์ ์์๋ค๊ฐ ์๋ฒ๊ฐ ์ฒ๋ฆฌ ๊ฐ๋ฅํ ์๋๋ก ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐ์ํ ์ ์๋ค.
- ๋จ์
- ์ฌ์ฉ์๊ฐ ๋ฒํผ์ ๋๋ ๋๋ฐ ํ๋ฉด ์ซ์๊ฐ 0.5~1์ด ๋ค์ ์ฌ๋ผ๊ฐ ์ ์๋ค.
- Redis๋ Kafka ๊ฐ์ ๋ณ๋์ ๋ฉ์์ง ๋ธ๋ก์ปค๋ฅผ ์ด์ํด์ผ ํ๋ค.
- ์ฅ์ : ๋์์ฑ ๋ฌธ์ ์์ฒด๋ฅผ ์์ฒ ์ฐจ๋จํ๋ฉฐ DB ๋ถํ๊ฐ ์ ๋ค.
- ๋จ์ : ์์คํ ๊ตฌ์ถ ๋น์ฉ์ด ํฌ๊ณ ์ค์๊ฐ ์๋ต์ด ์ด๋ ค์ ํ ์กฐ์น๊ฐ ํ์ํ๋ค.
์ฌ์ฉ์์ ์์ฒญ์ ์ฆ์ DB์ ๋ฐ์ํ์ง ์๊ณ ๋ฉ์์ง ํ(Message Queue)์ ์์๋ ๋ค, ๋ณ๋์ ์์ปค(Worker)๊ฐ ํ๋์ฉ ๊บผ๋ด์ด ์ฒ๋ฆฌํ๋ ๊ฒ์ด ํต์ฌ์ด๋ค. ์ฌ๊ธฐ์๋ Redis๋ฅผ ๋๊ธฐ์ด๋ก ์ฌ์ฉํ์ฌ ์์ฑํ๋ค.
1. ์๋น์ค ๋ ์ด์ด: ์์ฒญ์ ํ์ ์๊ธฐ (Producer)
์ฌ์ฉ์๋ ๋๊ธฐ์ด์ ๋ฉ์์ง๊ฐ ๋ค์ด๊ฐ๋ ๊ฒ๋ง ํ์ธํ๊ณ ๋ฐ๋ก ์๋ต์ ๋ฐ๋๋ค. ์ด ์์ ์๋ DB ์ ๋ฐ์ดํธ๊ฐ ์ผ์ด๋์ง ์์ผ๋ฏ๋ก ์ฑ๋ฅ์ด ๋น ๋ฅด๋ค.
@Service
@RequiredArgsConstructor
public class ArticleLikeService {
private final RedisTemplate<String, String> redisTemplate;
private static final String LIKE_QUEUE = "article_like_task_queue";
/**
* ๋น๋๊ธฐ ์์ฐจ ์ฒ๋ฆฌ ๋ฐฉ์ - ์์ฒญ ์ ์
*/
public void likeAsync(Long articleId, Long userId) {
// "articleId:userId:TYPE" ํํ๋ก ๋ฉ์์ง ์์ฑ
String message = articleId + ":" + userId + ":LIKE";
// Redis List์ ์ค๋ฅธ์ชฝ(๋ค)์ ์ฝ์
(Queue ์ญํ )
redisTemplate.opsForList().rightPush(LIKE_QUEUE, message);
}
}
2. ์์ปค(Worker): ํ์์ ๊บผ๋ด์ด ์์ฐจ ์ฒ๋ฆฌ (Consumer)
๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํ๋๋ ์ค๋ ๋๊ฐ ํ๋ฅผ ๊ฐ์ํ๋ค๊ฐ ๋ฐ์ดํฐ๊ฐ ๋ค์ด์ค๋ฉด ํ๋์ฉ ๊บผ๋ด์ด ์ฒ๋ฆฌํ๋ค. ํ ๋ฒ์ ํ๋์ฉ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋์์ฑ ์ถฉ๋์ด ๋ฐ์ํ์ง ์๋๋ค.
@Component
@RequiredArgsConstructor
public class LikeWorker {
private final RedisTemplate<String, String> redisTemplate;
private final ArticleLikeRepository articleLikeRepository;
private final ArticleLikeCountRepository articleLikeCountRepository;
private final Snowflake snowflake = new Snowflake();
private static final String LIKE_QUEUE = "article_like_task_queue";
// 0.1์ด๋ง๋ค ํ๋ฅผ ํ์ธํ์ฌ ์ฒ๋ฆฌ (ํน์ ๋ฌดํ ๋ฃจํ๋ก ๋๊ธฐ)
@Scheduled(fixedDelay = 100)
@Transactional
public void processLikeQueue() {
// ์ผ์ชฝ(์)์์ ํ๋ ๊บผ๋ด์ค๊ธฐ
String message = redisTemplate.opsForList().leftPop(LIKE_QUEUE);
if (message == null) return;
String[] data = message.split(":");
Long articleId = Long.parseLong(data[0]);
Long userId = Long.parseLong(data[1]);
String type = data[2];
if ("LIKE".equals(type)) {
// ์ข์์ ๋ด์ญ ์ ์ฅ
articleLikeRepository.save(ArticleLike.create(snowflake.nextId(), articleId, userId));
// ์ข์์ ์ ์นด์ดํธ ์
๋ฐ์ดํธ (๋น๊ด์ ๋ฝ ์์ด ์ผ๋ฐ update๋ก๋ ์์ )
articleLikeCountRepository.increase(articleId);
} else {
// ์ข์์ ์ทจ์
}
}
}
์ธ ๊ฐ์ง ์ ๋ต์ ๋ํด ํ๋ก ์ ๋ฆฌํ์๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
| ๊ตฌ๋ถ | ๋น๊ด์ ๋ฝ (๋ฐฉ๋ฒ 1) | ๋น๊ด์ ๋ฝ (๋ฐฉ๋ฒ 2) | ๋๊ด์ ๋ฝ | ๋น๋๊ธฐ ์์ฐจ ์ฒ๋ฆฌ |
| ๋ฝ ์ ์ | UPDATE ์์ ์๋ง ์งง๊ฒ | ์กฐํ๋ถํฐ ์ปค๋ฐ๊น์ง | ์์ (๋ฒ์ ์ฒดํฌ๋ง ํจ) | ์์ (๋ฉ์์ง ํ ํ์ฉ) |
| ์๋ | ๋น ๋ฆ | ๋ณดํต | ๋งค์ฐ ๋น ๋ฆ (์ถฉ๋ ์์ ์) | ๊ฐ์ฅ ๋น ๋ฆ (์๋ต ์์ฃผ) |
| ๋์ด๋ | ๋ฎ์ (SQL ์์ฃผ) | ๋ณดํต (JPA ํ์ฉ) | ๋ณดํต (์ถฉ๋ ํ์ฒ๋ฆฌ ํ์) | ๋์ (์ธํ๋ผ ๊ตฌ์ถ ํ์) |
| ์์ ์ฑ | ๋งค์ฐ ๋์ | ๋งค์ฐ ๋์ | ์ถฉ๋ ์ ์ฌ์ฉ์ ์คํจ ์๋ต | ๋งค์ฐ ๋์ (์์ฐจ ๋ณด์ฅ) |
| ๋ฐ์ดํฐ ๋ฐ์ | ์ฆ์ ๋ฐ์ | ์ฆ์ ๋ฐ์ | ์ฆ์ ๋ฐ์ | ์ง์ฐ ๋ฐ์ (์ต์ข ์ผ๊ด์ฑ) |
- ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ด ์ต์ฐ์ ์ด๋ฉฐ, ๋ก์ง์ด ๋จ์ํ๋ค๋ฉด?
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์์์ ์ฐ์ฐ์ ํ์ฉํ๋ ๋น๊ด์ ๋ฝ(๋ฐฉ๋ฒ 1)์ด ๊ฐ์ฅ ํจ์จ์ ์ด๋ค. ๋ฝ ์ ์ ์๊ฐ์ ์ต์ํํ๋ฉด์๋ ์ ํํ ์นด์ดํ ์ ๋ณด์ฅํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค
- ๊ฐ์ฒด์งํฅ์ ์ธ ์ฝ๋ ์ ์ง์ ๊ฐ๋ ฅํ ์ ํฉ์ฑ์ด ๋ชจ๋ ์ค์ํ๋ค๋ฉด?
- JPA์ ๊ฐ์ ์ ์ด๋ฆด ์ ์๋ ๋น๊ด์ ๋ฝ(๋ฐฉ๋ฒ 2)์ธ SELECT FOR UPDATE๋ฅผ ๊ณ ๋ คํ ์ ์๋ค. ๋ค๋ง, ๋ฝ ์ ์ ์๊ฐ์ด ๊ธธ์ด์ง ์ ์์ผ๋ฏ๋ก ํธ๋์ญ์ ์ ๋ฒ์๋ฅผ ์ต๋ํ ์งง๊ฒ ๊ฐ์ ธ๊ฐ๋ ์ค๊ณ๊ฐ ํ์ํ๋ค.
- ์ถฉ๋ ๋น๋๊ฐ ๋ฎ๊ณ ์์คํ
์ ์ ๋ฐ์ ์ธ ์ฒ๋ฆฌ๋์ด ์ค์ํ๋ค๋ฉด?
- ๋ฌผ๋ฆฌ์ ์ธ ๋ฝ ์ค๋ฒํค๋๊ฐ ์๋ ๋๊ด์ ๋ฝ์ด ์ข์ ๋์์ด ๋๋ค. ๋ค๋ง ๋ฒ์ ์ถฉ๋ ๋ฐ์ ์ ์ฌ์ฉ์์๊ฒ ์คํจ๋ฅผ ์๋ฆด ๊ฒ์ธ์ง, ํน์ ์ฌ์๋ ๋ก์ง์ ํตํด ์ฒ๋ฆฌํ ๊ฒ์ธ์ง์ ๋ํ ์ถ๊ฐ์ ์ธ ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค.
์ข์์ ์ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ์ธ ๊ฐ์ง ์ ๋ต์ ์ดํด๋ณด์๋ค. ๊ฒฐ๋ก ์ ์ธ ๊ฐ์ง ์ ๋ต์ ๋ํด ๋ชจ๋ ์ํฉ์ ์๋ฒฝํ๊ฒ ๋ค์ด๋ง๋ ์ ๋ต์ ์๋ค. ๊ฒฐ๊ตญ ์ฒํด์ง ๋น์ฆ๋์ค ์ํฉ๊ณผ ํธ๋ํฝ ํน์ฑ์ ๋ฐ๋ผ ์ต์ ์ ์ง์ ์ ์ ํํด์ผ ํ๋ค.
'๐ Backend' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Spring] ๋์์ธ ํจํด - Strategy Pattern (0) | 2023.08.22 |
|---|---|
| [Spring] ๋์์ธ ํจํด - Template Method ํจํด (0) | 2023.08.18 |
| [Spring] ThreadLocal๋ก ์ฑ๊ธํค ํจํด์ ๋์์ฑ ๋ฌธ์ ํด๊ฒฐ (0) | 2023.08.16 |
| [Spring] ์คํ๋ง ์ฝ์ด 2 - ๋ก๊ทธ ์ถ์ ๊ธฐ (0) | 2023.08.14 |
| Spring Boot๋ฅผ ํ์ฉํ์ฌ ๊ฒ์ํ API ์๋ฒ ์ ์ (2) - ์ํฐํฐ ์ค๊ณ, Repository ๊ตฌํ (0) | 2023.06.07 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
Dongwoongkim