简体   繁体   English

多个实例使用同一位置的缓存,但无法访问,需要良好的命名缓存实现

[英]Multiple instances use a co-located caching but fail to access, good named caching implementation required

We have been transferring our services and MVC4 website to the cloud, overall this process went fine. 我们一直在将我们的服务和MVC4网站转移到云中,总体而言,此过程进行得很好。 Except for caching, since we have moved to Azure it would also be wise to use some kind of caching which azure provides. 除了缓存之外,由于我们已经迁移到Azure,因此使用Azure提供的某种缓存也是明智的。 We choose for co-located / dedicated caching role which has the advantage that the cache is used over all the instances. 我们选择位于同一位置/专用的缓存角色,该角色具有在所有实例上使用缓存的优点。

Setting up the caching worked fine, I've got a named caching client which I only initialize when its required. 设置缓存工作正常,我有一个命名的缓存客户端,仅在需要时才初始化。 It is set up in a inherited layer of the controllers. 它是在控制器的继承层中设置的。 As soon as one of the functions is called, it checks if the connection to the data-cache is still there or its created. 一旦调用其中一个功能,它就会检查到数据缓存的连接是否仍然存在或已建立。 This all seems to work fine, but I'm building a module do retrieve prices. 这一切似乎都可以正常工作,但是我正在构建一个模块来检索价格。 And multiple ajax inserts (views which get inserted into the page with use of javascript) use these functions, some of them are called at the same time, by multiple ajax views. 多个ajax插入(使用javascript将其插入页面的视图)使用这些功能,其中一些功能被多个ajax视图同时调用。 Some of these views then return either a 404 or 500 error, and I cant explain where these are coming from except a non working caching, or something alike. 这些视图中的一些然后返回404或500错误,并且我无法解释这些视图来自何处,除了无法工作的缓存或类似的东西。

Can someone help me with a good implementation of the named caching (co-located or dedicated), since all I can find is many examples illustrating the initializing of the DataCacheFactory, but not of the data insertion and retrieval. 有人可以帮我很好地实现命名缓存(位于同一位置还是专用),因为我能找到的很多示例说明了DataCacheFactory的初始化,但没有数据的插入和检索。

Below is the code as I have it now, I've tried more ways with use of locking etc but this one so far worked best. 下面是我现在拥有的代码,我已经尝试了更多使用锁定等方法,但是到目前为止,这种方法效果最好。

private static object magicStick = new object();

    private static DataCacheFactory dcf = null;
    private static DataCache priceCache = null;

    protected void CreateCacheFactory()
    {
        dcf = new DataCacheFactory();

    }
    protected void CreatePricesCache()
    {
        if (dcf == null)
        {
            CreateCacheFactory();
        }
        priceCache = dcf.GetCache("Prices");

    }
protected PriceData GetPrices(int productID)
{
    if (priceCache == null)
    {
        CreatePricesCache();
    }
    string cacheKey = "something";
    lock (magicStick)
    {
        PriceData datas = priceCache.Get(cacheKey) as PriceData;
        if (datas == null)
        {
            lock (magicStick)
            {
                Services svc = new Services();
                PriceData pData = svc.PriceService.GetPrices(productID);
                if (pData != null && pData.Offers != null && pData.Offers.Count() > 0)
                {
                    datas = pData;
                    datas.Offers = datas.Offers.OrderBy(pr => (pr.BasePrice + pr.ShippingCosts)).ToArray();
                    priceCache.Add(cacheKey, datas, new TimeSpan(0, cachingTimePricesKK, 0));
                }
            }
        } 
        return datas;
    }
}

As soon as I get to a page where there are pricelists and the function above is called multiple times with the same arguments, there is a 5-10% chance that it returns an error rather then returning the results. 当我进入有价目表的页面,并且使用相同的参数多次调用上述函数时,它有5-10%的机会返回错误而不是返回结果。 Can anybody help me, im totally stuck with this for a week now and its eating me up inside. 有人可以帮我吗,我已经完全坚持了一个星期,它把我吃光了。

