目錄
1. 簡介
2. 新功能測驗驗證
2.1 新功能——ACL權限控制
2.1.1 ACL簡介
2.1.2 ACL 引數決議
2.1.3 ACL 賦權配置及示例
(1)ACL權限持久化方式
(2)ACL權限持久化配置示例
2.1.4 ACL部分原始碼簡析
(1)ACL初始化
(2)ACL權限加載
(3)ACL用戶操作
2.2 新功能——TLS加密管理
2.2.1 TLS簡介
2.2.2 TLS 配置與示例
(1)TLS 編譯示例
2.2.3 Redis TLS使用示例
2.2.4 TLS部分原始碼簡析
(1)TLS初始化
(2)TLS讀寫
2.2.5 TLS局限性
2.3新功能——多執行緒IO
2.3.1 多執行緒IO簡介
2.3.2 多執行緒IO實作及配置示例
(1)多執行緒IO流程
(2)多執行緒IO引數決議
2.3.3多執行緒IO使用及性能對比
(1)Redis版本間對比測驗
(2)Redis CPU間性能對比測驗
2.3.4 多執行緒IO部分原始碼簡析
(1)多執行緒IO初始化
(2)多執行緒IO任務處理
3. 小結
1. 簡介
Redis(Remote Dictionary Server),即遠程字典服務,是一個使用 C撰寫的開源(BSD許可)、包含多種資料結構、支持網路、基于記憶體、可選持久性的鍵值對存盤資料庫,是現在最受歡迎的NoSQL資料庫之一,依賴于Redis的高性能、多資料型別等特性,Redis應用場景十分廣泛,可用于游戲快取應用、互聯網快取應用、電商高并發應用及其他快取加速訪問應用,能有效承載巨大的讀寫壓力,輕松實作高并發訪問,
Redis最新版本為Redis6.X,其中有Redis6.0.X及Redis6.2.X兩個分支,Redis6.0中已于2020年上半年發布,6.0版本最新已發布至6.0.15,Redis6.0帶來了諸多新功能:
- 新增ACL權限控制,可實作賬號的權限管控;
- 新增TLS加密管理,可實作Redis加密訪問控制;
- 多執行緒IO,可實作單個Redis實體更高性能,
除此之外,Redis6.0還有RESP3協議、客戶端快取加速及redis-benchmark、redis-cli優化等新功能,
本文主要對Redis6.0的ACL權限管控、TLS加密管理及多執行緒IO進行了測驗驗證和決議,
2. 新功能測驗驗證
2.1 新功能——ACL權限控制
2.1.1 ACL簡介
Redis ACL 是Access Control List(訪問控制串列)的縮寫,該功能允許對訪問 Redis 的連接做一些可執行命令和可訪問 KEY 的限制,它的作業方式是,在連接之后,要求客戶端進行身份驗證,以提供用戶名和有效密碼,如果身份驗證成功,該客戶端連接與給定用戶系結,并具有該用戶的訪問權限,
Redis6.0版本之前,用戶只有一個default用戶,同一Redis實體所有讀寫操作都共享此用戶,難免出現誤操作洗掉資料或泄露資料情況,雖然可以使用rename命令禁用部分敏感操作,但也同時意味著需要進行敏感操作時,將有額外操作需要進行,權限管控復雜且不完善,在Redis6.0之后,通過ACL(權限管理)功能,可以設定不同的用戶并對其授權命令或資料權限,這一功能,可以有效降低用戶誤操作導致資料丟失或資料泄露風險,其中,密碼由SHA256進行加密,
Tips:linux下sha256加密方式:echo -n passowrd | sha256sum
2.1.2 ACL 引數決議
本章節簡要說明ACL常用命令,以及筆者使用時遇到的問題和需關注的地方,
常用的命令如下:
| 引數 | 說明 |
|---|---|
| CAT | 查看類別 |
| DELUSER | 洗掉用戶 |
| GENPASS | 創建密碼 |
| GETUSER | 獲得用戶 |
| HELP | 幫助 |
| LIST | 查看用戶詳情 |
| LOAD | 加載aclfile |
| SAVE | 保存至aclfile |
| SETUSER | 設定用戶 |
| USERS | 查看用戶 |
| WHOAMI | 查看當前用戶 |
| LOG | 顯示日志 |
1)ACL CAT示例:


ACL將所有命令分為21子類,ACL可以較細粒度地進行權限劃分,但部分命令同時處于不同的權限子類中,設定多個子類權限時,需關注這些命令權限問題,
2)ACL LIST 示例:
通過ACL生成的用戶以如下default、test賬號為例,進行簡要說明:

| 引數 | 說明 |
|---|---|
| user test | 代表用戶是test |
| on | 代表用戶是啟用的,如果是off,代表用戶是禁用的,在off狀態下,登錄會失敗; |
| #e...cc7 | 是sha256加密后的密碼串 |
| ~* | ~為添加指定模式的鍵(~*代表allkeys) |
| + | 代表用戶可以使用該命令,如果是 - ,代表用戶無法使用該命令 |
| @ | 用戶可以使用某類別命令,類別可以通過acl cat獲得 |
3)ACL SETUSER示例:

ACL SETUSER時,可通過“>”符號分次設定多個密碼且密碼均為有效;可通過“<”符號使密碼無效化,不建議同一賬號設定過多密碼,當密碼無法找回時,可先洗掉賬號再建立相同權限用戶方式更新密碼,以防有效密碼過多導致密碼泄露進而導致資料泄露,
對default用戶的權限設定需謹慎,筆者進行測驗時,設定了一個與default完全相同的admin用戶并將default用戶權限縮小,因操作原因出現了權限不可用情況,盡可能保留default權限不刪減,
普通用戶賦權后,可通過auth username password方式登錄普通賬號,此方式登錄需使用6.0及以上版本redis-cli客戶端,低版本客戶端無法識別,多版本混用需注意,
筆者測驗時,一個實體中生成7000+普通賬號,redis運行正常權限管控正常,示例如下:
acl setuser test1 >Admin123 ~* +get #賬號test1,密碼Admin123
acl setuser test2 >Admin123 ~* +set
acl setuser test2 >Admin123 ~* * +get +set
...
acl setuser test7000 >Admin123 ~* +@all
acl list #7000個用戶顯示正常
auth test7000 Admin123 #登陸正常
2.1.3 ACL 賦權配置及示例
(1)ACL權限持久化方式
通過上述的ACL SETUSER方式,對用戶的賬號進行了賦權后可進行持久化,Redis 實作ACL權限持久化的方式主要有兩種:
① redis.conf方式:直接將賬號密碼持久化保存在redis.conf中;
② aclfile方式:將賬號密碼保存至users.acl檔案中,并把users.acl 路徑寫入redis.conf,
兩種方式中,更推薦aclfile方式,因為redis.conf方式加載配置需要重啟Redis,而aclfile方式執行acl load即可,
此外,我們可以在客戶端對賬戶密碼進行操作,如果使用redis.conf方式,可通過config rewrite持久化;如果使用aclfile方式,可使用acl save進行持久化,
| 對比項 | redis.conf方式 | aclfile方式 |
|---|---|---|
| 加載配置 | 重啟Redis | 執行acl load |
| 持久化配置 | 執行config rewrite | 執行acl save |
(2)ACL權限持久化配置示例
兩種持久化方式的示例如下:
① redis.conf方式
cat redis.conf | grep "~*"可得:

② aclfile方式
- cat users.acl,查看賬號密碼權限:

- cat redis.conf | grep users.acl,查看aclfile檔案的位置:

