【问题标题】:Whats the best approach to handle pessimistic concurrency in Azure Cache?在 Azure 缓存中处理悲观并发的最佳方法是什么?
【发布时间】:2013-03-06 04:51:12
【问题描述】:

我是 azure 缓存的新手并面临一个问题。

我先简单介绍一下这个场景。我们使用SQL Azure 作为我们应用程序的数据库。为了避免延迟问题和限制问题,我们使用 Azure 缓存(Web 角色上的共存缓存)。通过使用 Azure 缓存,我们只从数据库中获取数据一次并将其保存在缓存中以供进一步使用。

由于我们使用的是缓存数据,因此这里的挑战是在执行任何 DML 操作的任何时间点始终保持 SQL Azure DB 和 Azure 缓存之间的数据同步。我们通过首先更新数据库来做到这一点,如果更新成功则缓存数据无效。这种方法适用于正常情况。 但是,随着并发用户工作和执行更新,似乎存在问题。我们在更新缓存中的数据时使用悲观并发模型。在这里,我们使用瞬态重试策略来确保重试尝试(假设 5 次,固定间隔为 1 秒)。

示例代码如下所示:

Microsoft.Practices.TransientFaultHandling.RetryPolicy cacheRetryPolicy =
    GetAzureCacheRetryPolicy();

cacheRetryPolicy.Retrying += TransientRetryManager.OnRetrying;  
DataCacheLockHandle handle = null;
cacheRetryPolicy.ExecuteAction(() =>
{
    try
    {
        object obj = cache.GetAndLock(key, TimeSpan.FromSeconds(1), out handle);
        cache.PutAndUnlock(key, value, handle, expirationTime.Value, tags);
    }
    catch (DataCacheException ex)
    {
        if (ex.ErrorCode == DataCacheErrorCode.KeyDoesNotExist)
        {
            cache.Put(key, value, expirationTime.Value, tags);
        }
        else
        { 
            //This means wait till the cache is released. 
            //Throwing from here will allow to retry with Transient 
            //handling retry policy.                           
            throw ex; 
        }
    }
}

在这里,如果等待次数(比如说 6 次)超过重试次数(在我们的例子中是 5 次)。到第 6 次轮到它时,重试尝试已经结束,因此具有最新更新的第 6 次等待将无法在缓存中更新它。

有一种方法可以解决此问题,方法是在获取缓存键锁定时将所有等待排队,以防errorcodeobjectlocked

谁能建议处理这种情况的最佳方法?

【问题讨论】:

    标签: azure pessimistic-locking


    【解决方案1】:

    如果我没记错的话,缓存的结果并没有在数据库中保存最新的数据。

    --------------------------------------------------------------------------------
    This could happen in following Scenario
    --------------------------------------------------------------------------------
    Time        User 1                              User 2
    1           Updates DB data from A to B         Idle
    4           Adding data to cache                Updates DB data from B to C
    5           Still adding to cache               Adding data to cache
    7           Still adding to cache               caching is done
    9           Still adding to cache               current data is C
    10          caching is done
    11          current data is B (but it should be C)
    
    1. 用户 2 在用户 1 之后启动更新
    2. 所以理想情况下,最新数据应该是用户 2 的
    3. 但是用户 2 的缓存代码在用户 1 的代码之前完成,然后用户 1 的缓存代码被触发
    4. 因此最新结果将是用户 1,这不是预期的。

    如果是单实例应用我们可以使用线程锁来解决,因为Azure是多实例的,APP的命中率比较高,可以采用以下方法。

    也许不是最好的,但我们已经解决了这个问题,我们的应用程序在 6 个 Web 服务器上运行并且我们拥有超过 75k 的用户。

    我们总是在缓存中保留两个数据

    1. 需要缓存的内容
    2. 我们数据库中相同内容的 LastModified 列的值

    在向缓存添加新值之前,我们始终确保缓存中的 LastModified 数据小于我们在数据库中的日期。 出于某种原因,缓存的数据比当前的数据库数据多,然后不知何故,最新的值已经被推送到缓存,所以我们不加回来。

    So what we have done is
    -----------------------------------------------------------------------------------
    Time                User 1                      User 2
    -----------------------------------------------------------------------------------
    1           Updates DB data from A to B         Idle
    4           Adding data to cache                Updates DB data from B to C     
    5           still adding to cache               Adding data to cache
    7           Still adding to cache               caching is done with last modified date
    9           Still adding to cache               current data is C
    10          found that cached date is greater than the current
    11          skips caching
    

    【讨论】:

      猜你喜欢
      • 2022-01-11
      • 1970-01-01
      • 2010-09-06
      • 2015-11-19
      • 2011-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多