First I'd move your cache and cacheFactory instantiation out of your getPrices method. 首先,将您的cache和cacheFactory实例化移出getPrices方法。 Also, evaluate your need for the lock - this may be causing timeouts. 另外,请评估您对锁的需求-这可能会导致超时。 Another VERY important observation - you are using a constant cache key and saving/retrieving data for every productId with the same cache key. 另一个非常重要的发现-您正在使用恒定的缓存键,并为具有相同缓存键的每个productId保存/检索数据。 You should be using a cache key like: var cacheKey = string.format("priceDatabyProductId-{0}", productId); 您应该使用类似以下的缓存键: var cacheKey = string.format("priceDatabyProductId-{0}", productId); . You need to set some breakpoints and examine exactly what you are caching and retrieving from the cache. 您需要设置一些断点,并准确检查要缓存的内容以及从缓存中检索的内容。 The code as written will save the first productId to the cache and then keep returning that data regardless of the productId. 编写的代码会将第一个productId保存到缓存中,然后无论productId如何,都将继续返回该数据。

Here is a full working example we use in production using the "default" named cache in dedicated cache roles: 这是我们在生产中使用的完整工作示例,该生产在专用缓存角色中使用“默认”命名缓存:

public static class MyCache
{
    private static DataCacheFactory _cacheFactory = null;
    private static DataCache ACache
    {
        get
        {
            if (_cacheFactory == null)
            {
                try
                {
                    _retryPolicy.ExecuteAction(() => { _cacheFactory = new DataCacheFactory(); });
                    return _cacheFactory == null ? null : _cacheFactory.GetDefaultCache();
                }
                catch (Exception ex)
                {
                    ErrorSignal.FromCurrentContext().Raise(ex);
                    return null;
                }
            }

            return _cacheFactory.GetDefaultCache();
        }
    }

    public static void FlushCache()
    {
        ACache.Clear();
    }

    // Define your retry strategy: retry 3 times, 1 second apart.
    private static readonly FixedInterval  _retryStrategy = new FixedInterval(3, TimeSpan.FromSeconds(1));

    // Define your retry policy using the retry strategy and the Windows Azure storage
    // transient fault detection strategy.
    private static RetryPolicy _retryPolicy = new RetryPolicy<StorageTransientErrorDetectionStrategy>(_retryStrategy);

    // Private constructor to prevent instantiation
    // and force consumers to use the Instance property
    static MyCache()
    { }

    /// <summary>
    /// Add an item to the cache with a key and set a absolute expiration on it
    /// </summary>
    public static void Add(string key, object value, int minutes = 90)
    {
        try
        {
            _retryPolicy.ExecuteAction(() => { ACache.Put(key, value, TimeSpan.FromMinutes(minutes)); });
        }
        catch (Exception ex)
        {
            ErrorSignal.FromCurrentContext().Raise(ex);
        }
    }

    /// <summary>
    /// Add the object with the specified key to the cache if it does not exist, or replace the object if it does exist and set a absolute expiration on it
    /// only valid for Azure caching
    /// </summary>
    public static void Put(string key, object value, int minutes = 90)
    {
        try
        {  
            _retryPolicy.ExecuteAction(() => { ACache.Put(key, value, TimeSpan.FromMinutes(minutes)); });
        }
        catch (Exception ex)
        {
            ErrorSignal.FromCurrentContext().Raise(ex);
        }
    }

    /// <summary>
    /// Get a strongly typed item out of cache
    /// </summary>
    public static T Get<T>(string key) where T : class
    {
        try
        {
            object value = null;

            _retryPolicy.ExecuteAction(() => { value = ACache.Get(key); });

            if (value != null) return (T) value;
            return null;
        }
        catch (DataCacheException ex)
        {
            ErrorSignal.FromCurrentContext().Raise(ex);
            return null;
        }
        catch (Exception ex)
        {
            ErrorSignal.FromCurrentContext().Raise(ex);
            return null;
        }
    }
    /// <summary>
    /// Microsoft's suggested method for cleaning up resources such as this in a static class
    /// to ensure connections and other consumed resources are returned to the resource pool
    /// as quickly as possible.
    /// </summary>
    public static void Uninitialize()
    {
        if (_cacheFactory == null) return;
        _cacheFactory.Dispose();
        _cacheFactory = null;
    }
}

Note: this is also using the Transient Fault Handling block from the Enterprise Library for transient exception fault handling. 注意:这也使用企业库中的“瞬态故障处理”块进行瞬态异常故障处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM