|

其他

【Ehcache开发指南】007:Ehcache基础——集群缓存

集群缓存

简介

分布式缓存允许利用水平横向扩展的额外优势,而不会损失本地堆上层提供的低延迟。

  • 热数据在本地缓存,热数据在更快的层中缓存
  • 一个应用程序实例缓存的数据可供所有集群成员使用。
  • 集群中存在全量数据。
  • 可以部署一个或多个镜像服务器以提供高可用性

要使用Terracotta启用集群,必须部署配置有集群缓存存储的Terracotta服务器。为了方便起见,Ehcache 3.1引入了一个可下载的套件,其中包含Terracotta服务器和所需的客户端库。

然后,需要配置缓存管理器,以具有集群功能,以便它管理的缓存可以利用集群存储。最后,任何应分发的缓存都应配置集群存储层。

集群概念

在本节中,将讨论一些Terracotta集群术语和概念,在创建具有集群支持的缓存管理器和缓存之前,您需要了解这些术语和概念。

  • 服务器堆外资源:服务器堆外资源是在服务器上定义的存储资源。缓存可以在这些服务器堆外资源中为其集群层保留存储区域。
  • 集群层管理器:Ehcache集群层管理器是为缓存管理器提供集群功能的服务器端组件。缓存管理器连接到它,以访问服务器的存储资源,以便其中定义的缓存集群层可以使用这些资源。服务器端的Ehcache集群层管理器由唯一标识符标识。使用任何给定集群层管理器的唯一标识符,多个缓存管理器可以连接到同一集群层管理器,以便共享缓存数据。集群层管理器还负责管理集群缓存层的存储,具有以下不同的选项。
  • 专用池:专用池是分配给缓存集群层的固定数量的存储池。专用存储量直接从服务器堆外资源分配给这些池。此存储空间专门由给定的集群层使用。
  • 共享池:共享池也是固定数量的存储池,但可以由多个缓存的集群层共享。与专用池的情况一样,共享池也是从服务器堆外资源中划分出来的。这些共享池中的可用存储是严格共享的。换句话说,任何集群层都不能从共享池要求固定数量的存储。通过共享池共享存储并不意味着数据是共享的。也就是说,如果两个缓存使用共享池作为其集群层,则每个缓存的数据仍然是隔离的,但底层存储是共享的。因此,当达到资源容量并触发驱逐时,驱逐的映射可以来自共享池的任何集群层。

以下是上述概念的图形表示如下图2所示:

启动Terracotta服务器

下面的代码段定义了两个名为主服务器资源和辅助服务器资源的堆外资源,大小分别为128MB和96MB:

深色代码主题
复制
offheap-resources=primary-server-resource:128MB,secondary-server-resource:96MB

这可以在配置文件属性文件中定义,也可以在服务器启动期间定义。

假设在本地拥有集群Ehcache套件,请从提取ehcache-clustered套件开始。更改为解压缩的目录,然后执行位于$KIT_DIR/server/bin下的start-tc-server脚本以启动Terracotta服务器。然后,需要使用位于$KIT_DIR/tools/bin下的配置工具的activate命令激活集群。

检查以下信息日志,以确认服务器是否成功启动:

深色代码主题
复制
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服务器后,如上一节所述,现在可以继续创建缓存管理器。要创建具有集群支持的缓存管理器,需要提供集群服务配置。以下是一个代码示例,它显示了如何使用集群服务配置缓存管理器。

深色代码主题
复制
CacheManagerBuilder<PersistentCacheManager> clusteredCacheManagerBuilder =
    CacheManagerBuilder.newCacheManagerBuilder() //(1)
        .with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application")) //(2)
            .autoCreateOnReconnect(c -> c)); //(3)
PersistentCacheManager cacheManager = clusteredCacheManagerBuilder.build(true); //(4)

cacheManager.close(); //(5)

上述配置:

  • (1)返回org.ehcache.config.builders.CacheManagerBuilder实例。
  • (2)使用ClusteringServiceConfigurationBuilder静态方法.cluster(URI)将缓存管理器连接到返回集群服务配置生成器实例的指定URI处的集群存储。示例中提供的示例URI指向Terracotta服务器上名为“my-app”的集群存储实例(假设服务器运行在localhost和端口9410上)。
  • (3)如果集群存储尚不存在,请自动创建该存储。还允许在重新连接时自动创建,因为集群不是持久的。
  • (4)返回可用于创建集群缓存的完全初始化缓存管理器。
  • (5)关闭缓存管理器。

缓存管理器配置和服务器端资源的使用

此代码示例演示了上一节中解释的概念在使用更广泛的集群服务配置配置配置缓存管理器和集群缓存时的使用:

