来自 WCF REST 服务的 Azure 缓存间歇性响应时间

Posted

技术标签:

【中文标题】来自 WCF REST 服务的 Azure 缓存间歇性响应时间【英文标题】:Azure Cache intermittent response times from WCF REST service 【发布时间】:2014-07-26 01:54:15 【问题描述】:

我正在 Azure 中构建一个 EF6 Web 应用程序,并且我正在使用 Azure 缓存。 我正在测试对我的 WCF 服务的调用,但响应时间非常不稳定 - 介于 300 毫秒和 15 秒之间!

我根据this example配置了我的代码,它在本地运行良好

我已经进行了远程调试,我可以看到缓存键被找到并且数据正在从缓存中被调用,所以我很难理解为什么响应时间会有巨大的变化。大多数时候是 5 秒以上,这显然太长了。

我测试的例子如下:

WCF 服务 GET 请求到: http://feniksdev-staging.azurewebsites.net/EkckoNewsService.svc/getFriends

       // Cache client configured by settings in application configuration file.
        public DataCacheFactory cacheFactory = new DataCacheFactory();
        public DataCache _cache;
        public DataCache cache
        
            get 
            
                if (_cache == null)
                    _cache = cacheFactory.GetDefaultCache();

                return _cache;
            
            set  
         
...
...

[OperationContract]
    [System.ServiceModel.Web.WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "/getFriends")]
    public string getFriends()
    
        string cachekey = "getFriends/" + user.Id + "";
        object result = cache.Get(cachekey);
        if (result == null)
        
            using (EkckoContext entities = new EkckoContext())
            
                var frnds = entities.UserConnections.Where(uc => uc.UserId == user.Id).Select(uc => new  Name = uc.Friend.Username ).ToList();
                JsonSerializerSettings jsonSettings = new JsonSerializerSettings  PreserveReferencesHandling = PreserveReferencesHandling.Objects ;
                string json = JsonConvert.SerializeObject(frnds, jsonSettings);
                cache.Add(cachekey, json);
                return json;
            
        
        else
        
            return (string)result;
        
    

UserConnection 是我数据库中的一个简单表,目前没有数据,因此调用返回一个空的 JSON 数组。 user 是一个 Session 对象,目前user.Id 的默认值为 1

远程调试时,对象在缓存中找到并返回缓存的对象。一切都很好,除了响应时间仍然变化 20 倍(300 毫秒 - 6 秒)。

在远程调试其他 Web 服务方法之一时,尝试使用相应的键 (object result = cache.Get(cachekey);) 访问缓存对象时出现以下错误:

"ErrorCode:SubStatus:暂时出现故障。请稍后重试。(一个或多个指定的缓存服务器不可用,可能是由于网络或服务器繁忙造成的。对于本地缓存集群,还要验证以下内容条件。确保已为此客户端帐户授予安全权限,并检查所有缓存主机上的 AppFabric 缓存服务是否允许通过防火墙。此外,服务器上的 MaxBufferSize 必须大于或等于从发送的序列化对象大小客户端。)。附加信息:客户端试图与服务器通信:net.tcp://ekckodev.cache.windows.net:22238。"

然后我在我的配置中设置 maxBufferSize 如下:

    <configSections>
<section name="dataCacheClients" type="Microsoft.ApplicationServer.Caching.DataCacheClientsSection, Microsoft.ApplicationServer.Caching.Core" allowLocation="true" allowDefinition="Everywhere" />
    <section name="cacheDiagnostics" type="Microsoft.ApplicationServer.Caching.AzureCommon.DiagnosticsConfigurationSection, Microsoft.ApplicationServer.Caching.AzureCommon" allowLocation="true" allowDefinition="Everywhere" />
</configSections>
...
...
<system.web>
...
...
<caching>
      <outputCache defaultProvider="AFCacheOutputCacheProvider">
        <providers>
          <add name="AFCacheOutputCacheProvider" type="Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider, Microsoft.Web.DistributedCache" cacheName="default" dataCacheClientName="default" applicationName="AFCacheOutputCache" />
        </providers>
      </outputCache>
    </caching>
</system.web>
    ....
    ....
    ...
      <dataCacheClients>
        <dataCacheClient name="default">
          <autoDiscover isEnabled="true" identifier="ekckodev.cache.windows.net" />
          <localCache  isEnabled="true" sync="TimeoutBased" objectCount="100000" ttlValue="300" />
          <securityProperties mode="Message" sslEnabled="false">
            <messageSecurity authorizationInfo="xxxxxxxxxxxxxxxxxxxxxxx" />
          </securityProperties>
          <transportProperties connectionBufferSize="131072" maxBufferPoolSize="268435456"
                               maxBufferSize="8388608" maxOutputDelay="2" channelInitializationTimeout="60000"
                               receiveTimeout="600000"/>
        </dataCacheClient>
      </dataCacheClients>

