简体   繁体   English

Web-farm中的分布​​式临界区

[英]Distributed critical section in web-farm

I have about 50 web-sites, load-balanced across 5 web-servers. 我有大约50个网站,在5个网络服务器上进行负载均衡。 They all use Enterprise Library Caching, and access the same Caching database. 它们都使用Enterprise Library Caching,并访问相同的Caching数据库。 The items in the Caching database are refreshed every few hours, using an ICacheItemRefreshAction implementation. 使用ICacheItemRefreshAction实现,每隔几个小时刷新缓存数据库中的项目。

I want to guarantee that only one web-site ever refreshes the cache, by putting the refresh code in a critical section . 我想通过将刷新代码放在关键部分来保证只有一个网站刷新缓存。

  • If the web-sites were running in a single app-pool on a single server, I could use a lock() 如果网站在单个服务器上的单个应用程序池中运行,我可以使用锁()

  • If the web-sites were running in separate app-pools on a single server, I could use a Mutex . 如果网站在单个服务器上的单独应用程序池中运行,我可以使用互斥锁

However, these will not ensure the critical section across multiple web-servers. 但是,这些不能确保跨多个Web服务器的关键部分。

Currently, I am creating a new key in the caching database to act as a mutex. 目前,我正在缓存数据库中创建一个新密钥来充当互斥锁。 This will generally work, but I can see a slim chance that 2 processes could enter the critical section. 通常会起作用,但我可以看到2个进程可能进入关键部分的可能性很小。

public class TakeLongTimeToRefresh : ICacheItemRefreshAction
{
    #region ICacheItemRefreshAction Members

    public void Refresh(string removedKey, object expiredValue, CacheItemRemovedReason removalReason)
    {
        string lockKey = "lockKey";
        ICacheManager cm = CacheFactory.GetCacheManager();

        if (!cm.Contains(lockKey))
        {
            Debug.WriteLine("Entering critical section");
            // Add a lock-key which will never expire for synchronisation.
            // I can see a small window of opportunity for another process to enter
            // the critical section here...
            cm.Add(lockKey, lockKey, 
                   CacheItemPriority.NotRemovable, null, 
                   new NeverExpired());

            object newValue = SomeLengthyWebserviceCall();
            cm.Remove(removedKey);
            Utilities.AddToCache(removedKey, newValue);

            cm.Remove("lockkey");
        }
    }
}

Is there a way of having a guaranteed critical section to ensure I don't call the web-service twice? 有没有一种方法可以保证关键部分,以确保我不会两次调用Web服务?

EDIT I should add that I can't use a shared file, as the deployment policies will prevent it. 编辑我应该补充一点,我不能使用共享文件,因为部署策略会阻止它。

StackOverflow references: StackOverflow引用:

You have to involve some external lock acquisiton common to all. 你必须要涉及一些共同的外部锁定。 For example, a table t in SQL with one row and one lock field where you will acquire a lock with: 例如,SQL中的表t包含一行和一个锁定字段,您将获得锁定:

set transaction isolation serializable;
update t set lock = 1 where lock = 0;

check rows affected and if its 1 you have the lock, release it by updating lock to 0. This essentially piggybacks on SQLServer's row lock, if two start at the same time only one will gain U lock after S lock, the other one will block and subsequently return 0 rows affected (since the first transaction flipped it to 1). 检查受影响的行,如果它有1你有锁,则通过将lock更新为0来释放它。这基本上搭载SQLServer的行锁定,如果两个同时启动,只有一个在S锁定后获得U锁定,另一个将阻塞然后返回受影响的0行(因为第一个事务将其翻转为1)。

I suggest you move the logic for creating/returning a lock handle to database and combine them and this will guarantee it is always one process having the lock. 我建议你移动创建/返​​回锁定句柄的逻辑到数据库并组合它们,这将保证它始终是一个具有锁定的进程。

So the database could have a stored procedure which you ask for a lock, and either it will return empty result (unsuccessful) or will create a record and return it. 因此,数据库可能有一个存储过程,您要求锁定,并且它将返回空结果(不成功)或将创建一个记录并返回它。

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

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