Tips:redis6.2.X與redis6.0.X在acl權限控制上,明顯區別在于增加了 Pub/Sub channel (&*)管控,
2.1.4 ACL部分原始碼簡析
上面提到了ACL權限控制和持久化方式,下面對ACL初始化、權限加載、用戶操作原始碼進行簡要的決議,
(1)ACL初始化
在server.c的main函式中,有ACLInit()函式,ACLInit()中,主要為初始化ACL的結構,同時,ACLInitDefaultUse初始化默認用戶default,default用戶初始化時,具有全部權限及默認不需要密碼,
void ACLInit(void) {
Users = raxNew();
UsersToLoad = listCreate();
ACLLog = listCreate();
ACLInitDefaultUser();
server.requirepass = NULL; /* Only used for backward compatibility. */
}
(2)ACL權限加載
在ACLInit()完成后,main函式中通過ACLLoadUsersAtStartup()進行ACL權限加載,分別通過ACLLoadConfiguredUsers()及ACLLoadFromFile()函式判斷用戶資訊及加載方式,ACLLoadConfiguredUsers()使用redis.conf進行權限加載,ACLLoadFromFile()使用acl檔案進行權限加載,
void ACLLoadUsersAtStartup(void) {
if (server.acl_filename[0] != '\0' && listLength(UsersToLoad) != 0) {
serverLog(LL_WARNING,
"...");
exit(1);
}
if (ACLLoadConfiguredUsers() == C_ERR) {
serverLog(LL_WARNING,
"Critical error while loading ACLs. Exiting.");
exit(1);
}
if (server.acl_filename[0] != '\0') {
sds errors = ACLLoadFromFile(server.acl_filename);
if (errors) {
serverLog(LL_WARNING,
"Aborting Redis startup because of ACL errors: %s", errors);
sdsfree(errors);
exit(1);
}
}
}
(3)ACL用戶操作
在進行ACL操作命令時,實際呼叫了acl.c的aclCommad()命令,aclCommand中,對各類ACL操作分別進行了定義,如setuser,通過判斷命令中是否含setuser關鍵字,再判斷usename是否含有空格,user是否已存在,最后呼叫ACLSetUser(),ACLCreateUser()實作setuser操作,
void aclCommand(client *c) {
char *sub = c->argv[1]->ptr;
if (!strcasecmp(sub,"setuser") && c->argc >= 3) {
sds username = c->argv[2]->ptr;
/* Check username validity. */
if (ACLStringHasSpaces(username,sdslen(username))) {
addReplyErrorFormat(c,
"Usernames can't contain spaces or null characters");
return;
}
user *tempu = ACLCreateUnlinkedUser();
user *u = ACLGetUserByName(username,sdslen(username));
if (u) ACLCopyUser(tempu, u);
for (int j = 3; j < c->argc; j++) {
if (ACLSetUser(tempu,c->argv[j]->ptr,sdslen(c->argv[j]->ptr)) != C_OK) {
char *errmsg = ACLSetUserStringError();
addReplyErrorFormat(c,
"Error in ACL SETUSER modifier '%s': %s",
(char*)c->argv[j]->ptr, errmsg);
ACLFreeUser(tempu);
return;
}
}
/* Overwrite the user with the temporary user we modified above. */
if (!u) u = ACLCreateUser(username,sdslen(username));
serverAssert(u != NULL);
ACLCopyUser(u, tempu);
ACLFreeUser(tempu);
addReply(c,shared.ok);
}
...
}
在普通用戶使用權限時,通過ACLCheckCommandPerm()及ACLGetUserCommandBit()函式判斷用戶是否具有操作權限,如無權限則報ACL_DENIED_CMD權限不足,
2.2 新功能——TLS加密管理
2.2.1 TLS簡介
TLS(Transport Layer Security,安全傳輸層)是建立在傳輸層TCP協議之上的協議,服務于應用層,在實作上分為記錄層和握手層兩層,其中握手層又含四個子協議:握手協議、更改加密規范協議、應用資料協議和警告協議,實作了將應用層的報文進行加密后再交由TCP進行傳輸的功能,解決了保密、完整性、認證等網路安全問題,Redis從6.0版本開始支持TLS安全加密,

