介绍
分布式缓存使您可以利用水平扩展的其他好处,而不会损失本地堆上层提供的低延迟。
-
热点数据在本地缓存,热点数据在更快的层中
-
由一个应用程序实例缓存的数据可用于所有群集成员。
-
群集中有完整数据。
-
可以部署一台或多台镜像服务器来提供HA
要使用Terracotta启用群集,您将必须部署配置了群集缓存存储的Terracotta服务器。为了方便起见,Ehcache 3.1引入了一个可下载的工具包,其中包含Terracotta服务器以及必需的客户端库。
然后,您将需要配置缓存管理器以具有集群功能,以便其管理的缓存可以利用集群存储。最后,应使用群集存储层配置应分发的所有缓存。
聚类概念
在本节中,我们讨论在创建具有集群支持的缓存管理器和缓存之前需要了解的一些Terracotta集群术语和概念。
服务器堆外资源
服务器堆外资源是在服务器上定义的存储资源。缓存可以在这些服务器非堆资源内为其集群层保留一个存储区域。
集群层经理
Ehcache 群集层管理器是服务器端组件,可为缓存管理器提供群集功能。高速缓存管理器连接到它以访问服务器的存储资源,以便在其中定义的高速缓存的群集层可以使用这些资源。服务器端的Ehcache群集层管理器由唯一标识符标识。使用任何给定集群层管理器的唯一标识符,多个缓存管理器可以连接到同一集群层管理器,以共享缓存数据。集群层管理器还负责使用以下不同选项管理缓存的集群层的存储。
专用泳池
专用池是分配给缓存的群集层的固定数量的存储池。专用的存储量直接从服务器的堆外资源分配给这些池。而且此存储空间仅由给定的群集层使用。
共用泳池
共享池也是固定数量的存储池,但是可以由多个缓存的群集层共享。与专用池一样,共享池也从服务器堆外资源中划出。这些共享池中的可用存储是严格共享的。换句话说,任何群集层都无法从共享池中请求固定数量的存储。
通过共享池共享存储并不意味着数据已共享。也就是说,如果两个缓存使用共享池作为它们的集群层,则每个缓存的数据仍然是隔离的,但基础存储是共享的。因此,当达到资源容量并触发逐出时,逐出的映射可能来自共享池的任何群集层。
这是上述概念的图形表示:
启动Terracotta服务器
您可以使用以下配置启动Terracotta服务器。它包含文档其余部分中的所有样本所需的最低配置。
<span style="color:#111111"><span style="color:#333333"><code><?xml version="1.0" encoding="UTF-8"?>
<tc-config xmlns="http://www.terracotta.org/config"
xmlns:ohr="http://www.terracotta.org/config/offheap-resource">
<plugins>
<config>
<ohr:offheap-resources>
<ohr:resource name="primary-server-resource" unit="MB">128</ohr:resource>
<ohr:resource name="secondary-server-resource" unit="MB">96</ohr:resource>
</ohr:offheap-resources>
</config>
</plugins>
</tc-config></code></span></span>
上面的配置定义了两个命名服务器堆外资源:
名为128的堆外资源primary-server-resource 。 | |
另一个secondary-server-resource 具有96 MB容量的堆外资源。 |
本文档的其余部分详细说明了如何配置缓存管理器和缓存以消耗服务器的堆外资源。
假设您有本地可用的集群式Ehcache套件,请首先提取ehcache集群的套件。转到解压缩的目录,然后执行以下start-tc-server脚本,以上述配置启动Terracotta服务器:
在Windows上:
<span style="color:#111111"><span style="color:#333333"><code>cd <path/to/terracotta/kit>/server/bin
start-tc-server.bat -f <path/to/server/config>/tc-config.xml</code></span></span>
在Unix / Mac上:
<span style="color:#111111"><span style="color:#333333"><code>cd <path/to/terracotta/kit>/server/bin
./start-tc-server.sh -f <path/to/server/config>/tc-config.xml</code></span></span>
JAVA_HOME 启动Terracotta服务器时, 您需要指向Java 8安装。 |
检查以下INFO
日志,以确认服务器是否成功启动, Terracotta Server instance has started up as ACTIVE node on 0:0:0:0:0:0:0:0:9410 successfully, and is now ready for work.
创建具有集群功能的缓存管理器
如上一节所述,启动Terracotta服务器后,现在可以继续创建缓存管理器。为了创建具有集群支持的缓存管理器,您将需要提供集群服务配置。这是一个代码示例,显示了如何使用群集服务配置缓存管理器。
<span style="color:#111111"><span style="color:#333333"><code>CacheManagerBuilder<PersistentCacheManager> clusteredCacheManagerBuilder =
CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
.autoCreate(c -> c));
PersistentCacheManager cacheManager = clusteredCacheManagerBuilder.build(true);
cacheManager.close(); </code></span></span>
返回org.ehcache.config.builders.CacheManagerBuilder 实例。 | |
使用ClusteringServiceConfigurationBuilder 静态方法.cluster(URI) 将高速缓存管理器连接到URI 指定的返回群集服务配置构建器实例的指定位置的群集存储。该示例中URI 提供的示例指向Terracotta服务器上名为“ my-application”的群集存储实例(假设该服务器在本地主机和端口9410上运行)。 | |
自动创建群集存储(如果尚不存在)。 | |
返回一个完全初始化的缓存管理器,可用于创建集群缓存。 | |
关闭缓存管理器。 |
缓存管理器配置和服务器端资源的使用
此代码示例演示了使用更广泛的集群服务配置来配置缓存管理器和集群缓存时,上一节中解释的概念的用法:
<span style="color:#111111"><span style="color:#333333"><code>CacheManagerBuilder<PersistentCacheManager> clusteredCacheManagerBuilder =
CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application")).autoCreate(server -> server
.defaultServerResource("primary-server-resource")
.resourcePool("resource-pool-a", 8, MemoryUnit.MB, "secondary-server-resource")
.resourcePool("resource-pool-b", 10, MemoryUnit.MB)))
.withCache("clustered-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredDedicated("primary-server-resource", 8, MemoryUnit.MB))))
.withCache("shared-cache-1", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool-a"))))
.withCache("shared-cache-2", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool-a"))));
PersistentCacheManager cacheManager = clusteredCacheManagerBuilder.build(true);
cacheManager.close();</code></span></span>
defaultServerResource(String) on ClusteringServiceConfigurationBuilder instance设置缓存管理器的默认服务器堆外资源。从该示例中,缓存管理器将其默认服务器堆外资源设置为服务器中的资源primary-server-resource 。 | |
使用指定的名称(resource-pool-a )和大小(28MB)从指定的服务器堆外资源中消耗的缓存管理器添加资源池secondary-server-resource 。高速缓存管理器级别的资源池直接映射到服务器端的共享池。 | |
使用指定的名称(resource-pool-b )和大小(32MB)为缓存管理器添加另一个资源池。由于未显式传递服务器资源标识符,因此该资源池将在步骤3中提供的默认服务器资源中消耗掉。这表明具有集群支持的缓存管理器可以从多个服务器非堆资源中创建多个资源池。 | |
提供要创建的缓存配置。 | |
ClusteredResourcePoolBuilder.clusteredDedicated(String, long, MemoryUnit) 从指定的服务器堆外资源向缓存分配专用的存储池。在此示例中,从分配了32MB的专用池用于集群缓存primary-server-resource 。 | |
ClusteredResourcePoolBuilder.clusteredShared(String) 传递资源池的名称,则指定shared-cache-1 使用同一资源池(resource-pool-a )与其他缓存共享存储资源。 | |
配置另一个shared-cache-2 与共享资源池(resource-pool-a )的缓存()shared-cache-1 。 | |
使用集群缓存创建完全初始化的缓存管理器。 |
当从共享池中为缓存分配了一块内存时,它将永远保留,并且永远不会重新分配给共享池的另一个缓存。 |
Ehcache群集层管理器生命周期
将高速缓存管理器配置为连接到集群层管理器时,有三种可能的连接模式:
<span style="color:#111111"><span style="color:#333333"><code>CacheManagerBuilder<PersistentCacheManager> autoCreate = CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
.autoCreate(server -> server
.resourcePool("resource-pool", 8, MemoryUnit.MB, "primary-server-resource")))
.withCache("clustered-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool"))));
CacheManagerBuilder<PersistentCacheManager> expecting = CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
.expecting(server -> server
.resourcePool("resource-pool", 8, MemoryUnit.MB, "primary-server-resource")))
.withCache("clustered-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool"))));
CacheManagerBuilder<PersistentCacheManager> configless = CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application")))
.withCache("clustered-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool"))));</code></span></span>
在自动创建模式下,如果不存在集群层管理器,则使用提供的配置创建一个。如果存在并且其配置与提供的配置匹配,则建立连接。如果提供的配置不匹配,则缓存管理器将无法初始化。 | |
在预期模式下,如果存在集群层管理器,并且其配置与提供的配置匹配,则建立连接。如果提供的配置不匹配或集群层管理器不存在,则高速缓存管理器将无法初始化。 | |
在无配置模式下,如果存在集群层管理器,则无论其配置如何都将建立连接。如果不存在,则缓存管理器将无法初始化。 |
配置集群缓存
集群存储层
<span style="color:#111111"><span style="color:#333333"><code>CacheConfiguration<Long, String> config = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(2, MemoryUnit.MB)
.with(ClusteredResourcePoolBuilder.clusteredDedicated("primary-server-resource", 8, MemoryUnit.MB)))
.withService(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
.build();
Cache<Long, String> cache = cacheManager.createCache("clustered-cache-tiered", config);
cache.put(42L, "All you need to know!");</code></span></span>
配置缓存的堆层。 | |
使用从服务器的堆外资源配置专用大小的集群层ClusteredResourcePoolBuilder 。 |
等效的XML配置如下:
<span style="color:#111111"><span style="color:#333333"><code><cache alias="clustered-cache-tiered">
<resources>
<heap unit="MB">10</heap>
<tc:clustered-dedicated unit="MB">50</tc:clustered-dedicated>
</resources>
<tc:clustered-store consistency="strong"/>
</cache></code></span></span>
指定用于缓存的堆层。 | |
通过集群名称空间中的定制服务配置来指定用于缓存的集群层。 |
指定一致性级别
Ehcache提供两个级别的一致性:
最终的
此一致性级别指示在返回操作时不能保证写操作的可见性。其他客户端可能仍会看到给定密钥的陈旧值。但是,此一致性级别保证了对于(K, V1)
已更新为的映射(K, V2)
,一旦客户端看到(K, V2)
,它将再也不会看到(K, V1)
。
强大
此一致性级别提供了强大的可见性保证,确保在写操作返回时其他客户端将能够立即对其进行观察。这带来了为此保证所需的写操作的延迟损失。
<span style="color:#111111"><span style="color:#333333"><code>CacheConfiguration<Long, String> config = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredDedicated("primary-server-resource", 2, MemoryUnit.MB)))
.withService(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
.build();
Cache<Long, String> cache = cacheManager.createCache("clustered-cache", config);
cache.put(42L, "All you need to know!"); </code></span></span>
在此处使用强一致性,通过使用其他服务配置来指定一致性级别。 | |
利用上面使用的一致性,put 仅当所有其他客户端的对应映射都无效时,此操作才返回。 |
等效的XML配置如下:
<span style="color:#111111"><span style="color:#333333"><code><cache alias="clustered-cache">
<resources>
<tc:clustered-dedicated unit="MB">50</tc:clustered-dedicated>
</resources>
<tc:clustered-store consistency="strong"/>
</cache></code></span></span>
通过clustered 名称空间中的定制服务配置来指定一致性级别。 |
群集缓存过期
群集缓存的过期工作与例外有关,该例外会Expiry#getExpiryForAccess
尽力处理群集层。它可能不如本地层那么准确。
群集未指定的继承
我们提供了一个选项,该选项允许在缓存管理器内部创建缓存,而不必显式定义其集群层资源池分配。为了使用此功能,必须已经使用共享或专用资源池创建了群集层。
在这种情况下,只需使用clustered()
资源池即可完成集群资源的定义。这实际上意味着未指定,表示您期望它已经存在。然后,它将继承创建集群层时配置的集群资源池。
此选项提供许多好处。主要好处是它允许一个客户端处理群集资源池配置,从而简化了群集配置,然后所有后续客户端都可以继承此配置。此外,它还减少了群集池分配配置错误。更重要的是,规模计算仅需一个人完成,并在一个位置进行更新。因此,任何程序员都可以使用缓存,而不必担心使用匹配的资源池分配。
下面的示例代码显示了如何实现。
<span style="color:#111111"><span style="color:#333333"><code>CacheManagerBuilder<PersistentCacheManager> cacheManagerBuilderAutoCreate = CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
.autoCreate(server -> server
.resourcePool("resource-pool", 8, MemoryUnit.MB, "primary-server-resource")));
PersistentCacheManager cacheManager1 = cacheManagerBuilderAutoCreate.build(false);
cacheManager1.init();
CacheConfiguration<Long, String> cacheConfigDedicated = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clusteredDedicated("primary-server-resource", 8, MemoryUnit.MB)))
.withService(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
.build();
Cache<Long, String> cacheDedicated = cacheManager1.createCache("my-dedicated-cache", cacheConfigDedicated);
CacheManagerBuilder<PersistentCacheManager> cacheManagerBuilderExpecting = CacheManagerBuilder.newCacheManagerBuilder()
.with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
.expecting(server -> server
.resourcePool("resource-pool", 8, MemoryUnit.MB, "primary-server-resource")));
PersistentCacheManager cacheManager2 = cacheManagerBuilderExpecting.build(false);
cacheManager2.init();
CacheConfiguration<Long, String> cacheConfigUnspecified = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.with(ClusteredResourcePoolBuilder.clustered()))
.withService(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
.build();
Cache<Long, String> cacheUnspecified = cacheManager2.createCache("my-dedicated-cache", cacheConfigUnspecified); </code></span></span>
使用自动创建配置第一个缓存管理器 | |
为集群dedicated 资源池构建缓存配置 | |
my-dedicated-cache 使用缓存配置创建缓存 | |
按预期配置第二个缓存管理器(自动创建关闭) | |
为未指定的群集资源池构建缓存配置,该配置将使用先前配置的群集专用资源池。 | |
创建具有相同名称的缓存,my-dedicated-cache 并使用群集未指定的缓存配置 |