Redis 6(一)Redis 6的新特性

Redis 6 新特性

文章目录

    • Redis 6 新特性
      • 1. 模块
      • 2. SSL / TLS
        • TLS支持
      • 3. ACL(访问控制列表)
      • 4. RESP3
        • RESP3 类型
      • 5. 客户端缓存
        • 客户端缓存的Redis实现
      • 6. 多线程
        • Redis为什么不使用多线程
          • 原文:
          • 谷歌翻译:
          • 总结
        • 开启多线程配置
        • Redis6.0采用多线程后,性能的提升效果如何
        • 流程模型
        • 开启多线程后,是否会存在线程并发安全问题
      • 7. Redis-benchmark 集群支持与 Redis-cli 改进
      • 8. Redis Cluster Proxy 集群代理
        • Redis群集代理的主要功能:
      • 9. Disque 模块
        • Disque,内存中的分布式作业队列
        • 项目历史和状态:
    • 其他相关
      • 最初的 Redis 6
      • Redis的版本迭代和里程碑
      • 使用版本: Redis 6.2.3
      • 版本更新

Redis 6发布说明 Redis 6.0.0 GA is out

1. 模块

​ Redis 6 的 Modules API 达到了一个新高度,发展迅速,因为 Redis Labs 从零开始就使用模块系统来开发非常复杂的内容,使得 Redis 实际上变成一个框架,可以将系统作为模块来编写,而不必从头开始发明所有东西。

2. SSL / TLS

TLS支持

​ Redis从版本6开始支持SSL / TLS,这是一项可选功能,需要在编译时启用。

​ 这一特性值得一提的是,工作是完全在没有 antirez (安提雷斯, Redis 创始人兼核心开发者)参与的情况下完成的,这显示了 Redis 开发过程的变化。

​ 这可能需要简单结合一下背景:Redis 6 中 commit 次数最多的是 antirez,达到 685 次,而排在第二位的 zhaozhao.zz commit 数量是 81。 2020-05-01

3. ACL(访问控制列表)

​ Redis ACL的最佳介绍是ACL文档本身。作者认为 Redis 需要 ACL,因为人们在更大的环境中需要更好地控制哪些客户端可以执行某些操作。同时,向 Redis 添加 ACL 的另一个要点是隔离,以保护数据免受应用程序错误的侵害。Redis 中还为 ACL 提供了 Redis 模块接口,因此开发者可以编写自定义身份验证方法。

4. RESP3

​ 这是 Redis 6 中的新网络协议,但它是可选的,连接以 RESP2 模式开始,只有使用新的 HELLO 命令进行握手时,才进入新的协议模式。

​ 为什么要使用新协议?因为旧的语义不够。此外,RESP3 中还有其它功能,但是主要思想是能够直接从Redis返回复杂的数据类型,~~而客户端对于数据类型的转换是透明的。~~而客户端不必知道要转换为哪种类型来转换返回的平面数组,也不必知道返回的数字而不是正确的布尔值,并且以此类推。

​ 相关链接:

  • 为什么RESP3将是Redis 6支持的唯一协议 ​
  • RESP3 规范

RESP3 类型

RESP3 放弃的RESP的第二个版本的混淆字眼,并且采用了更简单的理解名称的类型,所以你会看到没有提及 散装答复或者多批量回复本文件中。

以下是RESP3实现的类型:

等同于RESP版本2的类型

  • Array: N个其他类型的有序集合
  • Blob string: 二进制安全字符串
  • Simple string: 节省空间的非二进制安全字符串
  • Simple error: 节省空间的非二进制安全错误代码和消息
  • Number: 有符号64位范围内的整数

