net stop winmgmt

ren %windir%\System32\Wbem\Repository Repository_backup

net start winmgmt

winmgmt /salvagerepository

cd /d %windir%\system32\wbem

for /f %s in ('dir /b *.dll') do regsvr32 /s %s

for /f %s in ('dir /b *.mof *.mfl') do mofcomp %s

wmiprvse /regserver

重启即可

首先看一下三种基于时间的清理或刷新缓存数据的方式:

expireAfterAccess:当缓存项在指定的时间段内没有被读或写就会被回收。

expireAfterWrite:当缓存项在指定的时间段内没有更新就会被回收。

refreshAfterWrite:当缓存项上一次更新操作之后的多久会被刷新。

考虑到时效性,我们可以使用expireAfterWrite,使每次更新之后的指定时间让缓存失效,然后重新加载缓存。guava cache会严格限制只有1个加载操作,这样会很好地防止缓存失效的瞬间大量请求穿透到后端引起雪崩效应。

然而,通过分析源码,guava cache在限制只有1个加载操作时进行加锁,其他请求必须阻塞等待这个加载操作完成;而且,在加载完成之后,其他请求的线程会逐一获得锁,去判断是否已被加载完成,每个线程必须轮流地走一个“获得锁,获得值,释放锁”的过程,这样性能会有一些损耗。这里由于我们计划本地缓存1秒,所以频繁的过期和加载,锁等待等过程会让性能有较大的损耗。

因此我们考虑使用refreshAfterWrite。refreshAfterWrite的特点是,在refresh的过程中,严格限制只有1个重新加载操作,而其他查询先返回旧值,这样可以有效地减少等待和锁争用,所以refreshAfterWrite会比expireAfterWrite性能好。但是它也有一个缺点,因为到达指定时间后,它不能严格保证所有的查询都获取到新值。了解过guava cache的定时失效(或刷新)原来的同学都知道,guava cache并没使用额外的线程去做定时清理和加载的功能,而是依赖于查询请求。在查询的时候去比对上次更新的时间,如超过指定时间则进行加载或刷新。所以,如果使用refreshAfterWrite,在吞吐量很低的情况下,如很长一段时间内没有查询之后,发生的查询有可能会得到一个旧值(这个旧值可能来自于很长时间之前),这将会引发问题。

可以看出refreshAfterWrite和expireAfterWrite两种方式各有优缺点,各有使用场景。那么能否在refreshAfterWrite和expireAfterWrite找到一个折中?比如说控制缓存每1s进行refresh,如果超过2s没有访问,那么则让缓存失效,下次访问时不会得到旧值,而是必须得待新值加载。由于guava官方文档没有给出一个详细的解释,查阅一些网上资料也没有得到答案,因此只能对源码进行分析,寻找答案。经过分析,当同时使用两者的时候,可以达到预想的效果,这真是一个好消息呐!

推荐内容