我目前正在使用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”支持的用例,如果是,如何正确配置它?
答案 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内完成所有锁定。