Redis
Remote Dictionary Server,采用 ANSI C 编写的 K-V数据库
类型
-
string 最大存储值为256mb,底层由SDS(simple dynamic string)实现,优势是访问长度仅需O(1)
-
hash
-
list 存储有序字符串,最大2^32-1个元素
-
set
同list,但不允许重复
- sorted set 已排序的都字符串集合,但不允许重复
– 其它
- GEO 地理位置
- HyperLogLog 基数统计
- Bitsmap bit数组,类似boolean filter
redis设计架构
-
单线程业务,多线程存储,redis6.0引入多线程也仅仅是为了提高解析命令的速度
-
虚拟内存
虚拟内存机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。
击穿,穿透,雪崩
击穿
某个key在过期点的时候,突然出现大量请求查找这个key
穿透
访问一个不存在的key的时候
雪崩
指缓存中数据大批量到过期时间,访问落到db上,造成db压力过大
持久化机制
RDB
RDB持久化,是指在指定的时间间隔内,执行指定次数的写操作,将内存中的数据集快照写入磁盘中,它是Redis默认的持久化方式。执行完操作后,在指定目录下会生成一个dump.rdb文件,Redis 重启的时候,通过加载dump.rdb文件来恢复数据
分为手动触发和自动触发
优点 适合大规模的数据恢复场景,如备份,全量复制等
缺点 没办法做到实时持久化/秒级持久化。
AOF
采用日志的形式来记录每个写操作,追加到文件中,重启时再重新执行AOF文件中的命令来恢复数据。它主要解决数据持久化的实时性问题
优点 数据一致性和完整性更高 缺点 内容越多,文件越大,恢复变慢,它需要将所有命令执行一遍
高可用
主从
类似mysql主从,master负责写,slave负责读
哨兵
监视其他节点的状态
集群
Gossip,HashSlot 16384
分布式锁
setnx
setnx nx [expired]
优点:实现简单
缺点:若在分布式中未同步则会造成多个client获取到锁
redisson
优点:可用性高
缺点:需要自己循环获取锁,性能消耗高,同setnx的缺点
redlock
优点:解决了单点问题
缺点:维护成本高
持久化
AOF
-
AOF文件中实际存储的是 Redis 协议下的命令记录,把每一次写操作以追加的形式记录在其中以文件的形式刷到磁盘里.
-
fsync
策略-
无
fsync
: 数据容易丢失 -
每秒
fsync
: 默认策略,性能正常,由后台线程执行,最多丢失1秒的数据,但文件大小随着时间线性增长,若用来恢复数据会非常缓慢。 -
每次写
fsync
: 牺牲大部分性能,文件也大,但基本不会丢失数据
-
RDB
-
一种快照机制,每个一段时间会对内存数据进行一次快照,保存在
rdb
文件中 -
SAVE
和BGSAVE
命令分别是同步保存和 fork 子进程保存 -
RDB 文件非常紧凑,它保存了 Redis 某个时间点上的数据集。RDB 恢复大数据集时速度要比 AOF 快。但是 RDB 不适合那些对时效性要求很高的业务,因为它只保存了快照,在进行恢复时会导致一些时间内的数据丢失。
-
如果数据量很大的话
rdb
它要保存一个完整的数据集 是一个大的工作 如果时间间隔设置的太短,那么严重影响redis的性能 但是按照常规设置的话 如5分钟一次 那么如果宕机或者重启 就会基于上次做rdb的时间,而丢失分钟级的数据
管道技术
-
Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
-
管道技术最显著的优势是提高了 redis 服务的性能。
事务
-
批量操作在发送 EXEC 命令前被放入队列缓存。
-
收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
-
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:
- 开始事务。
- 命令入队。
- 执行事务。
+命令 | 描述 |
---|---|
DISCARD |
取消事务,放弃执行事务块内的所有命令。 |
EXEC |
执行所有事务块内的命令。 |
MULTI |
标记一个事务块的开始。 |
UNWATCH |
取消 WATCH 命令对所有 key 的监视。 |
WATCH key [key ...]
监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
集群
概念
-
Redis集群中的节点都需要打开两个TCP连接。一个连接用于正常的给Client提供服务,比如6379,还有一个额外的端口(通过在这个端口号上加10000)作为数据端口,比如16379。第二个端口用于集群总线,这是一个用二进制协议的点对点通信信道。这个集群总线(Cluster bus)用于节点的失败侦测、配置更新、故障转移授权,等等。客户端从来都不应该尝试和这些集群总线端口通信,它们只应该和正常的Redis命令端口进行通信。注意,确保在你的防火墙中开放着两个端口,否则,Redis集群节点之间将无法通信。
-
所有
Redis
节点彼此相连(内部 PING-PONG)机制 -
节点
Fail
至少通过集群半数以上的节点检测失效才生效 -
客户端只需要连接其中一个节点即可
-
Redis-Cluster
负责把物理节点映射到[0-16383]slot
上,cluster
负责维护node <-> slot <-> value
Redis 集群分片
-
Redis
集群不同一致性哈希,它用一种不同的分片形式,在这种形式中,每个key都是一个概念性(hash slot)的一部分。 Redis集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点 -
允许添加和删除集群节点。如增加一个新的节点D,那么需要从A、B、C节点上删除一些hash slot给到D。同样地,如果从集群中删除节点A,那么会将A上面的hash slot 移动到B和C,当节点A上是空的时候就可以将其从集群中完全删除。
Redis 集群主从模式
-
投票过程需要整个集群的
Master
节点参与,当其中存在与集群半数以上的Master
节点通讯失败,则剔除此Master
-
Master-Slave
模式,当集群中有Master
节点失败的话,则其Slave
节点将有一个提升为新的Master
节点。 -
如果集群任意
Master
挂掉,若其没有Slave
.集群进入fail
状态,也可以理解成集群的slot映射[0-16383]
不完整时进入fail状态. -
如果集群超过半数以上
master
挂掉,无论是否有slave
,集群进入fail
状态.
#主从模式配置
bind 0.0.0.0
port 6379
logfile "6379.log"
dbfilename "dump-6379.rdb"
daemonize yes
rdbcompression yes
#slaveof 192.168.81.135 6379 这个配置应用的是slave节点,指定的是 master 节点
# slave-read-only yes 默认 slave 节点只提供读取,可以通过设置
Reids 集群一致性
Redis
集群不能保证强一致性
集群搭建
- 修改配置文件
# redis.conf文件 #客户端端口 port 7000 #pid文件 pidfile /var/run/redis_6379.pid # 启用集群 cluster-enable yes # 由redis集群自动生成 cluster-config-file nodes.conf # 集群ping-pong超时时间 ms cluster-node-timeout 5000 #是否启用aof appendonly on
名词解释
这几种情况都是从缓存没有获取到数据,大量的并发请求到了数据源,给数据源造成很大压力,从而可能引发问题
-
缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
-
缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
-
缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
优化
-
使用短的key
-
避免使用
keys *
:这个命令是阻塞的,使用SCAN
代替 -
设置
key
的过期时间
线上解决方案
-
缓存穿透 采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。 提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。 对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
-
缓存击穿 利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。
-
缓存雪崩 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期