redis结构:
String,Hash,List,Set,Zet
持久化:
RDB 快照形式
AOF 追加
1,redis既然是单线程的,为啥处理速度很快
redis每秒处理100000+的QPS,基于内存操作,只是我们在处理网络请求的时候,是单线程处理,redis Server在运行的时候肯定不止一个线程,单线程省去了很多上下文切换的时间,redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。
2.分布式锁
加锁使用setnx(); key可以为当前线程id,value随便,当执行完后返回1,表明没有加锁,可以使用,当返回0的时候,表明当key已经存在,加锁失败,解锁的话del(key),
锁超时:当线程获取锁之后,挂掉了,那么锁就无法释放,这个时候需要设置expire()超时时间,保证到期释放锁
问题一: setnx 和expire操作非原子性,解决:redis高版本有set()方法设置超时时间
问题二: 线程执行时间太长,超时时间过了,其他线程获取锁执行,redis误删其他的锁,解决:删除锁时校验是否为当前线程
校验和删除非原子性操作,可以通过LUA脚本来操作,
String luaScript = 'if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end';
redisClient.eval(luaScript , Collections.singletonList(key), Collections.singletonList(threadId));
问题三:问题二虽然避免了误操作,但是同时有两个线程在访问代码块,有高并发问题
解决:可以开启守护线程,用来给过期的锁续命,当快要到时间的时候,程序还没执行完,这个时候,守护线程会执行expire命令
续命,
虽是高可用,但是会出现问题,集群的话主从复制,是异步的,master同步到slave时候,可能会导致数据丢失
问题三,缓存穿透和缓存雪崩
缓存穿透: 无用的值,多次咋访问数据库,数据库中不存在,比如id为 -1:
解决:接口层做权限校验和基础的数据校验
针对数据库中不存在的对象,也保存到数据库中,设置有效时间短点
缓存击穿: 针对缓存中没有,但是数据库中有的数据,一旦缓存到期,由于并发量特别大,导致数据库压力大,
解决: 设置热点数据,永不过期
加互斥锁
缓存雪崩: 指大量数据同一时间到期,导致查询数据量巨大,引起数据库压力大 甚至down机,
解决: 设置有效时间随机
设置热点数据永不过期
如果redis分布式部署,则热点数据分布在不同机器上
redis 热点数据问题:
如何查找热点数据,根据点击量或根据时间可以用Zset(),set(key1, key2,value);
来源:CSDN
作者:初衷不悔
链接:https://blog.csdn.net/weixin_39048143/article/details/103608559