牛皮了!Redis 6.0 如何实现大幅度的性能提升!

2023-12-28 11:32

本文主要是介绍牛皮了!Redis 6.0 如何实现大幅度的性能提升!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

牛皮了!Redis 6.0 如何实现大幅度的性能提升

 

导读:

Redis可以轻松支撑100k+ QPS,离不开基于Reactor模型的I/O Multiplexing,In-memory操作,以及单线程执行命令避免静态消耗。尽管性能已经能满足大多数应用场景,但是如何继续在迭代中继续优化,以及在多核时代利用上多线程的优势,也是大家关注的重点。我们知道性能优化在系统资源层面可以从I/O以及CPU上入手,对于Redis而言,其功能不过度依赖CPU计算能力,即不是CPU密集型的应用,而In-memory的操作也绕开了通常会拖慢性能的磁盘I/O,所以在Redis 6.0版本中,将从网络I/O入手,引入Threaded I/O辅助读写,在一些场景下实现了大幅度的性能提升。本文将介绍Redis的事件模型,分析Threaded I/O是如何帮助提升性能,以及其实现的原理。

Introduction

Redis从6.0版本开始引入了Threaded I/O,目的是为了提升执行命令前后的网络I/O性能。本文会先从Redis的主流程开始分析,讲解网络I/O发生在哪里,以及现有的网络I/O模型,然后介绍Threaded I/O的新模型、实现以及生效场景,最后会进行场景测试,对比Threaded I/O关闭与开启,以及启用Threaded I/O与在单实例上搭建集群的性能差异。如果你已经了解过Redis的循环流程,可以直接跳至浪Threaded I/O相关 的部分;如果你只关心新功能的实际提升,可以跳至 性能测试 部分查看。

Redis是如何运行的

事件循环

main

Redis的入口位于server.c下, main() 方法流程如图所示。

牛皮了!Redis 6.0 如何实现大幅度的性能提升

 

在意main() 方法中Redis首先需要做的是 初始化各种库以及服务配置 。具体举例:

  • crc64_init() 会初始化一个crc校验用的Lookup Table
  • getRandomBytes() 为 hashseed 填充随机元素作为初始化值,用作哈希表的seed
  • ...
  • initServerConfig() 中执行了大量对 server 对象属性的初始化操作:
    • 初始化 server.runid ,如 16e05f486b8d41e79593a35c8b96edaff101c194
    • 获取当前的时区信息,存放至 server.timezone 中
    • 初始化 server.next_client_id 值,使得连接进来的客户端id从1开始自增
    • ...
  • ACLInit() 是对Redis 6.0新增的ACL系统的初始化操作,包括初始化用户列表、ACL日志、默认用户等信息
  • 通过 moduleInitModulesSystem() 和 tlsInit() 初始化模块系统和SSL等
  • ...

初始化结束后,开始 读取用户的启动参数 ,和大多数配置加载过程类似,Redis也通过字符串匹配等分析用户输入的 argc 和 argv[] ,这个过程中可能会发生:

  • 获取到配置文件路径,修改 server.configfile 的值,后续用于加载配置文件
  • 获取到启动选项参数,如 loadmodule 和对应的Module文件路径,保存至 options 变量中

解析完参数之后,执行 loadServerConfig() , 读取配置文件并与命令行参数options的内容进行合并 ,组成一个 config 变量,并且逐个将name和value设置进configs列表中。对于每个config,有对应的switch-case的代码,例如对于 loadmodule ,会执行 queueLoadModule() 方法,以完成真正的配置加载:

...} else if (!strcasecmp(argv[0],"logfile") && argc == 2) {   ...         } else if (!strcasecmp(argv[0],"loadmodule") && argc >= 2) {queueLoadModule(argv[1],&argv[2],argc-2);} else if (!strcasecmp(argv[0],"sentinel")) {
...

回到 main 方法的流程,Redis会开始打印启动的日志,执行 initServer() 方法,服务根据配置项,继续 为 server 对象初始化内容 ,例如:

  • 创建事件循环结构体 aeEventLoop (定义在ae.h),赋值给 server.el
  • 根据配置的db数目,分配大小为 sizeof(redisDb) * dbnum 的内存空间, server.db 保存这块空间的地址指针
  • 每个db都是一个redisDb结构,将这个结构中的保存key、保存过期时间等的字典初始化为空dict
  • ...

此后就是一些根据不同运行模式的初始化,例如常规模式运行时会记录常规日志、加载磁盘持久化的数据;而在sentinel模式运行时记录哨兵日志,不加载数据等。

在所有准备操作都完成后, Redis开始陷入 aeMain() 的事件循环,在这个循环中会不断执行 aeProcessEvents() 处理发生的各种事件,直到Redis结束退出 。

两种事件

Redis中存在有两种类型的事件: 时间事件 、 文件事件 。

时间事件也就是到了一定时间会发生的事件,在Redis中它们被记录成一个链表,每次创建新的时间事件的时候,都会在链表头部插入一个 aeTimeEvent 节点,其中保存了该事件会在何时发生,需要调用什么样的方法处理。遍历整个链表我们可以知道离最近要发生的时间事件还有多久,因为链表里面的节点按照自增id顺序排列,而在发生时间的维度上是乱序的。

牛皮了!Redis 6.0 如何实现大幅度的性能提升

 

文件事件可以看作I/O引起的事件,客户端发送命令会让服务端产生一个读I/O,对应一个读事件;同样当客户端等待服务端消息的时候需要变得可写,让服务端写入内容,因此会对应一个写事件。 AE_READABLE 事件会在客户

这篇关于牛皮了!Redis 6.0 如何实现大幅度的性能提升!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/545806

相关文章

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Linux在线解压jar包的实现方式

《Linux在线解压jar包的实现方式》:本文主要介绍Linux在线解压jar包的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux在线解压jar包解压 jar包的步骤总结Linux在线解压jar包在 Centos 中解压 jar 包可以使用 u

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

PowerShell中15个提升运维效率关键命令实战指南

《PowerShell中15个提升运维效率关键命令实战指南》作为网络安全专业人员的必备技能,PowerShell在系统管理、日志分析、威胁检测和自动化响应方面展现出强大能力,下面我们就来看看15个提升... 目录一、PowerShell在网络安全中的战略价值二、网络安全关键场景命令实战1. 系统安全基线核查

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构