2.2.2 TLS 配置與示例
Redis 內部使用 OpenSSL 開發庫來實作TLS功能,因此,需要在 Redis 編譯之前預先安裝 OpenSSL 套件庫,此外,TLS是可選功能,需要在編譯時加上引數后才會加入TLS功能,
下面將對TLS編譯使用進行示例,并簡要說明程序中遇到的問題和需關注的地方,
(1)TLS 編譯示例
編譯時,需添加 BUILD_TLS=yes以加入TLS功能,因為依賴主機OpenSSL版本,所以不同OpenSSL版本主機編譯出的redis-server不通用,此外,需要注意gcc版本,下面以CentOS7.6、Ubuntu16.04為例進行說明及錯誤示例,
① 以CentOS7.6為例
執行 “make BUILD_TLS=yes”時出現has no member named報錯:

原因為gcc版本過低,升級gcc版本即可,升級方式:
yum -y install centos-release-scl scl-utils-build
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
升級完成后,執行gcc -v,出現gcc version 9.3.1 20200408 (Red Hat 9.3.1-2) (GCC)即為升級成功,再次編譯執行“make distclean;make BUILD_TLS=yes”,即可編譯成功,
② 以Ubuntu16.04為例
執行“make BUILD_TLS=yes”,若出現“jemalloc/jemalloc.h: No such file or directory”或“Newer version of jemalloc required”報錯:


方案一:README.md檔案的官方解決方案
在README.md檔案中,Redis官方給出了解決方案“To force compiling against libc malloc, use: % make MALLOC=libc”,再次執行“make distclean”,筆者將“make BUILD_TLS=yes”命令,改為“make BUILD_TLS=yes MALLOC=libc”,即可編譯成功,
方案二:關注deps/jemalloc權限是否錯誤
通過wget獲得對應Redis版本后,替換掉deps檔案夾中內容,再次執行“make distclean;make BUILD_TLS=yes”,若通過這種方式可以編譯成功,Redis采用tcmalloc時碎片率會更低最低,
使用redis:6.0.X替換容器版Redis6.0的鏡像時,使用CentOS7.6編譯鏡像無法啟動,使用Ubuntu16.04可成功啟動,經分析,CentOS7.6與Ubuntu16.04的OpenSSL版本分別為OpenSSL 1.0.2k-fips、OpenSSL 1.1.1,因OpenSSL版本不同,所以編譯出的redis-server不通用,驗證時,使用Ubuntu16.04上編譯的redis-server啟動于CentOS7.6時,出現報錯,可證明不通用,

(2)TLS 證書生成
在完成Redis TLS編譯后,根據Redis官方檔案TLS.md中說明,可通過如下命令生成根CA證書和服務器證書:
./utils/gen-test-certs.sh
其中,生成DH(Diffie-Hellman)params檔案耗時較長,
相關證書在配置時限制如下:
| 證書 | 是否必選 |
|---|---|
| ca.crt | 必選 |
| redis.crt | 必選 |
| redis.key | 必選 |
| redis.dh | 可選 |
分析gen-test-certs.sh可知,所有證書均通過openssl生成,在實際使用中,除了使用shell腳本生成證書,還可以通過java、golang等代碼方式呼叫ssl、tls、x509庫生成,其中,證書有效期可以通過days動態生成,到期后可以對證書進行續期,

