Redis6.0穩(wěn)定版本已經(jīng)發(fā)布了存和,大版本發(fā)布肯定會有一些新特性,比如開發(fā)人員心心念念的多線程支持,他真的旦部,來了。
Overview
Salvatore Sanfilippo(以下均簡稱為作者)在 Redis Day New York 上的分享在YouTube 上已經(jīng)發(fā)布较店,原鏈接請見https://www.youtube.com/watch?v=lo-Pgf_l7_M
當然你需要科學上網(wǎng)
一士八、對用戶使用有直接影響的功能
- ACL用戶權(quán)限控制功能
- RESP3:新的 Redis 通信協(xié)議
- Cluster 管理工具
- SSL 支持
二、Redis 內(nèi)部的優(yōu)化
- IO多線程支持
- 新的Module API
- 新的 Expire 算法
三泽西、外部工具
- Redis Cluster Proxy
- Disque
ACL
目前的 Redis(5及以下版本)曹铃,沒有用戶權(quán)限管理這個概念,只有一個AUTH密碼驗證功能捧杉,基本上能夠接入的用戶就是root用戶陕见。
ACL 就是為了避免接入的用戶進行危險命令的操作開發(fā)的功能秘血,這類命令如 FLUSHALL,DEBUG等评甜。
多年來 Redis 管理員通過RENAME命令來進行限制灰粮。另一方面,開發(fā)人員有時候不清楚一些Redis 驅(qū)動的內(nèi)部實現(xiàn)忍坷,可能無意中觸發(fā)一些危險命令粘舟,所以也需要進行限制。
Redis 6 中加入ACL的功能佩研,能夠?qū)尤氲挠脩暨M行三個層面的權(quán)限控制:
(1)接入權(quán)限:用戶名和密碼柑肴;
(2)可以執(zhí)行的命令;
(3)可以操作的 KEY旬薯。
下面我們實際代碼中看看效果晰骑,下面展示我創(chuàng)建一個用戶aaron,設(shè)置他的密碼绊序,允許執(zhí)行所有命令硕舆,針對所有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命令的權(quán)限骤公。
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 的用戶,他只能創(chuàng)建以 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 時的用戶凌节,默認情況下這個用戶有所有的權(quán)限,當然了趁猴,我們也可以像以前那樣給默認用戶設(shè)置權(quán)限刊咳。通過ACL list可以查看當前有哪些用戶和他們的權(quán)限和密碼(前提是該用戶有ACL命令的權(quán)限)。
127.0.0.1:6380> ACL list
1) "user aaron on >mypasswd ~* +@all -set"
2) "user default on nopass ~* +@all"
作者提到ACL功能是基于 bitmap 實現(xiàn)的儡司,對性能幾乎沒有影響娱挨。
關(guān)于ACL功能就介紹到這里,有興趣的作者可以看官方文檔:
https://redis.io/topics/acl
RESP3
RESP 全稱 REdis Serialization Protocol捕犬,是 Redis 服務(wù)端與客戶端之間通信的協(xié)議跷坝。Redis 5 使用的是 RESP2,而 Redis 6 開始在兼容 RESP2 的基礎(chǔ)上碉碉,開始支持 RESP3柴钻。其實一開始作者是打算完全放棄 RESP2的,后來被勸退了垢粮。詳情見鏈接(http://antirez.com/news/125)贴届。
那么 RESP3 有哪些改進的地方呢?
在 RESP2 中,所有的返回內(nèi)容毫蚓,都是一個字符串數(shù)組的形式占键,不管是 list 還是 sorted set。因此客戶端需要自行去根據(jù)類型進行解讀元潘,增加了客戶端實現(xiàn)的復(fù)雜性畔乙。
下面以具體的命令展示 RESP3 中的具體變化。
127.0.0.1:6379> HSET myhash a 1 b 2 c 3
(integer) 3
127.0.0.1:6379> HSET myhash a 1 b 2 c 3
(integer) 0
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 #轉(zhuǎn)換成RESP3的命令
1# "server" => "redis"
2# "version" => "6.0.3"
3# "proto" => (integer) 3
4# "id" => (integer) 4
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"
其實可以看到協(xié)議版本切換后返回結(jié)果直觀上是key-value翩概,還可以通過telnet之后進行操作看返回結(jié)果:
telnet 127.0.0.1 6379
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
HGETALL myhash
*6
$1
a
$1
1
$1
b
$1
2
$1
c
$1
3
HELLO 3 #轉(zhuǎn)換成RESP3的命令
HGETALL myhash
%3
$1
a
$1
1
$1
b
$1
2
$1
c
$1
3
可以看到牲距,以前返回兩個field的hash,就是直接無差別地返回6個值钥庇,而新的RESP3就會告訴客戶端返回3個key-value牍鞠,通過%表示鍵值對(也成為map類型)的個數(shù)。
其他新的定義還有不少上沐,比如支持 Boolean 類型皮服,set集合類型等等,有興趣的讀者参咙,也是可以去詳細看看 RESP3 的設(shè)計稿:
https://github.com/antirez/RE...
除了具體的數(shù)據(jù)類型,RESP3 開始支持KEY屬性類型(Attribute type)硫眯,使服務(wù)器和客戶端之間可以實現(xiàn)更復(fù)雜的功能蕴侧,比如返回信息里帶上一個Key的訪問頻率,使客戶端能實現(xiàn)更智能的緩存功能(http://antirez.com/news/130)两入。
話說净宵,客戶端緩存功能,可以說是在提升 Redis 作為緩存的讀寫能力有了質(zhì)的飛躍裹纳,值得期待择葡。
Cluster 管理工具
作者分享說redis-trib.rb的功能集成到redis-cli,但這個不是 Redis 5 就已經(jīng)做了的事情嗎剃氧?看了一圈敏储,也并沒有太大的變化,就增加了一個backup命令朋鞍。
除了redis-cli已添,其實另一個工具的優(yōu)化更讓人喜聞樂見,就是redis-benchmark滥酥。官方benchmark工具總算支持cluster了更舞,通過多線程的方式對多個分片進行壓測。
支持 SSL 連接
Amazon 提供的一個功能坎吻,在 Redis 6 中 merge 進來缆蝉。沒有提及細節(jié),不清楚對性能有多大影響。
IO多線程
可能看到這里大家很開心刊头,終于TM支持多線程贝搁,不過你可能高興的有點早了,這里不是你想的多線程芽偏。
眾所周知雷逆,Redis是單線程的。Redis在處理客戶端的請求時污尉,包括獲取 (socket 讀)膀哲、解析、執(zhí)行被碗、內(nèi)容返回 (socket 寫) 等都由一個順序串行的主線程處理某宪,這就是所謂的“單線程”。
但如果嚴格來講從Redis4.0之后并不是單線程锐朴,除了主線程外兴喂,它也有后臺線程在處理一些較為緩慢的操作,例如清理臟數(shù)據(jù)焚志、無用連接的釋放衣迷、大key的刪除等等。
為什么一直是單線程
官方曾做過類似問題的回復(fù):使用Redis時酱酬,幾乎不存在CPU成為瓶頸的情況壶谒, Redis主要受限于內(nèi)存和網(wǎng)絡(luò)。
例如在一個普通的Linux系統(tǒng)上膳沽,Redis通過使用pipelining每秒可以處理100萬個請求汗菜,所以如果應(yīng)用程序主要使用O(N)或O(log(N))的命令,它幾乎不會占用太多CPU挑社。
使用了單線程后陨界,可維護性高。多線程模型雖然在某些方面表現(xiàn)優(yōu)異痛阻,但是它卻引入了程序執(zhí)行順序的不確定性菌瘪,帶來了并發(fā)讀寫的一系列問題,增加了系統(tǒng)復(fù)雜度录平、同時可能存在線程切換麻车、甚至加鎖解鎖、死鎖造成的性能損耗斗这。
Redis通過AE事件模型以及IO多路復(fù)用等技術(shù)动猬,處理性能非常高,因此沒有必要使用多線程表箭。單線程機制使得 Redis 內(nèi)部實現(xiàn)的復(fù)雜度大大降低赁咙,Hash 的惰性 Rehash、Lpush 等等 “線程不安全” 的命令都可以無鎖進行。
為什么改進成多線程
Redis將所有數(shù)據(jù)放在內(nèi)存中彼水,內(nèi)存的響應(yīng)時長大約為100納秒崔拥,對于小數(shù)據(jù)包,Redis服務(wù)器可以處理80,000到100,000 QPS凤覆,這也是Redis處理的極限了链瓦,對于80%的公司來說,單線程的Redis已經(jīng)足夠使用了盯桦。
但隨著越來越復(fù)雜的業(yè)務(wù)場景慈俯,有些公司動不動就上億的交易量,因此需要更大的QPS拥峦。
常見的解決方案是在分布式架構(gòu)中對數(shù)據(jù)進行分區(qū)并采用多個服務(wù)器贴膘,但該方案有非常大的缺點,例如要管理的Redis服務(wù)器太多略号,維護代價大刑峡;某些適用于單個Redis服務(wù)器的命令不適用于數(shù)據(jù)分區(qū);數(shù)據(jù)分區(qū)無法解決熱點讀/寫問題玄柠;數(shù)據(jù)偏斜突梦,重新分配和放大/縮小變得更加復(fù)雜等等。
從Redis自身角度來說随闪,因為讀寫網(wǎng)絡(luò)的read/write系統(tǒng)調(diào)用占用了Redis執(zhí)行期間大部分CPU時間阳似,瓶頸主要在于網(wǎng)絡(luò)的 IO 消耗, 優(yōu)化主要有兩個方向:
- 提高網(wǎng)絡(luò) IO 性能,典型的實現(xiàn)比如使用 DPDK 來替代內(nèi)核網(wǎng)絡(luò)棧的方式
- 使用多線程充分利用多核铐伴,典型的實現(xiàn)比如 Memcached。
協(xié)議棧優(yōu)化的這種方式跟 Redis 關(guān)系不大俏讹,支持多線程是一種最有效最便捷的操作方式当宴。所以總結(jié)起來,redis支持多線程主要就是兩個原因:
- 可以充分利用服務(wù)器 CPU 資源泽疆,目前主線程只能利用一個核
- 多線程任務(wù)可以分攤 Redis 同步 IO 讀寫負荷
Redis6.0 采用多線程后户矢,性能的提升效果如何
Redis 作者 antirez 在 RedisConf 2019分享時曾提到:Redis 6 引入的多線程 IO 特性對性能提升至少是一倍以上。國內(nèi)也有大牛曾使用unstable版本在阿里云esc進行過測試殉疼,GET/SET 命令在4線程 IO時性能相比單線程是幾乎是翻倍了梯浪,詳情見https://zhuanlan.zhihu.com/p/76788470
Redis6.0 多線程實現(xiàn)機制
1、主線程負責接收建立連接請求瓢娜,獲取 socket 放入全局等待讀處理隊列
2挂洛、主線程處理完讀事件之后,通過 RR(Round Robin) 將這些連接分配給這些 IO 線程
3眠砾、主線程阻塞等待 IO 線程讀取 socket 完畢
4虏劲、主線程通過單線程的方式執(zhí)行請求命令,請求數(shù)據(jù)讀取并解析完成,但并不回寫
5柒巫、主線程阻塞等待 IO 線程將數(shù)據(jù)回寫 socket 完畢
6励堡、解除綁定,清空等待隊列
該設(shè)計有如下特點:
IO 線程要么同時在讀 socket堡掏,要么同時在寫应结,不會同時讀或?qū)?/p>
IO 線程只負責讀寫 socket 解析命令,不負責命令處理
Proxy
針對 Cluster 的代理泉唁,這么多年了鹅龄,仍然有不少人在Cluster的接入方式上掙扎,因為缺少合適的驅(qū)動而無法使用Cluster游两。所以開發(fā)了這個Proxy功能砾层。作者也強調(diào),雖然這個Proxy 讓 Cluster 擁有了像單實例一樣的接入方式贱案,但是本質(zhì)上還是 Cluster肛炮,不支持的命令還是不會支持,比如跨 slot 的多Key操作宝踪。
其實社區(qū)早已有過不少 Proxy 方面的嘗試侨糟,而且有些做的還不錯。那么這個官方的 Proxy 究竟會給我們帶來什么驚喜呢瘩燥?還是讓我們拭目以待吧秕重。
Disque
這個本來是作者幾年前開發(fā)的一個基于 Redis 的消息隊列工具,但多年來作者發(fā)現(xiàn) Redis 在持續(xù)開發(fā)時厉膀,他也要持續(xù)把新的功能合并到這個Disque 項目里面溶耘,這里有大量無用的工作。因此這次他在 Redis 的基礎(chǔ)上通過 Modules 功能實現(xiàn) Disque服鹅。
如果業(yè)務(wù)并不需要保持嚴格消息的順序凳兵,這個 Disque 能提供足夠簡單和快速的消息隊列功能。
總結(jié)
目前先整理這么多企软,后續(xù)可能會有補充庐扫。