RESP3引入的类型(新增的类型)

  • Null:一个空值代替RESP v2*-1$-1空值。

  • Double: 浮点数

  • Boolean: true or false

  • Blob error: 二进制安全错误代码和消息。

  • Verbatim string: 应该向人类显示的二进制安全字符串,不要进行任何转义或过滤。例如LATENCY DOCTOR,Redis中的输出。映射:键值对的有序集合。键和值可以是任何其他RESP3类型。

  • Map: 键值对的有序集合。键和值可以是任何其他RESP3类型。

  • Set: N个其他类型的无序集合。

  • Attribute: 与Map类型类似,但是客户端应继续阅读忽略属性类型的回复,并将其作为附加信息返回给客户端。

  • Push: 带外数据。格式类似于Array类型,但是客户端应该只检查第一个字符串元素,说明带外数据的类型,如果针对此特定类型的推送信息注册了一个,则调用回调。推送类型与回复无关,因为它们是服务器可以随时在连接中推送的信息,因此如果客户端正在读取命令的回复,则客户端应继续读取。

    ​ 带外数据(out—of—band data),有时也称为加速数据(expedited data),是指连接双方中的一方发生重要事情,想要迅速地通知对方。这种通知在已经排队等待发送的任何“普通”(有时称为“带内”)数据之前发送。

    ​ 带外数据设计为比普通数据有更高的优先级。

    ​ 带外数据是映射到现有的连接中的,而不是在客户机和服务器间再用一个连接。

  • Hello: 与Map类型类似,但仅在客户端和服务器之间建立连接时才发送,以便用不同的信息(例如服务器的名称,版本等)欢迎客户端。

  • Big number: 无法用数字类型表示的大数字

5. 客户端缓存

客户端缓存是一种用于创建高性能服务的技术。它利用应用程序服务器中的可用内存(通常是与数据库节点相比是不同的计算机),以便将数据库信息的某些子集直接存储在应用程序端。

通常,当需要某些数据时,应用程序服务器将向数据库询问此类信息,如下图所示:

+-------------+                                +----------+
|             | ------- GET user:1234 -------> |          |
| Application |                                | Database |
|             | <---- username = Alice ------- |          |
+-------------+                                +----------+

使用客户端缓存时,应用程序将直接将流行查询的答复存储在应用程序内存中,以便以后可以重用此类答复,而无需再次联系数据库。

+-------------+                                +----------+
|             |                                |          |
| Application |       ( No chat needed )       | Database |
|             |                                |          |
+-------------+                                +----------+
| Local cache |
|             |
| user:1234 = |
| username    |
| Alice       |
+-------------+

尽管用于本地缓存的应用程序内存可能不会很大,但是与请求诸如数据库之类的网络服务相比,访问本地计算机内存所需的时间要小几个数量级。由于经常非常频繁地访问相同百分比的数据,因此该模式可以极大地减少应用程序获取数据的延迟,并同时减少数据库端的负载。

此外,在许多数据集中,项目很少更改。例如,社交网络中的大多数用户帖子都是不可变的,或者很少由用户编辑。再加上通常一小部分帖子非常受欢迎的事实,或者是因为一小群用户拥有大量关注者,并且/或者因为最近的帖子具有更高的知名度,所以很清楚为什么这样的模式会非常受欢迎有用。

通常,客户端缓存的两个主要优点是:

  1. 可用的数据延迟非常短。
  2. 数据库系统接收较少的查询,从而可以使用较少的节点数来提供相同的数据集。

客户端缓存的Redis实现

Redis客户端缓存支持称为Tracking,它具有两种模式:

  • 在默认模式下,服务器会记住给定客户端访问了哪些键,并在修改了相同的键时发送无效消息。这将花费服务器端的内存,但是仅针对客户端可能在内存中拥有的一组密钥发送无效消息。
  • 相反,在广播模式下,服务器不会尝试记住给定客户端访问了哪些键,因此该模式在服务器端根本不会花费任何内存。相反,客户端订阅键前缀(例如object:或)user:,并且每次触摸与该前缀匹配的键时,都会收到通知消息。

6. 多线程

Redis为什么不使用多线程

​ 众所周知,Redis 之前的版本一直都是典型的单线程模型(注意:这里不是指 Redis 单实例中只有一个线程,而是表示 核心操作模块由单线程完成,当然另外还有一些 辅助线程 从旁协助,比如 LRU 的淘汰过程),为什么不使用多线程呢,其实原因很简单(官方解释)

原文:

Redis is single threaded. How can I exploit multiple CPU / cores?

It’s not very frequent that CPU becomes your bottleneck with Redis, as usually Redis is either memory or network bound. For instance, using pipelining Redis running on an average Linux system can deliver even 1 million requests per second, so if your application mainly uses O(N) or O(log(N)) commands, it is hardly going to use too much CPU.

