redis单线程主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。
一、redis为什么这么快
使用内存、单线程、IO多路复用、内部数据结构
1.redis是单线程,没有使用现代多核CPU的多线程?
线程上下文切换、资源互斥访问需要加锁。代价大,复杂
2.IO多路复用模型:向服务端请求数据时,每个请求都有一个标记,有一个东西监视着标记,一旦可以响应数据,就去做操作。(类似电影院大厅的屏幕,有电影放完了就去打扫并换下一个影片)
IO阻塞模型:向服务端请求数据时,阻塞工作线程,等待响应
IO非阻塞模型:向服务端请求数据时,使用另一个线程去轮询问服务器有没有准备好数据,如果没有准备好,工作线程先去干别的工作。轮询线程一直问直到准备好了,跳出循环。
redis使用的io模型是多路复用模型
3.数据结构底层
二、持久化机制
Redis是一个基于内存的数据库,它的数据是存放在内存中,内存有个问题就是关闭服务或者断电会丢失。Redis的数据也支持写到硬盘中,这个过程就叫做持久化。
1.RDB
Redis提供如下2中持久化方式 RDB(Redis DataBase) :在指定的时间间隔内,定时的将 redis 存储的数据生成Snapshot快照并存储到磁盘等介质上;
触发rdb的时机:客户端下运行save或者bgsave
save命令会让主进程去执行持久化,这样就不能响应查询了,而且由于是向磁盘写,耗时长,一般在停机的时候使用。
bgsave命令fork一个子进程去执行持久化,主进程不受影响。
配置rdb,redis.conf配置文件中:
save 900 1 #表示在900秒内修改一次redis就执行一次bgsave命令
save " " #禁用rdb
持久化文件要保存的位置
持久化文件的名字
是否压缩,建议不开启,压缩会消耗cpu,磁盘不值钱。
问题:异步持久化,如果当redis子线程持久化的数据正常被父线程再修改的时候怎么办?
rdb内部采用COPY-ON-WRITE技术,用副本来替换原来内存中的数据
2.AOF
AOF(Append Of File) :将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。
恢复数据时,再次执行一遍日志文件。
刷盘策略
always每次写入都先保存一下命令日志。
everysec一秒做一次日志报存
no同步硬盘由操作系统完成,通常是30秒
注意:aof文件可能记录对同一个key的多次操作,没有意义,而且很长
解决??aof重写
触发时机:直接调用 bgrewriteaof 命令。
配置文件中:
auto-aof-rewrite-min-size 表示运行AOF重写时文件最小体积,默认为64MB
auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值
3.对比
AOF文件体积比较大
RDB数据不完整 60秒做一次持久化:可能数据丢失 ;AOF最多1秒做一次持久化。
AOF恢复慢,RDB恢复快。AOF需要重新执行那些命令。
三、问题
1.缓存雪崩
缓存中大量key同时失效,导致流量请求到db中,造成db负载压力过大挂掉,这种情况叫做缓存雪崩。
怎么避免? 分散key的过期时间。
2.缓存穿透
大量请求同时访问一个不存在的key,导致流量走到db。
怎么避免? 添加一个默认值null,可以使用布隆过滤器判断是不是存在
3.缓存击穿
大量请求同时访问一个过期的key,导致流量走到db。
怎么避免? 加分布式锁避免
四、架构
Redis 支持三种集群模式,分别为主从模式、哨兵模式和Cluster模式。
主从模式
在Redis的主从复制架构中,系统通过定义主库(master)和从库(slave)的角色,实现数据的高效同步和备份。
master的读写能力。当在master上执行任何改变数据的操作时,这些更改会自动且实时地同步到所有slave。
单向数据流:数据同步流是单向的,意味着数据只从master流向slave,确保了数据同步的一致性和可靠性。
slave的只读特性:slave通常被配置为只读模式,它们接收并存储从master传来的数据。这样设计主要是为了分散读取压力,从而提高系统的整体读取性能。
主slave的对应关系:一个master可以对应多个slave,形成一对多的关系。这种结构利于数据的冗余备份和读取负载的分散。相反,一个slave只能对应一个master,以保持数据同步的一致性。 slave的容错性:如果某个slave出现故障,它对系统其他部分的影响是最小的。即便在slave宕机的情况下,其它slave仍能继续提供读服务,master也能保持正常的读写操作。当故障的slave恢复后,它会自动从master同步缺失的数据。
master故障的影响:master的故障会导致Redis暂时无法处理新的写请求,但已连接的slave可以继续提供读服务。一旦master恢复,Redis会重新提供完整的读写服务。
master故障的应对机制:在当前的master发生故障时,系统不会自动在slave中选择一个新的master。这需要通过额外的高可用性解决方案来实现,例如使用Redis Sentinel或Redis Cluster来管理master的选举和故障转移。
全量同步(salve第一次连接master、salve宕机太久超过repl_backlog)
第一阶段:salve和master建立连接携带id,判断是不是第一次连接,如果是就返回版本信息。
第二阶段:执行bgsave,folk出一个进程,报存数据并发送给salve。在folk出的进程执行期间,主进程可能还会有数据存入。将存入的命令记录在一个文件中
第三阶段:发送缓存命令,salve执行缓存命令。
怎么判断是第一次连接?
salve会继承master的repID,如果id不一致说明是第一次建立连接。
增量同步 (salve断开又恢复,在repl_backlog找到offset偏移量位置的数据)
repl_backlog是一个环形数组,salve如果宕机太久就不能恢复了,就得去做全量同步。
哨兵机制
master挂了?哨兵监控集群,mater挂了选一个salve做master。原mater活了之后当salve。
1.作用
监控故障、故障转移、通知客户端那个是主节点那个是从节点
2.怎么检测节点没有挂?
心跳机制,每隔一段时间,ping一下,如果有响应就ok。如果超过半数的哨兵认为这个节点挂了,就客观认为下线了。
3.怎么选举新的主节点?
首先判断salve和redis断开的时间长度,如果超过指定值就没有选举权
判断salve配置文件中的salve-priority结点,优先级为0没有选举权,默认是1
判断salve运行id,越小优先级越高。
4.怎么进行故障转移
sentinel向选举上的节点发送slave no one 让它变成主节点
sentinel给其他的节点发送 slaveof ip 端口 ,这些节点成为新master的从节点
将故障结点强制标记为slave修改配置文件
分片集群
redis-cli -c -p 端口 集群机制启动redis客户端
1.哈希槽的概念
多个master,实现高并发写,每个master有几个slave,实现高并发的写。每个master被分配一段哈希槽,保存和获取redis值时,根据有效key(如果有{}根据{}里面的计算)计算hash值,根据hash值判断这个key存到那个master中。
发生故障时自动切换主节点。
2.一致性哈希算法
存数据:根据给节点分配的hash槽,将节点映射到哈希环上的某个位置。当存一个key时,计算该key的有效哈希。根据hash值找到哈希环的位置。顺时针找下一个节点就是这个数据要存入的节点。
新增节点:新增一个节点,计算哈希值,比如该节点在3和4之间。根据节点和值存储的映射关系,只需要修改4结点分配的哈希槽就行。无需修改全部结点的哈希槽,性能更好。