μννΈμ¨μ΄ κ°λ°μμ λμμ± λ¬Έμ λ λ°μ΄ν° μΌκ΄μ±κ³Ό μμ€ν μμ μ±μ μν΄ λ°λμ κ³ λ €ν΄μΌ νλ μμλ€. νΉν, λ°μ΄ν°λ² μ΄μ€λ₯Ό λ€λ£¨λ μ ν리μΌμ΄μ μμλ μ¬λ¬ μ¬μ©μμ μμ²μ λμμ μ²λ¦¬νλ©΄μλ λ°μ΄ν°μ μ νμ±μ μ μ§νλ κ²μ΄ ν΅μ¬μ΄λ€.
μ μ°©μ μ΄λ²€νΈλ μ¬κ³ μ²λ¦¬λ λμμ±(Concurrency) λ¬Έμ κ° λ°μνκΈ° μ¬μ΄ μμμΌλ‘, λ€μμ μμ²μ΄ λμμ μ²λ¦¬λ λ μ νμ±κ³Ό μΌκ΄μ±μ μ μ§ν΄μΌ νλ€. μ΄λ₯Ό ν΄κ²°νκΈ° μν΄ λ€μν λμμ± μ μ΄ λ°©λ²μ μ¬μ©ν μ μμΌλ©°, μμ€ν μ μꡬ μ¬νκ³Ό νΈλν½μ λ°λΌ μ ν©ν λ°©λ²μ μ νν΄μΌ νλ€.
1. λ°μ΄ν°λ² μ΄μ€ λ 벨μμ λμμ± μ μ΄
νΈλμμ & λ½
λ°μ΄ν°λ² μ΄μ€ νΈλμμ μ μ¬μ©νμ¬ SELECT ... FOR UPDATEλ‘ μ¬κ³ λ₯Ό μ‘°ννκ³ μ λ°μ΄νΈ μ λ½μ κ±Έμ΄ λμμ±μ μ μ΄. λΉκ΄μ λ½μ μΌμ’ μ΄λ€.
START TRANSACTION;
SELECT stock FROM inventory WHERE product_id = 1 FOR UPDATE;
UPDATE inventory SET stock = stock - 1 WHERE product_id = 1 AND stock > 0;
COMMIT;
λ°μ΄ν°λ² μ΄μ€ μμ€μμ μ νν λμμ±μ 보μ₯ν΄ μ€λ€. νμ§λ§ λ½μ΄ κ±Έλ¦° μνμμ ν΄λΉ νΈλμμ μ΄ μλ£λ λκΉμ§ λ€λ₯Έ νΈλμμ μ΄ λ°μ΄ν°μ μ κ·Όνμ§ λͺ»νλ€. κ·Έλμ λμ νΈλν½μμ μ±λ₯μ ν λ¬Έμ λ₯Ό μΌμΌν¬ μ μλ€.
λν λΆμ° λ°μ΄ν°λ² μ΄μ€μμ λ½μ΄ ν κ³³μ λ°μ΄ν°λ§ μ κΈμ κ±ΈκΈ°μ λ€λ₯Έ λ°μ΄ν°λ² μ΄μ€μ λ°μ΄ν°λ μ κ·Ό κ°λ₯νκΈ°μ νκ³κ° μλ€.
λΉκ΄μ λ½(Pessimistic Lock)
μΆ©λμ΄ λ°μν κ°λ₯μ±μ΄ λμ κ²½μ° μ¬μ©λλ λμμ± μ μ΄ κΈ°λ²μ΄λ€. μμ νΈλμμ & λ½κ³Ό κ°μ΄ λ°μ΄ν°λ² μ΄μ€μ λ½μ κ±°λ λ°©μμ΄λ€. μ ν리μΌμ΄μ μ½λμμ μ€μ μ΄ κ°λ₯νλ€.
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Product p WHERE p.id = :id")
Product findProductForUpdate(@Param("id") Long id);
λ°μ΄ν°λ₯Ό μ½κ±°λ μμ νκΈ° μ μ LOCK μ νλνμ¬ λ€λ₯Έ νΈλμμ μ μ‘μΈμ€λ₯Ό μ°¨λ¨νλ€.
λμμ± λ¬Έμ κ° λΉλ²νκ² μΌμ΄λλ€λ©΄ rollbackμ νμλ₯Ό μ€μΌ μ μκΈ° λλ¬Έμ μ±λ₯μ μΌλ‘ μ’λ€. λͺ¨λ νΈλμ μ μ lockμ μ¬μ©νκΈ° λλ¬Έμ, lockμ΄ νμνμ§ μμ μν©μ΄λλΌλ 무쑰건 lockμ κ±Έμ΄μ μ±λ₯μ λ¬Έμ κ° λ μ μλ€. νΉν read μμ μ΄ λ§μ΄ μΌμ΄λλ κ²½μ° λ¨μ μ΄ λ μ μλ€. λν, μ μ°©μ μ΄λ²€νΈκ°μ΄ λ§μ νΈλν½μ΄ λͺ°λ¦¬λ μν©μ΄λ μ¬λ¬ ν μ΄λΈμ lockμ κ±Έλ©΄μ μλ‘ μμμ΄ νμν κ²½μ°, λ°λλ½μ΄ λ°μν μ μκ³ μ΄λ λΉκ΄μ λ½μΌλ‘ ν΄κ²°ν μ μλ λΆλΆμ΄λ€.
λν λκ°μ΄ λΆμ° λ°μ΄ν°λ² μ΄μ€ νκ²½μμλ μ νμ μ΄λ€.
λκ΄μ λ½(Optimistic Lock)
λκ΄μ λ½μ λ°μ΄ν° λ³κ²½ μμ μλ§ μΆ©λμ κ²μ¬νλ λ°©μμ΄λ€. μλνλ©΄ λκ΄μ λ½μ λ°μ΄ν° μΆ©λμ΄ μμ£Ό λ°μνμ§ μλ μν©μμ μ±λ₯μ μ΅μ ννκΈ° μν΄ μ¬μ©λκΈ° λλ¬Έμ΄λ€.
λ μ½λμ version νλλ₯Ό μΆκ°νκ³ , μ λ°μ΄νΈ μ 체ν¬νλ€. λ§μ½ versionμ΄ λ³κ²½λμμΌλ©΄ μ¬μλ(μΆ©λ κ°μ§) μ ν΅ν΄ μΆ©λμ ν΄κ²°νλ€. μμμ Lockμ μ§μ κ±Έμ΄μ μ μ νμ§ μκ³ , λμμ± λ¬Έμ κ° μ€μ λ‘ λ°μνλ©΄ κ·Έλκ°μ μ²λ¦¬νλ λ°©μμ΄λ€. μμμ μ½μμ λ λ²μ μ΄ 7μ΄μλλ° μμ νλ €κ³ νλ λ²μ μ΄ 8 μ΄λ©΄ κ·Έ μ¬μ΄μ λ€λ₯Έ νΈλμμ μ΄ μμ μνλ₯Ό μ λ°μ΄νΈ νλ€λ λ»μ΄λλ€. κ·ΈλΌ νΈλμμ μ λ‘€λ°±ν΄μ λ€μ μ²λ¦¬νλ€.
@Entity
public class {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int stock;
@Version
private Long version;
}
μ€μ λ‘ lockμ μ¬μ©νμ§ μκ³ versionμ μ΄μ©ν¨μΌλ‘μ μ ν©μ±μ λ§μΆκΈ°μ μ±λ₯λ©΄μμ μ 리νλ€. νμ§λ§ λμμ± λ¬Έμ κ° λΉλ²νκ² μΌμ΄λλ©΄ κ³μ rollback μ²λ¦¬λ₯Ό ν΄μ£Όμ΄μΌ νλ€.
λΆμ° λ°μ΄ν°λ² μ΄μ€ νκ²½μμλ μ νμ μ΄λ€.
2. μ ν리μΌμ΄μ λ 벨μμ λμμ± μ μ΄
Synchronized ν€μλ μ¬μ©
Javaμ synchronized ν€μλλ₯Ό μ¬μ©νμ¬ νΉμ μ½λ λΈλ‘μ λμ μ€νμ μ°¨λ¨νλ€.
public synchronized void updateStock(int productId, int quantity) {
// μ¬κ³ μ²λ¦¬ λ‘μ§
}
κ°λ¨ν ꡬνμ΄ κ°λ₯νμ§λ§, λ¨μΌ μ ν리μΌμ΄μ μμλ§ μλνκΈ°μ μλ²κ° μ¬λ¬ κ°μΈ λΆμ° μμ€ν νκ²½μμλ μ¬μ©ν μ μλ€.
λΆμ°λ½ μ¬μ©
λΆμ°λ½μ μ¬λ¬ μ ν리μΌμ΄μ λλ νλ‘μΈμ€ κ°μ 곡μ λ μμμ λν λμ μ‘μΈμ€λ₯Ό μ μ΄νκΈ° μν΄ μ¬μ©λλ€.
μΉ μ ν리μΌμ΄μ μμ λλΆλΆ Redis, Zookeeper λ±μ νμ©νμ¬ λΆμ° νκ²½μμ λ½μ ꡬννλ€. λΆμ° μμ€ν μμ μ ν리μΌμ΄μ μ 곡μ μμμ μ κ·ΌνκΈ° μ μ λ½μ μμ²λ€. λ½μ΄ μ±κ³΅μ μΌλ‘ νλλλ©΄ μμ μ μννκ³ , μλ£ ν λ½μ ν΄μ λ€. λ½μ΄ μ΄λ―Έ μ μ μ€μ΄λΌλ©΄, μμ²μ μ€ν¨νκ±°λ λκΈ° μνλ‘ μ²λ¦¬λλ€.
private final RedissonClient redissonClient;
public DistributedLockExample(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
public void executeCriticalTask() {
RLock lock = redissonClient.getLock("criticalTaskLock");
try {
if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { // λ½ μλ (μ΅λ 10μ΄ λκΈ°, 30μ΄ μ μ§)
// 곡μ μμ μμ
System.out.println("Lock acquired, executing critical task...");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock(); // λ½ ν΄μ
System.out.println("Lock released.");
}
}
λΆμ°νκ²½μμλ λ½ κ΅¬νμ΄ κ°λ₯νκΈ° λλ¬Έμ λ리 μ¬μ©λλ λ°©μμ΄λ€. λΆμ° λ½μ μΈλΆ μμ€ν μ΄ κ΄λ¦¬νμ¬ λ½μ μνλ₯Ό μ€μμμ κ΄λ¦¬νλ€. λ°λΌμ μ ν리μΌμ΄μ μ΄λ DBμ λ½μ κ±°λ κ²μ΄ μλκΈ° λλ¬Έμ λμ μ±λ₯κ³Ό μμ μ±μ μ 곡νλ€.
Redisλ₯Ό νμ©νκΈ°μ Redis κ΅¬μΆ μ΄ν΄λ₯Ό νμλ‘ νκ³ , λ½ νλ λ° ν΄μ μ€ν¨ μ 볡ꡬ λ‘μ§ νμνλ€. λν λ€νΈμν¬ μ§μ°μ΄λ μ₯μ λ‘ μΈν λ¬Έμ μ λλΉν μ μμ΄μΌ νλ€.
3. λ―Έλ€μ¨μ΄λ₯Ό νμ©ν λμμ± μ μ΄
λ©μμ§ ν κ°μ λ―Έλ€μ¨μ΄λ₯Ό νμ©ν λ°©λ²μ΄λ€. λͺ¨λ μ¬κ³ μ²λ¦¬ μμ²μ λ©μμ§ ν(Kafka, RabbitMQ λ±)μ λ£κ³ μμ°¨μ μΌλ‘ μ²λ¦¬νλ€. μμ°μ(Producer)κ° μμ²μ νμ 보λ΄κ³ , μλΉμ(Consumer)κ° μ΄λ₯Ό νλμ© μ²λ¦¬νλ€. λΉλκΈ° μ²λ¦¬λ‘ μμ²μ μ¦μ μ²λ¦¬νμ§ μκ³ νλ μ΄λ²€νΈ λ‘κ·Έμ μ μ₯ν λ€ μμ°¨μ μΌλ‘ μ²λ¦¬νλ€.
νΈλν½ κΈμ¦μλ μμ μ μΈ μ²λ¦¬ κ°λ₯νλ€. νμ μλ μμ²μ μλΉνλ©° λμνκΈ°μ λμμ± λ¬Έμ κ° λ°μνμ§ μλλ€. λ‘κ·Έ κΈ°λ°μ Kafkaλ₯Ό μ¬μ©νλ€λ©΄ λͺ¨λ μ΄λ²€νΈλ€μ λ‘κ·Έ νμμΌλ‘ λ¨κΈ°κΈ° λλ¬Έμ λ³κ²½ μ¬νμ μΆμ ν μ μλ€.
μμ²μ λν΄ λκΈ°μ μΌλ‘ μ²λ¦¬ νμ§ μκ³ λ€νΈμν¬ ν΅μ μ νκΈ°μ μ½κ°μ μ§μ°μ΄ λ°μν μ μλ€.
μ€λ³΅ μ²λ¦¬, μμ λ¬Έμ , λ³λͺ© νμ λ±μ΄ λ°μν κ°λ₯μ±μ μ‘΄μ¬νκΈ°μ, λ©±λ±μ± μ€κ³, μμ 보μ₯ λ©μ»€λμ¦, Consumer νμ₯ λ±μ μ λ΅μ μ¬μ©ν΄ νλ€. λν μΆκ°μ μΈ λ―Έλ€μ¨μ΄λ₯Ό νμ©νκΈ°μ μ΄μλν μ΄ν΄μ κ΅¬μΆ λ° κ΄λ¦¬κ° νμνλ€.
'System Design' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
μ€λ¬΄μμ μμ£Ό μ νκ² λλ μν° ν¨ν΄ (0) | 2024.12.26 |
---|
λκΈ