Redis 6.0新特性

文章目录

  • 总览
  • Redis 6.0新特性
    • 多线程IO(Threaded I/O)
      • 那么为什么不能采用多线程操作命令?
      • 为什么引入多线程IO?
      • 多线程IO启用
      • 多线程IO香吗?
    • RESP3协议
    • ACLs
    • SSL支持
    • 客户端缓存(Client side caching)
    • Redis Cluster proxy

总览

在刚刚过去的5.1长假中,Redis的作者antirez在个人博客宣布Redis 6.0.0 stable版本release(http://antirez.com/news/132)。在新版本中,增加了诸多的特性,其中最令人激动的特性就是支持了IO多线程,antirez称之为最大的一次更新(it is the largest release of Redis ever as far as I can tell)下面,我们来看一下6.0版本的新特性。

Redis 6.0新特性

  • 众多新模块(modules)API
  • 更好的过期循环(expire cycle)
  • SSL
  • ACLs权限控制
  • RESP3协议
  • 客户端缓存(Client side caching)
  • 多线程IO(Threaded I/O)
  • 无盘复制副本(Diskless replication on replicas)
  • Redis-benchmark的集群支持和Redis-cli优化
  • 重写Systemd支持(Systemd support rewrite)
  • Redis集群代理与Redis 6一同发布(但在不同的repo)
  • Disque模块与Redis 6一同发布

antirez对其中的几个新特性进行了介绍,我们来具体看一下。

多线程IO(Threaded I/O)

Redis 6.0开始支持多线程IO,Redis 终于实现多线程了!?先打住,多线程是不可能多线程的,别多想~

Redis 在处理客户端的请求时,包括获取(Socket 读)、解析、执行、内容返回(Socket 写)等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。

那么为什么不能采用多线程操作命令?

官方曾做过类似问题的回复:使用 Redis 时,几乎不存在 CPU 成为瓶颈的情况, Redis 主要受限于内存和网络。

例如在一个普通的 Linux 系统上,Redis 通过使用 Pipelining 每秒可以处理 100 万个请求,所以如果应用程序主要使用 O(N) 或 O(log(N)) 的命令,它几乎不会占用太多 CPU。

使用了单线程后,可维护性高。

如果使用多线程执行命令,引入的问题例如复杂性、锁的效率会大大增加。多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。

Redis 通过 AE 事件模型以及 IO 多路复用等技术,处理性能非常高,因此没有必要使用多线程。

单线程机制使得 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等 “线程不安全” 的命令都可以无锁进行。

为什么引入多线程IO?

从 Redis 自身角度来说,因为读写网络的 Read/Write 系统调用占用了 Redis 执行期间大部分 CPU 时间,瓶颈主要在于网络的 IO 消耗。

优化主要有两个方向:

  • 提高网络 IO 性能,典型的实现比如使用 DPDK 来替代内核网络栈的方式。
  • 使用多线程充分利用多核,典型的实现比如 Memcached。

协议栈优化的这种方式跟 Redis 关系不大,支持多线程是一种最有效最便捷的操作方式。

所以总结起来,Redis 支持多线程主要就是两个原因:

  • 可以充分利用服务器 CPU 资源,目前主线程只能利用一个核。
  • 多线程任务可以分摊 Redis 同步 IO 读写负荷。

多线程IO启用

Redis 6.0 的多线程默认是禁用的,只使用主线程。如需开启需要修改 redis.conf 配置文件:

io-threads-do-reads yes

开启多线程后,还需要设置线程数,否则是不生效的。同样修改 redis.conf 配置文件:

io-threads 4

关于线程数的设置,官方有一个建议:4 核的机器建议设置为 2 或 3 个线程,8 核的建议设置为 6 个线程,线程数一定要小于机器核数。

还需要注意的是,线程数并不是越大越好,官方认为超过了 8 个基本就没什么意义了。

多线程IO香吗?

作者 antirez 在 RedisConf 2019 分享时曾提到:Redis 6 引入的多线程 IO 特性对性能提升至少是一倍以上。

美团技术团队的官方博客中,表示压测的结果,开启多线程IO后性能提升显著:

Redis 6.0新特性_第1张图片

Redis 6.0新特性_第2张图片
详细参见:https://zhuanlan.zhihu.com/p/76788470

RESP3协议

RESP 全称 REdis Serialization Protocol,是 Redis 服务端与客户端之间通信的协议。RESP2 协议已经使用了很多年,antirez希望使用一个新的协议来支持新的特性,一开始antirez是打算完全放弃 RESP2 的,全面切换为 RESP3 协议,但是很快又改变了主意,所以 RESP3 协议在Redis 6里面是让用户决定的,Redis连接用 RESP2 建立,如果用户用HELLO命令握手,就可以进入RESP3协议的模式。

为什么需要新协议?因为旧协议不满足语义上的需求了。尽管有一些 RESP3 专属的新功能,但是最主要的原因是我们需要允许Redis返回复杂的数据类型,而且不用客户端“必须”得知道如扁平数组要转成什么类型、数字怎么正确和布尔值对应等才能处理。

在 RESP2 中,所有的返回内容,都是一个字符串数组的形式,不管是 list 还是 sorted set。因此客户端需要自行去根据类型进行解读,增加了客户端实现的复杂性。

下面以具体的命令展示 RESP3 中的具体变化。

127.0.0.1:6379> HSET myhash a 1 b 2 c 3
(integer) 3

127.0.0.1:6379> HGETALL myhash
1) "a"
2) "1"
3) "b"
4) "2"
5) "c"
6) "3"