但我仍然会得到如此不稳定的响应时间——尤其是在重复打同一个服务调用时。

添加 maxbuffersize 配置后,缓存调用仍然是命中注定的。一些获取对象;其他时候我得到相同的异常,但是端口不同

"...客户端正在尝试与服务器通信:net.tcp://ekckodev.cache.windows.net:22233。""

这可能是防火墙问题吗?如果是这样,我该如何打开相应的端口?

我在实例化 DataCache 对象时也遇到了以下异常:

_cache = cacheFactory.GetDefaultCache();

ErrorCode:SubStatus:暂时失败。请稍后重试。 (一个或多个指定的缓存服务器不可用,这可能是由于网络或服务器繁忙造成的。 对于本地缓存集群,还要验证以下条件。确保安全权限具有 已为此客户帐户授予权限,并检查是否允许 AppFabric 缓存服务通过 所有缓存主机上的防火墙。服务器上的 MaxBufferSize 也必须大于或等于 从客户端发送的序列化对象大小。)

对我为什么会得到这样的结果有什么想法吗?使用缓存肯定不会比没有缓存快,所以缓存中似乎存在某种延迟,这似乎不正确......

提前感谢您的帮助!

更新: 在做了更多搜索之后,似乎我不是唯一一个遇到这个问题的人: poor performance with azure cache

我很难相信这是我应该期待的表现

更新 2 我已从我的服务中注释掉所有与缓存相关的代码并再次运行相同的测试。如果没有缓存,响应时间会明显降低! “getFriends”调用在没有缓存的情况下平均约为 250 毫秒,但在缓存中超过 5 秒时达到峰值。 我的另一种获取大约 4kb 数据的方法在使用缓存时达到了 20+ 秒的峰值,现在在没有缓存的情况下平均大约为 2 秒。

再次:我很难相信这是我应该期待的表现

更新 3 我现在放弃了 Azure 缓存,转而使用 MemoryCache。很好的例子here 我的服务调用现在在浏览器中持续花费大约 300 毫秒。

我已经向 Microsoft Azure 支持人员开出了一张关于 Azure 缓存的票,所以当他们联系我并询问他们为什么他们的缓存如此垃圾时,我会更新这篇文章。就在我对微软的信心正在攀升的时候:/

【问题讨论】:

你确定缓存是慢组件吗?陶氏是你确定的吗? 是的 - 我在实施 Azure 缓存之前、期间和之后进行了速度测试。然后在实现 MemCache 之后再次执行。如前所述,我还进行了远程调试,以确保它从缓存而不是数据库中获取数据。唯一改变的变量是缓存。问题可能归结为配置错误,但我根据 MS 的示例仔细检查了我的配置 我会分析网站以找出缓存内部的时间花在哪里。堆栈通常仅通过函数名称就可以提供重要的线索来了解正在发生的事情。只需在站点有负载时暂停调试器 10 次。大多数时候它很可能会在慢速组件中停止。查看堆栈(包括外部代码)。 你说得对,这不是你应该期待的表现。你能确认你的缓存/sqldb/网站都在同一个区域吗? 是的,他们都在同一个地区(西欧)。自从切换到 MemCache 后,我没有遇到任何类似的问题。微软后来建议我尝试 RedisCache,但我还没有时间(或者没有兴趣!)。再次感谢大家的意见 【参考方案1】:

看来您得出了正确的结论,即不要使用 Azure 托管缓存。大约 6 个月前,Microsoft 开始建议针对 Azure 中基于 Redis 的缓存产品进行所有新开发。

We recommend all new developments use Azure Redis Cache.

奇怪的是,他们没有显示在“旧”Azure 管理站点 (manage.windowsazure.com) 中创建 Redis 缓存的选项,但他们确实在“预览”Azure management portal 中有它。

【讨论】:

以上是关于来自 WCF REST 服务的 Azure 缓存间歇性响应时间的主要内容,如果未能解决你的问题,请参考以下文章

Sql Azure Dac 导入/导出服务是 WCF 或 REST 还是其他?

是否可以创建 WCF 服务端点来处理来自 Azure 服务总线的死信?

发布后在 Azure 云服务中托管的 WCF 服务错误

WCF REST (WebHttpBinding) 可以遵守 PROGRAMMATIC 输出缓存策略吗?

从 WCF 4 REST 模板获取调试输出

Azure 服务总线与服务远程处理、HTTP 和 WCF