redis保证与数据库数据一致性方案:
延时双删除:先删除redis--》更新mysql--》 延时1秒--》删除redis
为什么:第一次删除,保证再低并发读的时候,数据一致
延时删除 :保证在频繁写的时候,数据的一致性
另外如果再设置一个过期时间,就可以完全保证数据的一致性;
6种淘汰策略:
访问过期:
如果查询了某个过期 key,但定期删除没有删除掉,那就将其删除了。key 没过期就正常返回。
定期回收过期值:
定时任务在每个数据库空间随机检查20个键,当发现过期时删除对应的键。 如果超过检查数25%的键过期,循环执行回收逻辑直到不足25%或 运行超时为止,慢模式下超时时间为25毫秒。 如果之前回收键逻辑超时,则在Redis触发内部事件之前再次以快模 式运行回收过期键任务,快模式下超时时间为1毫秒且2秒内只能运行1次。 快慢两种模式内部删除逻辑相同,只是执行的超时时间不同。
满内存
noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。 大多数写命令都会导致占用更多的内存(有极少数会例外, 如 DEL )。
allkeys-lru:所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。
allkeys-random: 所有key通用; 随机删除一部分 key。
volatile-lru:只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。
volatile-random:只限于设置了 expire 的部分; 随机删除一部分 key。
volatile-ttl:只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。
expire就是设置过期时间
linux命令: set、get 数值会覆盖,key区分大小写 mset、mget
redies支持的数据类型: 回答:一共五种
(一)String 这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。
(二)hash 这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。
(三)list 使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适—取行情信息。就也是个生产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。
(四)set 因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。
(五)sorted set sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。
redies的持久化方法:
RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照
优点:对redies的性能影响小;重启服务,数据恢复快
缺点:定时快照,期间没有生成快照的信息可能丢失
AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集
优点:数据实时备份到日志文件,不会出现数据丢失
缺点:每次写操作都执行日志写入,消耗redies性能;产生的文件比RDB的大,数据恢复的时间慢
redies的实现分布式锁 分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁(setx实现);3. 基于ZooKeeper的分布式锁 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 分布式锁的要求: 互斥性。在任意时刻,只有一个客户端能持有锁。 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。 加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
缓存击穿: 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大
处理方法: 1、接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2、从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
缓存击穿 缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期) 这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案
1、设置热点数据永远不过期。
2、加互斥锁,
缓存雪崩 缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。 设置热点数据永远不过期。
redies的集群方式: 1.主从复制:
1.从服务器启动后,回向主服务器方式请求
2.主服务器收到请求后,执行指令,生产快照文件,并发送,期间继续执行客户端写请求,并将操作指令缓存到缓存
3.主服务器生成完快照文件后,发送给从服务器
4.从服务器完成快照的载入以后,开始接受指令请求,并开始执行主服务器写缓存的执行
5.主服务器执行写命令后,都会向从服务器方式写命令,从服务器执行相同的写操作。
优缺点:
支持主从复制,主机会自动将数据同步到从机,可以进行读写分离 Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题
哨兵的作用就是监控Redis系统的运行状况。它的功能包括以下两个。
哨兵的工作流程:
每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN) 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN) 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
优点:
哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。 主从可以自动切换,系统更健壮,可用性更高。 缺点:
Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
Redis-Cluster集群
总结:主从复制实现了读写分离,都是不能宕机切换;哨兵模式可以实现宕机的切换,但是不可以扩容;Redis-Cluster集群,使用了发片的技术,并且每个节点都可以主从切换
redis的淘汰机制
redis的数据一致问题解决方案
如果这次选举不成功,比如三个小的主从A,B,C组成的集群,A的master挂了,A的两个小弟发起选举,结果B的master投给A的小弟A1,C的master投给了A的小弟A2,这样就会发起第二次选举,选举轮次标记+1继续上面的流程。事实上从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票。 同时下面公式里面的随机数,也可以有效避免slave同时发起选举,导致的平票情况。
•延迟计算公式:
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
•SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举(理论上)。