3

我目前正在通过 Maven 使用 Spring Boot Starter 1.4.2.RELEASE 和 Geode Core 1.0.0-incubating,针对由 Geode Locator 和 2 个缓存节点组成的本地 Docker 配置。

我在这里查阅了文档:

http://geode.apache.org/docs/guide/developing/distributed_regions/locking_in_global_regions.html

我已经配置了一个 cache.xml 文件以与我的应用程序一起使用,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<client-cache
        xmlns="http://geode.apache.org/schema/cache"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://geode.apache.org/schema/cache
                        http://geode.apache.org/schema/cache/cache-1.0.xsd"
        version="1.0">
    <pool name="serverPool">
        <locator host="localhost" port="10334"/>
    </pool>
    <region name="testRegion" refid="CACHING_PROXY">
        <region-attributes pool-name="serverPool"
                scope="global"/>
    </region>
</client-cache>

在我的 Application.java 中,我通过以下方式将该区域公开为 bean:

@SpringBootApplication
public class Application {

    @Bean
    ClientCache cache() {
        return new ClientCacheFactory()
                .create();
    }

    @Bean
    Region<String, Integer> testRegion(final ClientCache cache) {
        return cache.<String, Integer>getRegion("testRegion");
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

在我的“服务”DistributedCounter.java 中:

@Service
public class DistributedCounter {

@Autowired
private Region<String, Integer> testRegion;

/**
 * Using fine grain lock on modifier.
 * @param counterKey {@link String} containing the key whose value should be incremented.
 */
public void incrementCounter(String counterKey) {
    if(testRegion.getDistributedLock(counterKey).tryLock()) {
        try {
            Integer old = testRegion.get(counterKey);
            if(old == null) {
                old = 0;
            }
            testRegion.put(counterKey, old + 1);
        } finally {
            testRegion.getDistributedLock(counterKey).unlock();
        }
    }
}

我已经使用 gfsh 配置了一个名为 /testRegion 的区域 - 但是没有选项表明它的类型应该是“GLOBAL”,只有各种其他选项可用 - 理想情况下,这应该是一个持久的和复制的缓存,尽管如此以下命令:

create region --name=/testRegion --type=REPLICATE_PERSISTENT

使用方法:http: //geode.apache.org/docs/guide/getting_started/15_minute_quickstart_gfsh.html很容易在我的两个节点配置上看到持久性和复制的功能。

但是,上面的 DistributedCounter 中的锁定不会导致任何错误 - 但当两个进程尝试获取同一个“键”上的锁时它只是不起作用 - 第二个进程不会被阻止获取锁。Gemfire 论坛有一个较早的代码示例,它使用 DistributedLockService - 当前文档警告不要将其用于锁定区域条目。

支持原子增量长的“映射”的细粒度锁定用例是否是受支持的用例,如果是,如何适当地配置它?

4

3 回答 3

2

这仅适用于服务器端代码(例如在函数中)。

从客户端代码中,您可以使用“region.putIfAbsent”实现锁定语义。

如果有 2 个(或多个)客户端在同一个 region 和 key 上调用这个 API,只有一个会成功 put,返回值为 null。该客户端被认为持有锁。其他客户将获得获胜者放置的对象。这很方便,因为如果您“放置”的值包含客户端的唯一标识符,那么失败者甚至知道谁持有锁。

让一个区域条目代表一个锁还有其他很好的好处。锁在故障中仍然存在。您可以使用区域到期来设置锁的最长租用时间,并且如前所述,很容易分辨谁持有锁。

希望这可以帮助。

于 2016-11-28T22:44:45.883 回答
2

似乎 GFSH 没有提供提供正确范围 = GLOBAL 的选项。

也许您可以使用 --cache-xml-file 选项启动一个服务器...这将指向一个 cache.xml 文件。

cache.xml 文件应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schema.pivotal.io/gemfire/cache" xsi:schemaLocation="http://schema.pivotal.io/gemfire/cache http://schema.pivotal.io/gemfire/cache/cache-8.1.xsd" version="8.1" lock-lease="120" lock-timeout="60" search-timeout="300" is-server="true" copy-on-read="false">
<cache-server port="0"/>
<region name="testRegion">
    <region-attributes data-policy="persistent-replicate" scope="global"/>
</region>
</cache>

此外,客户端配置不需要在region-attributes中定义范围

于 2016-11-28T23:16:20.053 回答
2

DistributedLock 和 RegionDistributedLock 的 Region API 仅支持具有全局范围的 Region。这些 DistributedLock 仅在集群内具有 DistributedLockService 名称(即 Region 的完整路径名)内的锁定范围。例如,如果全局区域存在于服务器上,则该区域的 DistributedLocks 只能在该服务器或该集群内的其他服务器上使用。

缓存客户端最初是一种分层缓存的形式,这意味着一个集群可以作为客户端连接到另一个集群。如果客户端创建了一个实际的全局区域,那么客户端内的 DistributedLock 将仅在该客户端及其所属的集群内具有范围。DistributedLocks 无论如何都不会传播到此类客户端连接到的服务器。

正确的方法是在服务器上存在的全局区域上编写利用 DistributedLock API 的函数。您将这些功能部署到服务器,然后从客户端在服务器上调用它们。

通常,避免使用全局区域,因为每个单独的 put 都会在服务器集群中获取一个 DistributedLock,这是一个非常昂贵的操作。

您可以通过在服务器上创建自定义 DistributedLockService 来对非全局区域执行类似的操作,然后使用函数来锁定/解锁您需要在该集群中全局同步的代码。在这种情况下,Region 上的 DistributedLock 和 RegionDistributedLock API(对于非全局区域)将不可用,并且所有锁定都必须​​使用 DistributedLockService API 在服务器上的函数内完成。

于 2016-11-29T18:34:19.127 回答