λ°λλ½ λ°μ μμΈκ³Ό λ‘κ·Έ λΆμ
- #deadlock
- #shared lock
- #exclusive lock
- #s lock
- #x lock
- #transaction
λ€μ΄κ°λ©°
μλ νμΈμ. μλμ λ°±μλ κ°λ°μ μ΄μ°¬ν¬μ λλ€.
μλμμ μλΉμ€ νΉμ±μ μ€νμ΄ν¬μ± νΈλν½μ΄ μμ£Ό λ°μν©λλ€.
κ°μλ€μ μ¨λ² ν맀 μ€νμ΄λ νμ ν맀μ κ°μ μ΄λ²€νΈμ± ν맀μμ μ£Όλ‘ λ°μνλλ°μ, μκ°μ μΌλ‘ νΈλν½μ΄ λͺ°λ¦¬λ€ 보면 κ²°μ μͺ½μμ κ°λ λ°λλ½μ΄ λ°μνλ λ¬Έμ κ° μμμ΅λλ€.
μ΄λ² ν¬μ€νΈμμλ μλμ μλΉμ€μμ λ°λλ½μ΄ λ°μνλ μμΈκ³Ό κ·Έμ λν λ‘κ·Έλ₯Ό λΆμν΄ λ³΄λλ‘ νκ² μ΅λλ€.
λ°λλ½μ΄λ
μ΄λ―Έμ§ μΆμ²: λκ°ν°
κ²μμ ν΄λ³΄λ©΄ λ§μ κ³³μμ μλμ κ°μ΄ λ°λλ½μ μ μνκ³ μμ΅λλ€.
μ΄μ체μ μμ λ°λλ½(κ΅μ°©μν)μ΄λ μμ€ν μμμ λν μκ΅¬κ° λ€μν¨ μνλ‘, λ€μκ³Ό κ°μ μ‘°κ±΄μ΄ λμμ μΆ©μ‘±λ λ λ°μν©λλ€.
- μνΈ λ°°μ (Mutual Exclusion): μμμ λμμ μ¬λ¬ κ°μ μμ μ΄ μ¬μ©ν μ μκ³ , ν λ²μ νλμ μμ λ§ μ¬μ©ν μ μμ΅λλ€.
- μ μ λκΈ° (Hold and Wait): μμ μ μ΄λ―Έ μ΄λ€ μμμ μ μ ν μνμμ λ€λ₯Έ μμμ κΈ°λ€λ¦½λλ€.
- λΉμ μ (No Preemption): λ€λ₯Έ μμ μ΄ μ μ ν μμμ κ°μ λ‘ λΊμ μ μμ΅λλ€. μμμ ν΄λΉ μμ μ΄ μλ°μ μΌλ‘ λ°λ©ν λκΉμ§ μ μ λ©λλ€.
- μν λκΈ° (Circular Wait): μμ κ°μ μμμ κΈ°λ€λ¦¬λ μν ννμ μ¬μ΄ν΄μ΄ νμ±λ©λλ€.
λ°λλ½μ λ°μ μμΈμ μ¬λ¬κ°μ§κ° μμ§λ§ μ΄λ² ν¬μ€νΈμμλ 2λ² μ μ λκΈ° μν©μμμ λ°λλ½ λ°μμ μ¬λ‘λ₯Ό λΆμν΄ λ³΄κ² μ΅λλ€.
곡μ λ½κ³Ό λ°°ν λ½
λ‘κ·Έ λΆμμ μμ, λ½μ μ’ λ₯μ λν΄ μ κΉ μ§κ³ λμ΄κ°κ² μ΅λλ€.
Lockμ λ²μ
- Record Lock: λ‘μ°κ° μλ DBμ index recordμ 걸리λ Lock.
- Gap Lock: λ μ½λλ€ μ¬μ΄μ κ°(Gap)μ λ½νλ κ²μ μλ―Έν©λλ€. λ€λ₯Έ νΈλμμ μ΄ ν΄λΉ λ²μμ μνλ λ μ½λλ₯Ό μΆκ°νκ±°λ μμ ν μ μλλ‘ λ§μμ€λλ€.
Lockμ μ’ λ₯
Sλ½κ³Ό Xλ½μ λ°μ΄ν°λ² μ΄μ€μμ λμμ± μ μ΄λ₯Ό μν΄ μ¬μ©λλ λ½μ μ’ λ₯μ λλ€. κ°κ° 곡μ λ½(Shared Lock, Sλ½)κ³Ό λ°°νμ λ½(Exclusive Lock, Xλ½)μΌλ‘λ λΆλ¦¬λ©° μ¬λ¬ νΈλμμ κ°μ λ°μ΄ν° μ κ·Ό μΆ©λμ λ°©μ§νκ³ λ°μ΄ν° μΌκ΄μ±μ μ μ§νκΈ° μν΄ μ¬μ©λ©λλ€.
-
S Lock (Shared Lock) 곡μ λ½μ΄λΌκ³ λ λΆλ¦¬λ©°, μ¬λ¬ νΈλμμ μ΄ λμμ ν΄λΉ μμμ μ½μ μ μκ² ν©λλ€. μ¬λ¬ νΈλμμ κ°μ Sλ½μ λμμ νλν μ μμΌλ©°, μ½κΈ° μμ μ μ¬μ©λ©λλ€. Sλ½μ νλν νΈλμμ μ λ€λ₯Έ νΈλμμ μμ ν΄λΉ μμμ μ½μ μ μμ§λ§, λ³κ²½ μμ μ μνν μ μμ΅λλ€.
-
X Lock (Exclusive Lock) λ°°νμ λ½μ΄λΌκ³ λ λΆλ¦¬λ©°, ν΄λΉ μμμ λν λ°°νμ μΈ μ κ·Όμ μ 곡ν©λλ€. νΈλμμ μ΄ Xλ½μ νλνλ©΄, λ€λ₯Έ νΈλμμ μ ν΄λΉ μμμ λν μ½κΈ° λλ μ°κΈ° μμ μ μνν μ μμ΅λλ€. Xλ½μ λ°μ΄ν°λ₯Ό λ³κ²½νλ μμ μ μ¬μ©λ©λλ€. νΈλμμ μ΄ Xλ½μ νλνλ©΄, λ€λ₯Έ νΈλμμ μμλ κ·Έ μμμ μ κ·Όν μ μκ² λ©λλ€. Sλ½μ μ¬λ¬ νΈλμμ μ΄ λμμ μ½κΈ° μμ μ μνν μ μκ³ , Xλ½μ λ°°νμ μΈ μ κ·Όμ μꡬνμ¬ μ½κΈ° λ° μ°κΈ° μμ μ λ μ ν©λλ€. μ΄λ¬ν λ½λ€μ λμμ± μ μ΄λ₯Ό ν΅ν΄ λ°μ΄ν°λ² μ΄μ€μ λ°μ΄ν° 무결μ±κ³Ό μΌκ΄μ±μ μ μ§νλ©°, μ¬λ¬ νΈλμμ κ°μ μΆ©λμ λ°©μ§ν©λλ€.
Record Lock, Gap Lock μλ S Lock, X lockμ΄ μ‘΄μ¬νλ€κ³ μ΄ν΄νλ©΄ λκ² μ΅λλ€.
μλμ μλΉμ€μμμ λ°λλ½ λ°μ μμΈ
μ ν
μ΄λΈμ μ€λͺ
μ μν΄ κ·Ήν μΌλΆλ§ μλ₯Ό λ€μ΄ λνλΈ κ²μ΄λ©° μνκ³Ό μ£Όλ¬Έ ν
μ΄λΈμ 1:N κ΄κ³λ₯Ό κ°μ§κ³ μμ΅λλ€.
μ£Όλ¬Έμ μμλΆν° μλ£κΉμ§λ λ§μ μμ
μ νκ² λμ§λ§ λ°λλ½μ μ£Ό μμΈμ΄ λμλ λΆλΆμ μλμ κ°μ΅λλ€.
- ν΄λΉ 쿼리λ TypeORMμΌλ‘ ꡬνλμμ΅λλ€.
- μ£Όλ¬Έ μμ± api - order ν μ΄λΈμ insert ν©λλ€.
- μ£Όλ¬Έ μλ£ api - product ν μ΄λΈμ sold_count(μ¬κ³ )λ₯Ό update ν©λλ€.
μ£Όλ¬Έ μμλΆν° μ£Όλ¬Έ μλ£κΉμ§ μ΄λμ λ μκ°μ°¨κ° μ‘΄μ¬ν μ λ°μ μκΈ°μ νΈλν½μ΄ μ μ ν λλ 1λ²κ³Ό 2λ²μ΄ λμμ μ€νλλ κ²½μ°κ° κ±°μ μμ΅λλ€. νμ§λ§ μ£Όλ¬Έμ΄ λͺ°λ¦¬λ©΄ μ λκ°μ apiκ° κ±°μ λμμ μ¬λ¬κ°κ° μ€νλ κ°λ₯μ±μ΄ μ‘΄μ¬ν©λλ€.
μλλ μ€μ μλμ μλΉμ€μμμ κ²°μ μ λ°μν λ°λλ½ λ‘κ·Έλ₯Ό μμμ λ§μΆ° κ°λ¨νκ² μμ ν κ²μΈλ°μ, μ΄λ€ μμΈμ μν΄ λ°μνλμ§ νλνλ λΆμν΄λ³΄λλ‘ νκ² μ΅λλ€.
λ°λλ½ λ‘κ·Έ λΆμ
TRANSACTION 1
2022-xx-xx 0x:1x:3x 2b4eb987d700
**_ (1) TRANSACTION:
TRANSACTION 2346332882, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 13 lock struct(s), heap size 376, 10 row lock(s), undo log entries 5
MySQL thread id 23460, OS thread handle 0x2b4e34bcb700, query id 3040990 10.1.1.178 service_api update
INSERT INTO `order`(`id`, `product_id`) VALUES (DEFAULT, 3086)`
_** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 844 page no 28 n bits 144 index `PRIMARY` of table `wonderwall`.`product` trx id 2346332882 lock mode S locks rec but not gap waiting
Record lock, heap no 144 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
...
λ¨Όμ 1λ² νΈλμμ
μ λ‘κ·Έλ₯Ό λΆμν΄ λ³΄κ² μ΅λλ€.
INSERT INTO `order`(`id`, `product_id`) VALUES (DEFAULT, 3086)`
order tableμ product ν μ΄λΈμ PKμΈ product_idλ₯Ό ν¬ν¨νμ¬ insertλ₯Ό μλνκ³ μμ΅λλ€.
_** (1) WAITING FOR THIS LOCK TO BE GRANTED:
νμ§λ§ insertλ₯Ό μλνλ€κ° λ°λλ½μ΄ λ°μνμ΅λλ€. μ λ‘κ·Έλ λ½μ νλνκΈ° μν΄ λκΈ°νκ³ μλ€λ κ²μ μλ―Έν©λλ€. μ΄λ€ λ½μ νλνκΈ° μν΄ λκΈ°νκ³ μλμ§ νμΈν΄ λ³΄κ² μ΅λλ€.
RECORD LOCKS space id 844 page no 28 n bits 144 index `PRIMARY` of table `wonderwall`.`product` trx id 2346332882 lock mode S locks rec but not gap waiting
product tableμ primary μΈλ±μ€μ λ μ½λμ λ½μ΄ κ±Έλ €μκ³ , Sλ½μ λκΈ°νκ³ μλ€κ³ 보μ¬μ§λλ€. μ¬κΈ°μ μ΄ν΄λ΄μΌ ν λΆλΆμ λκ°μ§μ
λλ€.
- μ λ μ½λ λ½μ΄ κ±Έλ Έλκ°
- insertλ₯Ό νλ €λ©΄ Xλ½μ΄ νμνλ° μ Sλ½μ λκΈ°νλκ°
μ¬κΈ°μλ 2λ²μ λν λ΄μ©λ§ μ€λͺ
νκ³ λμ΄κ°κ³ , 1λ²μ λν λ΄μ©μ μλμ 2λ² νΈλμμ
μ λΆμνλ©° μΆκ°λ‘ μ€λͺ
νλλ‘ νκ² μ΅λλ€.
insertλ₯Ό νλ €λ©΄ Xλ½μ νλν΄μΌ νλ€κ³ μμμ μ€λͺ
ν΄λ¨λλ° λ‘κ·Έλ₯Ό νμΈν΄λ³΄λ Sλ½μ λκΈ°νκ³ μμ΅λλ€. μ΄λ»κ² λκ±ΈκΉμ?
μ΄λ λ°μ΄ν°μ μΌκ΄μ±κ³Ό λμμ±μ 보μ₯νκΈ° μν μ μ΄ λ©μ»€λμ¦ λλ¬ΈμΈλ°μ, μΌλ°μ μΌλ‘ Xλ½μ νλνκΈ° μν΄μλ λ¨Όμ Sλ½μ νλν΄μΌ ν©λλ€.
Sλ½μ μ¬λ¬ νΈλμμ
μμ λμμ νλν μ μλ 곡μ λ½μ΄κΈ° λλ¬Έμ λ°μ΄ν°μ μΌκ΄μ±μ μ μ§νλ©΄μ λμμ μ½μ μ μμ΅λλ€. νμ§λ§ Xλ½μ λ°°νμ μΈ μ κ·Όμ μꡬνκΈ° λλ¬Έμ λ€λ₯Έ νΈλμμ
μ΄ Sλ½μ 보μ νκ³ μλ κ²½μ° Xλ½μ νλνκΈ° μν΄μλ λ€λ₯Έ νΈλμμ
μ΄ λ³΄μ νκ³ μλ Sλ½μ΄ λͺ¨λ 컀λ°λκ±°λ λ‘€λ°±λ λκΉμ§ λκΈ°ν΄μΌλ§ ν©λλ€.
μ΄λ¬ν μ΄μ λ‘ μ λ‘κ·Έμμλ Sλ½μ λκΈ°νκ³ μλ€κ³ λμ€λ κ²μ΄λ©°, μ€μ λμμ Sλ½ νλ -> Xλ½ νλ -> insert μμλ‘ μ§νλ©λλ€.
TRANSACTION 2
**_ (2) TRANSACTION:
TRANSACTION 2346332859, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 22 lock struct(s), heap size 376, 25 row lock(s), undo log entries 10
MySQL thread id 23391, OS thread handle 0x2b4e34a45700, query id 3040994 10.1.2.132 service_api updating
UPDATE `product` SET `sold_count` = sold_count + 1 WHERE `id`=3086`
_** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 844 page no 28 n bits 144 index `PRIMARY` of table `wonderwall`.`product` trx id 2346332859 lock_mode X locks rec but not gap
Record lock, heap no 144 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
...
μ΄λ²μλ 2λ² νΈλμμ
μ λΆμν΄ λ³΄κ² μ΅λλ€.
UPDATE `product` SET `sold_count` = sold_count + 1 WHERE `id`=3086`
product ν μ΄λΈμ sold_count 컬λΌμ update νλ €κ³ μλν©λλ€.
HOLDS THE LOCK(S)
μ΄ λ‘κ·Έλ ν΄λΉ νΈλμμ μ΄ λ³΄μ νκ³ μλ λ½μ μ’ λ₯λ₯Ό μλ―Έν©λλ€. Sλ½μ 보μ νκ³ μλ κ²μΌλ‘ 보μ΄λλ°μ, Xλ½μ 보μ νκ³ μμ΄μΌ ν κ² κ°μλ° λκ° μ΄μν©λλ€. μ’ λ μ΄ν΄λ³΄κ² μ΅λλ€.
RECORD LOCKS space id 844 page no 28 n bits 144 index `PRIMARY` of table `wonderwall`.`product` trx id 2346332859 lock_mode X locks rec but not gap Record lock
1λ² νΈλμμ
μμ μ€λͺ
νλ€ λ§μλ λ μ½λ λ½μ΄ κ±Έλ €μλ μ΄μ κ° μ΄κ³³μ μμ΅λλ€.
2λ² νΈλμμ
μμ product ν
μ΄λΈμ sold_countλ₯Ό λ₯Ό μ
λ°μ΄νΈ νκΈ° μν΄ λ μ½λ λ½μ κ±Έμ΄λμ μνμ΄λ©°, updateλ₯Ό μ€νν΄μΌ νκΈ° λλ¬Έμ Xλ½μ νλν μνμ
λλ€.
μμμ μ€λͺ
νλ―μ΄ Xλ½μ νλνλ €λ©΄ Sλ½μ νλν΄μΌ νλ, Sλ½λ 보μ νκ³ μμ κ²μ
λλ€.
κ·Έλ¬λ©΄ λ°©κΈ μ μ HOLDS THE LOCK(S) μ΄λΆλΆμμ μ Xλ½μ΄ μλ Sλ½μ 보μ νκ³ μλ€κ³ λμ€λμ§μ λν μλ¬Έμ΄ ν릴 κ² κ°μ΅λλ€.
1λ² νΈλμμ
μ
μ₯μμ 보면 κΆκ·Ήμ μΌλ‘λ Xλ½μ νλμ΄ λͺ©νμ΄λ, Xλ½λ³΄λ€ Sλ½μ λ¨Όμ νλν΄μΌ νκΈ° λλ¬Έμ λ‘κ·ΈμμΌλ‘λ 2λ² νΈλμμ
μ΄ Sλ½μ 보μ νκ³ μλ κ²μΌλ‘ 보μ΄λ κ²μ
λλ€.
μ 리λ₯Ό ν΄λ³΄μλ©΄ 2λ² νΈλμμ
μ΄ λ³΄μ νκ³ μλ Xλ½μ νλνκΈ° μν΄ 1λ² νΈλμμ
μ΄ λκΈ°νλ κ³Όμ μμ λ°λλ½μ΄ λ°μνκ³ μμλ κ²μΌλ‘ 보μ¬μ§λλ€.
λ§μΉλ©°
μ΄λ² ν¬μ€νΈμμλ λ°λλ½μ λ°μ μμΈκ³Ό λ‘κ·Έλ₯Ό λΆμν΄ λ³΄μμ΅λλ€.
μ΅κ·Όμ μ€νν ν둬 μ€ν μ΄μμλ μλ‘μ΄ λ°©λ²μ μ¬μ©νμ¬ μ¬κ³ μ²λ¦¬λ₯Ό μ§ννκ³ λ°λλ½μ ννΌνκ³ μ νλλ°μ, λ€μ ν¬μ€νΈμΈ λ°λλ½ μλ°©κ³Ό SQS λμ
λ€λ€λ³΄λλ‘ νκ² μ΅λλ€.