深色代码主题
复制
CacheManagerBuilder<PersistentCacheManager> clusteredCacheManagerBuilder =
    CacheManagerBuilder.newCacheManagerBuilder()
        .with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application")).autoCreateOnReconnect(server -> server
            .defaultServerResource("primary-server-resource")  //(1)
            .resourcePool("resource-pool-a", 8, MemoryUnit.MB, "secondary-server-resource")  //(2)
            .resourcePool("resource-pool-b", 10, MemoryUnit.MB)))  //(3)
        .withCache("clustered-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,  //(4)
            ResourcePoolsBuilder.newResourcePoolsBuilder()
                .with(ClusteredResourcePoolBuilder.clusteredDedicated("primary-server-resource", 8, MemoryUnit.MB))))  //(5)
        .withCache("shared-cache-1", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
            ResourcePoolsBuilder.newResourcePoolsBuilder()
                .with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool-a"))))  //(6)
        .withCache("shared-cache-2", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
            ResourcePoolsBuilder.newResourcePoolsBuilder()
                .with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool-a"))));  //(7)
PersistentCacheManager cacheManager = clusteredCacheManagerBuilder.build(true);  //(8)

cacheManager.close();

上述配置:

  • (1)ClusteringServiceConfigurationBuilder实例上的defaultServerResource(String)为缓存管理器设置默认的服务器堆外资源。从示例中,缓存管理器将其默认的服务器堆外资源设置为服务器中的primary-server-resource。
  • (2)为缓存管理器添加一个资源池,该资源池具有指定的名称(resource-pool-a)和大小(28MB),从命名的服务器堆外secondary-server-resource资源中消耗。缓存管理器级别的资源池直接映射到服务器端的共享池。
  • (3)使用指定的名称(resource-pool-b)和大小(32MB)为缓存管理器添加另一个资源池。由于服务器资源标识符未显式传递,因此此资源池将从步骤3中提供的默认服务器资源中消耗。这表明,具有集群支持的缓存管理器可以从几个服务器堆外资源中创建多个资源池。
  • (4)提供要创建的缓存配置。
  • (5)ClusteredResourcePoolBuilder.clusteredDedicated(String, long, MemoryUnit)从指定的服务器堆外资源为缓存分配专用存储池。在此示例中,从primary-server-resource为集群缓存分配了一个32MB的专用池。
  • (6)ClusteredResourcePoolBuilder.clusteredShared(String),传递资源池的名称指定 shared-cache-1与使用同一资源池(resource-pool-a)的其他缓存共享存储资源。
  • (7)配置与 shared-cache-1共享资源池(resource-pool-a)的另一个缓存( shared-cache-2)。
  • (8)使用集群缓存创建完全初始化的缓存管理器。

:当缓存从共享池中分配了内存块时,它将永远保留,并且永远不会重新分配到共享该池的另一个缓存。

Ehcache集群层管理器生命周期

配置缓存管理器以连接到集群层管理器时,有三种可能的连接模式:

深色代码主题
复制
CacheManagerBuilder<PersistentCacheManager> autoCreate = CacheManagerBuilder.newCacheManagerBuilder()
        .with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
            .autoCreate(server -> server  //(1)
              .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> autoCreateOnReconnect = CacheManagerBuilder.newCacheManagerBuilder()
        .with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
            .autoCreateOnReconnect(server -> server  //(2)
              .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  //(3)
              .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"))) 
        //(4)
        .withCache("clustered-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
            ResourcePoolsBuilder.newResourcePoolsBuilder()
                .with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool"))));

上述配置:

  • (1)在自动创建模式下,如果不存在集群层管理器,则将使用提供的配置创建一个集群层管理器。如果它存在,并且其配置与提供的配置匹配,则建立连接。如果提供的配置不匹配,则缓存管理器将无法初始化。
  • (2)在重新连接时自动创建模式中,还支持在重新连接到集群时自动创建任何必要的实体。此行为在非持久性集群中非常有用,以防集群因重新启动(计划或意外)而失去其状态。
  • (3)在预期模式下,如果存在集群层管理器,并且其配置与提供的配置匹配,则将建立连接。如果提供的配置不匹配或集群层管理器不存在,则缓存管理器将无法初始化。
  • (4)在无配置模式下,如果存在集群层管理器,则将建立连接,而不考虑其配置。如果缓存管理器不存在,则缓存管理器将无法初始化。

配置集群缓存

集群存储层

深色代码主题
复制
CacheConfiguration<Long, String> config = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
    ResourcePoolsBuilder.newResourcePoolsBuilder()
        .heap(2, MemoryUnit.MB) //(1) 
        .with(ClusteredResourcePoolBuilder.clusteredDedicated("primary-server-resource", 8, MemoryUnit.MB)))  //(2)
    .withService(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
    .build();

Cache<Long, String> cache = cacheManager.createCache("clustered-cache-tiered", config);
cache.put(42L, "All you need to know!");

上述配置:

  • (1)配置缓存的堆层。
  • (2)使用ClusteredResourcePoolBuilder从服务器堆外资源配置专用大小的集群层。

等效XML配置如下:

深色代码主题
复制
<cache alias="clustered-cache-tiered">
  <resources>
    <heap unit="MB">10</heap> <!--(1)-->
    <tc:clustered-dedicated unit="MB">50</tc:clustered-dedicated> <!--(2)-->
  </resources>
  <tc:clustered-store consistency="strong"/>
</cache>

上述配置:

  • (1)指定缓存的堆层。
  • (2)通过集群命名空间中的自定义服务配置指定缓存的集群层。

指定一致性级别

Ehcache提供两个级别的一致性:

1. 最终一致性

此一致性级别表示当写入操作返回时,不保证写入操作的可见性。其他客户端可能仍看到给定密钥的过时值。但是,此一致性级别保证,对于更新到(K, V1)的映射(K, V2),一旦客户端看到(K, V2),它将永远不会再看到(K, V1)。

2. 强一致性

此一致性级别提供了强大的可见性保证,确保当写入操作返回时,其他客户端将能够立即观察到它。这将对提供此保证所需的写入操作带来延迟。

深色代码主题
复制
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)) //(1) 
    .build();

Cache<Long, String> cache = cacheManager.createCache("clustered-cache", config);
cache.put(42L, "All you need to know!"); //(2) 

上述配置:

  • (1)通过使用其他服务配置指定一致性级别,在此处使用强一致性。
  • (2)使用上面使用的一致性,只有当所有其他客户端都已使相应的映射无效时,此put操作才会返回。

等效XML配置如下:

深色代码主题
复制
<cache alias="clustered-cache">
  <resources>
    <tc:clustered-dedicated unit="MB">50</tc:clustered-dedicated>
  </resources>
  <tc:clustered-store consistency="strong"/>  <!--(1)-->
</cache>

上述配置:

  • (1)通过集群命名空间中的自定义服务配置指定一致性级别。

集群缓存过期

集群缓存中的过期工作时,有一个例外,即Expiry#getExpiryForAccess是在尽最大努力的基础上处理集群层的。它可能没有本地层那么准确。

集群未指定继承

我们包括了一个选项,允许在缓存管理器中创建缓存,而不必显式定义其集群层资源池分配。要使用此功能,集群层必须已使用shared或者dedicated资源池创建。

在这种情况下,集群资源的定义只需使用clustered()资源池完成。这实际上意味着unspecified,并表示您希望它已经存在。然后,它将继承集群资源池,因为它是在创建集群层时配置的。

此选项提供了许多好处。主要的好处是,它允许集群资源池配置由一个客户端处理,然后所有后续客户端都可以继承此配置,从而简化了集群配置。此外,它还减少了集群池分配配置错误。更重要的是,规模计算只需要由一个人完成,并在一个位置更新。因此,任何程序员都可以使用缓存,而不必担心使用匹配的资源池分配。

下面的示例代码显示了如何实现这一点。

深色代码主题
复制
CacheManagerBuilder<PersistentCacheManager> cacheManagerBuilderAutoCreate = CacheManagerBuilder.newCacheManagerBuilder()
        .with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
          .autoCreateOnReconnect(server -> server //(1)   
            .resourcePool("resource-pool", 8, MemoryUnit.MB, "primary-server-resource")));

PersistentCacheManager cacheManager1 = cacheManagerBuilderAutoCreate.build(false);
cacheManager1.init();
try {
  CacheConfiguration<Long, String> cacheConfigDedicated = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
    ResourcePoolsBuilder.newResourcePoolsBuilder()
      .with(ClusteredResourcePoolBuilder.clusteredDedicated("primary-server-resource", 8, MemoryUnit.MB)))  //(2)
    .withService(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
    .build();

  Cache<Long, String> cacheDedicated = cacheManager1.createCache("my-dedicated-cache", cacheConfigDedicated);  //(3)

  CacheManagerBuilder<PersistentCacheManager> cacheManagerBuilderExpecting = CacheManagerBuilder.newCacheManagerBuilder()
    .with(ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost/my-application"))
      .expecting(server -> server  //(4)
        .resourcePool("resource-pool", 8, MemoryUnit.MB, "primary-server-resource")));

  PersistentCacheManager cacheManager2 = cacheManagerBuilderExpecting.build(false);
  cacheManager2.init();
  try {
    CacheConfiguration<Long, String> cacheConfigUnspecified = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
      ResourcePoolsBuilder.newResourcePoolsBuilder()
        .with(ClusteredResourcePoolBuilder.clustered()))  //(5)
      .withService(ClusteredStoreConfigurationBuilder.withConsistency(Consistency.STRONG))
      .build();

    Cache<Long, String> cacheUnspecified = cacheManager2.createCache("my-dedicated-cache", cacheConfigUnspecified); //(6)
  } finally {
    cacheManager2.close();
  }
} finally {
  cacheManager1.close();
}

上述配置:

  • (1)在重新连接时使用自动创建配置第一个缓存管理器
  • (2)为dedicated模式专用资源池构建缓存配置
  • (3)使用缓存配置创建缓存my-dedicated-cache
  • (4)将第二个缓存管理器配置为expecting
  • (5)为集群unspecified资源池构建缓存配置,该资源池将使用先前配置的集群dedicated资源池。
  • (6)创建具有相同名称my-dedicated-cache的缓存,并使用集群unspecified的缓存配置
点赞
收藏
回复
分享
举报
浏览492 发布于2022-03-05 07:22未知归属地
全部评论
最多点赞
最新发布
最早发布
写回答
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。
发表

我要发帖子

了解社区公约,与您携手共创和谐专业的开发者社区。