Redis原理

Redis内存模型

redisServer
public class redisServer {int dbnum;// 当前redis节点内数据库数量,默认16redisDb[] db;// 数组,保存数据库信息redisClient clients;// 链表,保存客户端信息// serverCron函数维护的属性Date unixtime;// 秒级别时间戳long mstime;// 毫秒级别时间戳Date lruclock;// LRU时钟,每十秒更新一次long ops_sec_samples;// Redis server每秒执行命令次数long stat_peak_memory;// Redis server内存峰值记录int shutdown_asap;// Redis server运行状态 1关闭 0运行int cronloops;// serverCron函数计数器// 持久化相关String rdb_child_pid;// 执行BGSAVE子进程ID,-1表示未执行String aof_child_pid;// 执行BGREWRITEAOF子进程ID,-1表示未执行long dirty;// 修改计数器Date lastsave;// 上次BGSAVE时间sdshdr aof_buf;// AOF缓冲区// 慢查询相关long slowlog_entry_id;// 下一条慢查询日志IDObject slowlog;// 慢查询日志链表long slowlog_log_slower_than;// 超出该属性值则为慢查询,单位微秒long slowlog_max_len;// 慢查询日志保存数量
}
redisDb
public class redisDb{dict dict;// 保存键值对dict expires;// 保存设置过期时间的键和过期时间dict watched_keys;// 保存被WATCH监视的键
}
redisClient
public class redisClient{redisDb db;// 当前客户端正在使用的数据库sdshdr querybuf;// 输入缓冲区String[] argv;// 命令与命令参数数组int argc;// argv长度sdshdr buf;// 输出缓冲区int bufpos;// buf已使用长度int authenticated;// 0未通过身份验证 1通过身份验证
}

Redis数据结构

Redis Java对象形式展示Redis数据结构

Redis运行机制

Redis server初始化
  1. 实例化redisServer对象
  2. 根据用户指定参数和配置文件初始化redisServer对象属性
  3. 初始化redisServer对象其他属性
  4. 创建常量:“OK"字符串和"0”-"9999"字符串
  5. 为serverCron创建时间事件
  6. 加载持久化文件(AOF或RDB)
  7. 开始执行时间事件

第六步加载持久化文件流程图

Created with Raphaël 2.3.0redis启动是否开启aof?是否存在aof文件重播aof文件是否成功启动成功启动失败是否存在rdb文件加载rdb文件是否成功yesnoyesnoyesnoyesnoyesno
Redis client发送请求
  1. Redis client将操作指令根据RESP协议进行封装
  2. Redis client调用write将消息写入操作系统内核的send buffer
  3. 操作系统内核将消息发送至网卡
  4. 网卡通过网际路由发送至服务器网卡
Redis server接收请求
  1. 服务器网卡接收到消息
  2. 操作系统内核将消息放至recv buffer
  3. Redis server调用read将消息保存至redisClient.querybuf(输入缓冲区)
  4. Redis server解析请求内容,保存至redisClient.argv(操作命令与操作命令参数数组)redisClient.argc(argv长度)
  5. 调用操作命令执行器
Redis server处理请求
  1. 根据操作命令去命令表查询操作命令对应的命令函数(redisCommand)
  2. 根据redisClient.argc和redisCommand.arity验证操作命令参数个数是否正确
  3. 根据redisClient.authenticated验证客户端是否通过身份验证
  4. 调用命令函数
  5. 将处理结果保存至redisClient.buf(输出缓冲区)
  6. 进行后续处理(慢查询日志 & redisCommand计数+1 & AOF & 同步)
  7. 将处理结果发送给Redis client

Redis其他维护工作
读取一个键时,判断如果已过期,则删除
读取一个键后,更新命中或不命中次数
读取一个键后,更新LRU时间
修改一个键时,判断是否有客户端watch这个键,有则设为脏
修改一个键后,redisServer.dirty+1
修改一个键后,同步给其他节点

Redis事件

文件事件

套接字:socket
IO多路复用程序:Redis底层使用epoll
文件事件分派器:事件执行者
事件处理器:连接应答处理器、命令请求处理器和命令回复处理器

文件事件处理流程

  1. 套接字准备好执行连接应答、写入、读取、关闭等操作时,会产生一个文件事件
  2. IO多路复用程序监听多个套接字,把产生事件的套接字放在一个队列里
  3. IO多路复用程序有序推送套接字给文件事件分派器
  4. 文件事件分派器根据事件类型,选择事件处理器调用函数
