真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

提升Redis性能的小技巧有哪些

這篇文章主要介紹了提升redis性能的小技巧有哪些,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

邢臺(tái)ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!

01 使用 pipeline

Redis 是基于請(qǐng)求-響應(yīng)模型的 TCP 服務(wù)器。意味著單次請(qǐng)求 RTT(往返時(shí)間),取決于當(dāng)前網(wǎng)絡(luò)狀況。這會(huì)導(dǎo)致單個(gè) Redis 請(qǐng)求可能非???,比如通過(guò)本地環(huán)路網(wǎng)卡??赡芊浅B热缣幱诰W(wǎng)絡(luò)狀況不佳的環(huán)境。

另一方面,Redis 每次請(qǐng)求-響應(yīng),都涉及到 read 和 write 系統(tǒng)調(diào)用。甚至?xí)|發(fā)多次 epoll_wait 系統(tǒng)調(diào)用(Linux 平臺(tái))。這導(dǎo)致 Redis 不斷在用戶態(tài)和內(nèi)核態(tài)進(jìn)行切換。

static int connSocketRead(connection *conn, void *buf, size_t buf_len) {
    // read 系統(tǒng)調(diào)用
    int ret = read(conn->fd, buf, buf_len);}static int connSocketWrite(connection *conn, const void *data, size_t data_len) {
    // write 系統(tǒng)調(diào)用
    int ret = write(conn->fd, data, data_len);}int aeProcessEvents(aeEventLoop *eventLoop, int flags) {
    // 事件觸發(fā),Linux 下為 epoll_wait 系統(tǒng)調(diào)用
    numevents = aeApiPoll(eventLoop, tvp);}

那么,如何節(jié)省往返時(shí)間和系統(tǒng)調(diào)用次數(shù)呢?批處理是一個(gè)好的辦法。

為此,Redis 提供了 「pipeline」。pipeline 的原理很簡(jiǎn)單,將多個(gè)命令打包成「一個(gè)命令」發(fā)送。Redis 收到后,解析成多個(gè)命令執(zhí)行。最終將多個(gè)結(jié)果打包返回。

「pipeline 可以有效的提升 Redis 性能」。

但是,使用 pipeline 有幾點(diǎn)需要你留意

  1. 「pipeline 不能保證原子性」。在一次 pipeline 命令執(zhí)行期間,可能會(huì)執(zhí)行其它 client 發(fā)起的命令。請(qǐng)記住,pipeline 只是批量處理命令。想要保證原子性,使用 MULTI 或者 Lua 腳本。

  2. 「單次 pipeline 命令不宜過(guò)多」。當(dāng)使用 pipeline 時(shí),Redis 會(huì)將 pipeline 命令的響應(yīng)結(jié)果,暫存在內(nèi)存 Reply buffer 中,等待所有命令執(zhí)行完畢后返回。如果 pipeline 命令過(guò)多,可能會(huì)導(dǎo)致占用較多內(nèi)存??梢詫蝹€(gè) pipeline 拆分成多個(gè) pipeline。


02 開啟 IO 多線程

在「Redis 6」版本以前,Redis 是 「單線程」讀取、解析、執(zhí)行命令的。Redis 6 開始,引入了 IO 多線程。

IO 線程負(fù)責(zé)讀取命令、解析命令、返回結(jié)果。開啟后可以有效提升 IO 性能。

我畫了一張示意圖供你參考

提升Redis性能的小技巧有哪些
如上圖所示,主線程和 IO 線程會(huì)共同參與命令的讀取、解析以及結(jié)果響應(yīng)。

但執(zhí)行命令的,為 「主線程」

IO 線程默認(rèn)關(guān)閉,你可以修改 redis.conf 以下配置開啟。

io-threads 4
io-threads-do-reads yes

「io-threads」 是 IO 線程數(shù)(包含主線程),我建議你根據(jù)機(jī)器,設(shè)置不同值進(jìn)行壓測(cè),取最優(yōu)值。


03 避免 big key

Redis 執(zhí)行命令是單線程的,這意味著 Redis 操作「big key」有阻塞的風(fēng)險(xiǎn)。

big key 通常指的是 Redis 存儲(chǔ)的 value 過(guò)大。包括:

  • 單個(gè) value 過(guò)大。如 200M 大小的 String。

  • 集合元素過(guò)多。如 List、Hash、Set、ZSet 中有幾百、上千萬(wàn)數(shù)據(jù)。

舉個(gè)例子,假設(shè)我們有一個(gè) 200M 大小的 String key,名稱為「foo」。

