基于内存的key-value数据库
单进程单线程,1秒10万次读写,适合小数据量的高性能操作和运算上。
5种数据结构,string,hash,list,set,zset
Rdb和aof持久化策略
单个value最大1G
当你的key很小而value很大时,使用VM内存.
当你的key很大时,拆分大key为多个小key
什么是缓存穿透?
一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。
如何避免?
1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。【感觉应该用的不多吧】
缓存雪崩
什么是缓存雪崩?
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
如何避免?
1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
2:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
3:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期(此点为补充)
分布式锁
setnx和get,getset三个方法
setnx成功,加锁成功
setnx失败,get锁的过期时间与当前时间比较,如果锁过期了,getset设置锁的新的过期时间,返回旧的过期时间。
如果两个过期时间相等,加锁成功
如果失败,150毫秒后重试,最多10秒还失败,就加锁失败
while (timeout >= 0) {
String expireTime = System.currentTimeMillis() + expireMillis + "";
//把锁的过期时间写入锁的值
//原子方法,应该也是同步的
boolean setnx = setnx(LOCK_KEY, expireTime);
//拿到锁
if (setnx) {
locked = true;
log.debug("redis加锁成功, {} = {}", LOCK_KEY, expireTime);
return true;
}
//没拿到锁, 但是锁过期了
String oldExpireTime = get(LOCK_KEY);
if (oldExpireTime != null && Long.parseLong(oldExpireTime) < System.currentTimeMillis()) {
//getSet是同步的, 多个线程串行
//第一个线程getSet的结果和get的结果相同, 拿到锁
String beforeExpireTime = getSet(LOCK_KEY, expireTime);
if (beforeExpireTime != null && beforeExpireTime.equals(oldExpireTime)) {
locked = true;
log.debug("redis加锁成功, {} = {}", LOCK_KEY, expireTime);
return true;
}
}
//随机时间, 防止多个线程同时抢锁
try {
Thread.sleep(sleepMillis);
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
timeout -= sleepMillis;
}
Redis持久化方案
Rdb方式
Redis默认的方式,redis通过快照来将数据持久化到磁盘中。
设置持久化快照的条件
在redis.conf中修改持久化快照的条件,如下:
900秒修改1次,则持久化
300秒修改10次,则持久化
60秒内修改10000次,则持久化
Rdb问题
一旦redis非法关闭,那么会丢失最后一次持久化之后的数据。
如果数据不重要,则不必要关心。
如果数据不能允许丢失,那么要使用aof方式。
Aof方式
Redis默认是不使用该方式持久化的。Aof方式的持久化,是操作一次redis数据库,则将操作的记录存储到aof持久化文件中。
开启aof方式的持久化方案
将redis.conf中的appendonly改为yes,即开启aof方式的持久化方案。
查找/aof
找到appendonly no
按I进入insert模式,修改为
appendonly yes
按esc,:wq保存
需要重启redis后,bin目录内多了appendonly.aof文件,文件大小是0
操作一次数据库后,就记录一次,appendonly.aof的文件就变大
总结
1、aof文件比rdb更新频率高,优先使用aof还原数据。
2、aof比rdb更安全也更大
3、rdb性能比aof好
4、如果两个都配了优先加载AOF
redis如何控制AOF大小
Redis的AOF机制有点类似于Mysql binlog
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,redis引入了AOF重写机制压缩文件。文件能缩小的原因是:
1.旧文件中的无效命令不会保留,如del key1,sort。
2.多条合并成一条,如lplush list a,lplush list b转换为lplush a b,也可以合并重复项。
重写的好处:减少AOF日志尺寸,减少内存占用,加快数据库恢复时间。
AOF重写可以手动触发和自动触发:
1.手动触发可以调用bgrewriteaof。
2.根据如下两个参数自动触发。
redis.conf
#代表当前AOF文件空间和上次重写后AOF空间的比值。
auto-aof-rewrite-percentage 100
#AOP超过10m就开始收缩
auto-aof-rewrite-min-size 10mb
AOF缩减自身文件大小的时候,数据库来了新的操作怎么办?
由于AOF的重写是由Redis主线程之外一个子线程执行,是在AOF写入的时候,会重新建立一个AOF重写缓冲区,当用户对数据库进行操作时,会把用户的操作追加到AOF重写缓冲区和AOF缓冲区中,此时AOF文件写入操作会同时从AOF缓冲区和AOF重写缓冲区两个地方读入数据,这样就保证了用户的添加修改操作的不丢失。