时间事件serverCron函数
  1. 更新时间戳redisServer.unixtime和redisServer.mstime
  2. 更新LRU时钟redisServer.lruclock
  3. 更新Redis server每秒执行命令次数redisServer.ops_sec_samples
  4. 更新Redis server内存峰值记录redisServer.stat_peak_memory
  5. 处理SIGTERM信号,接收到SIGTERM信号把redisServer.shutdown_asap设置为1
  6. 检查客户端资源
  7. 检查数据库资源
  8. 检查持久化操作运行状态
  9. 如果开启AOF持久化,将AOF缓冲区内容写入AOF
  10. redisServer.cronloops+1

第七步检查数据库资源补充
检查数据库资源主要就是根据删除策略删除部分过期的键。

删除策略
定时删除:设置键过期时间的同时创建一个定时器,由Redis时间事件触发删除(该时间事件并不是serverCron)
惰性删除:访问一个键的时候判断是否过期,过期则删除
定期删除:这种策略是以上两种策略的折中方案,可以手动配置执行时长和频率(默认扫描超时时间25ms)

Redis使用的删除策略
惰性删除+定期删除

定期删除实现原理
每次检查一个数据库的键,若过期则删除,用一个全局变量记录检查到第几个数据库,下次执行定期删除继续检查后一个数据库,直至所有数据库全部检查完,全局变量置为0

redis内存不足时处理策略
noeviction:停止写服务,可执行读请求和del请求(默认策略)
volatile-lru:删除设置了过期时间的key(最少使用次数的key)
volatile-ttl:删除设置了过期时间的key(寿命最短的key)
volatile-random:删除设置了过期时间的key(随机的key)
allkeys-lru:删除最少使用次数的key
allkeys-random:删除寿命最短的key
volatile-xxx:删除设置了过期时间的key
allkeys-xxx:删除所有key

Redis持久化

RDB

触发条件
手动触发(save命令和bgsave命令)
自动触发(save m n)(主从复制)(shutdown命令)

  • save命令会阻塞Redis server,直至RDB文件创建完成(基本弃用)
  • bgsave命令会创建子进程来生成RDB文件,创建子进程过程中父进程阻塞
  • save m n指m秒发生n次操作,会自动触发bgsave;根据redisServer.dirty和redisServer.lastsave属性进行判断,由时间事件serverCron负责触发
  • 主从复制场景下,从节点执行全量复制,主节点会执行bgsave命令,将RDB文件发送给从节点
  • shutdown命令会自动生成RDB文件,然后再结束进程

bgsave执行流程

  1. 父进程根据redisServer.rdb_child_pid判断是否有正在执行的子进程,有就直接返回
  2. fork子进程,fork过程中父进程阻塞
  3. fork完成,父进程继续处理请求,子进程创建RDB文件(全量数据)
  4. 子进程发送信号给父进程
  5. serverCron函数识别信号并替换RDB文件

父进程和子进程共享内存数据,父进程修改数据会拷贝数据页(4K),在备份上进行修改
过期的键不会保存至RDB文件
主节点加载RDB文件时,过期键不会加载至内存
从节点加载RDB文件时,会全量加载,从节点不会主动删除键,主节点发送del命令才能删除

AOF

开启AOF持久化:appendonly yes
AOF执行流程分为三步:命令追加+文件写入+文件重写

  • 命令追加:将执行成功的修改操作写入redisServer.aof_buf
  • 文件写入:根据策略将缓冲区数据写入磁盘
    always:缓冲区有数据就写入磁盘(每一条都会写,写完再执行,不会丢数据)
    no:等待操作系统通过write命令调用,通常为30秒一次
    everysec:等待操作系统通过fsync命令调用,每秒一次(默认策略)
  • 文件重写:将Redis内的数据转换成命令,写入新的AOF文件

文件重写触发条件
手动触发(bgrewriteaof命令)
自动触发(AOF文件超过64MB 并且 新AOF文件大于原AOF文件)
为什么AOF最多可能丢失2秒的数据
Redis会记录上次fsync命令成功的时间,如果不到2秒,不触发fsync;如果超过2秒,则阻塞进行fsync。因此在触发fsync之前突然宕机可能会丢失2秒数据。

Redis4.0混合持久化

开启混合持久化:aof-use-rdb-preamble yes
Redis5.0默认开启混合持久化
混合持久化执行流程

  1. 手动/自动触发bgrewriteaof命令
  2. 主进程fork子进程,fork过程中主进程阻塞
  3. 子进程将全量数据以RDB格式写入AOF文件,主进程将操作命令写入AOF缓冲区和AOF重写缓冲区
  4. 子进程通知主进程,主进程将AOF重写缓冲区数据以AOF格式写入AOF文件
  5. 主进程将新AOF文件替换原AOF文件(AOF文件前半段是RDB格式数据,后半段是AOF格式命令)

