为原子数据结构配置和使用Geode区域和锁

时间:2016-11-28 17:12:21

标签: apache geode

我目前正在使用Spring Boot Starter 1.4.2.RELEASE和Geode Core 1.0.0 - 通过Maven孵化,针对由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 - 当前文档警告不要使用锁定区域条目。

细粒度锁定的用例是否支持原子增量longs的“map”支持的用例,如果是,如何正确配置它?

3 个答案:

答案 0 :(得分: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

中定义范围

答案 1 :(得分:1)

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

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

如果2个(或更多)客户端在同一区域和密钥上调用此API,则只有一个成功放置,这由返回值null指示。该客户端被认为持有锁。其他客户将获得获胜者提出的对象。这很方便,因为如果您“放置”的值包含客户端的唯一标识符,那么输家甚至知道谁持有锁。

区域条目代表锁具有其他好处。锁存在故障中。您可以使用区域到期来设置锁定的最长租约时间,并且如前所述,可以很容易地判断谁持有锁定。

希望这有帮助。

答案 2 :(得分:1)

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

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

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

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

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