我目前正在使用Spring Boot Starter 1.4.2。RELEASE和Geode Core 1.0.0-通过Maven孵化,针对由Geode定位器和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
使用how-to at:http://geode.apache.org/docs/guide/getting_started/15_minute_quickstart_gfsh.html很容易在我的两个节点配置上看到持久性和复制的功能。
然而,上面分布式计数器中的锁定不会导致任何错误——但是当两个进程试图获取同一个“键”上的锁时,它就不起作用了——第二个进程不会被阻止获取锁。在Gemfire论坛上有一个早期的代码示例,它使用分布式锁服务——当前的留档警告不要将其用于锁定区域条目。
细粒度锁定支持原子增量long的“map”的用例是否是支持的用例,如果是,如何适当配置?
这些分布式锁的区域API仅支持具有全局作用域的区域。这些分布式锁仅在集群中具有分布式锁服务名称(即区域的完整路径名称)内的锁定作用域。例如,如果全局区域存在于服务器上,则该区域的分布式锁只能在该服务器或该集群中的其他服务器上使用。
缓存客户端最初是分层缓存的一种形式,这意味着一个集群可以作为客户端连接到另一个集群。如果客户端创建了一个实际的全局区域,那么客户端中的分布式锁将仅在该客户端及其所属集群中具有范围。分布式锁无论如何都不会传播到此类客户端连接的服务器。
正确的方法是在服务器上存在的全局区域上编写利用分布式锁API的函数。您将把这些函数部署到服务器,然后从客户端在服务器上调用它们。
通常,避免使用Global区域,因为每个单独的put都会在Server的集群中获取一个分布式锁,这是一个非常昂贵的操作。
您可以对非全局区域执行类似的操作,方法是在服务器上创建自定义分布式锁服务,然后使用函数锁定/解锁需要在该集群中全局同步的代码。在这种情况下,区域上的分布式锁和区域分布式锁API(对于非全局区域)将不可用,所有锁定都必须在服务器上使用分布式锁服务API的函数中完成。
这仅适用于服务器端代码(例如在Functions中)。
从客户端代码中,您可以使用"region. putIfAbsend"实现锁定语义学。
如果2个(或更多)客户端在同一个区域和键上调用此API,则只有一个客户端将成功放置,这由返回值null表示。这个客户端被认为持有锁。其他客户端将获得获胜者放置的对象。这很方便,因为如果您“放置”的值包含客户端的唯一标识符,那么输家甚至知道谁持有锁。
使用区域条目表示锁还有其他好处。锁可以在故障中存活。您可以使用区域过期来设置锁的最长租用时间,并且如前所述,很容易判断谁持有锁。
希望这有帮助。
似乎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>
客户端配置也不需要在区域属性中定义范围