持久化对过期键的处理
RDB持久化:已过期键不会保存至RDB文件
AOF持久化:已过期键删除后会在AOF文件追加一条del命令
AOF重写:已过期键不会写入AOF文件

Redis高可用

主从复制模式

优点
读写分离:主节点写,从节点读
故障恢复:主节点宕机,将从节点升级为主节点
缺点
主/从节点故障恢复需要人工干预
写操作无法负载均衡
连接建立阶段

  1. 从节点masterhost记录主节点ip,masterport记录主节点port
  2. 从节点发送slaveof命令给主节点,主节点返回OK
  3. 从节点与主节点建立socket连接,从节点socket用于接收RDB文件以及其他命令,主节点socket保存在redisServer.clients
  4. 从节点发送ping命令给主节点,主节点返回pong
  5. 从节点发送auth命令给主节点进行身份验证
  6. 从节点发送端口号给主节点,主节点后续会将数据发送至该端口

数据同步阶段

  • 从节点发送psync命令给主节点,主节点判断全量复制或者部分复制

命令传播阶段

  • 主节点操作命令执行成功后,发送操作命令给从节点
  • 主从节点心跳机制和REPLCONF ACK机制

repl-disable-tcp-nodelay yes:合并操作命令,40ms发送一次
repl-disable-tcp-nodelay no:每次操作命令发送一次
心跳机制:主节点每10秒发送ping命令给从节点
REPLCONF ACK机制:从节点每秒发送REPLCONF ACK命令给主节点,维护offset属性

哨兵模式

优点
自动实现主节点故障恢复
缺点
节点故障恢复仍需要人工干预
写操作无法负载均衡
实现原理
每个哨兵节点维护了三个定时任务

  1. 向主节点发送info命令获取最新主从结构
  2. 通过发布订阅获取其他哨兵节点信息
  3. 向其他节点发送ping命令进行心跳检测

心跳检测过程中,主节点没有回复,哨兵节点将主节点主观下线,并通过sentinel is-master-down-by-addr命令询问其他哨兵节点主节点状态,如果判断主观下线的哨兵节点到达一定数量,则对该主节点进行客观下线,开始进行选举。
选择领导者哨兵节点算法:Raft算法,先到先得。
选择主节点算法:

  1. 过滤掉不健康的从节点
  2. 选择优先级最高的从节点
  3. 若优先级无法区分,选择offset最大的从节点
  4. 若offset无法区分,选择runid最小的从节点

min-slaves-to-write 1:至少有1个从节点在正常工作
min-slaves-max-lag 10:10秒未收到从节点反馈,就认为其断开

集群模式

优点
解决写操作无法负载均衡的问题
实现原理
集群模式将16384个槽分布在各个主节点上,数据通过数据分区方案落在各个槽中。
数据分区策略

  • 哈希取余分区
  • 一致性哈希分区
  • 虚拟节点一致性哈希分区

集群成员

  • 数据节点(主节点和从节点)
  • 哨兵节点
    主节点读写,从节点只负责备份数据
    每个节点维护2个端口
  • 普通端口:用户提供服务
  • 集群端口(普通端口+10000):用于集群各个节点通信

增加节点

  1. 启动节点
  2. 节点握手
  3. 迁移槽
  4. 指定主从关系

减少节点

  1. 迁移槽
  2. 节点下线

迁移槽步骤(迁移工具:redis-trib)

  1. redis-trib将原节点和目标节点状态设置为过渡状态
  2. redis-trib获取槽key列表
  3. 挨个迁移key(原节点将该key数据序列化,发送至目标节点,目标节点将该key数据反序列化,原节点删除该key)该步骤是同步阻塞的

访问过渡状态节点的key

  1. 客户端向原节点发送get指令,因为key数据已迁移至目标节点,所以原节点返回moved(重定向)指令
  2. 客户端向目标节点发送asking指令,目标节点返回"OK"
  3. 客户端向目标节点发送get指令获取数据

故障转移
集群识别某个主节点下线,由其他主节点投票选一个从节点成为主节点

Redis高可用对过期键的处理
主节点恢复RDB文件:已过期键不会加载至内存
从节点恢复RDB文件:已过期键会加载至内存
主从复制模式主节点删除已过期键后会发送del命令给从节点,从节点不会主动删除过期键

