redisjava监听_从零⼿写实现redis(四)添加
前⾔
java从零⼿写实现redis(⼀)如何实现固定⼤⼩的缓存?
java从零⼿写实现redis(三)redis expire 过期原理
java从零⼿写实现redis(三)内存数据如何重启不丢失?
本节,让我们来⼀起学习⼀下如何实现类似 guava-cache 中的 removeListener 删除,和类似 redis 中的慢⽇志监控的slowListener。
删除
说明
我们在两种场景下删除数据是对⽤户透明的:
(1)size 满了之后,进⾏数据淘汰。
(2)expire 过期时,清除数据。
这两个特性对⽤户本来应该是⽆感的,不过⽤户如果关⼼的话,也可以通过添加删除来获取到相关的变更信息。
实现思路
为了实现删除的监听,我们需要到删除的位置,然后调⽤即可。
evict 驱除的场景
每次 put 数据时,都会校验 size 是否达到最⼤的限制,如果达到,则进⾏ evict 淘汰。expire 过期的场景
⽤户指定 expire 时间之后,回后台异步执⾏刷新。
也存在惰性删除的场景。
接⼝定义
为了统⼀,我们将所有的删除都定义统⼀的接⼝:
/**
* 删除接⼝
*
* @author binbin.hou
* @since 0.0.6
* @param <K> key
* @param <V> value
*/
public interface ICacheRemoveListener<K,V> {
/**
* 监听
* @param context 上下⽂
* @since 0.0.6
*/
void listen(final ICacheRemoveListenerContext<K,V> context);
}
内置实现
系统内置的实现如下:
public class CacheRemoveListener<K,V> implements ICacheRemoveListener<K,V> {
private static final Log log = Log(CacheRemoveListener.class);
@Override
public void listen(ICacheRemoveListenerContext<K, V> context) {
log.debug("Remove key: {}, value: {}, type: {}",
context.key(), context.value(), pe());
}
}
这个是默认开启的,暂时⽆法关闭。
⾃定义
⽤户可以⾃⼰的需要,进⾏⾃定义实现:java上下文context
public class MyRemoveListener<K,V> implements ICacheRemoveListener<K,V> {
@Override
public void listen(ICacheRemoveListenerContext<K, V> context) {
System.out.println("【删除提⽰】可恶,我竟然被删除了!" + context.key());
}
}
测试
ICache<String, String> cache = CacheBs.<String,String>newInstance()
.size(1)
.addRemoveListener(new MyRemoveListener<String, String>())
.build();
cache.put("1", "1");
cache.put("2", "2");
我们指定 cache 的⼤⼩为1,设置我们⾃定义的删除。
这⾥的删除可以添加多个。
⽇志
测试⽇志如下:
[DEBUG] [2020-09-30 19:32:54.617] [main] [c.CacheRemoveListener.listen] - Remove key: 2, value: 2, type: evict 【删除提⽰】可恶,我竟然被删除了!2
慢操作
说明
redis 中会存储慢操作的相关⽇志信息,主要是由两个参数构成:
(1)slowlog-log-slower-than 预设阈值,它的单位是毫秒(1秒=1000000微秒)默认值是10000
(2)slowlog-max-len 最多存储多少条的慢⽇志记录
不过 redis 是直接存储到内存中,⽽且有长度限制。
根据实际⼯作体验,如果我们可以添加慢⽇志的监听,然后有对应的存储或者报警,这样更加⽅便问题的分析和快速反馈。所以我们引⼊类似于删除的。
实现思路
我们处理所有的 cache 操作,并且记录对应的操作耗时。
如果耗时操作⽤户设置的时间阈值,则调⽤慢操作。
接⼝定义
为了保证接⼝的灵活性,每⼀个实现都可以定义⾃⼰的慢操作阈值,这样便于分级处理。
⽐如超过 100ms,⽤户可以选择输出 warn ⽇志;超过 1s,可能影响到业务了,可以直接接⼊报警系统。
public interface ICacheSlowListener {
/**
* 监听
* @param context 上下⽂
* @since 0.0.6
*/
void listen(final ICacheSlowListenerContext context);
/**
* 慢⽇志的阈值
* @return 慢⽇志的阈值
* @since 0.0.9
*/
long slowerThanMills();
}
⾃定义
实现接⼝ ICacheSlowListener
这⾥每⼀个都可以指定⾃⼰的慢⽇志阈值,便于分级处理。
public class MySlowListener implements ICacheSlowListener {
@Override
public void listen(ICacheSlowListenerContext context) {
System.out.println("【慢⽇志】name: " + hodName());
}
@Override
public long slowerThanMills() {
return 0;
}
}
使⽤
ICache<String, String> cache = CacheBs.<String,String>newInstance()
.addSlowListener(new MySlowListener())
.build();
cache.put("1", "2");
<("1");
测试效果
[DEBUG] [2020-09-30 17:40:11.547] [main] [c.CacheInterceptorCost.before] - Cost start, method: put [DEBUG] [2020-09-30 17:40:11.551] [main] [c.CacheInterceptorCost.after] - Cost end, method: put, cost: 10ms 【慢⽇志】name: put
[DEBUG] [2020-09-30 17:40:11.554] [main] [c.CacheInterceptorCost.before] - Cost start, method: get [DEBUG] [2020-09-30 17:40:11.554] [main] [c.CacheInterceptorCost.after] - Cost end, method: get, cost: 1ms 【慢⽇志】name: get
实际⼯作中,我们可以针对慢⽇志数据存储,便于后期分析。
也可以直接接⼊报警系统,及时反馈问题。
⼩结
实现起来⽐较简单,但是对于使⽤者的作⽤是⽐较⼤的。⽂中主要讲述了思路,实现部分因为篇幅限制,没有全部贴出来。
开源地址: github/houbb/cache
github/houbb/cache
觉得本⽂对你有帮助的话,欢迎点赞评论收藏关注⼀波~
你的⿎励,是我最⼤的动⼒~

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。