redis-redis为什么这么快
Published on 2024-08-27 17:11 in Loading... with 早点下班回家吃饭叻

redis-redis为什么这么快

Redis为什么这么快?

作者:w08e

博客:https://www.cnblogs.com/w08e

📙 NOTE

redis热门问题 冲冲冲

答题思路

核心围绕存储方式、架构设计与使用方式回答:

回答话术

Redis 官方早前发布过一套基准测试,在 Redis 服务连接数小于 1 万时,并发数量每秒可以达到 10-12 万左右。连接数在 3-6 万 时,也能支持每秒 5-6 万的并发。

我觉得 Redis 之所以操作这么快,主要有以下几方面原因:

  • 从存储方式上看:Redis 是基于内存的数据库,而直接访问内存的速度要比访问磁盘高上几个数量级。这是 Redis 快最主要的原因。
  • 从设计上看:Redis 在架构上采用了 IO 多路复用提高了资源利用率,通过多线程非阻塞式 IO 提高请求的处理效率 ,使用单线程执行大部分命令以避免上下文切换,部分重命令则允许异步执行,并且在设计上针对最底层的数据结构进行了精细的优化,以保证任何操作都具备尽可能低的复杂度。
  • 从使用方式上看:Redis 的功能非常纯粹,用户直接面向经过精心设计的数据结构进行操作,因此效率极高,此外,用户还可以根据自己的业务场景采用最合适的数据结构,这也间接提高了操作效率。

问题详解

1. 基于内存操作

Redis 是基于内存操作的数据库,这是它快的最根本原因。

一般情况下,计算机访问一次 SSD 硬盘大概需要 50 ~ 150 纳秒,如果是传统的硬盘时间则需要 1 ~ 10 毫秒,而访问一次内存仅需要 120 微秒。可见,磁盘和内存访问的速度最少差了一千倍。

除了少数一些需要需要跟磁盘打交道的时候(比如持久化),大部分时候 Redis 都只在内存中进行读写,因此它的效率极高。

2. 合理的线程模型

我们一般说“Redis”是单线程的,实际上是指 Redis 使用单个主线程来执行大部分的命令。这个设计使得 Redis 可以避免因频繁的上下文切换以及各种同步机制带来的性能开销,同上也避免的了为了保证数据结构支持并发操作而引入的代码复杂度。

不过,Redis 也并非真的就是单线程的,从 4.0 开始,Redis 就引入了 UNLINK 这类命令,用于异步执行删除等重操作,并在 6.0 以后引入了专门的 IO 线程,实现了多线程的非阻塞式 IO,它们也进一步的提升了 Redis 的执行效率。

这里我们要顺带强调一下,虽然 Redis 的单个主线程模型确实带来的不少的好处,但是这个设计更多的还是在性能与设计之间取得的一个平衡。实际上不少市面上开源或者大公司内部自研的 KV 数据库 —— 比如 KeyDB 或者 Dragonfly —— 都是基于多线程模型实现的,它们以单机模式运行在多核机器上时也确实表现出了比 Redis 更高的性能。

3. 高效的 IO 模型

3.1. IO 多路复用

image.png

为了提高资源利用率,提高服务吞吐量,Redis 在内部实现了一套网络事件库,它支持基于 Solaris 中的 evport、Linux 中的 epoll、Mac OS/FreeBSD 中的 kQueue ……等操作系统函数实现高效的 IO 多路复用。

在这个模型中,它将会来自客户端的网络请求作为一个事件发布到队列中,然后线程将同步的获取事件并派发到不同的处理器,而处理器处理完毕后又会再发布另一个事件……整个主流程都由 Redis 的主线程在一个不间断的循环中完成,这就是事件循环。

熟悉 Netty 的同学可能会觉得有点既视感,因为两者都可以认为基于反应器模式实现的 IO 模型,不过 Netty 可以有多个事件循环,并且还可以划分为 Boss 和 Worker 两类事件循环组,而 Redis 只有一个事件循环,并且在早期版本只有一个 IO 线程(也就是主线程本身)。

3.2. 多线程非阻塞式 IO

随着请求规模的扩大,单个线程在网络 IO 上消耗的 CPU 时间越来越多,它逐渐成为了 Redis 的性能瓶颈。因此在 6.0 版及以上版本,Redis 正式引入了多线程来处理网络 IO。

在新的版本中,Redis 依然使用单个主线程来执行命令,但是使用多个线程来处理 IO 请求,主线程不再负责包括建立连接、读取数据和回写数据这些事情,而只是专注于执行命令。

image.png

这个做法在保证单注线程设计的原有优点的情况下,又进一步提高了网络 IO 的处理效率。

4. 数据结构

Redis 的高性能很大程度上依赖于它丰富而高效的数据结构,而它们在底层实现上,都针对不同的使用场景进行了精心的设计和优化

Redis 共有 5 种基本数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。

这 5 种数据类型是直接提供给用户使用的,是数据的保存形式,其底层实现主要依赖这 8 种数据结构:简单动态字符串(SDS)、LinkedList(双向链表)、Dict(哈希表/字典)、SkipList(跳跃表)、Intset(整数集合)、ZipList(压缩列表)、QuickList(快速列表)。

数据类型 底层数据结构 应用场景
String SDS 它可以存储任何数据 - 字符串、整数、浮点值、JPEG 图像、序列化的 Ruby 对象或您希望它承载的任何其他内容
List 列表 LinkedList/ZipList/QuickList Redis Lists 保存按插入顺序排序的字符串元素集合。从两端推送或弹出项目、根据偏移量进行修剪、读取单个或多个项目,或按值和位置查找或删除项目。您还可以对异步消息传输进行阻塞调用。
Set 集 Dict(哈希表/字典)、Intset Redis Sets 数据结构存储一组唯一的成员。使用 Set,您可以添加、获取或删除成员、检查成员资格或检索随机成员。使用排序算法,您还可以执行集合运算(例如交集、并集和集合差集)并计算集合基数
Sorted Set ZipList(压缩列表)、SkipList(跳表) Redis 有序集包含一组按浮点分数排序的唯一>成员。与集合一样,您可以添加、获取或删除单个成员,并执行集合运算,例如并集、交集、集合差集和计算基数。此外,您还可以根据分数或成员值查询集合,聚合、过滤和排序结果。
Hash 散 列 Dict(哈希表/字典)、ZipList(跳表) Redis 哈希是一种数据类型,表示字符串字段和字符串值之间的映射。Redis 哈希结构存储一组字段值对,不会占用太多空间,因此非常适合表示数据对象。它提供了添加、获取或删除单个项目、获取整个哈希或使用哈希中的一个或多个字段作为计数器的功能。
Stream redis流 用于管理高速数据流(如消息队列)。凭借现成的分区、复制和持久性,它可以以亚毫秒级的延迟每秒捕获和处理数百万个数据点。
Bitmap 位图 它提供命令来获取和设置给定位置的位值,并在多个位图键之间执行 AND、OR、XOR 和 NOT 运算
Bitfield 位域 它允许在给定位置增加和减少计数器,并且当计数器达到其上限时会标记溢出。
Geospatial 地理空间索引 附近的人
HyperLogLog 基数统计,热门网站活跃ip统计

官网参考地址: https://redis.io/redis-enterprise/data-structures/

posted @   早点下班回家吃饭叻  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示