執(zhí)行如下命令

127.0.0.1:6379> GET foo

當(dāng)返回結(jié)果時(shí),Redis 會(huì)分配 200m 的內(nèi)存,并執(zhí)行 memcpy 拷貝。

void _addReplyProtoToList(client *c, const char *s, size_t len) {
    ...
    if (len) {
        /* Create a new node, make sure it is allocated to at
         * least PROTO_REPLY_CHUNK_BYTES */
        size_t size = len < PROTO_REPLY_CHUNK_BYTES? PROTO_REPLY_CHUNK_BYTES: len;
        // 分配內(nèi)存(例子中為 200m)
        tail = zmalloc(size + sizeof(clientReplyBlock));
        /* take over the allocation's internal fragmentation */
        tail->size = zmalloc_usable_size(tail) - sizeof(clientReplyBlock);
        tail->used = len;
        // 內(nèi)存拷貝
        memcpy(tail->buf, s, len);
        listAddNodeTail(c->reply, tail);
        c->reply_bytes += tail->size;

        closeClientOnOutputBufferLimitReached(c, 1);
    }}

而 Redis 輸出 buf 為 16k

// server.h#define PROTO_REPLY_CHUNK_BYTES (16*1024) /* 16k output buffer */typedef struct client {
    ...
    char buf[PROTO_REPLY_CHUNK_BYTES];} client;

這意味著 Redis 無(wú)法單次返回響應(yīng)數(shù)據(jù),需要注冊(cè)「可寫事件」,從而觸發(fā)多次 write 系統(tǒng)調(diào)用。

這里有兩個(gè)耗時(shí)點(diǎn):

  • 分配大內(nèi)存(也可能釋放內(nèi)存,如 DEL 命令)

  • 觸發(fā)多次可寫事件(頻繁執(zhí)行系統(tǒng)調(diào)用,如 write、epoll_wait)

那么,如何找出 big key 呢?

如果 slow log 出現(xiàn)了簡(jiǎn)單命令,如 GET、SET、DEL,大概率是出現(xiàn)了 big key。

127.0.0.1:6379> SLOWLOG GET
    3) (integer) 201323  // 單位微妙
    4) 1) "GET"
       2) "foo"

其次,可以通過(guò) Redis 分析工具來(lái)查找 big key。

$ redis-cli --bigkeys -i 0.1
...
[00.00%] Biggest string found so far '"foo"' with 209715200 bytes

-------- summary -------

Sampled 1 keys in the keyspace!
Total key length in bytes is 3 (avg len 3.00)

Biggest string found '"foo"' has 209715200 bytes

1 strings with 209715200 bytes (100.00% of keys, avg size 209715200.00)
0 lists with 0 items (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
0 streams with 0 entries (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)

對(duì)于 big key,有以下幾點(diǎn)建議:

1.業(yè)務(wù)中盡量避免 big key 出現(xiàn)。當(dāng)出現(xiàn) big key 時(shí),你要判斷這樣設(shè)計(jì)是否合理,又或者是出現(xiàn)了 bug。

2.將 big key 拆分為多個(gè)小 key。

3.使用替代命令。

  • 如果 Redis 版本大于 4.0,可使用 UNLINK 命令替代 DEL。Redis 版本大于 6.0,可開啟 lazy-free 機(jī)制。將釋放內(nèi)存操作,放到后臺(tái)線程執(zhí)行。

  • LRANGE、HGETALL 等替換為 LSCAN、HSCAN 分次獲取。

但我還是建議在業(yè)務(wù)中避免 big key。


04 避免執(zhí)行時(shí)間復(fù)雜度高的命令

我們知道 Redis 是「單線程」執(zhí)行命令的。執(zhí)行時(shí)間復(fù)雜度高的命令,很可能會(huì)阻塞其它請(qǐng)求。

復(fù)雜度高的命令和元素?cái)?shù)量有關(guān)。通常有以下兩種場(chǎng)景。

  1. 元素太多,消耗 IO 資源。如 HGETALL、LRANGE,時(shí)間復(fù)雜度為 O(N)。

  2. 計(jì)算過(guò)于復(fù)雜,消費(fèi) CPU 資源。如 ZUNIONSTORE,時(shí)間復(fù)雜度為 O(N)+O(M log(M))

Redis 官方手冊(cè),標(biāo)記了命令執(zhí)行的時(shí)間復(fù)雜度。建議你在使用不熟悉的命令前,先查看手冊(cè),留意時(shí)間復(fù)雜度。

