오늘날 기업들은 높은 트래픽을 개발하고 있습니다. ASP.NET 코어 수많은 동시 사용자를 대상으로 하는 웹 애플리케이션. 클러스터형 아키텍처에서 부하 분산 애플리케이션 서버에서 여러 클라이언트가 캐시 데이터에 액세스할 수 있습니다. 이러한 상황에서는 여러 사용자가 동일한 데이터에 액세스하고 변경하려고 하기 때문에 경쟁 조건(두 명 이상의 사람이 동일한 공유 데이터를 동시에 보고 편집하려고 할 때)이 발생합니다.
이러한 경쟁 조건은 종종 다음을 발생시킵니다. 데이터 불일치 그리고 무결성 문제도 있습니다. 게다가 이는 실시간 데이터 정확도에 의존하는 애플리케이션에 위험을 초래합니다. 다행히도 NCache, 기업은 분산된 것을 활용할 수 있습니다 잠금 확장 가능한 메모리 내 캐싱 환경에서 강력한 데이터 일관성을 보장하는 메커니즘입니다.
주요 요점
- 레이스 조건 방지: 분산 잠금은 여러 클라이언트가 동시에 동일한 캐시된 데이터를 수정할 수 없도록 함으로써 데이터 불일치를 제거합니다.
- 낙관적 잠금(버전 관리): 내부 항목 버전 관리 기능을 활용하여 업데이트 전에 데이터의 유효성을 검사합니다. 이는 고성능을 제공하며 데이터 충돌이 드문 환경에 이상적입니다.
- 비관적 잠금(배타적): LockHandle을 사용하여 소스에서 항목을 명시적으로 잠급니다. 이는 최대 처리량보다 엄격한 일관성이 더 중요한 중요 데이터에 가장 적합합니다.
- 확장 가능한 일관성: NCache 클러스터 환경 전반에 걸쳐 이러한 메커니즘을 제공하여 잠금 로직이 단일 서버가 아닌 모든 캐시 노드에서 동기화되도록 보장합니다.
- 전략적 구현: 둘 중 하나를 선택하는 것은 작업 부하에 따라 다릅니다. 읽기 작업이 많은 애플리케이션에서는 속도 유지를 위해 낙관적 잠금을 사용하고, 쓰기 작업이 많은 애플리케이션에서는 절대적인 데이터 무결성 유지를 위해 비관적 잠금을 사용할 수 있습니다.
데이터 일관성을 위한 분산 잠금
의 도움으로 NCache의 분산 잠금 메커니즘을 사용하면 동시 업데이트 중에 특정 캐시 항목을 잠글 수 있습니다. 이렇게 하면 한 번에 하나의 프로세스만 항목을 수정할 수 있으므로 경쟁 상황이 방지되어 데이터 무결성이 보장됩니다.
NCache 두 가지 유형의 잠금 기능을 제공합니다.
데이터 일관성을 위해 분산 잠금이 필수적인 이유는 무엇입니까?
두 사용자가 잔액이 30,000인 동일한 은행 계좌에 액세스하는 은행 애플리케이션을 생각해 보세요. 한 사용자는 15,000을 인출하고 다른 사용자는 5,000을 입금합니다. 경쟁 조건이 처리되지 않으면 최종 잔액이 예상대로 15,000이 아닌 35,000 또는 20,000이 될 수 있습니다.
경쟁 조건의 분석:
- 시간 t1: 사용자 1은 잔액 = 30,000인 은행 계좌를 가져옵니다.
- 시간 t2: 사용자 2은 잔액 = 30,000인 은행 계좌를 가져옵니다.
- 시간 t3: 사용자 1이 15,000을 인출하고 잔액을 15,000으로 업데이트합니다.
- 시간 t4: 사용자 2가 5,000을 입금하고 잔액을 35,000으로 업데이트합니다.
이러한 시나리오를 방지하려면 NCache의 잠금 이러한 메커니즘은 애플리케이션 로직이 스레드로부터 안전하고 한 번에 하나의 업데이트만 허용되도록 보장합니다.
낙관적 잠금(캐시 항목 버전)
낙관적 잠금 사용 캐시 항목 버전 관리 동시 업데이트를 관리합니다. 캐시된 각 개체에는 버전 번호가 있으며, 이 번호는 모든 수정 시 증가합니다. 캐시 항목을 업데이트하기 전에 애플리케이션은 버전 번호를 검색하여 수정 사항을 저장하기 전에 확인합니다. 그 사이에 다른 업데이트가 버전을 변경한 경우 데이터 무결성을 유지하기 위해 업데이트가 거부됩니다.

그림 1: 낙관적 잠금 시퀀스 다이어그램
낙관적 잠금 구현 NCache
낙관적 잠금을 구현하려면 아래 코드 샘플을 참조하세요.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//The following C# example demonstrates version-based updates where the "Insert" operation succeeds only if the "version" matches the server-side value. using Alachisoft.NCache.Client; ICache cache = CacheManager.GetCache("myCache"); string key = "order:456"; // Retrieve item with version CacheItem cacheItem = cache.GetCacheItem(key); long version = cacheItem.Version; // Modify data Order order = (Order)cacheItem.Value; order.Status = "Shipped"; try { // Update only if the version matches cache.Insert(key, new CacheItem(order), version); Console.WriteLine("Update successful."); } catch (OperationFailedException ex) { Console.WriteLine("Optimistic lock failed: " + ex.Message); } |
비관적 잠금(배타적 잠금)
비관적 잠금 잠금이 해제될 때까지 다른 사용자가 캐시 항목을 수정하지 못하도록 합니다. 이 접근 방식은 데이터 수정에 대한 엄격한 제어가 필요한 시나리오에서 유용합니다.

