오늘날 기업은 수만 명의 동시 사용자에게 서비스를 제공하는 트래픽이 많은 ASP.NET 웹 응용 프로그램을 개발하고 있습니다. 여러 클라이언트는 애플리케이션 서버가 로드 밸런싱된 환경에 배치되는 클러스터 환경에서 캐시 데이터에 액세스할 수 있습니다. 이러한 병렬 조건에서 여러 사용자가 종종 동일한 데이터에 액세스 및 수정하려고 시도하고 경쟁 조건을 트리거합니다.
경쟁 조건은 두 명 이상의 사용자가 동일한 공유 데이터에 동시에 액세스하고 변경하려고 시도하지만 결국 잘못된 순서로 수행되는 경우입니다. 이 상황은 데이터 무결성과 일관성을 잃을 위험이 높습니다. 인메모리, 확장 가능한 캐싱 솔루션의 출현으로 NCache 분산 잠금 메커니즘을 제공함으로써 기업은 데이터 일관성을 크게 향상시킬 수 있습니다.
NCache 세부 정보 문서 잠금 및 제어 NCache 기술 문서
데이터 일관성을 위한 분산 잠금
NCache 분산 메커니즘을 제공합니다. 잠금 .NET에서 동시 업데이트 중에 특정 캐시 항목을 잠글 수 있습니다. 이러한 경우 데이터 일관성을 유지하려면 NCache 분산 잠금 관리자 역할을 하며 두 가지 유형의 잠금을 제공합니다.
나중에 블로그에서 자세히 다루도록 하겠습니다. 지금은 분산 잠금 서비스 없이 데이터 무결성 위반이 발생하는 방법을 이해하기 위해 다음 시나리오를 고려하십시오.
두 명의 사용자가 30,000의 잔액으로 동일한 은행 계좌에 동시에 액세스합니다. 한 사용자는 15,000을 인출하고 다른 사용자는 5,000을 입금합니다. 올바르게 수행된 경우 최종 잔액은 20,000이어야 합니다. 반대로 처리되지 않은 경쟁 조건이 발생하면 위에서 볼 수 있듯이 은행 잔고가 15,000 또는 35,000이 됩니다.
이 경쟁 조건이 발생하는 방법은 다음과 같습니다.
- 시간 t1: 사용자 1은 잔액 = 30,000인 은행 계좌를 가져옵니다.
- 시간 t2: 사용자 2은 잔액 = 30,000인 은행 계좌를 가져옵니다.
- 시간 t3: 사용자 1은 15,000을 인출하고 은행 계좌 잔고 = 15,000을 업데이트합니다.
- 시간 t4: 사용자 2는 5,000을 예치하고 은행 계좌 잔고 = 35,000을 업데이트합니다.
두 경우 모두 스레드 관리에 적합하지 않은 코드 블록은 은행에 재앙이 될 수 있습니다. 따라서 다음 섹션에서 방법을 살펴보겠습니다. NCache 애플리케이션 로직이 스레드로부터 안전한지 확인하기 위한 잠금 메커니즘을 제공합니다.
낙관적 잠금(항목 버전)
In 낙관적 잠금, NCache 사용 캐시 항목 버전 관리. 서버 측에서 모든 캐시된 개체에는 모든 캐시 항목 업데이트 시 증가하는 버전 번호가 연결되어 있습니다. NCache 그런 다음 최신 버전에서 작업 중인지 확인합니다. 그렇지 않은 경우 캐시 업데이트를 거부합니다. 이렇게 하면 한 사용자만 업데이트할 수 있고 다른 사용자 업데이트는 실패합니다.
둘 다 사용하여 캐시에 항목을 추가할 수 있습니다. 추가 or 끼워 넣다 방법.
- Add 메서드는 캐시에 새 항목을 추가하고 처음으로 항목 버전을 저장합니다.
- 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 28 29 30 31 32 33 |
// Pre-condition: Cache is already connected // An item is added in the cache with itemVersion // Specify the key of the cacheItem string key = "Product:1001"; // Initialize the cacheItemVersion CacheItemVersion version = null; // Get the cacheItem previously added in the cache with the version CacheItem cacheItem = cache.GetCacheItem(key, ref version); // If result is not null if (cacheitem != null) { // CacheItem is retrieved successfully with the version // If result is Product type var prod = new Product(); prod = cacheItem.GetValue(); prod.UnitsInStock++; // Create a new cacheItem with updated value var updateItem = new CacheItem(prod); CacheItemVersion version = cache.Insert(key, updateItem); // If it matches, the insert will be successful, otherwise it will fail } else { // Item could not be retrieved due to outdated CacheItemVersion } |
위의 예에서 두 개의 서로 다른 애플리케이션이 제품 데이터를 포함하는 단일 캐시를 사용합니다. CacheItem이 캐시에 추가됩니다. 두 응용 프로그램 모두 현재 버전으로 항목을 가져옵니다. 버전. Application1은 다음을 수정합니다. 상품명 그런 다음 항목 버전을 업데이트하는 캐시에 항목을 다시 삽입합니다. 새로운 버전. Application2에는 여전히 다음 항목이 있습니다. 버전. application2가 항목의 재고 단위를 업데이트하고 캐시에 항목을 다시 삽입하면 항목 삽입이 실패합니다. 따라서 Application2는 해당 cacheItem에서 작동하도록 업데이트된 버전을 가져와야 합니다.
NCache 세부 정보 낙관적 잠금 캐시 항목 버전 관리
그러나 캐시에서 사용 가능한 최신 버전이 있을 수 있는 기존 항목을 가져오려면 NCache 를 제공합니다 GetIf최신 방법. 현재 버전을 메서드 호출의 인수로 지정하면 캐시가 적절한 결과를 반환합니다. 특정 버전이 캐시에 있는 버전보다 낮으면 메서드는 새 항목을 반환하고, 그렇지 않으면 null을 반환합니다.
아래 코드를 살펴보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Get object from cache var result = cache.GetIfNewer(key, ref version); // Check if updated item is available if (result != null) { // An item with newer version is available if (result is Product) { // Perform operations according to business logic } } else { // No new itemVersion is available } |
위의 예에서는 Product:1001 키와 항목 버전을 사용하여 캐시에 항목을 추가합니다. 항목의 최신 버전을 사용할 수 있는 경우 GetIf최신 메서드는 캐시 항목 버전을 사용하여 항목을 가져옵니다.
낙관적 잠금으로, NCache 분산 캐시에 대한 모든 쓰기가 각 애플리케이션이 보유하고 있는 버전과 일치하도록 합니다. 우리를 참조하십시오 공무원 NCache 문서 광범위한 코드 예제.
NCache 세부 정보 GetIf최신 CacheItem 버전 관리
비관적 잠금(배타적 잠금)
데이터 일관성을 보장하는 다른 방법은 캐시된 데이터에 대한 배타적 잠금을 획득하는 것입니다. 이 메커니즘은 비관적 잠금 . 잠금 핸들을 사용하여 항목을 잠그고 다른 모든 사용자가 해당 캐시 항목에 대한 쓰기 작업을 수행하지 못하도록 차단합니다. ㅏ 잠금 핸들 잠금 API가 반환한 캐시의 모든 잠긴 항목과 연결된 핸들입니다.
다음 예제에서는 LockHandle을 만든 다음 1001초 동안 키로 Product:10 키를 사용하여 항목을 잠궈 10초 후에 항목이 자동으로 잠금 해제되도록 합니다.
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 |
// Pre-Requisite: Cache is already connected // Item is already added in the cache // Specify the key of the item string key = $"Product:1001"; //Create a new LockHandle LockHandle lockHandle = null; // Specify time span of 10 seconds for which the item remains locked TimeSpan lockSpan = TimeSpan.FromSeconds(10); // Lock the item for a time span of 10 seconds bool lockAcquired = cache.Lock(key, lockSpan, out lockHandle); // Verify if the item is locked successfully if (lockAcquired == true) { // Item has been successfully locked } else { // Key does not exist // Item is already locked with a different LockHandle } |
항목을 가져오는 동안 잠금을 성공적으로 획득하면 이 잠금이 있는 한 다른 응용 프로그램이 이 항목을 가져오거나 업데이트할 수 없음을 알기 때문에 이제 응용 프로그램이 안전하게 작업을 수행할 수 있습니다. 데이터를 업데이트하고 잠금을 해제하기 위해 동일한 잠금 핸들로 삽입 API를 호출합니다. 그렇게 하면 캐시에 데이터가 삽입되고 잠금이 해제되어 모든 다른 응용 프로그램에서 캐시된 데이터를 사용할 수 있습니다.
시간 제한이 있는 모든 잠금을 획득해야 한다는 것을 기억하십시오. 기본적으로 시간 초과가 지정되지 않은 경우 NCache 무기한으로 항목을 잠그고, 타임스팬.제로. 잠금을 해제하지 않고 응용 프로그램이 충돌하는 경우 항목이 영원히 잠긴 상태로 유지될 수 있는 경우가 있습니다. 해결 방법은 다음과 같습니다. 강제로 해제 그러나 이 관행은 바람직하지 않습니다. 따라서 교착 상태 또는 스레드 기아를 방지하기 위해 최소 TimeSpan 동안 항목을 잠급니다.
NCache 세부 정보 비관적 잠금 캐시된 데이터로 잠금 사용 블로그
분산 잠금에서 장애 조치 지원
이후 NCache 인메모리이고, 분산 캐시, 데이터 손실이 없고 가용성이 높도록 완벽한 장애 조치 지원도 제공합니다. 서버 오류가 발생하는 경우 클라이언트 응용 프로그램은 계속 원활하게 작동합니다. 마찬가지로 분산 시스템의 잠금도 복제 노드에 의해 복제되고 유지 관리됩니다. 애플리케이션 중 하나가 잠금을 획득하는 동안 노드가 실패하면 지정된 속성을 사용하여 새 노드로 자동 전파됩니다. 예를 들면 다음과 같습니다. 잠금 만료.
결론
그렇다면 낙관적이든 비관적이든 당신에게 가장 적합한 잠금 메커니즘은 무엇입니까? 글쎄, 그것은 당신의 사용 사례와 당신이 달성하고자하는 것에 달려 있습니다. 낙관적 잠금은 특히 응용 프로그램이 읽기 집약적일 때 비관적 잠금보다 향상된 성능 이점을 제공합니다. 반면, 비관적 잠금은 데이터 일관성 관점에서 더 안전합니다. 따라서 잠금 장치를 신중하게 선택하십시오. 자세한 내용은 웹 사이트. 질문이 있는 경우, 여기를 클릭해주세요. 전문가가 도와드리겠습니다!