實(shí)際業(yè)務(wù)中,你應(yīng)該盡量避免時(shí)間復(fù)雜度高的命令。如果必須要用,有兩點(diǎn)建議

  1. 保證操作的元素?cái)?shù)量,盡可能少。

  2. 讀寫分離。復(fù)雜命令通常是讀請(qǐng)求,可以放到「slave」結(jié)點(diǎn)執(zhí)行。


05 使用惰性刪除 Lazy free

key 過(guò)期或是使用 DEL 刪除命令時(shí),Redis 除了從全局 hash 表移除對(duì)象外,還會(huì)將對(duì)象分配的內(nèi)存釋放。當(dāng)遇到 big key 時(shí),釋放內(nèi)存會(huì)造成主線程阻塞。

為此,Redis 4.0 引入了 UNLINK 命令,將釋放對(duì)象內(nèi)存操作放入 bio 后臺(tái)線程執(zhí)行。從而有效減少主線程阻塞。

Redis 6.0 更進(jìn)一步,引入了 Lazy-free 相關(guān)配置。當(dāng)開啟配置后,key 過(guò)期和 DEL 命令內(nèi)部,會(huì)將「釋放對(duì)象」操作「異步執(zhí)行」。

void delCommand(client *c) {
    delGenericCommand(c,server.lazyfree_lazy_user_del);}void delGenericCommand(client *c, int lazy) {
    int numdel = 0, j;

    for (j = 1; j < c->argc; j++) {
        expireIfNeeded(c->db,c->argv[j]);
        // 開啟 lazy free 則使用異步刪除
        int deleted = lazy ? dbAsyncDelete(c->db,c->argv[j]) :
                              dbSyncDelete(c->db,c->argv[j]);
        ...
    }}

建議至少升級(jí)到 Redis 6,并開啟 Lazy-free。


06 讀寫分離

Redis 通過(guò)副本,實(shí)現(xiàn)「主-從」運(yùn)行模式,是故障切換的基石,用來(lái)提高系統(tǒng)運(yùn)行可靠性。也支持讀寫分離,提高讀性能。

你可以部署一個(gè)主結(jié)點(diǎn),多個(gè)從結(jié)點(diǎn)。將讀命令分散到從結(jié)點(diǎn)中,從而減輕主結(jié)點(diǎn)壓力,提升性能。

提升Redis性能的小技巧有哪些


07 綁定 CPU

Redis 6.0 開始支持綁定 CPU,可以有效減少線程上下文切換。

CPU 親和性(CPU Affinity)是一種調(diào)度屬性,它將一個(gè)進(jìn)程或線程,「綁定」到一個(gè)或一組 CPU 上。也稱為 CPU 綁定。

設(shè)置 CPU 親和性可以一定程度避免 CPU 上下文切換,提高 CPU L1、L2 Cache 命中率。

早期「SMP」架構(gòu)下,每個(gè) CPU 通過(guò) BUS 總線共享資源。CPU 綁定意義不大。

提升Redis性能的小技巧有哪些
而在當(dāng)前主流的「NUMA」架構(gòu)下,每個(gè) CPU 有自己的本地內(nèi)存。訪問(wèn)本地內(nèi)存有更快的速度。而訪問(wèn)其他 CPU 內(nèi)存會(huì)導(dǎo)致較大的延遲。這時(shí),CPU 綁定對(duì)系統(tǒng)運(yùn)行速度的提升有較大的意義。

提升Redis性能的小技巧有哪些
現(xiàn)實(shí)中的 NUMA 架構(gòu)比上圖更復(fù)雜,通常會(huì)將 CPU 分組,若干個(gè) CPU 分配一組內(nèi)存,稱為 「node」。

你可以通過(guò) 「numactl -H 」命令來(lái)查看 NUMA 硬件信息。

$ numactl -H
available: 2 nodes (0-1)node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
node 0 size: 32143 MB
node 0 free: 26681 MB
node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39
node 1 size: 32309 MB
node 1 free: 24958 MB
node distances:
node 0 1
  0: 10 21
  1: 21 10

上圖中可以得知該機(jī)器有 40 個(gè) CPU,分組為 2 個(gè) node。

node distances 是一個(gè)二維矩陣,表示 node 之間 「訪問(wèn)距離」,10 為基準(zhǔn)值。上述命令中可以得知,node 自身訪問(wèn),距離是 10。跨 node 訪問(wèn),如 node 0 訪問(wèn) node 1 距離為 21。說(shuō)明該機(jī)器「跨 node 訪問(wèn)速度」比「node 自身訪問(wèn)速度」慢 2.1 倍。