그림 2: 비관적 잠금 시퀀스 다이어그램
비관적 잠금 구현 NCache
비관적 잠금을 구현하려면 NCache, 아래 코드 샘플을 참조하세요.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//This snippet shows how to acquire an explicit lock using "AcquireLock", ensuring no other thread can modify the item until "ReleaseLock" is called. using Alachisoft.NCache.Client; using Alachisoft.NCache.Runtime.Exceptions; ICache cache = CacheManager.GetCache("myCache"); string key = "customer:123"; LockHandle lockHandle = new LockHandle(); try { // Acquire lock with a timeout cache.AcquireLock(key, TimeSpan.FromSeconds(10), out lockHandle); // Perform operations while holding the lock Customer customer = (Customer)cache.Get(key, lockHandle); customer.Name = "Updated Name"; cache.Insert(key, new CacheItem(customer), lockHandle); } catch (LockingException ex) { Console.WriteLine("Lock acquisition failed: " + ex.Message); } finally { // Release the lock cache.ReleaseLock(key, lockHandle); } |
Get 중 잠금 및 Insert 시 잠금 해제
또 다른 비관적 잠금 접근 방식은 항목을 잠그는 것입니다. 가져 오는 중 그와 공개 항목을 업데이트하는 동안 잠금을 해제합니다. 이렇게 하면 업데이트가 완료될 때까지 페치된 데이터가 변경되지 않습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using Alachisoft.NCache.Client; using Alachisoft.NCache.Runtime.Exceptions; ICache cache = CacheManager.GetCache("myCache"); string key = "product:789"; LockHandle lockHandle = new LockHandle(); try { // Lock item during Get operation Product product = (Product)cache.Get(key, TimeSpan.FromSeconds(10), out lockHandle); // Modify the product data product.Price += 10; // Update item and release the lock cache.Insert(key, new CacheItem(product), lockHandle, true); } catch (LockingException ex) { Console.WriteLine("Lock operation failed: " + ex.Message); } finally { // Ensure the lock is released if not already released cache.ReleaseLock(key, lockHandle); } |
| 제품 특장점 | 낙관적 잠금(버전 관리) | 비관적 잠금(독점) |
| 핵심 메커니즘 | 아이템 버전 관리를 사용합니다. 시스템은 마지막 가져오기 이후 버전이 변경되었는지 확인합니다. | LockHandle을 사용합니다. 이 시스템은 설정된 기간 동안 단일 사용자에게 독점적인 접근 권한을 부여합니다. |
| 동시성 수준 | 높음. 여러 사용자가 동시에 업데이트를 읽고 시도할 수 있으며 차단되지 않습니다. | 낮은 수준입니다. 한 명의 사용자만 해당 항목을 수정할 수 있으며, 다른 사용자는 기다려야 합니다. |
| 성능 영향 | 최소한의 보안만 제공합니다. 서버에 물리적 잠금이 걸려 있지 않으므로 최대 처리량을 보장합니다. | 난이도: 중상. 자물쇠를 너무 오래 잡고 있거나 경쟁이 심할 경우 병목 현상이 발생할 수 있습니다. |
| 충돌 처리 | 버전이 일치하지 않으면 업데이트가 실패하고 애플리케이션은 다시 시도해야 합니다(충돌 감지). | 다른 사용자가 잠금 해제될 때까지 접근을 차단하여 충돌을 방지합니다(충돌 방지). |
| 이상적인 사용 사례 | 읽기 작업이 많고 경합이 적은 데이터. 예: 제품 카탈로그, 사용자 프로필 또는 구성 데이터. | 쓰기 작업이 많고 정확성이 요구되는 데이터. 예: 재무 잔액, 재고 조사, 좌석 예약. |
맺음말
고용함으로써 NCache분산 잠금 기능을 통해 개발자는 분산 애플리케이션에서 높은 데이터 일관성을 보장할 수 있습니다. 비관적 잠금은 중요한 업데이트에 대한 엄격한 제어를 제공하는 반면, 낙관적 잠금은 낮은 충돌 시나리오에서 더 높은 성능을 제공합니다. 이러한 전략을 구현하면 높은 동시성 워크로드에서도 데이터 무결성이 보장되어 애플리케이션이 안정적이고 확장 가능하게 유지됩니다.
자주 묻는 질문 (FAQ)
- 분산 캐시에서 락킹이란 무엇인가요?
분산 캐시에서 잠금(Locking)은 여러 서버에서 한 번에 하나의 클라이언트만 캐시된 항목을 수정할 수 있도록 보장하는 메커니즘으로, 동시 업데이트 충돌을 방지합니다. - 데이터 일관성을 위해 데이터 잠금이 중요한 이유는 무엇입니까?
잠금 기능은 여러 애플리케이션이나 서비스가 동일한 캐시된 데이터를 동시에 읽거나 쓰려고 할 때 발생하는 경쟁 조건과 업데이트 손실을 방지합니다. - 분산 캐시 잠금은 데이터베이스 잠금과 어떻게 다른가요?
분산 캐시 잠금은 메모리 내 애플리케이션 노드와 캐시 서버 간에 작동하는 반면, 데이터베이스 잠금은 일반적으로 스토리지 수준에서 작동하며 더 높은 지연 시간을 유발할 수 있습니다. - 분산 캐시에서 락킹을 사용하면 성능에 영향을 미치나요?
네, 락킹은 조정 오버헤드를 발생시키므로 높은 처리량과 읽기 작업이 많은 워크로드보다는 엄격한 일관성이 요구되는 데이터에 선택적으로 사용해야 합니다.