However, to maximize CPU usage you can start multiple instances of Redis in the same box and treat them as different servers. At some point a single box may not be enough anyway, so if you want to use multiple CPUs you can start thinking of some way to shard earlier.

You can find more information about using multiple Redis instances in the Partitioning page.

However with Redis 4.0 we started to make Redis more threaded. For now this is limited to deleting objects in the background, and to blocking commands implemented via Redis modules. For future releases, the plan is to make Redis more and more threaded.

谷歌翻译:

Redis是单线程的。如何利用多个CPU /内核?

CPU并不是您使用Redis的瓶颈,因为通常Redis要么受内存限制,要么受网络限制。例如,使用在平均Linux系统上运行的流水线Redis每秒可以发送一百万个请求,因此,如果您的应用程序主要使用O(N)或O(log(N))命令,则几乎不会使用过多的CPU 。

但是,为了最大程度地利用CPU,您可以在同一框中启动多个Redis实例,并将它们视为不同的服务器。在某个时候,单个盒子可能还不够,因此,如果您要使用多个CPU,则可以开始考虑更早地进行分片的某种方法。

您可以在“分区”页面中找到有关使用多个Redis实例的更多信息。

但是,在Redis 4.0中,我们开始使Redis具有更多线程。目前,这仅限于在后台删除对象,以及阻止通过Redis模块实现的命令。对于将来的版本,计划是使Redis越来越线程化。

总结

简单说来就是:

  • 根据以往的场景,普通 KV 存储 瓶颈压根不在 CPU,而往往可能受到 内存网络I/O 的制约
  • Redis 中有各种类型的数据操作,甚至包括一些事务处理,如果采用多线程,则会被多线程产生的切换问题而困扰,也可能因为加锁导致系统架构变的异常复杂,更有可能会因为加锁解锁甚至死锁造成的性能损耗

当然,单线程也会有 不能充分利用多核资源 弊端,这是一个权衡;而通常 Redis(包括 Redis cluster) 的性能已经足够我们使用

开启多线程配置

默认情况下,Redis 6 多线程是禁用的,我们可以在配置文件选择开启:

vim redis.conf

#开启IO多线程
io-threads-do-reads yes

#配置线程数量,如果设为1就是主线程模式。
io-threads 4

关于线程数的设置,官方有一个建议:4核的机器建议设置为2或3个线程,8核的建议设置为6个线程,线程数一定要小于机器核数。还需要注意的是,线程数并不是越大越好,官方认为超过了8个基本就没什么意义了。

Redis6.0采用多线程后,性能的提升效果如何

Redis 作者 antirez 在 RedisConf 2019分享时曾提到:Redis 6 引入的多线程 IO 特性对性能提升至少是一倍以上。国内也有大牛曾使用unstable版本在阿里云esc进行过测试,GET/SET 命令在4线程 IO时性能相比单线程是几乎是翻倍了。

测试环境

Redis Server: 阿里云 Ubuntu 18.04,8 CPU 2.5 GHZ, 8G 内存,主机型号 ecs.ic5.2xlarge
Redis Benchmark Client: 阿里云 Ubuntu 18.04,8 2.5 GHZ CPU, 8G 内存,主机型号 ecs.ic5.2xlarge

测试结果

Redis 6(一)Redis 6的新特性_第1张图片

详见:https://zhuanlan.zhihu.com/p/76788470

说明1:这些性能验证的测试并没有针对严谨的延时控制和不同并发的场景进行压测。数据仅供验证参考而不能作为线上指标。

说明2:如果开启多线程,至少要4核的机器,且Redis实例已经占用相当大的CPU耗时的时候才建议采用,否则使用多线程没有意义。所以估计80%的公司开发人员看看就好。

流程模型

(1). 流程如下:(如下图 图6.1 - 图6.3)

  • 主线程获取 socket 放入等待列表
  • 将 socket 分配给各个 IO 线程(并不会等列表满)
  • 主线程阻塞等待 **IO 线程(多线程)**读取 socket 完毕
  • 主线程执行命令 - 单线程(如果命令没有接收完毕,会等 IO 下次继续)
  • 主线程阻塞等待 **IO 线程(多线程)**将数据回写 socket 完毕(一次没写完,会等下次再写)
  • 解除绑定,清空等待队列

