创建高可用性AppFabric缓存集群

时间:2012-09-11 20:12:06

标签: appfabric appfabric-cache

除了在群集配置中设置Secondaries=1以启用HighAvailability,特别是在缓存客户端配置上,还有什么内容吗?

我们的配置:

使用about配置,我们会看到在三台主机上创建的主要和次要区域,但是当其中一台主机停止时,会发生以下异常:

  • ErrorCode<ERRCA0018>:SubStatus<ES0001>:The request timed out.
  • An existing connection was forcibly closed by the remote host
  • No connection could be made because the target machine actively refused it 192.22.0.34:22233
  • An existing connection was forcibly closed by the remote host

高可用性是否能够在不中断服务的情况下处理主机停机?我们正在使用一个命名区域 - 这会破坏高可用性吗?我在某处读到命名区域只能存在于一个主机上(我确实验证了另一个主机上存在辅助区域)。我觉得我们错过了一些缓存客户端配置可以实现高可用性,任何有关此事的见解都将非常感激。

2 个答案:

答案 0 :(得分:4)

高可用性是关于保护数据,而不是每秒都可用(因此重试例外)。当缓存主机出现故障时,您会收到异常,并且应该重试。在此期间,访问HA缓存可能会在重新忙乱并创建额外副本时向您返回重试异常。区域更复杂,因为它导致更大的块必须在它再次出现之前被复制。

此外,客户端保持与所有缓存主机的连接,因此当一个缓存主机发生故障时,它会抛出发生错误的异常。

基本上当一台主机出现故障时,Appfabric就会惊慌失措,直到HA缓存中再次存在所有数据的两个副本。我们在它前面创建了一个小层来处理这个逻辑,并一次丢弃一个服务器,以确保它处理所有场景,以便我们的应用程序继续工作,但只是稍慢一点。

答案 1 :(得分:1)

在与Microsoft打开票证后,我们将其缩小为具有静态DataCacheFactory对象。

public class AppFabricCacheProvider : ICacheProvider
{
    private static readonly object Locker = new object();
    private static AppFabricCacheProvider _instance;
    private static DataCache _cache;

    private AppFabricCacheProvider()
    {
    }

    public static AppFabricCacheProvider GetInstance()
    {
        lock (Locker)
        {
            if (_instance == null)
            {
                _instance = new AppFabricCacheProvider();
                var factory = new DataCacheFactory();
                _cache = factory.GetCache("AdMatter");
            }
        }
        return _instance;
    }
    ...
}

查看AppFabric中的tracelog,客户端仍在尝试连接所有主机而不处理主机关闭。重置客户端上的IIS会强制创建新的DataCacheFactory(在我们的App_Start中)并停止例外。

MS工程师同意这种方法是最佳实践方式(我们还发现了几篇关于此的文章:见linklink

他们正在继续为我们调查解决方案。与此同时,我们提出了以下临时解决方法,在我们遇到上述异常之一的情况下强制创建新的DataCacheFactory对象。

public class AppFabricCacheProvider : ICacheProvider
{
    private const int RefreshWindowMinutes = -5;

    private static readonly object Locker = new object();
    private static AppFabricCacheProvider _instance;
    private static DataCache _cache;
    private static DateTime _lastRefreshDate;

    private AppFabricCacheProvider()
    {
    }

    public static AppFabricCacheProvider GetInstance()
    {
        lock (Locker)
        {
            if (_instance == null)
            {
                _instance = new AppFabricCacheProvider();
                var factory = new DataCacheFactory();
                _cache = factory.GetCache("AdMatter");
                _lastRefreshDate = DateTime.UtcNow;
            }
        }
        return _instance;
    }

    private static void ForceRefresh()
    {
        lock (Locker)
        {
            if (_instance != null && DateTime.UtcNow.AddMinutes(RefreshWindowMinutes) > _lastRefreshDate)
            {
                var factory = new DataCacheFactory();
                _cache = factory.GetCache("AdMatter");
                _lastRefreshDate = DateTime.UtcNow;
            }
        }
    }

    ...

    public T Put<T>(string key, T value)
    {
        try
        {
            _cache.Put(key, value);
        }
        catch (SocketException)
        {
            ForceRefresh();
            _cache.Put(key, value);
        }
        return value;
    }

当我们了解更多信息时,会更新此帖子。