127.0.0.1:6379> HELLO 3 #转换成RESP3的命令
1# "server" => "redis"
2# "version" => "999.999.999"
3# "proto" => (integer) 3
4# "id" => (integer) 5
5# "mode" => "standalone"
6# "role" => "master"
7# "modules" => (empty array)

127.0.0.1:6379> HGETALL myhash
1# "a" => "1"
2# "b" => "2"
3# "c" => "3"

以前返回两个field的hash,就是直接无差别地返回4个值,而新的RESP3就会告诉客户端返回两个key-value,通过%表示键值对(也成为map类型)的个数。

更加详细的设计,请参见 RESP3 的详细设计:https://github.com/antirez/RESP3/blob/master/spec.md

ACLs

目前的 Redis(5及以下版本),没有用户权限管理这个概念,只有一个AUTH密码验证功能,基本上能够接入的用户就是root用户。

Redis需要ACLs(权限控制),因为在更大的环境中人们需要权限控制模块去更好地控制不同客户端能做哪些操作。另一个点就是,加入权限控制也是为了在从应用bug中更好地保护数据。

如果账户(worker)只能执行BRPOPLPUSH,那其他的开发者在不小心加了一行用于测试、清理测试数据的FLUSHALL而导致数据丢失、然后经历5小时恢复的噩梦的概率会更低。

Redis 6 中加入ACL的功能,能够对接入的用户进行三个层面的权限控制:

  • 接入权限:用户名和密码
  • 可以执行的命令
  • 可以操作的 KEY

具体详细操作可以参见官方文档说明:https://redis.io/topics/acl

SSL支持

关于这一点,作者antirez只是简单的提了一下,并没有详细的解释,这里就不妄加臆断。

客户端缓存(Client side caching)

客户端缓存的功能是该版本的全新特性,服务端能够支持让客户端缓存values,Redis作为一个本身作为一个缓存数据库,自身的性能是非常出色的,但是如果可以在Redis客户端再增加一层缓存结果,那么性能会更加的出色。Redis实现的是一个服务端协助的客户端缓存,叫做tracking。客户端缓存的命令是:

CLIENT TRACKING ON|OFF [REDIRECT client-id] [PREFIX prefix] [BCAST] [OPTIN] [OPTOUT] [NOLOOP]

tracking开启时, Redis会"记住"每个客户端请求的key,当key的值发现变化时会发送失效信息给客户端(invalidation message)。失效信息可以通过 RESP3 协议发送给请求的客户端,或者转发给一个不同的连接(支持RESP2+ Pub/Sub)。

更多的详细操作,这里就不进行过多的介绍了,具体可以参见:http://antirez.com/news/130

这是一个令人激动的新特性,但是作者antirez对这个特性表示是6.0中最不成熟的特性(however I think that right now this is the most immature feature of Redis 6)。并表示在后续的版本中会继续进行优化,我们拭目以待。

Redis Cluster proxy

针对 Cluster 的代理,这么多年了,仍然有不少人在Cluster的接入方式上挣扎,因为缺少合适的驱动而无法使用Cluster。所以开发了这个Proxy功能。作者也强调,虽然这个Proxy 让 Cluster 拥有了像单实例一样的接入方式,但是本质上还是 Cluster,不支持的命令还是不会支持,比如跨 slot 的多Key操作。

详情参见:https://github.com/RedisLabs/redis-cluster-proxy

本篇参考:
正式支持多线程!Redis 6.0与老版性能对比评测
Redis 6 RC1 is out today
Redis 6 新功能提前看

你可能感兴趣的:(缓存)