Redis 作为轻量级的NoSql缓存数据库,有着使用简单快速的特点,并且可以方便实现分布式锁,为日常应用开发常用的一个技术栈,本文就简略介绍Redis,并且基于Redis 6.6版本。
Redis的常用数据结构
String | 底层是个数组链表,值不到1M,会double的扩容,之后扩容增加1M,最大是512M |
List | zipList的双向链表,zipList是一块连续的空间,超过zipList的大小后会再分配一块空间的zipList |
Set | 底层是一个hash表,数据无序并且不允许重复数据 |
Zset | 无重复数据的有序集合,用source来进行权重排序,底层数据结构部分是HashMap<String,Double>, 也有部分是跳跃表,将数据进行分层跳跃查询 |
Hash | 类似hashMap,存储对象, 适合存储对象,数据量小用zipList,数据量大用hashtable |
Bitmap | 是可以进行位操作的字符串,可以按位进行数据的设置,并且可以取 [与 或 非],使用场景可以是存储大量活跃用户 |
hyperLogLog | 统计基数【数据不同】,占用空间会比bitMaps,Set,Hash要小,并且可以不同k值之间进行merge |
geosaptial | 针对地理信息经纬度进行操作,可以设置单位显示地区的距离,南北极暂时不包括 |
Redis事物
事务是一个单独的隔离操作,所有命令都会序列化、按顺序地执行,执行过程中也不会被其他客户端发送来的命令请求打断。
Muti【组队阶段开启事务】 ---> Exec【执行事务阶段】
Diacard【取消事务】
1. 组队阶段有错误,执行中全部不执行
2. 组队中没有错误,执行中只有执行有误的被不执行
Redis事务是乐观锁,通过版本号来支持,可以通过watch 指令来观测事务执行的结果
Redis持久化
Redis 是缓存数据库,存储到磁盘上被称为持久化;启动时都会自动同步到redis缓存中去
持久化的2个方式,RDB和AOP,都开启默认优先使用AOF的文件数据
1.【RDB】
1)RDB 指定的时间间隔内,将内存中的数据集快照写入磁盘,恢复时将快照文件直接读入内存里 save同步/bgsave异步,默认开启
A:使用:可以自己自助配置规则:20s内有3个key进行持久化
B:会开启一个fork的线程进行数据的同步,数据会暂时写到一个临时的文件中,写完之后再替换到dump.db文件中【写时复制技术】
C:若发生redis宕机,会丢失最后一次未同步到dump文件中的数据
D:大量的数据同步需要2倍的持久化文件的空间
2.【AOP】
AOF 【Append Only File】默认不开启 appendonlyfile yes
A:记录redis中的所有写操作(增删改)追加的到文件中去,不仅记录数据,还要记录指令
B:文件损坏,可以通过redis-check-aof --fix修复
C: AOF缓存策略:
appendfsync always 始终进行同步,不会丢失数据,但性能比较差
appendfsync everysec 每秒钟进行同步,宕机会丢失当前秒数据
appendfsync no 不主动同步数据,把同步机制
D:压缩重写aof文件,当文件大小超过128M的时候,会自动开启压缩重写aof文件的线程,会将aof文件内容按照压缩指令写到一个临时的文件中,当文件写完毕之后,再将aof文件进行替换,跟RDB机制一样,写时复制技术
Redis主从复制
主节点负责写,从节点负责读,分散主节点的读写压力;
【配置】
include /default/redis.conf
pidfile /var/run/redis_XXX.pid
port XXX
dbfilename dumpXXX.db
【从节点配置】
1)slaveof ip port 将该节点配置成从节点
2)slaveof no one 将从节点变成主节点
3) 一个从节点也可以是另一个从节点的主节点
【查看信息】
1)info replication
【特点】
1)从服务器挂掉重启后要手动重新加入从节点,加入后的从节点能同步主节点当前所有的缓存信息
2)主服务器挂掉后,从服务器不会任何变化,主服务器重启后跟挂掉之前一致,自动连接从节点
【主从复制原理】
1)从服务器加入后,主动向master发送同步数据消息
2)master接到消息后,进行数据的持久化,rdb文件,并将持久化后的文件发送给从节点,从节点读取文件到内存中,完成全量同步数据
3)之后master节点有新的内容后会主动发送数据到从节点,完成增量的数据同步
【哨兵模式】
1)需要启动sentinel,配置的数量是1的话,代表有一台机器在主节点挂掉后,同意选举即可开始选举
2)选举可以通过 replica-probity 进行配置优先级,数字小的优先级高
3)相同优先级选择同步数据offset大的
4)都相同选择run id小的,runId为redis启动时自动创建的40多位的唯一码
Redis集群
【集群配置】
include /myredis/redis.conf
pidfile "/var/run/redis_6379.pid"
port 6379
dbfilename "dump6379.rdb"
cluster-enable yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
【启动】
{replicas 1 }最简单的分配方式
redis-cli --cluster create --cluster-replicas 1 ip:port
【分配原则】
不同master尽量属于不同的主机,slave节点尽量不与自己的master节点是同一主机
【存储数据】
1)数据存储的过程中,会对Key值进行计算,得出数值放到固定的slot中,redis cluster有16783个slot,比如3个集群进行均分,计算的key值根据值将数据进行存储;不属于本slot的集群接到请求,会将请求进行转发到固定slot所在的机器;
2)添加多个key值需要进行分组,分组的组名将进行key值的计算。
【查询流程】
「计算k1的数值」
cluster keyslot k1
「计算本主机内slot12708内的key有多少个」
cluster countkeysinslot 12708
「获取在本机内前4个的key值」
cluster getkeysinslot 4
【故障恢复】
cluster中某主节点挂掉,从节点主动上升为master节点,挂掉节点重启后自动变为从节点
cluster-require-full-coverage yes
集群中某主从节点挂掉,整个集群不再提供服务
cluster-require-full-coverage no
集群中某主从节点挂掉,挂掉的节点slot部分不再提供服务
Redis应用常见问题
缓存击穿
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
【解决方案】
1)预先设置热门数据,加大key时长
2)实时调整
3)使用锁 :设置热点数据永远不过期。 加互斥锁,互斥锁
缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
【解决方案】
1)空值进行缓存
2)设置白名单:用bitmaps
3)采用布隆过滤器
4)进行实时监控:需要排查访问对象
缓存雪崩
缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉
【有效应对】
1)构建多级缓存架构:nginx + redis + 其他缓存
2)使用锁或者队列
3)设置过期标志更新缓存(当缓存快过期的时候,开启新线程进行缓存更新)
4)将缓存失效时间分散开
Redis 分布式锁
1. 分布式加锁,并设置锁的过期时间,setnxAndexprie
【解决锁无法释放的问题,并解决两个指令的原子性问题】
2.采用uuid形式验证是否是自己的加的锁,之后再进行删除
3.lua脚本支持原子性操作,不会被其他命令插队,保证操作redis的原子性