Rdis 基本工作原理 就是 线程模型;;因为redis 是由 单线程 NIO 异步的这么一个线程模型;;
1、线程模型
redis 数据类型比 memcached 多很多,可以在更多复杂的环境下用。
redis 是单线程,memcached 是多线程
存储大量小数据 redis 性能会更高,若存储 100k 以上的大数据那么memcached的性能会比 redis 好
redis功能更加强大
memcached 没有原生的集群模式,所以memcached 原生是不支持集群的
redis 官方就是支持 redis cluster 集群模式 ,比 memcached 来说更好。
为什么 Redis 单线程模型效率也能这么高;高并发 ;一共三点
1.纯内存操作
2.核心是基于非阻塞 IO 多路复用机制
3.单线程避免了多线程的频繁上下文切换问题
首先 IO 多路复用只是去监听事件和压事件,而实际去处理事件的是 事件处理器,因为是基于纯内存的多以处理事件的时候时可能只需要几毫秒就搞定了;
2、数据类型
redis 数据类型基本用法
String
这是最基本的类型了,就是普通的 set 和 get,做简单的 kv 缓存
hash
这是类似 map 的之中结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌入其他的对象)给缓存在 redis 里,然后每次读写缓存的时候,可以就操作 hash 里的某个字段。
key=42
value=
{
"id":42
“name":yaya
"age":20
}
hash 类的数据结构,主要是用来存放一些对象,把一些简单的对象给缓存起来,后续操作的时候,你可以仅仅修改这个对象中的某个 字段 的值
key=42
value=
{
"id":42
“name":yaya
"age":21
}
list
有序列表,这个是可以玩很多花样的
微博,某个大v的粉丝,就可以以 list 的格式放在 redis 里去缓存
key=某大v
value=【静静,琪琪,雅雅】
比如通过 list 存储一些列表型的数据结构,类似粉丝列表、文章的评论列表了之类的东西
比如可以通过 lrange 命令,就是从某个元素开始读取多少个元素。可以基于 list 实现分页查询,这个很棒的一个功能,基于 redis 实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页一页走。
比如可以搞一个简单的消息队列,从 list 头怼进去,从 list 尾巴哪里弄出来;
set
无序集合,自动去重;
直接基于 set 将系统里需要去重的数据丢进去,自动就给去重了。如果你需要对一些数据进行快速的全局去重,你当然也可以基于 jvm 内存里的 hashSet 进行去重,但是如果你的某个系统部署在多台机器上呢?
得基于 redis 进行全局的 set 去重;
可以基于 set 玩交集、并集、差集的操作,比如交集吧,可以把两个人的粉丝列表整一个交集,看看两个的共同好友是谁。对吧;
把两个大 v 的粉丝都放在两个 set 中,对两个 set 做交集;如果 set 做交集就百度;api调用了
sorted set zset
排序的 set 去重但是可以排序,写进去的时候一个分数,自动根据分数排序,这个可以玩很多花样,最大的特点是有个分数可以自定义排序规则
比如说你要是根据时间对数据排序,那么可以写入进去的时候用某个时间作为分数,人家自动给你按照时间排序了
排行榜:
zadd board 88 jingjing
zadd board 89 qiqi
zadd board 90 yaya
zadd board 60 htion
自动根据 分数 排序
90 yaya
89 qiqi
88 jingjing
60 htion
接下来 zrevange board 0 99,就可以获取排名前 100 的用户,zrank board username,就可以看到用户在排行榜里的排名。
zrevrange board 0 3
获取排名前 3 的用户
90 yaya
89 qiqi
88 jingjing
现在 qiqi 的排序就是在第二
zrank board qiqi
2
3、过期策略
1)redis的过期策略能介绍一下?要不你再手写一个LRU?
干掉不常用的数据,缓存时基于内存的,内存是有限的;
数据是会过期的,要么自己设置个过期时间,
set key value 过期时间(1小时)
redis 内存一共10g,你现在往里面写了 5g 的数据,结果这些数据命名你都设置了过期时间,要求这些数据 1 小时之后都会过期,结果 1 小时之后,redis机器,怎么内存还占用还是 50% 呢?5g 数据过期了,我从 redis 里面是查不到了,结果过期的数据还占用着 redis 的内存;是有这种可能的;
1)设置过期时间
2)数据明明过期了,怎么还占用着内存呢?
如果假设你设置一个一批 key 只能存活 1 个小时,那么接下来 1 小时后,redis 是怎么对这批 key 进行删除的?
redis过期策略有哪些?定期删除 + 惰性删除
答:定期删除 + 惰性删除;
所谓定期删除,指的是 redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。假设 redis 里面放了 10 万个 key ,都设置了过期时间,你每各几百毫秒,就检查 10 万个key,那么 redis 基本上就死了,cup负载会很高,消耗在你的检查过期 key 上了。注意这里不可以每个 100ms 就遍历所有的设置过期时间的 key,那样就是一场性能上的灾难,实际上 redis 是每隔 100ms 随机抽取一些 key 来检查和删除的。
但是问题是,定期删除可能会导致很多过期的 key 到了时间并没有被删除掉,那么怎么整?所以就是惰性删除了,这就是说,在你获取某个 key 的时候,redis 会检查一下这个 key 是否设置了过期时间?如果过期了此时就会删除。
并不是 key 到时间就被删除掉,而是你查询这个 key 的时候,redis 在懒惰的检查一下。
定期删除没有被删除,就是说,你的过期 key ,靠定期删除没有被删除掉,还停留在内存里,占用着你的内存呢,除非你的系统去查一下那个 key,才会被 redis 给删除掉;
通过上述两种手段结合起来,保证过期的 key 一定会被干掉;
但是实际上这还是有问题的,如果定期删除漏掉了很多过期的 key,然后你也没及时去查,也就没有惰性删除了,此时会怎么样?如果大量过期的 key 堆积在内存里,导致 redis 内存块耗尽了,咋整?
答案:走内存淘汰机制。
内存淘汰有哪些:
1)noeviction:当内存不足以容纳新写入的数据时,新写入操作会报错,这个一般没人用;
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个最常用)
3)allkeys-random:当内存不足时,在键空间中,随机移除某个 key,这个一般没人用,为啥要随机,肯定是把最近少用的 key 给干掉啊;
4)volatile-lru:当内存不足时,在设置了过期时间的键空间中,移除最近最少用的 key (这个一般不太合适)
5)volatile-random:当内存不足时,在设置了过期时间的键空间中,随机移除某个 key
6)volatile-ttl:当内存不足时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除
LRU算法:
public class LRUCache<k,v>extends LinkedHashMap<k,v>{
private final int CACHE_SIZE;
//这里就是传递进来最多能缓存多少数据
public LRUCache(int cacheSize){
super((int)Math.ceil(cacheSize/0.75)+1,0.75f,true);
//这块就是设置一个 hashmap的初始化大小,同时最后一个true指的是让linkedhashmap 按照访问顺序来进行排序,最近访问的放在头,最老访问的就是最尾
CACHE_SIZE = cacheSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest){
return size() > CACHE_SIZE;
//这个意思就是说当 map 中的数据量大于指定的缓存个数的时候,就自动删除最老的数据
}
}
4、高并发 以及 高可用
redis replication -> 主从架构 -> 读写分离 -> 水平扩容支撑读高并发
1.master 持久化对于主从架构的安全保障的意义
如果采用了主从架构,那么建议必须开启 master node 的持久化;
不建议使用 slave node 作为 master node 的数据热备,因为那样的话,如果你关掉 master 的持久化,可能在 master 宕机重启的时候数据是空的,然后可能已经过复制,salve node数据也丢失了;
master -> RDB 和 AOF 都关闭了 -> 全部在内存中
master宕机,重启,是没有本地数据可以恢复的,然后就会直接俄认为自己 IDE 数据是空的
master 就会将空的数据同步到 slave 上去,所有 slave 的数据全部清空
100%的数据丢失
第一个:master节点,必须要使用持久化机制
第二个:master的各种备份方案,要不要做,万一本地所有文件丢失了;从备份中挑选一份 RDB 去恢复 master;这样才能确保 master 启动的时候,是有数据的
即使采用了后续的高可用机制,slave node 可以自动接管 master node,但是也可能 sentinal 还没有检测到 master failure,master node 就自动重启了,还是可能导致上面的所有slave node 数据清空故障;
高可用性: 365 天,在 365 天 * 99.99%的时间内,你的系统都是可以对外提供服务的,那就是好可用性;
redis的不可用:slave node 突然死了,redis进程死了,redis所在的辑器死了,一个 slave 挂掉了,是不会影响可用性的,还有其他的 slave 在提供相同数据下的相同的对外的查询服务;如果 master node 死掉了,会怎么样?没法写数据了,写缓存的时候全部失效了, slave node 还有什么用呢,没有master 给他们复制数据了,系统相当于就是不可用了,缓存不可用,高并发高性能的缓存不可用了,大量的流量,超过mysql 最大承载能力的大并发,打流量,会涌入 mysql 中,然后mysql 会宕机,整个系统不可用;
redis 高可用架构,叫故障转移,failover,也可以叫做 主备切换
哨兵至少需要3个实例,来保证自己的健壮性;
哨兵 + redis 主从的部署架构,是不会保证数据零丢失的,只能保证 redis 集群的高可用性
对于哨兵 + redis 主从这种复杂的部署架构,尽量在测试环境 和 生产环境,都进行充足的测试和演练;
哨兵集群:经典的 3 节点哨兵集群
哨兵本身也是分布式的
Configuration:quorum = 2,majority
哨兵机制:如果master node 不行了。那么slave node 就会在几秒内升级为 master node ,在旧的master node 的内存里的哪些数据,还没来得及给slave node ,旧挂掉了。
slave node 旧成了master node了 哪些内存中没来得及复制得数据不久丢失了吗;异步复制导致得数据丢失问题;
脑裂问题:master主节点,出现异常性的,有相同的数据,相同工作的两个节点,一个大脑所有的思考和行动。大脑一分为二,想去指挥同一个人,就是脑裂;
解决异步复制和脑裂的数据丢失
min-slaves-to-write 1
min-slaves-m ax-lag 10 减少异步数据
要求至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒;如果超过;master就不会接收任何请求;
哨兵机制 怎么判断是否宕机,宕机有两种状态,sdown 和 odown 转换机制
sdown 主观宕机。就一个哨兵如果自己觉得一个 master 宕机了,那么就是宕机了;
odown 客观宕机,如果quorum数量的哨兵都觉得一个master宕机了,那么就是客观宕机
如果一个 slave 跟 master 断开连接已经超过了 down-after-molliseconds 的十倍,外加 master 宕机的时长,那么 slave 就被认为不合适选举为 master
redis高并发:主从架构,一主多从,一般来说,很多项目其实久足够了,单主用来写入数据,单机几万 QPS,多从用来查询数据,多个实例可以提供每秒 10 万的 QPS。
redis 高并发的同时,还需要容纳大量的数据:一主多从,每个实例容纳了完整的数据,比如redis 主就10g的内存量,其实你就最多只能容纳 10 g 的数据量,如果你的缓存要容纳的数据量很多,达到了几十g,甚至几百g,那你就需要 redis 集群,而且用 redis 集群之后,可以提供可能每秒几十万的读写并发;
redis高可用:如果你做主从架构部署,其实就是加上哨兵就可以了,就可以实现,任何一个实例宕机,自动会进行主备切换。
redis 如果仅仅只是将数据缓存在内存里面,如果 redis 宕机了,再重启,内存里的数据就全部都弄丢了啊,你必须得用 redis 得持久化机制,将数据写入内存得同时,异步慢慢得将数据写入磁盘文件里,进行持久化;
如果 redis 宕机了,重新启动,自动从磁盘上加载之前的一些数据,就可以了,也许会丢失少许数据,但是至少不会将所有数据都弄丢
redis 持久化的意义:
redis 的持久化 rdb、aof,的区别,各自的特点是什么,适合什么场景;
redis 的企业级的持久化方案是什么,是用来跟企业级的场景结合起来使用的?
redis 持久化的意义,在于故障恢复;
比如你部署了一个 redis ,作为 cache 缓存,当然也可以保存一些重要的数据;
RDB持久化机制的优点
RDB持久化机制的缺点
AOF持久化机制的优点
AOF持久化机制的缺点
RDB和AOF到底如何选择
企业级别的 redis 架构来说,持久化是不可减少的
企业级别 redis 集群架构:海量数据、高并发、高可用
持久化主要是做灾难恢复,数据恢复,也可以归类到高可用的一个环节里面去;
比如redis整个挂了,然后redis就不可用了,你要做的事情是让redis变得可用,尽快变得可用
重启redis,尽快让他对外提供服务,如果你没做数据备份,这个时候redis启动了,也不可以用,数据都没了,很可能说,大量的请求过来,缓存全部都无法命中,在redis里面根本找不到数据,这个时候就死定了,缓存雪崩问题,所有请求,没有redis命中,就会musql数据库这种数据源头中去找,一下mysql承接高并发,然后就挂了;
RDB 恢复比 AOF 快
雪崩 和 穿透 是缓存最常见的现象;
缓存雪崩发生的现象:假设现在每秒 5000 请求过来;缓存在高峰期可以抗每秒 4000 次请求;所以这时候 缓存就会宕机;缓存宕机后 请求就会落到 数据库 ;高峰期,每秒有 1000 个请求落到数据库上;现在缓存宕机 有5000个请求落到了数据库;所以现在数据库也宕机了;数据库 一秒最多2000个请求;此时数据库会直接奔溃;缓存完了数据库完了 这个整个系统死了;
因为缓存事故,导致雪崩,进而导致公司收到损;缓存整体奔溃,雪崩,后台系统全部奔溃;只要缓存没有好,数据库你随便怎么启动都会奔溃;
缓存雪崩的事前事中事后的解决方案
事前:保证 redis 集群高可用,主从 + 哨兵,redis cluster,避免全盘奔溃;
事中:ehcache本地缓存 + hystrlx限流&降级,避免 MySql被打死:::1、用户发送一个请求 2、你收到请求,先查询本地缓存 如果没有在查询 redis 3、如果 ehcache 和 redis 都没有,就查询数据库 4、将数据库中的结果,写入 ehcache 和 redis;
事后:
缓存穿透的现象:
缓存穿透的解决:
原文:https://www.cnblogs.com/H-hy/p/11322853.html