Redis 6 新功能提前看!
本文内容主要基于 Salvatore Sanfilippo 在今年六月26-27日 Redis Day New York 上关于 Redis 6 新功能的分享,加上目前在官方(博客、Twitter等)已经公开内容作为补充,并通过 Github 上的 unstable 分支(截至本文时间2019年8月2日)进行测试验证。
Overview
Salvatore Sanfilippo(以下均简称为作者)在 Redis Day New York 上的分享在YouTube 上已经发布,原链接请见链接(当然,你需要科学的上网工具)。
啥也不说,先上原图。
嗯,相当魔性。这个就是作者分享的原图。别人都是带个精心准备好的PPT,他就带个白板上来画画画,有技术就可以为所欲为?>_<
作者先简单介绍 Redis 6 会给大家提供的新功能,包括:
一、对用户使用有直接影响的功能
- ACL用户权限控制功能
- RESP3:新的 Redis 通信协议
- Cluster 管理工具
- SSL 支持
二、Redis 内部的优化
- IO多线程支持
- 新的Module API
- 新的 Expire 算法
三、外部工具
- Redis Cluster Proxy
- Disque
作者分享着重介绍了(一)里面的1-3点,其他几点有所提及。本文也按照这个内容进行分享。
ACL
目前的 Redis(5及以下版本),没有用户权限管理这个概念,只有一个AUTH
密码验证功能,基本上能够接入的用户就是root
用户。
ACL 就是为了避免接入的用户进行危险命令的操作开发的功能,这类命令如 FLUSHALL
,DEBUG
等。还记得我之前分享过的一篇文章《从清档到二级索引》
多年来 Redis 管理员通过RENAME
命令来进行限制。另一方面,开发人员有时候不清楚一些Redis 驱动的内部实现,可能无意中触发一些危险命令,所以也需要进行限制。
Redis 6 中加入ACL的功能,能够对接入的用户进行三个层面的权限控制:
(1)接入权限:用户名和密码;
(2)可以执行的命令;
(3)可以操作的 KEY。
下面我们实际代码中看看效果,下面展示我创建一个用户aaron,设置他的密码,允许执行所有命令,针对所有KEY。
127.0.0.1:6380> ACL WHOAMI "default" 127.0.0.1:6380> ACL setuser aaron on >mypasswd +@all ~* OK 127.0.0.1:6380> AUTH aaron mypasswd OK 127.0.0.1:6380> ACL WHOAMI "aaron" 127.0.0.1:6380> GET foo (nil) 127.0.0.1:6380> SET foo bar OK
然后我尝试将 aaron 这个用户去掉SET
命令的权限。
127.0.0.1:6380> ACL setuser aaron -SET OK 127.0.0.1:6380> SET foo 123 (error) NOPERM this user has no permissions to run the 'set' command or its subcommand
我们也可以控制用户可以对哪些 KEY 进行操作,比如下面演示一个叫做 Ben 的用户,他只能创建以 ben
为前缀的 KEY。
127.0.0.1:6380> ACL setuser ben on >mypasswd +@all ~ben* OK 127.0.0.1:6380> set foo bar (error) NOPERM this user has no permissions to access one of the keys used as arguments 127.0.0.1:6380> set benfoo bar OK
"default" 用户是我们默认连接入 Redis 时的用户,默认情况下这个用户有所有的权限,当然了,我们也可以像以前那样给默认用户设置权限。通过ACL list
可以查看当前有哪些用户和他们的权限和密码(前提是该用户有ACL命令的权限)。
127.0.0.1:6380> ACL list 1) "user aaron on >mypasswd ~* +@all -set" 2) "user default on nopass ~* +@all"
作者提到ACL功能是基于 bitmap 实现的,对性能几乎没有影响。
关于ACL功能就介绍到这里,有兴趣的作者可以看官方文档:
https://redis.io/topics/acl
RESP3
RESP 全称 REdis Serialization Protocol,是 Redis 服务端与客户端之间通信的协议。Redis 5 使用的是 RESP2,而 Redis 6 开始在兼容 RESP2 的基础上,开始支持 RESP3。其实一开始作者是打算完全放弃 RESP2的,后来被劝退了。详情见链接(http://antirez.com/news/125)。
那么 RESP3 有哪些改进的地方呢?
照例上个原图:
这个图中,作者分享的是,在 RESP2 中,所有的返回内容,都是一个字符串数组的形式,不管是 list 还是 sorted set。因此客户端需要自行去根据类型进行解读,增加了客户端实现的复杂性。
下面以具体的命令展示 RESP3 中的具体变化。
127.0.0.1:6380> HSET myhash a 1 b 2 c 3 (integer) 3 127.0.0.1:6380> HGETALL myhash 1) "a" 2) "1" 3) "b" 4) "2" 5) "c" 6) "3" 127.0.0.1:6380> 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:6380> HGETALL myhash 1# "a" => "1" 2# "b" => "2" 3# "c" => "3"
其实从 redis-cli 来看意义不大,因为显示出来的信息已经经过处理,最直接的方式是直接telnet
之后进行操作看返回结果:
$ telnet 127.0.0.1 6380 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. AUTH aaron mypasswd +OK HGETALL myhash *4 $1 a $1 1 $1 b $1 2 HELLO 3 (此处省略) HGETALL myhash %2 $1 a $1 1 $1 b $1 2
可以看到,以前返回两个field的hash,就是直接无差别地返回4个值,而新的RESP3就会告诉客户端返回两个key-value,通过%
表示键值对(也成为map类型)的个数。
另外作者也对空字符串进行了定义:
(RESP2) GET null_key $-1 (RESP3) GET null_key _
其他新的定义还有不少,比如支持 Boolean 类型,set集合类型等等,有兴趣的读者,也是可以去详细看看 RESP3 的设计稿:
https://github.com/antirez/RE...
除了具体的数据类型,RESP3 开始支持KEY属性类型(Attribute type),使服务器和客户端之间可以实现更复杂的功能,比如返回信息里带上一个Key的访问频率,使客户端能实现更智能的缓存功能(http://antirez.com/news/130)。话说,客户端缓存功能,可以说是在提升 Redis 作为缓存的读写能力有了质的飞跃,值得期待。
其他
其他方面作者没有作太深入的分享,因此我下面也只是简单提一下,并且附上相关的资料,如果读者有兴趣想了解,欢迎留言给我,我下次分享相关主题。
Cluster 管理工具
作者分享说redis-trib.rb
的功能集成到redis-cli
,但这个不是 Redis 5 就已经做了的事情吗?看了一圈,也并没有太大的变化,就增加了一个backup
命令。
除了redis-cli
,其实另一个工具的优化更让人喜闻乐见,就是redis-benchmark
。
$ src/redis-benchmark --help Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests>] [-k <boolean>] (省略部分输出结果……) --threads <num> Enable multi-thread mode. --cluster Enable cluster mode. --enable-tracking Send CLIENT TRACKING on before starting benchmark.
官方benchmark工具总算支持cluster了,通过多线程的方式对多个分片进行压测。
支持 SSL 连接
Amazon 提供的一个功能,在 Redis 6 中 merge 进来。没有提及细节,不清楚对性能有多大影响。
IO多线程
Redis 终于实现多线程了!?先打住,多线程是不可能多线程的,这辈子都不可能多线程(后面这句是我加的)。
作者先简单解释了为什么不能多线程(复杂性、锁的效率等等),然后提到就是有一个事情可以做成多线程,就是针对客户端的这部分。这个操作通过系统调用写操作,将客户端的输入输出缓冲中的数据通过多线程IO与客户端交互。作者说这部分通常能够占到CPU负载的50%,将这部分通过其他线程进行处理,核心流程还是单线程,实现起来也比较简单,性价比超高,所以就做了。
这样能进一步提升单实例的性能,使用4核、8核等来分散写压力,不过再多几个核估计收益比不高了。如果真正想发挥多核性能,还是老路子——Cluster。
Modules API
新的Modules API,让Module功能可以做更多的事情,但作者没有展开讲。
新Expire过期算法
这部分因为涉及到的背景和算法比较多,所以会另外开一个 session 来分享。(视频也可以在YouTube上看了)
Proxy
针对 Cluster 的代理,这么多年了,仍然有不少人在Cluster的接入方式上挣扎,因为缺少合适的驱动而无法使用Cluster。所以开发了这个Proxy功能。作者也强调,虽然这个Proxy 让 Cluster 拥有了像单实例一样的接入方式,但是本质上还是 Cluster,不支持的命令还是不会支持,比如跨 slot 的多Key操作。
其实社区早已有过不少 Proxy 方面的尝试,而且有些做的还不错。那么这个官方的 Proxy 究竟会给我们带来什么惊喜呢?还是让我们拭目以待吧。
Disque
这个本来是作者几年前开发的一个基于 Redis 的消息队列工具,但多年来作者发现 Redis 在持续开发时,他也要持续把新的功能合并到这个Disque 项目里面,这里有大量无用的工作。因此这次他在 Redis 的基础上通过 Modules 功能实现 Disque。
如果业务并不需要保持严格消息的顺序,这个 Disque 能提供足够简单和快速的消息队列功能。
总结
对我来说,这个版本可以说有史以来变化最大的一次升级(如果不是最大也是之一了)。不管是从使用者,DBA,客户端工具开发者,还是运维的角度来看,都有了不少的变化。这次升级使得 Redis 从整体上更接近一个完整的数据库(对比 MongoDB)。另一方面,这次升级给所有相关的人员带来了很多变化,恐怕后面要忙好一阵子了。
不知道大家看完 Redis 6 的新功能之后有什么感想?限于篇幅,本文只是按作者重点分享的内容进行整理,其实每一项变化似乎都可以新写一篇文章来分享。如果有你感兴趣的内容,也可以留言一下,有机会下次我可以分享。
更多资讯,欢迎关注公众号:最简实践