(3)TLS 引數決議
Redis啟用TLS主要涉及如下引數:
--tls-cert-file /path/to/redis.crt
--tls-key-file /path/to/redis.key
--tls-ca-cert-file /path/to/ca.crt
--tls-dh-params-file /path/to/redis.dh
#以上4個引數為Redis證書及私鑰,包括可信任的根證書和DH PARAMS檔案路徑,本次測驗中為對tls-dh-params-file進行測驗,
--port 0
--tls-port 6379
#以上2個引數為TLS連接埠和非TLS連接埠,埠0代表完全禁用非TLS埠,
--tls-auth-clients yes
#以上為是否啟用雙向TLS并要求客戶端使用有效證書進行身份驗證,默認開啟,
--tls-replication yes
#Redis主服務器以相同的方式處理連接客戶端和從服務器,在從服務器端,必須指定tls-replication yes才能將TLS用于到主服務器的對外連接,sentinel也需要同步設定,
--tls-cluster yes
#Redis集群需使用tls-cluster yes以便為集群和跨節點連接啟用TLS,本次測驗中未涉及此引數,
2.2.3 Redis TLS使用示例
為方便查看,啟動引數直接置于啟動命令列,以單機版redis-server啟動為例:
./src/redis-server --tls-port 6379 --port 0 --tls-cert-file ./tests/tls/redis.crt --tls-key-file ./tests/tls/redis.key --tls-ca-cert-file ./tests/tls/ca.crt

redis server成功啟動,使用redis-cli進行連接,連接時,同時需要加上證書資訊:
./src/redis-cli --tls --cert ./tests/tls/redis.crt --key ./tests/tls/redis.key --cacert ./tests/tls/ca.crt

在進行主備版測驗時,redis-server及sentinel除新增上述引數外,需額外增加“--tls-auth-clients yes”和“--tls-replication yes”方可啟動成功,否則將無法連接,解釋見Redis TLS引數決議,
2.2.4 TLS部分原始碼簡析
(1)TLS初始化
在server.c的main函式中,tlsInit()函式用于初始化SSL庫,initServerConfig()、initConfigValues()用于初始化tls_port和tls_ctx_config等TLS相關引數(相關引數均在redis.conf中獲得),在InitServer()中,獲得的TLS引數tls_ctx_config和tls_port被用于tls.c的tlsConfigure()中用于初始化TLS,
if ((server.tls_port || server.tls_replication || server.tls_cluster)
&& tlsConfigure(&server.tls_ctx_config) == C_ERR) {
serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
exit(1);
}
(2)TLS讀寫
讀寫操作由connTLSRead()和connTLSWrite()組成,connTLSRead()是一個SSL_Read的封裝,將從tls連接中讀取的位元組緩沖到buf中,connTLSWrite()是一個SSL_Write的封裝,將位元組寫入data套接字,其中,tls_connection為建立起的tls連接,
static int connTLSRead(connection *conn_, void *buf, size_t buf_len) {
tls_connection *conn = (tls_connection *) conn_;
int ret;
int ssl_err;
if (conn->c.state != CONN_STATE_CONNECTED) return -1;
ERR_clear_error();
ret = SSL_read(conn->ssl, buf, buf_len);
...
return ret;
}
2.2.5 TLS局限性
Redis特性在于支持高并發且6.0開始支持多執行緒,然而開啟了TLS功能后,出現了明顯的局限性:
① 不再支持多執行緒功能(TLS.md:**Multi-threading I/O is not currently supported for TLS**);
② QPS顯著下降,經測驗只有未開啟TLS的60%(詳見下圖);
③ 6.0.X版本的redis-benchmark不支持TLS功能,需使用6.2.X版本的redis-benchmark才能執行測驗,
使用redis-benchmark在同一臺主機上進行對SET、GET、LRANGE_600測驗,結果如圖所示,

