InfinispanClusterManager
是基于 Infinispan 实现。
This implementation is packaged inside:
Maven (在 pom.xml
文件中):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-infinispan</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (在 build.gradle
文件中):
compile 'io.vertx:vertx-infinispan:3.6.2'
Vert.x 集群管理器包含以下几个功能:
发现并管理集群中的节点
管理集群端的主题订阅清单(这样就可以轻松得知集群中的那些节点订阅了那些 EventBus 地址)
分布式 Map 支持
分布式锁
分布式计数器
Vert.x 集群器并不处理节点之间的通信,在 Vert.x 中节点中的通信是直接由 TCP 链接处理的。
Vert.x 能够从 classpath 路径的 jar 自动检测并使用出 ClusterManager
的实现。不过需要确保在 classpath 没有其他的 ClusterManager
实现。
If you want clustering with this cluster manager in your Vert.x Maven or Gradle project then just add a dependency to
the artifact: io.vertx:vertx-infinispan:3.6.2
in your project.
If the jar is on your classpath as above then Vert.x will automatically detect this and use it as the cluster manager. Please make sure you don’t have any other cluster managers on your classpath or Vert.x might choose the wrong one.
You can also specify the cluster manager programmatically if you are embedding Vert.x by specifying it on the options when you are creating your Vert.x instance, for example:
ClusterManager mgr = new InfinispanClusterManager();
VertxOptions options = new VertxOptions().setClusterManager(mgr);
Vertx.clusteredVertx(options, res -> {
if (res.succeeded()) {
Vertx vertx = res.result();
} else {
// failed!
}
});
The default cluster manager configuration can be modified with infinispan.xml
and/or jgroups.xml
files.
The former configures the data grid, the latter group management and member discovery.
如果要覆盖其中任意一个配置文件,可以在 classpath
中添加对应的文件。
如果想在 fat jar 中内嵌相应的配置文件 ,此文件必须在 fat jar 的根目录中。
如果此文件是一个外部文件,则必须将其添加至 classpath
中。举个例子:
# infinispan.xml 和/或 jgroups.xml 在当前路径中
java -jar my-app.jar -cp . -cluster
# infinispan.xml 和/或 jgroups.xml 在 conf 目录中
java -jar my-app.jar -cp conf -cluster
还有一种方式来覆盖默认的配置文件,那就是利用系统配置 vertx.infinispan.config
和/或 vertx.jgroups.config
来实现:
# 指定一个外部文件为自定义配置文件
java -Dvertx.infinispan.config=./config/my-infinispan.xml -jar ... -cluster
# 从 classpath 中加载一个文件为自定义配置文件
java -Dvertx.infinispan.config=my/package/config/my-infinispan.xml -jar ... -cluster
The cluster manager will search for the file in classpath first, and fallback to the filesystem.
The system properties, when present, override any infinispan.xml
or jgroups.xml
on the classpath.
The xml files are Infinispan and JGroups configuration files and are described in detail in the documentation on the Infinispan and JGroups web-sites.
Important
|
if a jgroups.xml file is on the classpath or if you set the vertx.jgroups.config system property,
it will override any JGroups stack-file path defined in the Infinispan configuration file.
|
The default JGroups configuration uses multicast for discovery and TCP for group management. Make sure multicast is enabled on your network for this to work.
For full documentation on how to configure the transport differently or use a different transport please consult the Infinispan / JGroups documentations.
开发者可以通过 DefaultCacheManager
来复用已经存在的 cache manager
。
ClusterManager mgr = new InfinispanClusterManager(cacheManager);
VertxOptions options = new VertxOptions().setClusterManager(mgr);
Vertx.clusteredVertx(options, res -> {
if (res.succeeded()) {
Vertx vertx = res.result();
} else {
// failed!
}
});
在这种情况下,Vert.x 并不是 cache manager
的所有者,因此不能在关闭 Vert.x 时,停止 Infinispan 。
需要注意的是,需要通过如下配置来自定义 Infinispan 实例:
<cache-container default-cache="distributed-cache">
<distributed-cache name="distributed-cache"/>
<distributed-cache name="__vertx.subs"/>
<replicated-cache name="__vertx.haInfo"/>
<distributed-cache-configuration name="__vertx.distributed.cache.configuration"/>
</cache-container>
On Kubernetes, JGroups should be configured to use the KUBE_PING
protocol.
First, add the org.infinispan:infinispan-cloud:${infinispan.version}
and org.jgroups.kubernetes:jgroups-kubernetes:${jgroups.kubernetes.version}
dependencies to your project.
With Maven it looks like:
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-cloud</artifactId>
<version>${infinispan.version}</version>
</dependency>
<dependency>
<groupId>org.jgroups.kubernetes</groupId>
<artifactId>jgroups-kubernetes</artifactId>
<version>${jgroups.kubernetes.version}</version>
</dependency>
<dependency>
Then, set the vertx.jgroups.config
system property to default-configs/default-jgroups-kubernetes.xml
.
-Dvertx.jgroups.config=default-configs/default-jgroups-kubernetes.xml
This JGroups stack file is located in the infinispan-cloud
JAR and preconfigured for Kubernetes.
Also, set the project namespace as the scope for discovery.
ENV KUBERNETES_NAMESPACE my-project
Optionnaly, to create separate clusters in the same namespace, add a labels selector:
ENV KUBERNETES_LABELS my-label=my-value
Then, force usage of IPv4 in the JVM with a system property.
-Djava.net.preferIPv4Stack=true
Eventually, the setup needs a service account.
oc policy add-role-to-user view system:serviceaccount:$(oc project -q):default -n $(oc project -q)
Further configuration details are available on the Kubernetes discovery protocol for JGroups repository.
During rolling udpates, the Infinispan team recommends to replace pods one by one.
To do so, we must configure Kubernetes to:
never start more than one new pod at once
forbid more than one unavailable pod during the process
spec:
strategy:
type: Rolling
rollingParams:
updatePeriodSeconds: 10
intervalSeconds: 20
timeoutSeconds: 600
maxUnavailable: 1 (1)
maxSurge: 1 (2)
the maximum number of pods that can be unavailable during the update process
the maximum number of pods that can be created over the desired number of pods
Also, pod readiness probe must take cluster health into account.
Indeed, when a node joins or leaves the cluster, Infinispan rebalances the data across members, and it is better to avoid concurrent state transfers.
When the state transfer completes, the cluster health goes back to HEALTHY
.
The readiness probe can be implemented with Vert.x Health Checks:
Handler<Future<Status>> procedure = ClusterHealthCheck.createProcedure(vertx, true);
HealthChecks checks = HealthChecks.create(vertx).register("cluster-health", procedure);
After creation, it can be exposed over HTTP with a Vert.x Web router handler:
Router router = Router.router(vertx);
router.get("/readiness").handler(HealthCheckHandler.createWithHealthChecks(checks));
确认 JVM 在启动时 设置了下面两项配置:
-Djava.net.preferIPv4Stack=true -Djgroups.tcp.address=NON_LOOPBACK
通过上述两项系统配置,JGroups 才能正确的挑选出 Docker 创建的虚拟网络接口。
If the default multicast discovery configuration is not working here are some common causes:
MacOS 默认禁用组播。Google一下启用组播。
如果机器上有多个网络接口(也有可能是在运行 VPN 的情况下),那么 JGroups 很有可能是使用了错误的网络接口。
为了确保 JGroups 使用正确的网络接口,在配置文件中将 bind_addr
设置为指定IP地址。 例如:
<TCP bind_addr="192.168.1.20"
...
/>
<MPING bind_addr="192.168.1.20"
...
/>
另外,如果需要修改打包好的 jgoups.xml
文件,可以通过设置 jgroups.tcp.address
系统变量来达到目的
-Djgroups.tcp.address=192.168.1.20
当运行集群模式时,需要确保 Vert.x 使用正确的网络接口。
当通过命令行模式时,可以设置 cluster-host
参数:
vertx run myverticle.js -cluster -cluster-host your-ip-address
其中 your-ip-address
必须与 JGroup 中的配置保持一致。
当通过编程模式使用 Vert.x 时,可以调用方法
setClusterHost
来设置参数
VPN软件通常通过创建不支持多播虚拟网络接口来进行工作。如果有一个 VPN 运行,如果 JGroups与 Vert.x 不正确配置的话,VPN接口将被选择,而不是正确的接口。
所以,如果你运行在 VPN 环境中,参考上述章节,设置正确的网络接口。
在某些情况下,因为特殊的运行环境,可能无法使用组播。在这种情况下,应该配置其他网络传输协议,例如在 TCP 上使用 TCPPING
,在亚马逊云上使用 S3_PING
。
有关 JGroups 更多传输方式,以及如何配置它们,请咨询 JGroups文档 。
如果在 IPv6 地址配置有难点,请通过 java.net.preferIPv4Stack
配置强制使用 IPv4:
-Djava.net.preferIPv4Stack=true
在排除故障时,开启 Infinispan 和 JGroups 日志,将会给予很大的帮助。在 classpath
中添加 vertx-default-jul-logging.properties
文件(默认的JUL记录时),这是一个标准 java.util.loging(JUL) 配置文件。具体配置如下:
org.infinispan.level=INFO org.jgroups.level=INFO
或
java.util.logging.ConsoleHandler.level=INFO java.util.logging.FileHandler.level=INFO
Infinispan 依赖与 JBoss Logging 。JBoss Logging 是一个与多种日志框架的桥接器。
JBoss Logging 能够自动检测使用 classpath 中 JARS 中的日志框架实现。
如果在 classpath 有多种日志框架,可以通过设置系统变量 org.jboss.logging.provider
来指定具体的实现,例子:
-Dorg.jboss.logging.provider=log4j2
更多配置信息请参考 JBoss Logging guide 。
JGroups 默认采用 JDK Logging 实现。同时也支持 log4j 与 log4j2 ,如果相应的 jar 包 在 classpath 中。
如果想查阅更详细的信息,或实现自己的日志后端,请参考 JGroups 日志文档
The InfinispanAsyncMap
API allows to retrieve keys, values and entries as streams.
This can be useful if you need to go through the content of a large map for bulk processing.
InfinispanAsyncMap<K, V> infinispanAsyncMap = InfinispanAsyncMap.unwrap(asyncMap);
ReadStream<K> keyStream = infinispanAsyncMap.keyStream();
ReadStream<V> valueStream = infinispanAsyncMap.valueStream();
ReadStream<Map.Entry<K, V>> entryReadStream = infinispanAsyncMap.entryStream();