Redis Redis原理相关推荐

  1. 全面剖析Redis Cluster原理和应用 (good)

    redis redis cluster注意的问题 : 1.'cluster-require-full-coverage'参数的设置.该参数是redis配置文件中cluster模式的一个参数,从字面上基 ...

  2. Redis主从复制原理学习

    Redis主从复制原理学习总结 - 运维笔记 和Mysql主从复制的原因一样,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况.为了分担读压力,Redis支持主从复制,Redis的 ...

  3. redis单线程原理___Redis为何那么快-----底层原理浅析

    redis单线程原理 redis单线程问题 单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程. 1. 为什么说redis能够快速执行 ...

  4. Redis内核原理及读写一致企业级架构深入剖析1-综合组件环境实战

    本套技术专栏是作者(秦凯新)平时工作的总结和升华,并深度整理大量网上资源和专业书籍.通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客.QQ ...

  5. 深入理解redis复制原理

    深入理解redis复制原理 1.复制过程 2.数据间的同步 3.全量复制 4.部分复制 5.心跳 6.异步复制 1.复制过程 从节点执行 slaveof 命令. 从节点只是保存了 slaveof 命令 ...

  6. 高性能分布式缓存redis(持久化原理 安全策略 过期删除内存淘汰策略 性能压测 高可用 Redis Cluster)

    redis redis(持久化原理 安全策略 过期删除&内存淘汰策略 性能压测 高可用 Redis Cluster) 1. 持久化原理 1.1 持久化流程(落盘) 1.2 RDB详解 1.2. ...

  7. Redis 分布式算法原理

    Redis 分布式算法原理 传统分布式算法 Consistent hashing一致性算法原理 Hash倾斜性 虚拟节点 Consistent hashing命中率 举个栗子: 假设有一个图片 tes ...

  8. 全面剖析Redis Cluster原理和应用

    全面剖析Redis Cluster原理和应用 1.Redis Cluster总览 1.1 设计原则和初衷 在官方文档Cluster Spec中,作者详细介绍了Redis集群为什么要设计成现在的样子.最 ...

  9. 新书介绍 -- 《Redis核心原理与实践》

    大家好,今天给大家介绍一下我的新书 -- <Redis核心原理与实践>. 后端开发的同学应该对Redis都不陌生,Redis由于性能极高.功能强大,已成为业界非常流行的内存数据库. < ...

  10. 揭秘Redis持久化原理,探索fork与Copy-on-Write的魔法!

    大家好,我是小米,今天我将和大家一起探索Redis持久化原理中的两个关键概念:fork和Copy-on-Write.这两个概念对于理解Redis的数据持久化机制至关重要.让我们一起来揭开这些技术的神秘 ...

最新文章

  1. JavaScript面试系列:JavaScript设计模式之桥接模式和懒加载
  2. ubuntu18上安裝TeamViewer
  3. ipad流水布局及其旋转界面view间隔布局调整
  4. c++的string转char*遇到的指针问题
  5. DNS递归查询与迭代查询
  6. 谷歌中国开发者大会,感悟,激动
  7. dubbo 使用学习五(dubbo开发中使用到的一些服务配置方式)
  8. 【短语学习】True(False) Positives (Negatives) 的含义和翻译
  9. 一、部署虚拟环境来安装Linux系统
  10. apizza开发工具
  11. Python ---太空射击游戏
  12. OpenGL为什么配置GLAD及GLFW
  13. python编写移动平均_如何在Python中编写不同类型的移动平均线。
  14. 齐博免费 mysql_pconnect_齐博CMS:免费PHP+mysql 100M空间
  15. 联想V450笔记本 加装固态硬盘
  16. Python自学笔记————字符串
  17. tp对接抖音sdk_Thinkphp集成抖音SDK的实现方法
  18. 北理工嵩天Python学习笔记
  19. 解决Windows安装MySQL时出现msvcr120.dll文件丢失问题(完美解决)
  20. 衣新履靓,智能商业空间的鞋服行业应用

热门文章

  1. FDM怎么修改下载地址
  2. Oracle列转行unpivot函数的使用
  3. Java图形界面编程
  4. json转为html表格,将JSON转换为html表格
  5. hp服务器g5主板型号,【HP DL365 G5参数】HP DL365 G5系列服务器参数-ZOL中关村在线
  6. 2019做网站如何赚钱?哪种网站赚钱
  7. 应用中卡片做花边效果实现
  8. MSNMessenger也可离线留言(转)
  9. 接口测试系列——转转交易业务场景接口测试实践
  10. Linux-定时任务调度