使用 Apache Ignite.NET 瘦客户端锁定缓存

Lock cache with Apache Ignite.NET thin client

目前我们使用 Apache Ignite.NET 瘦客户端来缓存不同的数据集。当数据请求到来时,我们检查数据是否已经存储在缓存中,如果没有,则从数据库中请求数据并将其放入缓存中。

如果同时有两个数据请求,我想阻止多个数据库请求。 有没有办法在第一个数据库请求开始之前手动锁定缓存?因此第二个数据请求可以等到第一个请求完成。

我无法解决 isung .NET 并发原语的任务,因为缓存可以被多个客户端实例使用(负载平衡)。

我已经找到了 ICache.Lock(TK key) 方法,但它似乎只锁定缓存中的指定行,并且仅支持自托管模式,不支持 Ignite.NET这个客户。

说明问题的一小段代码:

var key = "cache_key"; 

using (var ignite = Ignition.StartClient(new Core.Client.IgniteClientConfiguration { Host = "127.0.0.1" }))
{
    var cacheNames = ignite.GetCacheNames();
    if (cacheNames.Contains(key))
    {
        return ignite.GetCache<int, Employee>(key).AsCacheQueryable();
    }
    else
    {
        var data = RequestDataFromDatabase();

        var cache = ignite.CreateCache<int, Employee>(new CacheClientConfiguration(
            EmployeeCacheName, new QueryEntity(typeof(int), typeof(Employee))));

        cache.PutAll(data);

        return cache.AsCacheQueryable();
    }
}

瘦客户端没有所需的API。

如果不需要检查单个记录,只需要知道缓存是否可用,可以多次调用CreateCache。它应该抛出一个异常,说明具有特定名称的缓存已经启动以供进一步调用。

try {
    var cache = ignite.CreateCache<int, Employee>(new CacheClientConfiguration(
            EmployeeCacheName, new QueryEntity(typeof(int), typeof(Employee))));
    // Cache created by this call => add data here
} catch (IgniteClientException e)  when (e.Message.Contains("already started")) {
    // Return existing cache, don't add data
}

如果您只需要初始化一次缓存,Alexander 提供了一个很好且简单的解决方案。

如果需要更复杂的同步逻辑,原子缓存操作(PutIfAbsentReplace)通常可以代替锁。例如,我们可以有一个特殊的缓存来跟踪其他缓存的状态:

        var statusCache = Client.GetOrCreateCache<string, string>("status");
        if (statusCache.PutIfAbsent("cache-name", "created"))
        {
            // Just created, add data
            ...
            //
            statusCache.Put("cache-name", "populated");
        }
        else
        {
            // Already exists, wait for data
            while (statusCache["cache-name"] != "populated")
                Thread.Sleep(1000);
        }