1) Redis的数据存放在内存中(速度快;减少计算的时间;减轻数据库压力);
请求处理单线程( 没有创建线程、销毁线程带来的消耗;b. 避免了上线文切换导致的CPU消耗;c. 避免了线程之间带来的竞争问题,例如加锁释放锁死锁等等);
同步非阻塞 I/O,多路复用处理并发连接.。
2)相比HashMap/Memcached,其有更丰富的数据类型;支持多种编程语言;功能丰富:持久化机制、内存淘汰策略、事务、发布订阅;支持集群、分布式
3)单个命令是原子性的(比如get set mget mset),要么成功要么失败,不存在并发干扰的问题
4)提供一组命令同时执行,提供事务(multi )和监听(watch)---->
事务可能引发的问题:例如入队的命令语法错误会直接报错不执行。但比如对String 使用Hash的命令,参数个数正确,但数据类型错误等的运行时错误只有错位的命令没有执行,但其他命令没有受到影响
5)支持Lua脚本: 一次发送多个命令,减少网络开销;Redis会将整个脚本作为一个整体执行,不会被其他请求打断,保持原子性;对于复杂的组合命令,我们可以放在文件中,可以实现命令复用;
2. 缓存和数据库不一致
非高并发下: 双删策略 先删缓存 写数据库 延迟 再删缓存
高并发下 : 内存队列做 异步串行化
删除缓存->更新数据库
读缓存发现不存在->将更新缓存请求放入队列,然后等待,同样的读操作
3.缓存雪崩:缓存挂掉 导致 数据都去请求DB
发生前:
存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
设置热点数据永远不过期
发生中:
中:本地eccache缓存+hystrix限流 降级
后:redis持久化,一旦重启自动从磁盘加载数据 快速恢复
4.缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案:
接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
5.缓存击穿:
热点问题缓存过期恰好被大量访问,这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
1、热点数据永不过期
2、加锁 第一个线程若未读到数据就加锁从数据库读取,然后放入。
3、定时过期前获取
6.内存回收
1)立即过期(主动淘汰) 2)惰性过期(被动淘汰) 3)定期过期
7.淘汰策略
Redis的内存淘汰策略,是指当内存使用达到最大内存极限时,需要使用淘汰算法来决定清理掉哪些数据,以保证新数据的存入。
1)策略 (建议使用volatile-Iru,在保证正常服务的情况下,优先删除最近最少使用的key。)
后缀: LRU,最近最少使用。 LFU,最不常用,按照使用频率删除, random,随机删除
前缀: volatile是针对设置了ttl的key,allkeys是针对所有
策略 |
含义 |
noeviction |
默认策略,不会删除任何数据,拒绝所有写入操作并返回客户端错误信息(error)OOM command not allowed when used memory,此时 Redis只响应读操作。 |
volatile-lru |
根据LRU算法删除设置了超时属性(expire)的键,直到腾出足够内存为止。如果没有可删除的键对象,回退到noeviction策略。 |
allkeys-lru |
根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够内存为止。 |
volatile-lfu |
在带有过期时间的键中选择最不常用的。 |
allkeys-lfu |
在所有的键中选择最不常用的,不管数据有没有设置超时属性。 |
volatile-random |
在带有过期时间的键中随机选择。 |
allkeys-random |
随机删除所有键,直到腾出足够内存为止。 |
volatile-ttl |
根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略。 |
如果没有设置ttl或者没有符合前提条件的 key 被淘汰,那么 volatile-Iru、volatile-random、volatile-ttl 相当于 noeviction(不做内存回收)
6.Redis持久化策略
https://blog.csdn.net/zhouhuahao/article/details/116058232
7.高可用
1)哨兵:
本质上只是一个运行在特殊模式之下的Redis。Sentinel 通过info命令得到被监听Redis 机器的 master,slave等信息。以够实现主从自动切换和获取主从切换后的最新的master节点, 来保证服务的可用性
2)Sentinel 集群
Raf算法: 准备(都是Follower状态)--- > 产生候选节点 ----> Leader选举 -----> 心跳检测 ----> 日志复制(节点同步)
3) master选举和从节点产生
对于所有的slave节点,一共有四个因素影响选举的结果,分别是断开连接时长、优先级排序、复制数量、进程id。
Ⅰ、如果与哨兵连接断开的比较久,超过了某个阈值,就直接失去了选举权。
Ⅱ、如果拥有选举权,那就看谁的优先级高,这个在配置文件里可以设置(replica-priority 100),数值越小优先级越高。
Ⅲ、如果优先级相同,就看谁从master中复制的数据最多(复制偏移量最大),选最多的那个
Ⅳ、如果复制数量也相同,就选择进程id最小的那个。
Ⅵ、选出Sentinel Leader之后,由Sentinel Leader向某个节点发送 slaveof no one 命令,让它成为独立节点。然后向其他节点发送slaveof x.x.x.xxxxx(本机IP端口),让它们成为这个节点的从节点,故障转移完成
4) 10秒一次发送info命令获取最新拓扑结构 只监控主节点即可 ;2秒一次 判断各个节点的哨兵对主节点是否正确一致; 1秒一次 每个哨兵向各个节点 及其他哨兵发送ping 判断心跳
10.Redis-Cluster集群
其结构特点:
1、所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
2、节点的fail是通过集群中超过半数的节点检测失效时才生效。
3、客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
4、redis-cluster把所有的物理节点映射到[0-16383]slot上(不一定是平均分配),cluster 负责维护node<->slot<->value。
5、Redis集群预分好16384个桶,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中。