本文介绍了Windows Server AppFabric缓存的分布式锁定服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an extension method for the Microsoft.ApplicationServer.Caching.DataCache object found in the Windows Server AppFabric SDK that looks like this:

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

namespace Caching
{
    public static class CacheExtensions
    {
        private static Dictionary<string, object> locks = new Dictionary<string, object>();

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

        public static T Fetch<T>(this DataCache @this, string key, Func<T> 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;
        }
    }
}

目的是让开发人员编写代码,说:首先尝试缓存,以获取一些数据。如果缓存中不可用,请执行指定的功能,将结果放入缓存中供下一个调用方使用,然后返回结果。像这样:

The intent is to let the developer write code that says, "fetch me some data by trying the cache first. if it's not available in cache execute the specified function, put the results in cache for the next caller, then return the results". Like this:

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

锁定限制了对单个线程执行可能长时间运行的函数调用,但仅限于在单个进程上执行同一台机器。您将如何扩展此模式以使锁定分布起来,以防止多个进程/机器一次执行该功能?

The locking limits executing the potentially long running function call to a single thread but only within a single process on the same machine. How would you expand on this pattern to make the locking distributed to prevent multiple processes/machines from executing the function at once?

推荐答案

AppFabric拥有自己的分布式锁定机制,您可以通过 GetAndLock / PutAndUnlock 方法族进行访问。如果您的项目被锁定,则正常的 Get 调用仍将成功并返回最后一个值,但进一步的 GetAndLock 调用将成功抛出异常。如果您的客户端是第一次请求缓存的对象,即使它实际上还不存在,您仍然可以锁定该密钥(它更像是 reservation 而不是固定锁) )。

AppFabric has it's own distributed locking mechanism which you can access through the GetAndLock/PutAndUnlock family of methods. If your item is locked, a normal Get call will still succeed and return the last value, but further GetAndLock calls will throw an Exception. In the case where your client is requesting a cached object for the first time, you can still lock the key even though it doesn't really exist yet (it's kind of more like a reservation than a solid lock).

public static T Fetch<T>(this DataCache @this, string key, Func<T> 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;
        }
    )
}

这篇关于Windows Server AppFabric缓存的分布式锁定服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-27 01:08