第 11 章 使用集群计数器
Data Grid 提供记录对象的计数,并在集群中的所有节点之间分布的计数器。
11.1. 集群计数器 复制链接链接已复制到粘贴板!
集群计数器 是在 Data Grid 集群中所有节点分布和共享的计数器。计数器可以具有不同的一致性级别:强和弱。
虽然强/弱一致性计数器具有单独的接口,但支持更新其值,但在更新其值时返回当前值,并提供事件。在本文档中提供了详细信息,以帮助您选择最适合您的用例。
11.1.1. 安装和配置 复制链接链接已复制到粘贴板!
要开始使用计数器,您需要在 Maven pom.xml
文件中添加依赖项:
pom.xml
<dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-clustered-counter</artifactId> </dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-clustered-counter</artifactId>
</dependency>
计数器可以通过本文档中详述的 CounterManager
接口配置 Data Grid 配置文件或按需。当 EmbeddedCacheManager
启动时,在启动时创建在 Data Grid 配置文件中配置的计数器。这些计数器可立即启动,它们在所有集群节点中可用。
configuration.xml
或以编程方式在 GlobalConfigurationBuilder
中:
另一方面,可以在初始化 EmbeddedCacheManager
后随时配置计数器。
CounterConfiguration
是不可变的,可以被重复使用。
如果计数器配置成功或为 false
,则方法 defineCounter ()
将返回 true
。但是,如果配置无效,则方法会抛出 CounterConfigurationException
。要查找是否已定义计数器,请使用 method isDefined ()
。
CounterManager manager = ... if (!manager.isDefined("someCounter")) { manager.define("someCounter", ...); }
CounterManager manager = ...
if (!manager.isDefined("someCounter")) {
manager.define("someCounter", ...);
}
11.1.1.1. 列出计数器名称 复制链接链接已复制到粘贴板!
要列出定义的所有计数器,method CounterManager.getCounterNames ()
返回在集群范围创建的所有计数器名称的集合。
11.1.2. CounterManager 接口 复制链接链接已复制到粘贴板!
CounterManager
接口是定义、检索和删除计数器的入口点。
嵌入式部署
CounterManager
会自动侦听 EmbeddedCacheManager
创建,然后为每个 EmbeddedCacheManager
执行实例的注册。它启动存储计数器状态所需的缓存并配置默认计数器。
检索 CounterManager
非常简单,就像调用 EmbeddedCounterManagerFactory.asCounterManager (EmbeddedCacheManager)
,如下例所示:
// create or obtain your EmbeddedCacheManager EmbeddedCacheManager manager = ...; // retrieve the CounterManager CounterManager counterManager = EmbeddedCounterManagerFactory.asCounterManager(manager);
// create or obtain your EmbeddedCacheManager
EmbeddedCacheManager manager = ...;
// retrieve the CounterManager
CounterManager counterManager = EmbeddedCounterManagerFactory.asCounterManager(manager);
服务器部署
对于 Hot Rod 客户端,CounterManager
在 RemoteCacheManager 中注册,并可以检索,如下所示:
// create or obtain your RemoteCacheManager RemoteCacheManager manager = ...; // retrieve the CounterManager CounterManager counterManager = RemoteCounterManagerFactory.asCounterManager(manager);
// create or obtain your RemoteCacheManager
RemoteCacheManager manager = ...;
// retrieve the CounterManager
CounterManager counterManager = RemoteCounterManagerFactory.asCounterManager(manager);
11.1.2.1. 通过 CounterManager 删除计数器 复制链接链接已复制到粘贴板!
通过 Strong/WeakCounter
接口和 CounterManager
删除计数器之间有一个区别。CounterManager.remove (String)
从集群中删除计数器值,并删除本地计数器实例中计数器中注册的所有监听程序。另外,计数器实例不再重复使用,它可能会返回无效的结果。
在另一端,Strong/WeakCounter
删除仅移除计数器值。实例仍然可以重复使用,监听器仍然可以正常工作。
如果在移除后访问计数器,则会重新创建计数器。
11.1.3. Counter 复制链接链接已复制到粘贴板!
计数器可以很强大(StrongCounter
)或弱一致性(WeakCounter
),它们都由一个名称来标识。它们有一个特定的接口,但它们共享一些逻辑,即它们都是异步的(每个操作返回 CompletableFuture
),提供更新事件,并可重置为其初始值。
如果您不想使用 async API,可以通过 sync ()
方法返回同步计数器。API 相同,但没有 CompletableFuture
返回值。
两种方法对这两个接口是通用的:
-
getName ()
返回计数器名称(identifier)。 -
getValue ()
返回当前计数器的值。 -
reset ()
允许将计数器的值重置为其初始值。 -
addListener ()
注册监听程序以接收更新事件。有关它的更多详细信息,请在 Notification 和 Events 部分中。 -
getConfiguration ()
返回计数器使用的配置。 -
remove ()
从集群中移除计数器值。仍可使用实例,并保留监听器。 -
sync ()
创建一个同步计数器。
如果在移除后访问计数器,则会重新创建计数器。
11.1.3.1. StrongCounter 接口:当一致性或绑定很重要时。 复制链接链接已复制到粘贴板!
强大的计数器提供使用存储在 Data Grid 缓存中的单个密钥来提供所需的一致性。所有更新都在密钥锁定下执行,以更新其值。另一方面,读取不会获取任何锁定,并读取当前的值。此外,使用此方案时,它允许绑定计数器值并提供原子操作,如 compare-and-set/swap。
可以使用 get
方法从 StrongCounter
()CounterManager
检索 StrongCounter。例如:
CounterManager counterManager = ... StrongCounter aCounter = counterManager.getStrongCounter("my-counter");
CounterManager counterManager = ...
StrongCounter aCounter = counterManager.getStrongCounter("my-counter");
由于每个操作都将达到单个键,因此 StrongCounter
具有较高的竞争率。
StrongCounter
接口添加以下方法:
-
incrementAndGet ()
逐一递增计数器并返回新值。 -
decrementAndGet ()
将计数器减少一次,并返回新值。 -
addAndGet ()
将 delta 添加到计数器的值中,并返回新值。 -
compareAndSet ()
和compareAndSwap ()
以原子方式设置计数器的值(如果当前值是预期的)。
当完成 CompletableFuture
时,操作被视为已完成。
compare-and-set 和 compare-and-swap 之间的区别在于,如果操作成功,则前者会返回 true,稍后返回上一个值。如果返回值与预期相同,则 compare-and-swap 可以成功。
11.1.3.1.1. 已绑定的 StrongCounter 复制链接链接已复制到粘贴板!
绑定后,当上述所有更新方法达到较低或上限时,所有更新方法都会抛出 CounterOutOfBoundsException
。例外有以下方法检查到达哪个侧绑定:
public boolean isUpperBoundReached(); public boolean isLowerBoundReached();
public boolean isUpperBoundReached();
public boolean isLowerBoundReached();
11.1.3.1.2. 使用案例 复制链接链接已复制到粘贴板!
在以下用例中,强计数器更适合:
- 在每次更新后需要计数器的值(例如,集群范围 ID 生成器或序列)
- 当需要有界计数器时(例如,速率限制器)
11.1.3.1.3. 使用示例 复制链接链接已复制到粘贴板!
以下是使用绑定计数器的另一个示例:
compare-and-set 与 Compare-and-swap 示例:
使用 compare-and-swap,它会保存一个调用计数器调用(counter.getValue ()
)
要将强计数器用作速率限制器,请配置 上限
和 lifespan
参数,如下所示:
lifespan
参数是一个实验性功能,可能会在以后的版本中删除。
11.1.3.2. WeakCounter 接口:何时需要速度 复制链接链接已复制到粘贴板!
WeakCounter
将计数器的值存储在 Data Grid 缓存中的多个键中。创建的密钥数量由 concurrency-level
属性配置。每个键存储计数器值的部分状态,并可同时更新。与 StrongCounter
相比,它的主要优点是缓存中较低争用。另一方面,其值的读取更为昂贵,不允许绑定。
reset 操作应谨慎处理。它不是 原子的,它会生成中间值。这些值可由读取操作以及注册的任何监听程序看到。
可以使用 get
方法从 WeakCounter
()CounterManager
检索 WeakCounter。例如:
CounterManager counterManager = ... StrongCounter aCounter = counterManager.getWeakCounter("my-counter);
CounterManager counterManager = ...
StrongCounter aCounter = counterManager.getWeakCounter("my-counter);
11.1.3.2.1. 弱计数接口 复制链接链接已复制到粘贴板!
WeakCounter
添加以下方法:
它们与 'StrongCounter's 类似,但它们不会返回新值。
11.1.3.2.2. 使用案例 复制链接链接已复制到粘贴板!
当不需要更新操作,或者不需要计数器的值时,弱计数器最适合的情况。收集统计信息是此类用例的良好示例。
11.1.3.2.3. 例子 复制链接链接已复制到粘贴板!
以下是弱计数器用法的示例。
11.1.4. 通知和事件 复制链接链接已复制到粘贴板!
强和弱计数器都支持监听器接收其更新事件。侦听器必须实现 CounterListener
,并可通过以下方法注册:
<T extends CounterListener> Handle<T> addListener(T listener);
<T extends CounterListener> Handle<T> addListener(T listener);
CounterListener
有以下接口:
public interface CounterListener { void onUpdate(CounterEvent entry); }
public interface CounterListener {
void onUpdate(CounterEvent entry);
}
返回的 Handle
对象具有在不再需要时删除 CounterListener
的主要目标。另外,它还允许访问它处理的 CounterListener
实例。它有以下接口:
public interface Handle<T extends CounterListener> { T getCounterListener(); void remove(); }
public interface Handle<T extends CounterListener> {
T getCounterListener();
void remove();
}
最后,CounterEvent
具有之前和当前的值和状态。它有以下接口:
对于未绑定的强大计数器和弱计数器,状态为 State.VALID
。state.LOWER_BOUND_REACHED
和 State.UPPER_BOUND_REACHED
仅对有界强计数器有效。
弱计数器 reset ()
操作将触发带有中间值的多个通知。