redis 核心
数据类型
| 类型 | 存储的值 | 读写能力 |
|---|---|---|
| String | 字符串,整数,浮点数,二进制 | 1.对整个字符串或字符串中的一部分执行操作 2.对整数或浮点数进行自增或自减 |
| List | 链表上每一个节点都包含了一个字符串 | 1.从链表两端进出元素 2.对链表进行修剪 3.读取单个或多个元素 4.根据值查找或移除元素 |
| Set | 字符串的无序集合,且唯一 | 1.添加,获取,删除,查找元素 2.交集,并集,差集 3.随机获取元素 |
| Hash | 键值对无序散列集 | 1.添加,获取,删除单个键值对 2.获取所有键值对 |
| ZSet | 字符串和浮点数之间的有序映射 | 1.添加,获取,删除单个元素 |
内存淘汰策略
- volatile-lru:从已经设置过期时间的数据集中,挑选最近最少使用的数据淘汰
- volatile-ttl:从已经设置过期时间的数据集中,挑选即将要过期的数据淘汰
- volatile-random:从已经设置过期时间的数据集中,随机挑选数据淘汰
- allkeys-lru:从所有的数据集中,挑选最近最少使用的数据淘汰
- allkeys-random:从所有的数据集中,随机挑选数据淘汰
- no-enviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键
过期策略
redis 为什么会有一个内存淘汰策略呢?
因为redis使用的过期策略是 定期删除 + 惰性删除
定期删除
redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的 key。
Redis 默认会每秒进行十次过期扫描(100ms一次),过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。从过期字典中随机 20 个 key;删除这 20 个 key 中已经过期的 key;
如果过期的 key 比率超过 1/4,那就重复步骤 1;
redis默认是每隔 100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载!
总结:定时随机的去删除过期的20个key
惰性删除
所谓惰性策略就是在客户端访问这个key的时候,redis对key的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西。
定期删除可能会导致很多过期key到了时间并没有被删除掉。所以就有了惰性删除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那个 key,才会被redis给删除掉。这就是所谓的惰性删除,即当你主动去查过期的key时,如果发现key过期了,就立即进行删除,不返回任何东西.
定期删除是集中处理,惰性删除是零散处理。
为什么要采用定期删除+惰性删除2种策略呢?
如果过期就删除。假设redis里放了10万个key,都设置了过期时间,你每隔几百毫秒,就检查10万个key,那redis基本上就死了,cpu负载会很高的,消耗在你的检查过期key上了.
但是问题是,定期删除可能会导致很多过期key到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。
并不是key到时间就被删除掉,而是你查询这个key的时候,redis再懒惰的检查一下
通过上述两种手段结合起来,保证过期的key一定会被干掉。
所以说用了上述2种策略后,上面说的内存淘汰机制这种现象就不难解释了:数据明明都过期了,但是还占有着内存
持久化
什么是持久化?
持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化Redis所有数据保持在内存中,对数据的更新将异步地保存到磁盘上。
redis 持久化方式?
- RDB---数据快照(默认)
- AOF---日志追加
RDB
RDB 持久化原理?
通过bgsave命令触发,然后父进程执行fork操作创建子进程,子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换(定时一次性将所有数据进行快照成一份副本存储在硬盘中)
RDB 优缺点?
优点: 是一个紧凑压缩的二进制文件,非常适合备份和灾难恢复,Redis加载RDB恢复数据远远快于AOF的方式。
缺点: 由于每次生成RDB开销较大,非实时持久化,当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。
RDB 配置:
save 900 1 在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10 在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。
rdbcompression ;默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。
rdbchecksum :默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,
但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
dbfilename :设置快照的文件名,默认是 dump.rdb
dir:设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名
关闭RDB:
1. redis-cli命令:config set save ""
2. 注释掉所有的 save 并开启 save ""
AOF
AOF 持久化原理?
开启后,Redis每执行一个修改数据的命令,都会把这个命令添加到AOF文件中。
AOF 优缺点?
优点: 实时持久化, AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写
缺点: 所以AOF文件体积逐渐变大,需要定期执行重写操作来降低文件体积,加载慢
AOF 配置:
appendfsync always 每次有数据修改发生时都会写入AOF文件。
appendfsync everysec 每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no 从不同步。高效但是数据不会被持久化。
appendonly yes|no 开启 关闭
appendfilename xxx 文件名
RDB 和 AOF 比较
| 命令 | RDB | AOF |
|---|---|---|
| 启动优先级 | 低 | 高 |
| 体积 | 小 | 大 |
| 恢复速度 | 快 | 慢 |
| 数据安全性 | 丢数据 | 根据策略决定 |
| 轻重 | 重 | 轻 |
| 占用存储空间 | 小 | 大 |
| 存储速度 | 慢 | 快 |
| 资源消耗 | 高 | 低 |
缓存问题
认识
缓存穿透: key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
缓存击穿: key对应的数据源存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
缓存雪崩: 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库
解决方案:
缓存穿透:
- 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力.
- 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
- 不管数据是否为空都进行缓存,为空可以设置很短的过期时间。
缓存击穿:
- 设置热点数据永远不过期,或者定时去更新热点数据
- 加锁,例如:使用互斥锁(mutex key)
缓存雪崩:
- reids 高可用 ;
- 通过加锁或者队列来限流并降级以达到降低DB压力(隔离组件)
- 数据预热,或热点数据永不过期
- 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
redis 高级使用
- 分布式锁
- 接口限流
- 共享session
- 接口幂等性
- 事务
- 订阅发布
redis 集群
主从模式
主从复制原理:
- 从服务器连接主服务器,发送SYNC命令;
- 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器bgsave执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成)
- 主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令(从服务器初始化完成后的操作)
主从复制优缺点:
优点:
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
- 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成
- Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。
- Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
- Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据
缺点:
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
哨兵模式
哨兵的主要功能:
- 监控所有节点数据库是否在正常运行
- master数据库出现故障时,可以自动通过投票机制,从slave节点中选举新的master,实现将从数据库转换为主数据库的自动切换。
哨兵模式的工作方式:
- 每个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较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂
- 当主服务器宕机后,从服务器切换成主服务器的那段时间,服务是不能用的。
cluster 模式
redis的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台redis服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了cluster模式,实现的redis的分布式存储,也就是说每台redis节点上存储不同的内容。
Redis-Cluster采用无中心结构,它的特点如下:
- 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
- 节点的fail是通过集群中超过半数的节点检测失效时才生效。
- 客户端与redis节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
Cluster 模式的工作方式:
在redis的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383。还有一个就是cluster,可以理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。
redis 哨兵模式实战
-
在从库的redis.windows.conf文件中配置slaveof 127.0.0.1 6380(主库的ip+port),如果主库有密码则配置masterauth ***
-
每一个redis目录中新建一份sentinel.conf 文件(port 不一致,其它保持一致,如果有该文件则不需要新建),内容为:
port 27001
sentinel monitor mymaster 127.0.0.1 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel config-epoch mymaster 14
sentinel leader-epoch mymaster 2
参数说明:
(1)sentinel monitor <master-name> <ip> <redis-port> <quorum>
master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了
例:sentinel monitor mymaster 127.0.0.1 6379 2
(2) sentinel down-after-milliseconds mymaster 30000
指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒
(3) sentinel config-epoch mymaster 14
执行故障转移时,从节点需要等待的时间
(4) sentinel leader-epoch mymaster 2
同时一时间最多18个slave可同时更新配置,
(5) sentinel auth-pass mymaster 123456
设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码
- 启动脚本(redis 和 哨兵sentinel.conf都要启动) 编写bat启动脚本:
Redis :
cd 7001
title redis-7001
redis-server.exe redis.windows.conf
sentinel:
cd 7001
title sentinel-7001
redis-server.exe sentinel.conf –sentinel
- 全部启动然后开始测试
- 查看结果
查看redis状态:
cmd 到redis目录 -> redis-cli.exe -p 7001 如有密码,则 auth 密码 -> info replication 查看
查看哨兵sentinel状态:
cmd 到redis目录 ->redis-cli.exe -p 哨兵配置端口 -> 输入info sentinel
- 可以关闭主库测试一下从库是否自动升成主库
- Springboot 连接哨兵模式,其他操作保持一致
spring:
redis:
sentinel:
master: mymaster # 主节点名称
nodes: localhost:27001,localhost:27002,localhost:27003 # 哨兵ip+port