简体   繁体   English

FF4J:特征存储的服务器端缓存

[英]FF4J: server side caching for feature store

I am using ff4j-spring-boot-starter with f4j-store-springjdbc to setup my ff4j server.我正在使用ff4j-spring-boot-starterf4j-store-springjdbc来设置我的 ff4j 服务器。 All my other microservices use the endpoints given by ff4j to access this feature store and the response is returned in JSON.我所有的其他微服务都使用 ff4j 提供的端点来访问这个特性存储,并且响应在 JSON 中返回。

Since the data does not change that often and we are trying to save unnecessary database calls, I am trying to cache my feature store on the server.由于数据不会经常更改,并且我们正在尝试保存不必要的数据库调用,因此我正在尝试在服务器上缓存我的功能存储。 Also, if the feature flag DB is down (for refresh/maintenance) we still want the other services to successfully start-up using these values from the cache.此外,如果功能标志 DB 已关闭(用于刷新/维护),我们仍然希望其他服务使用缓存中的这些值成功启动。

We imported ff4j-store-ehcache in our pom.xml我们在 pom.xml 中导入ff4j-store-ehcache

        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.RC2</spring-cloud.version>
        <ff4j.version>1.8.7</ff4j.version>
        <odbc.version>19.6.0.0.0</odbc.version>
    </properties>
    <dependency>
            <groupId>org.ff4j</groupId>
            <artifactId>ff4j-spring-boot-starter</artifactId>
            <version>${ff4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.ff4j</groupId>
            <artifactId>ff4j-store-springjdbc</artifactId>
            <version>${ff4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.ff4j</groupId>
            <artifactId>ff4j-web</artifactId>
            <version>${ff4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.ff4j</groupId>
            <artifactId>ff4j-store-ehcache</artifactId>
            <version>${ff4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.ff4j</groupId>
            <artifactId>ff4j-webapi-jersey2x</artifactId>
            <version>1.8.11</version>
        </dependency>
        <!-- FF4J dependencies - end -->

Our FeatureCacheProviderEhCache implementation looks like this in FF4jConfig.java looks like this.我们的 FeatureCacheProviderEhCache 实现在 FF4jConfig 中看起来像这样。java 看起来像这样。

@ConditionalOnClass({​​​​ ConsoleServlet.class, FF4jDispatcherServlet.class }​​​​)
public class Ff4jConfig extends SpringBootServletInitializer {​​​​

    @Autowired
    private DataSource dataSource;

    @Bean
    public ServletRegistrationBean<FF4jDispatcherServlet> ff4jDispatcherServletRegistrationBean(
            FF4jDispatcherServlet ff4jDispatcherServlet) {​​​​
        ServletRegistrationBean<FF4jDispatcherServlet> bean = new ServletRegistrationBean<FF4jDispatcherServlet>(
                ff4jDispatcherServlet, "/web-console/*");
        bean.setName("ff4j-console");
        bean.setLoadOnStartup(1);
        return bean;
    }​​​​

    @Bean
    @ConditionalOnMissingBean
    public FF4jDispatcherServlet getFF4jDispatcherServlet() {​​​​
        FF4jDispatcherServlet ff4jConsoleServlet = new FF4jDispatcherServlet();
        ff4jConsoleServlet.setFf4j(getFF4j());
        return ff4jConsoleServlet;
    }​​​​

    @Bean
    public FF4j getFF4j() {​​​​
        FF4j ff4j = new FF4j();
        FF4JCacheManager cacheManager = new FeatureCacheProviderEhCache();
        ff4j.setPropertiesStore(new PropertyStoreSpringJdbc(dataSource));
        ff4j.setFeatureStore(new FeatureStoreSpringJdbc(dataSource));
        ff4j.setEventRepository(new EventRepositorySpringJdbc(dataSource));
        ff4j.cache(cacheManager);
        

        // Enable audit mode
        ff4j.audit(true);

        return ff4j;
    }​​​​

}​​​​

WebConsole reflects the database changes as soon as they are commit and it does not seem like the cache is being hit or that the cache is storing any of the data in it. WebConsole 会在提交数据库更改后立即反映它们,并且似乎没有命中缓存或缓存正在其中存储任何数据。

I want to be able to use this cache without going to database for every single lookup.我希望能够使用此缓存而无需每次查找都进入数据库。

We also tried using InMemoryCacheManager as an alternate to FeatureCacheProviderEhCache, but same results.我们还尝试使用 InMemoryCacheManager 作为 FeatureCacheProviderEhCache 的替代品,但结果相同。 We do see the clear cache button on our web-console in both the implementations.在这两种实现中,我们确实在我们的 Web 控制台上看到了清除缓存按钮。

Also, is there a better way for me to test if my api calls are actually getting data from cache and not from db, without having to shutdown the db?另外,有没有更好的方法来测试我的 api 调用是否实际上是从缓存而不是从数据库获取数据,而无需关闭数据库?

Update: After implementing our own FeatureCacheProviderEhCache, and logging in it, I tried to access the api/ff4j and the featureNames is coming in as empty in that response.更新:在实现我们自己的 FeatureCacheProviderEhCache 并登录后,我尝试访问 api/ff4j 并且该响应中的featureNames为空。 Please refer to the log:请参考日志:

METHOD=getCacheFeatures, LINENO=160, MSG=getCacheFeatures :: [ name = ff4jCacheFeatures status = STATUS_ALIVE eternal = false overflowToDisk = true maxEntriesLocalHeap = 10000 maxEntriesLocalDisk = 10000000 memoryStoreEvictionPolicy = LRU timeToLiveSeconds = 120 timeToIdleSeconds = 120 persistence = LOCALTEMPSWAP diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: ; orderedCacheEventListeners:  maxBytesLocalHeap = 0 overflowToOffHeap = false maxBytesLocalOffHeap = 0 maxBytesLocalDisk = 0 pinned = false ]
METHOD=listCachedFeatureNames, LINENO=59, MSG=listCachedFeatureNames[]
METHOD=getCacheFeatures, LINENO=160, MSG=getCacheFeatures :: [ name = ff4jCacheFeatures status = STATUS_ALIVE eternal = false overflowToDisk = true maxEntriesLocalHeap = 10000 maxEntriesLocalDisk = 10000000 memoryStoreEvictionPolicy = LRU timeToLiveSeconds = 120 timeToIdleSeconds = 120 persistence = LOCALTEMPSWAP diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: ; orderedCacheEventListeners:  maxBytesLocalHeap = 0 overflowToOffHeap = false maxBytesLocalOffHeap = 0 maxBytesLocalDisk = 0 pinned = false ]

这是 API 的响应

The cache is created but it is not storing any values inside it.缓存已创建,但未在其中存储任何值。 I am setting the cache the way it says in the first answer.我正在按照第一个答案中所说的方式设置缓存。 I the logs, when I print listCachedFeatures(), that is printing as empty as well.我的日志,当我打印 listCachedFeatures() 时,它也打印为空。 I am still not able to see featureNames in the cache.我仍然无法在缓存中看到featureNames Which part am I not configuring correctly?我没有正确配置哪个部分?

First I would like to confirm that you use the cache properly.首先,我想确认您正确使用了缓存。 ff4j.cache(cacheManager) is what you want to do. ff4j.cache(cacheManager)是你想要做的。 Under the hood this is what is happening:这就是正在发生的事情:

public FF4j cache(FF4JCacheManager cm) {
    FF4jCacheProxy cp = new FF4jCacheProxy(getFeatureStore(), getPropertiesStore(), cm);
    setFeatureStore(cp);
    setPropertiesStore(cp);
    return this;
}
  1. When you edit features or properties values through the web console, FF4j knows cache needs to be evicted and db immediately updated, (cache will be used only for READ).当您通过 web 控制台编辑功能或属性值时, FF4j知道需要逐出缓存并立即更新数据库(缓存将仅用于读取)。

  2. FeatureCacheProviderEhCache and InMemoryCacheManager work the same way. FeatureCacheProviderEhCacheInMemoryCacheManager的工作方式相同。 The first use the JSR107.首先使用JSR107。 It is personal preference, maybe using ehcache you can switch to a distribute cache like Terracotta later.这是个人喜好,也许使用 ehcache 你可以稍后切换到像 Terracotta 这样的分布式缓存。

  3. How to know that only cache is used and not the DB (on read)?如何知道只使用缓存而不使用数据库(读取时)? You can either create an advice with AOP to decorate the class FeatureCacheProviderEhCache or more basic you copy the class in your project, update the method with proper logs and use your class as a CacheManager.您可以使用 AOP 创建建议来装饰 class FeatureCacheProviderEhCache或更基本的,您在项目中复制class ,使用适当的日志更新方法并使用 class 作为 aCacheManager。

  4. You may consider to use cache at your micro services level as well (if implemented in Java) and not only in the web console.您也可以考虑在微服务级别使用缓存(如果用 Java 实现),而不仅仅是在 web 控制台中。 If you do this, you can save some time by not executing the REST call to get JSON.如果这样做,您可以通过不执行 REST 调用来获取 JSON 来节省一些时间。

  5. EhCache and InMemory cache work as the name stated in memory, meaning 2 micro services may have different values in the cache. EhCache 和 InMemory 缓存如 memory 中所述的名称工作,这意味着 2 个微服务在缓存中可能具有不同的值。 If you want consistent caching among microservices (not mandatory) you want to use distributed cache like REDIS or HAZELCAST.如果您想要在微服务之间进行一致的缓存(非强制性),您想要使用分布式缓存,例如 REDIS 或 HAZELCAST。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM