Guava缓存,谷歌开源的一种本地缓存,使用本节点的内存来存储的,实现原理类似于ConcurrentHashMap,使用多个segments方式的细粒度锁,在保证线程安全的同时,支持高并发场景需求,同时支持多种类型的缓存清理策略,包括基于容量的清理、基于时间的清理、基于引用的清理等。
CacheLoader可以理解为一个固定的加载器,在创建Cache时指定,重写V load(K key) 方法后,当检索不存在的时会自动的加载数据。
package com.example.cache;
import com.google.common.cache.*;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* 描述:
* 本地缓存Ddmo
*
* @author XueGuCheng
* @create 2022-11-01 23:03
*/
public class GuavaCacheDemo {
// 模拟DB
private static final HashMap<Integer, String> map = new HashMap<>();
public static LoadingCache<Integer, String> createGuavaCache(){
return CacheBuilder.newBuilder()
// 设置并发级别为5,并发级别是指可以同时写缓存的线程数
.concurrencyLevel(5)
// 设置写缓存后10秒钟后过期
.expireAfterWrite(10, TimeUnit.SECONDS)
// 设置缓存容器的初始容量为8
.initialCapacity(8)
// 设置缓存最大容量为10,超过10之后就会按照LRU最近虽少使用算法来移除缓存项
.maximumSize(10)
// 设置统计缓存的各种统计信息(生产坏境关闭)
.recordStats()
// 设置缓存的移除通知
.removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause());
}
})
// 指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
.build(new CacheLoader<Integer, String>() {
@Override
public String load(Integer key) throws Exception {
// 往DB中查询数据
System.out.println("查询key:" + key + "的数据");
return map.get(key);
}
});
}
public static void main(String[] args) throws ExecutionException {
map.put(1,"java");
map.put(2,"天下");
map.put(3,"第一");
LoadingCache<Integer, String> loadingCache = createGuavaCache();
// 第一次缓存中没有数据,所以会往DB中查询数据
System.out.println(loadingCache.get(2));
// 第二次缓存中有数据,CacheLoader.load方法不会加载
System.out.println(loadingCache.get(2));
}
}
运行结果:

Callable在get时可以指定,效果跟CacheLoader一样,区别就是两者定义的时间点不一样,Callable更加灵活。
public static void main(String[] args) throws ExecutionException {
map.put(1,"java");
map.put(2,"天下");
map.put(3,"第一");
LoadingCache<Integer, String> loadingCache = createGuavaCache();
// 第一次缓存中没有数据,所以会往DB中查询数据
// System.out.println(loadingCache.get(2));
// // 第二次缓存中有数据,CacheLoader.load方法不会加载
// System.out.println(loadingCache.get(2));
int i = 3;
String s = loadingCache.get(i, new Callable<String>() {
@Override
public String call() throws Exception {
// 往DB中查询数据
System.out.println("(callable) 查询key:" + i + "的数据");
return map.get(i);
}
});
System.out.println(s);
}
运行结果:

清除策略:超过最大容量之后就会按照LRU最近虽少使用算法来移除缓存项。
public static void main(String[] args) throws ExecutionException {
map.put(1,"java");
map.put(2,"天下");
map.put(3,"第一");
map.put(4,"j");
map.put(5,"a");
map.put(6,"v");
LoadingCache<Integer, String> loadingCache = createGuavaCache();
// 此时缓存的最大容量为4,存放6个数据
for(int i = 1; i <= 6; i++){
System.out.println(loadingCache.get(i));
}
}
运行结果:

使用CacheBuilder.weigher(Weigher)指定一个权重函数,并且用CacheBuilder.maximumWeight(long)指定最大总重。
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumWeight(1000)
.weigher(new Weigher<Key, Graph>() {
public int weigh(Key k, Graph g) {
return g.vertices().size();
}
})
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) {
return createExpensiveGraph(key);;
}
});
expireAfterWrite与refreshAfterWrite混合使用情况:
例:
public static void main(String[] args) throws ExecutionException, InterruptedException {
map.put(1,"java");
map.put(2,"天下");
map.put(3,"第一");
map.put(4,"j");
map.put(5,"a");
map.put(6,"v");
LoadingCache<Integer, String> loadingCache = createGuavaCache();
// 此时缓存的过期时间为3s
for(int i = 1; i <= 6; i++){
System.out.println(loadingCache.get(i));
if (i>=3){
Thread.sleep(1000);
}
}
}
运行结果:
问题: 如果对缓存设置过期时间,在高并发下同时执行get操作,而此时缓存值已过期了,如果没有保护措施,则会导致大量线程同时调用生成缓存值的方法,比如从数据库读取,对数据库造成压力,这也就是我们常说的“缓存击穿”。
refreshAfterWrite: 当大量线程用相同的key获取缓存值时,只会有一个线程进入load方法,而其他线程则等待,直到缓存值被生成。这样也就避免了缓存击穿的危险。这两个配置的区别前者记录写入时间,后者记录写入或访问时间,内部分别用writeQueue和accessQueue维护。
默认情况下,监听器方法是在移除缓存时同步调用的。因为缓存的维护和请求响应通常是同时进行的,代价高昂的监听器方法在同步模式下会拖慢正常的缓存请求。假如在同步监听模式下,监听方法中的逻辑特别复杂,执行效率慢,那此时如果有大量的key进行清理,会使整个缓存性能变得很低下,所以此时适合用异步监听RemovalListeners.asynchronous(RemovalListener, Executor)把监听器装饰为异步操作,移除key与监听key的移除分属2个线程。
// 设置缓存的移除通知(同步)
.removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause());
}
})
// 设置缓存的移除通知(异步)
.removalListener(RemovalListeners.asynchronous(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
}
},Executors.newSingleThreadExecutor()))
我试过重新启动apache,缓存的页面仍然出现,所以一定有一个文件夹在某个地方。我没有“公共(public)/缓存”,那么我还应该查看哪些其他地方?是否有一个URL标志也可以触发此效果? 最佳答案 您需要触摸一个文件才能清除phusion,例如:touch/webapps/mycook/tmp/restart.txt参见docs 关于ruby-如何在Ubuntu中清除RubyPhusionPassenger的缓存?,我们在StackOverflow上找到一个类似的问题:
尝试在我的RoR应用程序中实现计数器缓存列时出现错误Unknownkey(s):counter_cache。我在这个问题中实现了模型关联:Modelassociationquestion这是我的迁移:classAddVideoVotesCountToVideos0Video.reset_column_informationVideo.find(:all).eachdo|p|p.update_attributes:videos_votes_count,p.video_votes.lengthendenddefself.downremove_column:videos,:video_vot
1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功
ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear
(本文是网络的宏观的概念铺垫)目录计算机网络背景网络发展认识"协议"网络协议初识协议分层OSI七层模型TCP/IP五层(或四层)模型报头以太网碰撞路由器IP地址和MAC地址IP地址与MAC地址总结IP地址MAC地址计算机网络背景网络发展 是最开始先有的计算机,计算机后来因为多项技术的水平升高,逐渐的计算机变的小型化、高效化。后来因为计算机其本身的计算能力比较的快速:独立模式:计算机之间相互独立。 如:有三个人,每个人做的不同的事物,但是是需要协作的完成。 而这三个人所做的事是需要进行协作的,然而刚开始因为每一台计算机之间都是互相独立的。所以前面的人处理完了就需要将数据
当我尝试进行bundle安装时,我的gem_path和gem_home指向/usr/local/rvm/gems/我没有写入权限,并且由于权限无效而失败。因此,我已将两个路径都更改为我具有写入权限的本地目录。这样做时,我进行了bundle安装,我得到:bruno@test6:~$bundleinstallFetchinggemmetadatafromhttps://rubygems.org/.........Fetchinggemmetadatafromhttps://rubygems.org/..Bundler::GemspecError:Couldnotreadgemat/afs/
我一直在Heroku上尝试不同的缓存策略,并添加了他们的memcached附加组件,目的是为我的应用程序添加Action缓存。但是,当我在我当前的应用程序上查看Rails.cache.stats时(安装了memcached并使用dalligem),在执行应该缓存的操作后,我得到current和total_items为0。在Controller的顶部,我想缓存我有的Action:caches_action:show此外,我修改了我的环境配置(对于在Heroku上运行的配置)config.cache_store=:dalli_store我是否可以查看其他一些统计数据,看看它是否有效或我做错
我有一个具有页面缓存的ControllerAction,我制作了一个清扫程序,它使用Controller和指定的Action调用expire_page...Controller操作呈现一个js.erb模板,所以我试图确保expire_page删除public/javascripts中的.js文件,但它没有这样做。classJavascriptsController"javascripts",:action=>"lol",:format=>'js')endend...所以,我访问javascripts/lol.js并呈现我的模板。我验证了public/javascripts/lol.js
我的Controller有这个:caches_action:render_ticker_for_channel,:expires_in=>30.seconds在我的路由文件中我有这个:match'/render_c_t/:channel_id'=>'render#render_ticker_for_channel',:as=>:render_channel_ticker在日志文件中我看到了这个:Writefragmentviews/mcr3.dev/render_c_t/63(11.6ms)我如何手动使它过期?我需要从与渲染Controller不同的Controller使它过期,但即使