可以看出,開啟TLS后,QPS明顯降低,
2.3新功能——多執行緒IO
2.3.1 多執行緒IO簡介
Redis6.0 之前都是使用單執行緒異步IO處理資料的,單執行緒IO只能使用一個CPU核,當key的value比較大時容易拖垮Redis,而且QPS到達10W+后難以更進一步,從Redis6.0開始支持多執行緒IO,多執行緒IO不僅可以充分利用服務器CPU資源,還可以分攤IO讀寫負荷,大幅提升了Redis性能,
2.3.2 多執行緒IO實作及配置示例
(1)多執行緒IO流程
流程主要如下:
① 主執行緒負責接收建立連接請求,獲取 socket 放入全域等待讀處理佇列;
② 主執行緒處理完讀事件后,通過 RR(Round Robin) 將這些連接分配給這些 IO 執行緒;
③ 主執行緒阻塞等待 IO 執行緒讀取 socket 完畢;
④ 主執行緒通過單執行緒的方式執行請求命令,請求資料讀取并決議完成,但并不執行;
⑤ 主執行緒阻塞等待 IO 執行緒將資料回寫 socket 完畢;
⑥ 解除系結,清空等待佇列,

(2)多執行緒IO引數決議
在redis.conf中,可以對多執行緒進行配置(修改配置需重啟redis實體),多執行緒配涉及兩個引數:
| 引數 | 說明 |
|---|---|
| io-threads | 開啟多執行緒的個數(io-thread最大值不能超過服務器CPU可使用總核數) |
| io-threads-do-reads | 取yes表示多執行緒開啟 |
2.3.3多執行緒IO使用及性能對比
添加多執行緒IO引數重啟redis后,通過redis-cli config get *命令可查看當前io-threads及io-threads-do-reads配置現況,
多執行緒IO主要表現在提升了redis的并發能力上,故對不同版本的redis及同版本redis在不同機器上進行了比對測驗,分析多執行緒IO提升能力,
(1)Redis版本間對比測驗
在同一臺主機上,對Redis4.0和Redis6.0進行redis-benchmark性能測驗,測驗時,redis-benchmark使用了--threads引數進行多執行緒測驗,測驗結果詳見下圖:

可以看出,Redis6.0較Redis4.0同在單執行緒時,性能并沒有得到提升;Redis6.0 二執行緒,較redis6.0單執行緒、Redis4.0并發量得到了明顯提升,因此,可以得出結論,多執行緒IO可明顯提高Redis的并發量,
(2)Redis CPU間性能對比測驗
多執行緒IO可明顯提升Redis并發量,在不同型別的CPU主機上測驗,也有不同的提升,具體如下:
① 多執行緒IO 并發上限不到單執行緒IO的三倍,io-threads到一定數之后(測驗時值為6-10,因服務器CPU差別),并發增幅極為有限,在這種情況下,即使增加執行緒數,也不能明顯增加Redis 并發量,只會導致服務器負載增加,
② CPU頻率越高,能達到的最大并發相對也越高,故選用CPU時,選擇較高頻率CPU可以提升Redis性能,使用時,打開高性能模式也可以提升Redis性能,
Redis6.0 SET Intel Xeon測驗結果:

2.3.4 多執行緒IO部分原始碼簡析
多執行緒IO中,組態檔redis.conf主要涉及的引數是io_threads_do_reads、io-threads,原始碼中,除了這兩個關鍵變數外,還會涉及io_threads_op、io_threads_pending等變數,
(1)多執行緒IO初始化
在server.c的main函式InitServerLast()中,有初始化多執行緒函式initThreadedIO(),函式中呼叫了pthread_create 來創建執行緒,并且注冊了執行緒回呼函式IOThreadMain(),
void initThreadedIO(void) {
server.io_threads_active = 0;
if (server.io_threads_num == 1) return;
if (server.io_threads_num > IO_THREADS_MAX_NUM) {
serverLog(LL_WARNING,"Fatal: too many I/O threads configured. "
"The maximum number is %d.", IO_THREADS_MAX_NUM);
exit(1);
}
/* Spawn and initialize the I/O threads. */
for (int i = 0; i < server.io_threads_num; i++) {
/* Things we do for all the threads including the main thread. */
io_threads_list[i] = listCreate();
if (i == 0) continue;
pthread_t tid;
pthread_mutex_init(&io_threads_mutex[i],NULL);
io_threads_pending[i] = 0;
pthread_mutex_lock(&io_threads_mutex[i]); /* Thread will be stopped. */
if (pthread_create(&tid,NULL,IOThreadMain,(void*)(long)i) != 0) {
serverLog(LL_WARNING,"Fatal: Can't initialize IO thread.");
exit(1);
}
io_threads[i] = tid;
}
}
(2)多執行緒IO任務處理
以多執行緒讀為例,使用了handleClientsWithPendingReadsUsingThreads 函式進行多執行緒讀,步驟如下:
① 通過 io_threads_active 和io_threads_do_reads 兩個標志判斷是否開啟了多執行緒IO,其中 io_threads_do_reads為redis.conf配置引數,io_threads_active通過呼叫startThreadedIO()進行置1操作;
② 主執行緒給作業執行緒分配client物件策略即輪詢策略,io_threads_op指定讀型別,通過給io_threads_pending[id]賦值啟動作業執行緒,作業執行緒在處理完自己鏈表的 client 物件后會清空自己的鏈表并重置 io_threads_pending[id] 為0;
③ 主執行緒的利用while將自己鏈表中的 client 處理完畢;
④ 最后,執行緒的pending和為0,跳出回圈完成讀事件的處理,
int handleClientsWithPendingReadsUsingThreads(void) {
if (!server.io_threads_active || !server.io_threads_do_reads) return 0;
int processed = listLength(server.clients_pending_read);
if (processed == 0) return 0;
if (tio_debug) printf("%d TOTAL READ pending clients\n", processed);
/* Distribute the clients across N different lists. */
listIter li;
listNode *ln;
listRewind(server.clients_pending_read,&li);
int item_id = 0;
while((ln = listNext(&li))) {
client *c = listNodeValue(ln);
int target_id = item_id % server.io_threads_num;
listAddNodeTail(io_threads_list[target_id],c);
item_id++;
}
/* Give the start condition to the waiting threads, by setting the
* start condition atomic var. */
io_threads_op = IO_THREADS_OP_READ;
for (int j = 1; j < server.io_threads_num; j++) {
int count = listLength(io_threads_list[j]);
io_threads_pending[j] = count;
}
/* Also use the main thread to process a slice of clients. */
listRewind(io_threads_list[0],&li);
while((ln = listNext(&li))) {
client *c = listNodeValue(ln);
readQueryFromClient(c->conn);
}
listEmpty(io_threads_list[0]);
/* Wait for all the other threads to end their work. */
while(1) {
unsigned long pending = 0;
for (int j = 1; j < server.io_threads_num; j++)
pending += io_threads_pending[j];
if (pending == 0) break;
}
if (tio_debug) printf("I/O READ All threads finshed\n");
...
/* Update processed count on server */
server.stat_io_reads_processed += processed;
return processed;
}
3. 小結
本次主要對Redis6.0的三個新功能ACL權限控制、TLS加密管理及多執行緒IO進行了功能性能測驗及分析,測驗時也兼帶對redis-cli、redis-benchmark新功能進行了一定的測驗驗證:
- ACL權限控制實作了Redis的賬號管理及權限分配,對Redis資料安全防止誤刪起到了一定的作用,
- TLS加密管理可以明顯增加Redis的訪問安全性,但犧牲了一定的性能,Redis作為一款高并發kv資料庫,使用TLS時需考慮安全與性能間的取舍,
- 多執行緒IO可明顯增加Redis并發量,在對Redis并發有較高需求時,可使用高頻多核CPU以提升Redis性能,
- redis-benchmark在6.0版本支持了多執行緒,測驗時可以多個執行緒同時進行,無需通過多臺主機同時壓測,也是一個較大的優化點,方便了壓測進行,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/303866.html
標籤:java