其實(shí),早在 2015 年,有人提出 Redis 需要支持設(shè)置 CPU 親和性,而當(dāng)時(shí)的 Redis 還沒(méi)有支持 IO 多線程,該提議擱置。

而 Redis 6.0 引入 IO 多線程。同時(shí),也支持了設(shè)置 CPU 親和性

我畫了一張 Redis 6.0 線程家族供你參考。

提升Redis性能的小技巧有哪些

上圖可分為 3 個(gè)模塊

  • 主線程和 IO 線程:負(fù)責(zé)命令讀取、解析、結(jié)果返回。命令執(zhí)行由主線程完成。

  • bio 線程:負(fù)責(zé)執(zhí)行耗時(shí)的異步任務(wù),如 close fd。

  • 后臺(tái)進(jìn)程:fork 子進(jìn)程來(lái)執(zhí)行耗時(shí)的命令。

Redis 支持分別配置上述模塊的 CPU 親和度。你可以在 redis.conf 找到以下配置(該配置需手動(dòng)開啟)。

# IO 線程(包含主線程)綁定到 CPU 0、2、4、6
server_cpulist 0-7:2
# bio 線程綁定到 CPU 1、3
bio_cpulist 1,3
# aof rewrite 后臺(tái)進(jìn)程綁定到 CPU 8、9、10、11
aof_rewrite_cpulist 8-11
# bgsave 后臺(tái)進(jìn)程綁定到 CPU 1、10、11
bgsave_cpulist 1,10-11

我在上述機(jī)器,針對(duì) IO 線程和主線程,進(jìn)行如下測(cè)試:

首先,開啟 IO 線程配置

io-threads 4 # 主線程 + 3 個(gè) IO 線程io-threads-do-reads yes # IO 線程開啟讀和解析命令功能

測(cè)試如下三種場(chǎng)景:

  1. 不開啟 CPU 綁定配置。

  2. 綁定到不同 node。
    「server_cpulist 0,1,2,3」

  3. 綁定到相同 node。
    「server_cpulist 0,2,4,6」

通過(guò) redis-benchmark 對(duì) get 命令進(jìn)行基準(zhǔn)測(cè)試,每種場(chǎng)景執(zhí)行 3 次。

$ redis-benchmark -n 5000000 -c 50 -t get --threads 4

結(jié)果如下:

1.不開啟 CPU 綁定配置

throughput summary: 248818.11 requests per second
throughput summary: 248694.36 requests per second
throughput summary: 249004.00 requests per second

2.綁定不同 node

throughput summary: 248880.03 requests per second
throughput summary: 248447.20 requests per second
throughput summary: 248818.11 requests per second

3.綁定相同 node

throughput summary: 284414.09 requests per second
throughput summary: 284333.25 requests per second
throughput summary: 265252.00 requests per second

根據(jù)測(cè)試結(jié)果,綁定到同一個(gè) node,qps 大約提升 15%

使用綁定 CPU,你需要注意以下幾點(diǎn):

  1. Linux 下,你可以使用 「numactl --hardware」查看硬件布局,確保支持并開啟 NUMA。

  2. 線程要盡可能分布在 「不同的 CPU,相同的 node」,設(shè)置 CPU 親和度才有效。否則會(huì)造成頻繁上下文切換和遠(yuǎn)距離內(nèi)存訪問(wèn)。

  3. 你要熟悉 CPU 架構(gòu),做好充分的測(cè)試。否則可能適得其反,導(dǎo)致 Redis 性能下降。


08 合理配置持久化策略

Redis 支持兩種持久化策略,RDB 和 AOF。

RDB 通過(guò) fork 子進(jìn)程,生成數(shù)據(jù)快照,二進(jìn)制格式。

AOF 是增量日志,文本格式,通常較大。會(huì)通過(guò) AOF rewrite 重寫日志,節(jié)省空間。

除了手動(dòng)執(zhí)行「BGREWRITEAOF」命令外,以下 4 點(diǎn)也會(huì)觸發(fā) AOF 重寫

  1. 執(zhí)行「config set appendonly yes」命令

  2. AOF 文件大小比例超出閾值,「auto-aof-rewrite-percentage」

  3. AOF 文件大小絕對(duì)值超出閾值,「auto-aof-rewrite-min-size」

  4. 主從復(fù)制完成 RDB 加載