(2). 特点如下:

  • IO 线程要么同时在读 socket,要么同时在写,不会同时读或写
  • IO 线程只负责读写 socket 解析命令,不负责命令处理(主线程串行执行命令)
  • IO 线程数可自行配置

图6.1
Redis 6(一)Redis 6的新特性_第2张图片


图6.2

Redis 6(一)Redis 6的新特性_第3张图片


图6.3

Redis 6(一)Redis 6的新特性_第4张图片


开启多线程后,是否会存在线程并发安全问题

​ 从上面的实现机制可以看出,Redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行。所以我们不需要去考虑控制 key、lua、事务,LPUSH/LPOP 等等的并发及线程安全问题。

7. Redis-benchmark 集群支持与 Redis-cli 改进

redis-cli集成了redis-trib.rb,优化了redis-benchmark,benchmark工具也支持cluster,可以通过多线程的方式对多个分片进行压测。

8. Redis Cluster Proxy 集群代理

在 Redis 集群中,客户端会非常分散,现在为此引入了一个集群代理,可以为客户端抽象 Redis 群集,使其像正在与单个实例进行对话一样。同时在简单且客户端仅使用简单命令和功能时执行多路复用。

Redis群集代理的主要功能:

  • 路由:每个查询都会自动路由到集群的正确节点
  • 多线程
  • 同时支持多路复用和专用连接模型
  • 即使在多路复用上下文中,也可以确保查询执行和答复顺序
  • ASK|MOVED错误后自动更新集群的配置:当答复中发生此类错误时,代理通过获取集群的更新配置并重新映射所有插槽来自动更新集群的内部表示。更新完成后,将重新执行所有查询,因此,从客户端的角度来看,一切正常进行(客户端将不会收到ASK | MOVED错误:他们将在收到请求后直接收到预期的回复)群集配置已更新)。
  • 跨槽/跨节点查询:支持许多命令,这些命令涉及属于不同插槽(甚至不同集群节点)的多个键。这些命令会将查询拆分为多个查询,这些查询将被路由到不同的插槽/节点。这些命令的回复处理是特定于命令的。某些命令(如MGET)将合并所有答复,就好像它们是单个答复一样。其他命令(例如MSET或)DEL将汇总所有答复的结果。由于这些查询实际上破坏了命令的原子性,因此它们的用法是可选的(默认情况下禁用)。有关更多信息,请参见下文。
  • 一些没有特定节点/插槽的命令(例如,DBSIZE传递给所有节点的命令)将减少映射,以便给出所有答复中包含的所有值的总和。
  • PROXY可用于执行某些特定于代理的操作的附加命令。

9. Disque 模块

Disque目的是构建分布式的内存中消息代理,此前它是一项实验功能,现在在 Redis 6 中成为模块,它可以支持集群消息总线 API,可以阻止和恢复客户端、支持计时器、模块私有数据的 AOF 和 RDB 控制功能。

Disque,内存中的分布式作业队列

​ Disque是一项正在进行的实验,目的是构建一个分布式的内存中消息代理。它的目标是捕获“ Redis作为作业队列”用例的本质,该用例通常是使用阻止列表操作来实现的,并通过简单的方法将其移动到即席,自包含,可扩展且容错的设计中。可以理解属性和保证,但在简单性,性能和作为C非阻塞网络服务器的实现方面仍类似于Redis。

项目历史和状态:

  • Disque大约在四年前作为Redis代码库的分支而开始,但是我(Salvatore)立即意识到,将两个项目之间的更改合并是不切实际的。该项目被搁置。
  • 同时,Redis获得了对模块的支持。从理论上讲,Disque可以实现为Redis模块,但是仍然缺少太多API。
  • 在2018年3月,我开始实现Redis模块API,以真正支持像Disque这样的分布式系统作为Redis模块,两个基本的增加是集群API和计时器。同时,我开始了第一个移植,但是还有很多工作要做,并且在Redis模块端需要模式API。
  • 当Redis 6路线图最终定稿时,我宣布具有相同API和功能的Disque模块将成为Redis 6发行版的一部分,其主要区别在于使用AGPL许可证发行。
  • 现在(2019年12月),Disque模块终于可以作为alpha质量代码使用了。

