【问题标题】:Spring boot - Evicting Cache with dynamic TTL periodSpring boot - 用动态 TTL 周期逐出缓存
【发布时间】:2020-09-25 07:24:35
【问题描述】:

从我的微服务(SERVICE-A)中,我对另一个微服务(SERVICE-B)进行了休息 api 调用以进行登录并获取访问令牌,该 API 将使用该令牌的 TTL 进行响应。 我需要缓存令牌,直到 SERVICE-B 响应的 TTL(秒)。所以我的实现如下,

@Cacheable("USERTOKEN")
public String getUserToken()
{
  //Hits Service-B
  //Gets token and TTL as a response from Service-B
  //Returns Token or Token with TTL
}

我需要将上述方法更改为

@Cacheable("USERTOKEN")
public String getUserToken()
{
  //Hits Service-B
  //Gets token and TTL as a response from Service-B
  //Sets expiry time for "USERTOKEN" cache   <-- this needs to be added
  //Returns Token or Token with TTL
}

即使在从 getUserToken() 返回之后,如果可以使用 getUserToken() 返回的 TTL 为“USERTOKEN”缓存设置ExpiryTime,它也可以。我们可以为驱逐设置 Scheduled,但这将是一个静态时间段。但在这里我需要根据服务 B 的响应将其设置为动态值。我怎样才能做到这一点。

【问题讨论】:

  • 你的 CacheProvider 和缓存存储是什么?你用的是spring的默认缓存管理器吗?
  • 是的.. Spring 的默认缓存管理器。我试过番石榴,但即使在那个过期时间也只能在使用 @Cacheable.. rite 之前设置?
  • 是的,你是对的。根据spring docs 部分8.7. How can I Set the TTL/TTI/Eviction policy/XXX feature?。 Spring 没有该功能,因为它提供了抽象缓存实现,您可以使用 Redis 等不同的缓存提供者来实现这一点

标签: java spring-boot guava spring-cache


【解决方案1】:

如果你使用caffeine cache,你可以使用不同的过期策略:

来自caffeine wiki page

// Evict based on a varying expiration policy
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
    .expireAfter(new Expiry<Key, Graph>() {
      public long expireAfterCreate(Key key, Graph graph, long currentTime) {
        // Use wall clock time, rather than nanotime, if from an external resource
        long seconds = graph.creationDate().plusHours(5)
            .minus(System.currentTimeMillis(), MILLIS)
            .toEpochSecond();
        return TimeUnit.SECONDS.toNanos(seconds);
      }
      public long expireAfterUpdate(Key key, Graph graph, 
          long currentTime, long currentDuration) {
        return currentDuration;
      }
      public long expireAfterRead(Key key, Graph graph,
          long currentTime, long currentDuration) {
        return currentDuration;
      }
    })
    .build(key -> createExpensiveGraph(key));

【讨论】:

    【解决方案2】:

    您使用的是哪种缓存服务?

    如果你使用 Redis 缓存,他们有很多命令:

    EXPIRE :设置密钥超时。 EXPIREAT :与之前相同,但采用绝对 Unix 时间戳(自 1970 年 1 月 1 日以来的秒数)。 TTL :返回具有超时的键的剩余生存时间 关于 Redis 过期,您必须了解的一件重要事情是:仅当使用 SET 或 GETSET 删除或覆盖键时,才会清除超时值。所有其他命令(INCR、LPUSH、HMSET、...)都不会更改初始超时。

    绝对过期是 Redis 使用 EXPIRE 的原生特性。要实现滑动过期,您只需在每个命令后重置为超时值。

    这样做的基本方法是

    MULTI
    GET MYKEY
    EXPIRE MYKEY 60
    EXEC
    

    【讨论】:

      【解决方案3】:

      如果您使用 Spring 的默认实现,您将无法设置缓存 TTL。但是对于其他提供商,例如 EhCache、Gemfire 和 Guava,您可以这样做,但只能在配置缓存管理器期间进行。 See ehcache DocumentationSpring's Gemfire's Documentation。对于Guava see

      像这样 - 对于 Ehcache。

      CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
        .with(CacheManagerBuilder.persistence(tmpDir.newFile("myData")))
        .withCache("threeTieredCache",
          CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
            ResourcePoolsBuilder.newResourcePoolsBuilder()
              .heap(10, EntryUnit.ENTRIES)
              .offheap(1, MemoryUnit.MB)
              .disk(20, MemoryUnit.MB, true))
            .withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofSeconds(20)))
        ).build(false);
      
      Configuration configuration = cacheManager.getRuntimeConfiguration();
      XmlConfiguration xmlConfiguration = new XmlConfiguration(configuration);  
      String xml = xmlConfiguration.toString(); 
      

      为了 - 宝石火

      <gfe:region-template id="BaseRegionTemplate" initial-capacity="51" load-factor="0.85" persistent="false" statistics="true"
            key-constraint="java.lang.Long" value-constraint="java.lang.String">
          <gfe:cache-listener>
            <bean class="example.CacheListenerOne"/>
            <bean class="example.CacheListenerTwo"/>
          </gfe:cache-listener>
          <gfe:entry-ttl timeout="600" action="DESTROY"/>
          <gfe:entry-tti timeout="300 action="INVLIDATE"/>
        </gfe:region-template>
      

      For - Caffiene 或 Guava 的内部实现

      LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
          .maximumSize(10_000)
          .expireAfterWrite(5, TimeUnit.MINUTES)
          .refreshAfterWrite(1, TimeUnit.MINUTES)
          .build(key -> createExpensiveGraph(key));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-16
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 2021-04-27
        • 2013-01-20
        • 1970-01-01
        相关资源
        最近更新 更多