Caching 在Grails中缓存昂贵web服务调用的最佳策略
我有一个简单的Grails应用程序,它需要在用户会话期间(在用户使用接口时)多次定期调用外部web服务 我希望缓存此web服务响应,但服务的结果大约每隔几天就会更改一次,因此我希望将其缓存一段时间(可能是每天刷新) Grails缓存插件似乎不支持“生存时间”实现,因此我一直在探索一些可能的解决方案。我想知道什么插件或编程解决方案最能解决这个问题 例如: BuildConfig.groovyCaching 在Grails中缓存昂贵web服务调用的最佳策略,caching,grails,Caching,Grails,我有一个简单的Grails应用程序,它需要在用户会话期间(在用户使用接口时)多次定期调用外部web服务 我希望缓存此web服务响应,但服务的结果大约每隔几天就会更改一次,因此我希望将其缓存一段时间(可能是每天刷新) Grails缓存插件似乎不支持“生存时间”实现,因此我一直在探索一些可能的解决方案。我想知道什么插件或编程解决方案最能解决这个问题 例如: BuildConfig.groovy plugins{ compile ':cache:1.0.0' } def getItems()
plugins{
compile ':cache:1.0.0'
}
def getItems(){
def items = MyService.getItems()
[items: items]
}
@Cacheable("itemsCache")
class MyService {
def getItems() {
def results
//expensive external web service call
return results
}
}
plugins{
compile ':cache:1.1.7'
compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
defaultCache {
maxElementsInMemory 10000
eternal false
timeToIdleSeconds 86400
timeToLiveSeconds 86400
overflowToDisk false
maxElementsOnDisk 0
diskPersistent false
diskExpiryThreadIntervalSeconds 120
memoryStoreEvictionPolicy 'LRU'
}
}
MyController.groovy
plugins{
compile ':cache:1.0.0'
}
def getItems(){
def items = MyService.getItems()
[items: items]
}
@Cacheable("itemsCache")
class MyService {
def getItems() {
def results
//expensive external web service call
return results
}
}
plugins{
compile ':cache:1.1.7'
compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
defaultCache {
maxElementsInMemory 10000
eternal false
timeToIdleSeconds 86400
timeToLiveSeconds 86400
overflowToDisk false
maxElementsOnDisk 0
diskPersistent false
diskExpiryThreadIntervalSeconds 120
memoryStoreEvictionPolicy 'LRU'
}
}
MyService.groovy
plugins{
compile ':cache:1.0.0'
}
def getItems(){
def items = MyService.getItems()
[items: items]
}
@Cacheable("itemsCache")
class MyService {
def getItems() {
def results
//expensive external web service call
return results
}
}
plugins{
compile ':cache:1.1.7'
compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
defaultCache {
maxElementsInMemory 10000
eternal false
timeToIdleSeconds 86400
timeToLiveSeconds 86400
overflowToDisk false
maxElementsOnDisk 0
diskPersistent false
diskExpiryThreadIntervalSeconds 120
memoryStoreEvictionPolicy 'LRU'
}
}
更新
有很多好的选择。我决定采用伯特建议的插件方法。我已经包括了一个示例答案,上面的代码示例有一些小的改动,以帮助其他想要做类似事情的人。此配置将在24小时后使缓存过期
BuildConfig.groovy
plugins{
compile ':cache:1.0.0'
}
def getItems(){
def items = MyService.getItems()
[items: items]
}
@Cacheable("itemsCache")
class MyService {
def getItems() {
def results
//expensive external web service call
return results
}
}
plugins{
compile ':cache:1.1.7'
compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
defaultCache {
maxElementsInMemory 10000
eternal false
timeToIdleSeconds 86400
timeToLiveSeconds 86400
overflowToDisk false
maxElementsOnDisk 0
diskPersistent false
diskExpiryThreadIntervalSeconds 120
memoryStoreEvictionPolicy 'LRU'
}
}
Config.groovy
plugins{
compile ':cache:1.0.0'
}
def getItems(){
def items = MyService.getItems()
[items: items]
}
@Cacheable("itemsCache")
class MyService {
def getItems() {
def results
//expensive external web service call
return results
}
}
plugins{
compile ':cache:1.1.7'
compile ':cache-ehcache:1.0.1'
}
grails.cache.config = {
defaultCache {
maxElementsInMemory 10000
eternal false
timeToIdleSeconds 86400
timeToLiveSeconds 86400
overflowToDisk false
maxElementsOnDisk 0
diskPersistent false
diskExpiryThreadIntervalSeconds 120
memoryStoreEvictionPolicy 'LRU'
}
}
通过单元测试(查找timeToLiveSeconds),我发现您可以在缓存级别配置缓存,而不是每个方法调用或类似的配置。使用此方法,可以配置grails.cache.config的设置
您可以使用time to live设置创建一个专用缓存,然后在服务中引用它。核心插件不支持TTL,但Ehcache插件支持TTL。看
该插件依赖于缓存管理器,但将其替换为使用Ehcache的缓存管理器(因此您需要同时安装两者)一个黑客/解决方法是使用@Cacheable(“itemsCache”)和@CacheFlush(“itemsCache”)的组合 告诉getItems()方法缓存结果
@Cacheable("itemsCache")
def getItems() {
}
然后使用另一种服务方法刷新缓存,您可以从作业中频繁调用缓存
@CacheFlush("itemsCache")
def flushItemsCache() {}
在与斯佩尔的几小时战斗失败后,我终于赢得了这场战争! 因此,正如您所知,Grails缓存没有现成的TTL。您可以坚持使用ehcache并进行一些奇特的配置。或者更糟糕的是,在保存/更新时添加逻辑刷新,但我的解决方案是:
@Cacheable(value = 'domainInstance', key="#someId.concat((new java.util.GregorianCalendar().getTimeInMillis()/10000))")
def getSomeStuffOfDb(String someId){
//extract something of db
}
}
还有一件事要指出。您可以跳过Config.groovy中的配置,它将自动创建和添加。
但是,如果您的应用程序在启动后立即处于加载状态,则会导致一些异常
2017-03-02 14:05:53,159 [http-apr-8080-exec-169] ERROR errors.GrailsExceptionResolver - CacheException occurred when processing request: [GET] /some/get
Failed to get lock for campaignInstance cache creation. Stacktrace follows:
因此,为了避免这种情况,请添加配置,以便缓存设施将提前准备好
grails.cache.enabled = true
grails.cache.clearAtStartup = true
grails.cache.config = {
defaults {
maxElementsInMemory 10000
overflowToDisk false
}
cache {
name 'domainInstance'
}
}
GregorianCalendar().getTimeInMillis()/10000将使TTL变为10秒/1000~1秒。这里是纯数学。是的,这是我发现的一种方法,但是这个插件不受欢迎。从文档中可以看出:“这个插件不再被维护。它已经被SpringSource开发和支持的缓存插件所取代。”我相信测试实际上是在设置不受支持的配置,作为测试的一部分。使用最新的缓存插件,你不能使它过期:“因为没有办法配置”生存时间“使用此插件,所有缓存项都没有超时,并保持缓存状态,直到JVM重新启动(因为备份存储在内存中)或缓存部分或完全清除(通过调用带有@cacheexecute注释的方法或操作或以编程方式)。“这就是说,您可以有一个cron作业,它可以访问使用@cacheexecute的web服务。至少这是一种变通方法。是的,我考虑过这种方法。为了更进一步,Quartz可以取代cron,将所有内容都保存在应用程序中。我希望缓存插件更像spring缓存插件。需要同时安装这两个插件。。救了我一天!