λ°λ“œλ½ λ°œμƒ 원인과 둜그 뢄석

2chan
  • #deadlock
  • #shared lock
  • #exclusive lock
  • #s lock
  • #x lock
  • #transaction

λ“€μ–΄κ°€λ©°

μ•ˆλ…•ν•˜μ„Έμš”. 원더월 λ°±μ—”λ“œ 개발자 μ΄μ°¬ν¬μž…λ‹ˆλ‹€.

원더월은 μ„œλΉ„μŠ€ νŠΉμ„±μƒ μŠ€νŒŒμ΄ν¬μ„± νŠΈλž˜ν”½μ΄ 자주 λ°œμƒν•©λ‹ˆλ‹€. κ°€μˆ˜λ“€μ˜ 앨범 판맀 μ˜€ν”ˆμ΄λ‚˜ ν•œμ •νŒλ§€μ™€ 같은 μ΄λ²€νŠΈμ„± νŒλ§€μ—μ„œ 주둜 λ°œμƒν•˜λŠ”λ°μš”, μˆœκ°„μ μœΌλ‘œ νŠΈλž˜ν”½μ΄ λͺ°λ¦¬λ‹€ 보면 결제μͺ½μ—μ„œ 가끔 λ°λ“œλ½μ΄ λ°œμƒν•˜λŠ” λ¬Έμ œκ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.
이번 ν¬μŠ€νŠΈμ—μ„œλŠ” 원더월 μ„œλΉ„μŠ€μ—μ„œ λ°λ“œλ½μ΄ λ°œμƒν•˜λŠ” 원인과 그에 λŒ€ν•œ 둜그λ₯Ό 뢄석해 보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.


λ°λ“œλ½μ΄λž€

이미지 좜처: λ•”κ°νˆ°


검색을 해보면 λ§Žμ€ κ³³μ—μ„œ μ•„λž˜μ™€ 같이 λ°λ“œλ½μ„ μ •μ˜ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

μš΄μ˜μ²΄μ œμ—μ„œ λ°λ“œλ½(κ΅μ°©μƒνƒœ)μ΄λž€ μ‹œμŠ€ν…œ μžμ›μ— λŒ€ν•œ μš”κ΅¬κ°€ 뒀엉킨 μƒνƒœλ‘œ, λ‹€μŒκ³Ό 같은 쑰건이 λ™μ‹œμ— 좩쑱될 λ•Œ λ°œμƒν•©λ‹ˆλ‹€.

  1. μƒν˜Έ 배제 (Mutual Exclusion): μžμ›μ€ λ™μ‹œμ— μ—¬λŸ¬ 개의 μž‘μ—…μ΄ μ‚¬μš©ν•  수 μ—†κ³ , ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μž‘μ—…λ§Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  2. 점유 λŒ€κΈ° (Hold and Wait): μž‘μ—…μ€ 이미 μ–΄λ–€ μžμ›μ„ μ μœ ν•œ μƒνƒœμ—μ„œ λ‹€λ₯Έ μžμ›μ„ κΈ°λ‹€λ¦½λ‹ˆλ‹€.
  3. 비선점 (No Preemption): λ‹€λ₯Έ μž‘μ—…μ΄ μ μœ ν•œ μžμ›μ„ κ°•μ œλ‘œ 뺏을 수 μ—†μŠ΅λ‹ˆλ‹€. μžμ›μ€ ν•΄λ‹Ή μž‘μ—…μ΄ 자발적으둜 λ°˜λ‚©ν•  λ•ŒκΉŒμ§€ μ μœ λ©λ‹ˆλ‹€.
  4. μˆœν™˜ λŒ€κΈ° (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으둜 κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

  1. μ£Όλ¬Έ 생성 api - order ν…Œμ΄λΈ”μ— insert ν•©λ‹ˆλ‹€.
  2. μ£Όλ¬Έ μ™„λ£Œ 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락을 λŒ€κΈ°ν•˜κ³  μžˆλ‹€κ³  λ³΄μ—¬μ§‘λ‹ˆλ‹€. μ—¬κΈ°μ„œ μ‚΄νŽ΄λ΄μ•Ό ν•  뢀뢄은 λ‘κ°€μ§€μž…λ‹ˆλ‹€.

  1. μ™œ λ ˆμ½”λ“œ 락이 κ±Έλ ΈλŠ”κ°€
  2. 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 λ„μž… 닀뀄보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

← λͺ©λ‘μœΌλ‘œ λŒμ•„κ°€κΈ°

Art Changes Life

λ…Έλ¨ΈμŠ€μ™€ ν•¨κ»˜ μ—”ν„°ν…Œν¬ 산업을 ν˜μ‹ ν•΄λ‚˜κ°ˆ 멀버λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.

μ±„μš© 쀑인 곡고 보기