与原始Disque存储库中的Disque 1.0 RC1相比,Disque模块的状态是什么?

  • 即使最初的Disque是候选发行版,即使它向前发展很快,这仍然是alpha代码。
  • 该模块尚缺乏任何持久层的实现。
  • 无法正常删除节点(离开节点状态):此标志尚未实现。
  • 有很多错误,并且可能会崩溃。它几天前才开始工作。
  • 可能缺少一些命令。值得一提的是,目前尚无HELLOINFODisque还没有。请注意,两者都与Redis命令名称冲突,因此它们将重命名为DISQUE HELLODISQUE INFO
  • 许可有所不同,Disque模块是AGPL,而最初的Disque项目(作为Redis分支)是BSD。

所有缺失的功能都将在接下来的几周内得到解决,以便提供一个可以进行Beta测试以及以后用于生产的模块。

警告:这是不稳定的代码,可能不适合生产使用。如果不是因为将来可能会更改的详细信息,该API被认为是稳定的,但是它是alpha代码,因此请谨慎使用!

其他相关

最初的 Redis 6

​ Redis 6.0-rc1(预发行版) 于 2019年12月20日 发布

Redis的版本迭代和里程碑

Redis从发布至今,已经有十余年的时光了,一直遵循着自己的命名规则:

  • 版本号第二位如果是奇数,则为非稳定版本 如2.7、2.9、3.1
  • 版本号第二位如果是偶数,则为稳定版本 如2.6、2.8、3.0、3.2
  • 当前奇数版本就是下一个稳定版本的开发版本,如2.9版本是3.0版本的开发版本

我们可以通过redis.io官网来下载自己感兴趣的版本进行源码阅读:

历史发布版本的源码:https://download.redis.io/releases/

其中有几个里程碑式的版本,需要我们了解下:


Redis 6(一)Redis 6的新特性_第5张图片


2020年4月17日,Redis 5.0.9发布。

5.0版本是直接升级到6.0版本,对于这个激进的升级,antirez表现得很有信心和兴奋,所以第一时间发文来阐述6.0的一些重大功能"Redis 6.0.0 GA is out!":

注:GA是Generally Available的缩写,意思是开发团队认为该版本是稳定版。

使用版本: Redis 6.2.3

此版本主要包含对影响认证客户端连接的安全问题的修复。

STRALGO LCS 命令中的整数溢出(CVE-2021-29477):Redis 6.0 版或更新的版本中存在一个整数溢出漏洞,可利用 STRALGO LCS 命令破坏堆并可能导致远程代码执行。从 6.0 开始,所有版本的 Redis 都存在整数溢出漏洞。

在 large intsets 的 COPY 命令中出现整数溢出(CVE-2021-29478):Redis 6.2 中的一个整数溢出漏洞可被利用来破坏堆并可能导致远程代码执行。该漏洞涉及改变默认的 set-max-intset-entries 配置值,创建一个由整数值组成的大型集合键,并使用 COPY 命令来复制它。整数溢出漏洞存在于从 2.6 开始的所有版本的 Redis 中,它可能导致损坏的 RDB 或 DUMP 有效载荷,但不能通过 COPY(6.2 之前不存在)进行利用。

只适用于 Redis 6.2 以前版本的错误修复:

  • 修复 moduleDefragGlobals 中的内存泄漏(#8853)
  • 修复执行 lazy freeing 客户端跟踪表时的内存泄漏(#8822)
  • 阻止滥用副本发送可能断言和使 Redis 崩溃的命令(#8868)

Other bug fixes:

  • 使用 monotonic clock 检查 Lua 脚本超时(#8812)
  • redis-cli:在 cluster 模式下重定向时,不要使用 unix socket(#8870)

Modules:

  • 修复 RM_GetClusterNodeInfo() 以正确填 master id(#8846)

更新说明:https://github.com/redis/redis/releases/tag/6.2.3

版本更新

​ 你可以从这里 https://github.com/redis/redis/tags 查看 redis 历史版本的发布信息

你可能感兴趣的:(redis)