RDB 和 AOF,都是在主線程中觸發(fā)執(zhí)行。雖然具體執(zhí)行,會(huì)通過(guò) fork 交給后臺(tái)子進(jìn)程。但 fork 操作,會(huì)拷貝進(jìn)程數(shù)據(jù)結(jié)構(gòu)、頁(yè)表等,當(dāng)實(shí)例內(nèi)存較大時(shí),會(huì)影響性能。

AOF 支持以下三種策略。

  1. appendfsync no:由操作系統(tǒng)決定執(zhí)行 fsync 時(shí)機(jī)。對(duì) Linux 來(lái)說(shuō),通常每 30 秒執(zhí)行一次 fsync,將緩沖區(qū)中的數(shù)據(jù)刷到磁盤上。如果 Redis qps 過(guò)高或?qū)?big key,可能導(dǎo)致 buffer 寫滿,從而頻繁觸發(fā) fsync。

  2. appendfsync everysec:每秒執(zhí)行一次 fsync。

  3. appendfsync always:每次「寫」會(huì)調(diào)用一次 fsync,性能影響較大。

AOF 和 RDB 都會(huì)對(duì)磁盤 IO 造成較高的壓力。其中,AOF rewrite 會(huì)將 Redis hash 表所有數(shù)據(jù)進(jìn)行遍歷并寫磁盤。對(duì)性能會(huì)產(chǎn)生一定的影響。

線上業(yè)務(wù) Redis 通常是高可用的。如果對(duì)緩存數(shù)據(jù)丟失不敏感??紤]關(guān)閉 RDB 和 AOF 以提升性能。

如果無(wú)法關(guān)閉,有以下幾點(diǎn)建議:

  1. RDB 選擇業(yè)務(wù)低峰期做,通常為凌晨。保持單個(gè)實(shí)例內(nèi)存不超過(guò) 32 G。太大的內(nèi)存會(huì)導(dǎo)致 fork 耗時(shí)增加。

  2. AOF 選擇 appendfsync no或者 appendfsync everysec

  3. AOF auto-aof-rewrite-min-size 配置大一些,如 2G。避免頻繁觸發(fā) rewrite。

  4. AOF 可以僅在從節(jié)點(diǎn)開啟,減輕主節(jié)點(diǎn)壓力。

根據(jù)本地測(cè)試,不開啟 AOF,寫性能大約能提升 20% 左右。


09 使用長(zhǎng)連接

Redis 是基于 TCP 協(xié)議,請(qǐng)求-響應(yīng)式服務(wù)器。使用短連接會(huì)導(dǎo)致頻繁的創(chuàng)建連接。

短連接有以下幾個(gè)慢速操作:

  1. 創(chuàng)建連接時(shí),TCP 會(huì)執(zhí)行三次握手、慢啟動(dòng)等策略。

  2. Redis 會(huì)觸發(fā)新建/斷開連接事件,執(zhí)行分配/銷毀客戶端等耗時(shí)操作。

  3. 如果你使用的是 Redis Cluster,新建連接時(shí),客戶端會(huì)拉取 slots 信息初始化。建立連接速度更慢。

所以,相對(duì)于性能快速的 Redis,創(chuàng)建連接是十分慢速的操作。

「建議使用連接池,并合理設(shè)置連接池大小」。

但使用長(zhǎng)連接時(shí),需要留意一點(diǎn),要有「自動(dòng)重連」策略。避免因網(wǎng)絡(luò)異常,導(dǎo)致連接失效,影響正常業(yè)務(wù)。


10 關(guān)閉 SWAP

SWAP 是內(nèi)存交換技術(shù)。將內(nèi)存按頁(yè),復(fù)制到預(yù)先設(shè)定的磁盤空間上。

內(nèi)存是快速的,昂貴的。而磁盤是低速的,廉價(jià)的。

通常使用 SWAP 越多,系統(tǒng)性能越低。

Redis 是內(nèi)存數(shù)據(jù)庫(kù),使用 SWAP 會(huì)導(dǎo)致性能快速下降

建議留有足夠內(nèi)存,并關(guān)閉 SWAP

我繪制了思維導(dǎo)圖,方便大家記憶。

提升Redis性能的小技巧有哪些
可以看到,性能優(yōu)化并不容易,需要我們了解很多底層知識(shí),并做出充分測(cè)試。在不同機(jī)器、不同系統(tǒng)、不同配置下,Redis 都會(huì)有不同的性能表現(xiàn)。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“提升Redis性能的小技巧有哪些”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!


網(wǎng)站題目:提升Redis性能的小技巧有哪些
路徑分享:http://weahome.cn/article/ipjseo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部