当前位置:  开发笔记 > 编程语言 > 正文

使用Windows Server AppFabric缓存的分布式锁服务

如何解决《使用WindowsServerAppFabric缓存的分布式锁服务》经验,为你挑选了1个好方法。

我有一个在Windows Server AppFabric SDK中找到的Microsoft.ApplicationServer.Caching.DataCache对象的扩展方法,如下所示:

using System;
using System.Collections.Generic;
using Microsoft.ApplicationServer.Caching;

namespace Caching
{
    public static class CacheExtensions
    {
        private static Dictionary locks = new Dictionary();

        public static T Fetch(this DataCache @this, string key, Func func)
        {
            return @this.Fetch(key, func, TimeSpan.FromSeconds(30));
        }

        public static T Fetch(this DataCache @this, string key, Func func, TimeSpan timeout)
        {
            var result = @this.Get(key);

            if (result == null)
            {
                lock (GetLock(key))
                {
                    result = @this.Get(key);

                    if (result == null)
                    {
                        result = func();

                        if (result != null)
                        {
                            @this.Put(key, result, timeout);
                        }
                    }
                }
            }

            return (T)result;
        }

        private static object GetLock(string key)
        {
            object @lock = null;

            if (!locks.TryGetValue(key, out @lock))
            {
                lock (locks)
                {
                    if (!locks.TryGetValue(key, out @lock))
                    {
                        @lock = new object();
                        locks.Add(key, @lock);
                    }
                }
            }

            return @lock;
        }
    }
}

目的是让开发人员编写代码,说"先通过尝试缓存来获取一些数据.如果在缓存中不可用,则执行指定的函数,将结果放入缓存中以供下一个调用者使用,然后返回结果".像这样:

var data = dataCache.Fetch("key", () => SomeLongRunningOperation());

执行潜在长时间运行的函数的锁定限制调用单个线程,但仅限于同一台机器上的单个进程.您将如何扩展此模式以使锁定分布以防止多个进程/机器立即执行该函数?



1> PhilPursglov..:

AppFabric拥有自己的分布式锁定机制,您可以通过GetAndLock/PutAndUnlock一系列方法访问它.如果您的项目已锁定,则正常Get调用仍将成功并返回最后一个值,但进一步GetAndLock调用将抛出异常.在您的客户端第一次请求缓存对象的情况下,您仍然可以锁定密钥,即使它尚不存在(它更像是一个预留而不是一个实体锁).

public static T Fetch(this DataCache @this, string key, Func func, TimeSpan timeout)
{
    var result = @this.Get(key);

    if (result == null)
    (
        DataCacheLockHandle handle;
        // We need a timespan to allow func time to run
        TimeSpan funcTimespan = New TimeSpan(0,1,0);

        try
        {
            // Lock the key
            // If something goes wrong here it will unlock at the end of funcTimespan
            var result = @this.GetAndLock(key, funcTimespan, handle);

            if (result == null)
            {
                // Still no value so go and run func
                result = func();

                @this.PutAndUnlock(key, result, handle, timeout);
            }
            else
            {
                // There's a value now so we'll unlock the key and reset it's timeout
                @this.Unlock(key, handle, timeout);
            }
        }
        catch (DataCacheException ex)
        {
            if (ex.ErrorCode == DataCacheErrorCode.ObjectLocked)
            {
                // Another process has locked the key so func must be running right now
                // We'll return null to the client
                result = null;
            }
        }

        if (result == null)
        {
            return null;
        }
        else
        {
            return (T)result;
        }
    )
}

推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有