2011-07-28 121 views
7

在对我们全新的主系统进行压力测试的原型时,我遇到了AppFabric Cache的并发问题。当同时使用相同的cacheKey调用多个DataCache.Get()和Put()时,我尝试存储相对较大的objet,我收到“ErrorCode:SubStatus:存在临时故障,请稍后再试。”它可以通过以下代码重现:AppFabric缓存并发问题?

 var dcfc = new DataCacheFactoryConfiguration 
     { 
      Servers = new[] {new DataCacheServerEndpoint("localhost", 22233)}, 
      SecurityProperties = new DataCacheSecurity(DataCacheSecurityMode.None, DataCacheProtectionLevel.None), 
     }; 

     var dcf = new DataCacheFactory(dcfc); 
     var dc = dcf.GetDefaultCache(); 

     const string key = "a"; 
     var value = new int [256 * 1024]; // 1MB 

     for (int i = 0; i < 300; i++) 
     { 
      var putT = new Thread(() => dc.Put(key, value)); 
      putT.Start();    

      var getT = new Thread(() => dc.Get(key)); 
      getT.Start(); 
     } 

当使用不同的密钥调用Get()或同步DataCache时,不会出现此问题。如果每次从DataCacheFactory调用DataCache(DataCache应该是线程安全的)或延长超时都可以获取DataCache,则它不起作用,并且仍然会收到错误。 MS看起来很奇怪,会留下这样的错误。有人遇到过类似的问题吗?

+0

重试后是一个非常通用的错误。尝试查看异常的内部执行或子状态,这可以给你提示发生了什么。这个例外可能仍然需要处理,但这至少会使其变得理性。 – user4444

回答

7

我也看到相同的行为,我的理解是,这是设计。高速缓存包含两个并发模型:

  • 乐观并发模型方法:GetPut ...
  • 悲观并发型号:GetAndLockPutAndLockUnlock

如果使用乐观并发模型方法如Get那么你必须准备好获得DataCacheErrorCode.RetryLater并处理适当 - 我也使用重试方法。

你可能会在MSDN找到更多的信息:Concurrency Models

3

我们在代码中也看到了这个问题。我们通过重载Get方法来解决这个问题,以捕获期望值,然后在回退到SQL的直接请求之前重试该调用N次。

这里是我们使用从缓存中获取数据

private static bool TryGetFromCache(string cacheKey, string region, out GetMappingValuesToCacheResult cacheResult, int counter = 0) 
    { 
    cacheResult = new GetMappingValuesToCacheResult(); 

    try 
    { 
     // use as instead of cast, as this will return null instead of exception caused by casting. 
     if (_cache == null) return false; 

     cacheResult = _cache.Get(cacheKey, region) as GetMappingValuesToCacheResult; 

     return cacheResult != null; 
    } 
    catch (DataCacheException dataCacheException) 
    { 
     switch (dataCacheException.ErrorCode) 
     { 
      case DataCacheErrorCode.KeyDoesNotExist: 
      case DataCacheErrorCode.RegionDoesNotExist: 
       return false; 
      case DataCacheErrorCode.Timeout: 
      case DataCacheErrorCode.RetryLater: 
       if (counter > 9) return false; // we tried 10 times, so we will give up. 

       counter++; 
       Thread.Sleep(100); 
       return TryGetFromCache(cacheKey, region, out cacheResult, counter); 
      default: 
       EventLog.WriteEntry(EventViewerSource, "TryGetFromCache: DataCacheException caught:\n" + 
         dataCacheException.Message, EventLogEntryType.Error); 

       return false; 
     } 
    } 
} 

那么当我们需要从高速缓存的东西代码,我们做的事:

TryGetFromCache(key, region, out cachedMapping) 

这允许我们使用try包装例外的方法。如果它返回false,我们知道缓存存在问题,我们可以直接访问SQL。

+0

感谢您的回复,我很高兴我并不孤单:-)但是我无法与这种解决方案协调一致,我无法想象它适用于生产中的关键任务应用程序。我会尝试将其报告给Microsoft,或者也可以使用Memcached。 –

+0

我帮你。我们在我们最重要的网络服务之一中使用此设置,每天点击量超过一百万次。一台服务器每分钟可能处理超过4000个事务。此设置将确保缓存有时间做出响应。 (以及尽可能在当地处理例外情况。)我喜欢尝试方法:) –

+0

请阅读http://appfabriccat.com/2011/07/reaching-stable-performance-in-appfabric-cache-with-a-非空闲缓存通道/ –