當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]Redis 作為優(yōu)秀的內(nèi)存數(shù)據(jù)庫(kù),其擁有非常高的性能,單個(gè)實(shí)例的 OPS 能夠達(dá)到 10W 左右。


Redis 作為優(yōu)秀的內(nèi)存數(shù)據(jù)庫(kù),其擁有非常高的性能,單個(gè)實(shí)例的 OPS 能夠達(dá)到 10W 左右。但也正因此如此,當(dāng)我們?cè)谑褂?Redis 時(shí),如果發(fā)現(xiàn)操作延遲變大的情況,就會(huì)與我們的預(yù)期不符。

你也許或多或少地,也遇到過(guò)以下這些場(chǎng)景:

  • 在 Redis 上執(zhí)行同樣的命令,為什么有時(shí)響應(yīng)很快,有時(shí)卻很慢?
  • 為什么 Redis 執(zhí)行 SET、DEL 命令耗時(shí)也很久?
  • 為什么我的 Redis 突然慢了一波,之后又恢復(fù)正常了?
  • 為什么我的 Redis 穩(wěn)定運(yùn)行了很久,突然從某個(gè)時(shí)間點(diǎn)開(kāi)始變慢了?
  • ...

如果你并不清楚 Redis 內(nèi)部的實(shí)現(xiàn)原理,那么在排查這種延遲問(wèn)題時(shí)就會(huì)一頭霧水。

如果你也遇到了以上情況,那么,這篇文章將會(huì)給你一個(gè)「全面」的問(wèn)題排查思路,并且針對(duì)這些導(dǎo)致變慢的場(chǎng)景,我還會(huì)給你一個(gè)高效的解決方案。

在正文開(kāi)始之前,我需要提醒你的是,這篇文章很長(zhǎng),涵蓋的 Redis 知識(shí)點(diǎn)也非常廣,全篇文章接近 2W 字,如果此時(shí)你的閱讀環(huán)境不適合專(zhuān)注閱讀,我建議你先收藏此文章,然后在合適的時(shí)間專(zhuān)注閱讀這篇文章。

如果你能耐心且認(rèn)真地讀完這篇文章,我可以保證,你對(duì) Redis 的性能調(diào)優(yōu)將會(huì)有非常大的收獲。

如果你準(zhǔn)備好了,那就跟著我的思路開(kāi)始吧!

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

Redis真的變慢了嗎?

首先,在開(kāi)始之前,你需要弄清楚 Redis 是否真的變慢了?

如果你發(fā)現(xiàn)你的業(yè)務(wù)服務(wù) API 響應(yīng)延遲變長(zhǎng),首先你需要先排查服務(wù)內(nèi)部,究竟是哪個(gè)環(huán)節(jié)拖慢了整個(gè)服務(wù)。

比較高效的做法是,在服務(wù)內(nèi)部集成鏈路追蹤,也就是在服務(wù)訪問(wèn)外部依賴(lài)的出入口,記錄下每次請(qǐng)求外部依賴(lài)的響應(yīng)延時(shí)。

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

如果你發(fā)現(xiàn)確實(shí)是操作 Redis 的這條鏈路耗時(shí)變長(zhǎng)了,那么此刻你需要把焦點(diǎn)關(guān)注在業(yè)務(wù)服務(wù)到 Redis 這條鏈路上。

從你的業(yè)務(wù)服務(wù)到 Redis 這條鏈路變慢的原因可能也有 2 個(gè):

  1. 業(yè)務(wù)服務(wù)器到 Redis 服務(wù)器之間的網(wǎng)絡(luò)存在問(wèn)題,例如網(wǎng)絡(luò)線(xiàn)路質(zhì)量不佳,網(wǎng)絡(luò)數(shù)據(jù)包在傳輸時(shí)存在延遲、丟包等情況
  2. Redis 本身存在問(wèn)題,需要進(jìn)一步排查是什么原因?qū)е?Redis 變慢

通常來(lái)說(shuō),第一種情況發(fā)生的概率比較小,如果是服務(wù)器之間網(wǎng)絡(luò)存在問(wèn)題,那部署在這臺(tái)業(yè)務(wù)服務(wù)器上的所有服務(wù)都會(huì)發(fā)生網(wǎng)絡(luò)延遲的情況,此時(shí)你需要聯(lián)系網(wǎng)絡(luò)運(yùn)維同事,讓其協(xié)助解決網(wǎng)絡(luò)問(wèn)題。

我們這篇文章,重點(diǎn)關(guān)注的是第二種情況。

也就是從 Redis 角度來(lái)排查,是否存在導(dǎo)致變慢的場(chǎng)景,以及都有哪些因素會(huì)導(dǎo)致 Redis 的延遲增加,然后針對(duì)性地進(jìn)行優(yōu)化。

排除網(wǎng)絡(luò)原因,如何確認(rèn)你的 Redis 是否真的變慢了?

首先,你需要對(duì) Redis 進(jìn)行基準(zhǔn)性能測(cè)試,了解你的 Redis 在生產(chǎn)環(huán)境服務(wù)器上的基準(zhǔn)性能。

什么是基準(zhǔn)性能?

簡(jiǎn)單來(lái)講,基準(zhǔn)性能就是指 Redis 在一臺(tái)負(fù)載正常的機(jī)器上,其最大的響應(yīng)延遲和平均響應(yīng)延遲分別是怎樣的?

為什么要測(cè)試基準(zhǔn)性能?我參考別人提供的響應(yīng)延遲,判斷自己的 Redis 是否變慢不行嗎?

答案是否定的。

因?yàn)?Redis 在不同的軟硬件環(huán)境下,它的性能是各不相同的。

例如,我的機(jī)器配置比較低,當(dāng)延遲為 2ms 時(shí),我就認(rèn)為 Redis 變慢了,但是如果你的硬件配置比較高,那么在你的運(yùn)行環(huán)境下,可能延遲是 0.5ms 時(shí)就可以認(rèn)為 Redis 變慢了。

所以,你只有了解了你的 Redis 在生產(chǎn)環(huán)境服務(wù)器上的基準(zhǔn)性能,才能進(jìn)一步評(píng)估,當(dāng)其延遲達(dá)到什么程度時(shí),才認(rèn)為 Redis 確實(shí)變慢了。

具體如何做?

為了避免業(yè)務(wù)服務(wù)器到 Redis 服務(wù)器之間的網(wǎng)絡(luò)延遲,你需要直接在 Redis 服務(wù)器上測(cè)試實(shí)例的響應(yīng)延遲情況。執(zhí)行以下命令,就可以測(cè)試出這個(gè)實(shí)例 60 秒內(nèi)的最大響應(yīng)延遲:

$ redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency 60 Max latency so far: 1 microseconds.
Max latency so far: 15 microseconds.
Max latency so far: 17 microseconds.
Max latency so far: 18 microseconds.
Max latency so far: 31 microseconds.
Max latency so far: 32 microseconds.
Max latency so far: 59 microseconds.
Max latency so far: 72 microseconds.

1428669267 total runs (avg latency: 0.0420 microseconds / 42.00 nanoseconds per run).
Worst run took 1429x longer than the average latency.

從輸出結(jié)果可以看到,這 60 秒內(nèi)的最大響應(yīng)延遲為 72 微秒(0.072毫秒)。

你還可以使用以下命令,查看一段時(shí)間內(nèi) Redis 的最小、最大、平均訪問(wèn)延遲:

$ redis-cli -h 127.0.0.1 -p 6379 --latency-history -i 1 min: 0, max: 1, avg: 0.13 (100 samples) -- 1.01 seconds range
min: 0, max: 1, avg: 0.12 (99 samples) -- 1.01 seconds range
min: 0, max: 1, avg: 0.13 (99 samples) -- 1.01 seconds range
min: 0, max: 1, avg: 0.10 (99 samples) -- 1.01 seconds range
min: 0, max: 1, avg: 0.13 (98 samples) -- 1.00 seconds range
min: 0, max: 1, avg: 0.08 (99 samples) -- 1.01 seconds range
...

以上輸出結(jié)果是,每間隔 1 秒,采樣 Redis 的平均操作耗時(shí),其結(jié)果分布在 0.08 ~ 0.13 毫秒之間。

了解了基準(zhǔn)性能測(cè)試方法,那么你就可以按照以下幾步,來(lái)判斷你的 Redis 是否真的變慢了:

  1. 在相同配置的服務(wù)器上,測(cè)試一個(gè)正常 Redis 實(shí)例的基準(zhǔn)性能
  2. 找到你認(rèn)為可能變慢的 Redis 實(shí)例,測(cè)試這個(gè)實(shí)例的基準(zhǔn)性能
  3. 如果你觀察到,這個(gè)實(shí)例的運(yùn)行延遲是正常 Redis 基準(zhǔn)性能的 2 倍以上,即可認(rèn)為這個(gè) Redis 實(shí)例確實(shí)變慢了

確認(rèn)是 Redis 變慢了,那如何排查是哪里發(fā)生了問(wèn)題呢?

下面跟著我的思路,我們從易到難,一步步來(lái)分析可能導(dǎo)致 Redis 變慢的因素。

使用復(fù)雜度過(guò)高的命令

首先,第一步,你需要去查看一下 Redis 的慢日志(slowlog)。

Redis 提供了慢日志命令的統(tǒng)計(jì)功能,它記錄了有哪些命令在執(zhí)行時(shí)耗時(shí)比較久。

查看 Redis 慢日志之前,你需要設(shè)置慢日志的閾值。例如,設(shè)置慢日志的閾值為 5 毫秒,并且保留最近 500 條慢日志記錄:

# 命令執(zhí)行耗時(shí)超過(guò) 5 毫秒,記錄慢日志 CONFIG SET slowlog-log-slower-than 5000 # 只保留最近 500 條慢日志 CONFIG SET slowlog-max-len 500

設(shè)置完成之后,所有執(zhí)行的命令如果操作耗時(shí)超過(guò)了 5 毫秒,都會(huì)被 Redis 記錄下來(lái)。

此時(shí),你可以執(zhí)行以下命令,就可以查詢(xún)到最近記錄的慢日志:

127.0.0.1:6379> SLOWLOG get 5
1) 1) (integer) 32693 # 慢日志ID 2) (integer) 1593763337 # 執(zhí)行時(shí)間戳 3) (integer) 5299 # 執(zhí)行耗時(shí)(微秒) 4) 1) "LRANGE" # 具體執(zhí)行的命令和參數(shù) 2) "user_list:2000" 3) "0" 4) "-1" 2) 1) (integer) 32692
   2) (integer) 1593763337
   3) (integer) 5044
   4) 1) "GET" 2) "user_info:1000" ...

通過(guò)查看慢日志,我們就可以知道在什么時(shí)間點(diǎn),執(zhí)行了哪些命令比較耗時(shí)。

如果你的應(yīng)用程序執(zhí)行的 Redis 命令有以下特點(diǎn),那么有可能會(huì)導(dǎo)致操作延遲變大:

  1. 經(jīng)常使用 O(N) 以上復(fù)雜度的命令,例如 SORT、SUNION、ZUNIONSTORE 聚合類(lèi)命令
  2. 使用 O(N) 復(fù)雜度的命令,但 N 的值非常大

第一種情況導(dǎo)致變慢的原因在于,Redis 在操作內(nèi)存數(shù)據(jù)時(shí),時(shí)間復(fù)雜度過(guò)高,要花費(fèi)更多的 CPU 資源。

第二種情況導(dǎo)致變慢的原因在于,Redis 一次需要返回給客戶(hù)端的數(shù)據(jù)過(guò)多,更多時(shí)間花費(fèi)在數(shù)據(jù)協(xié)議的組裝和網(wǎng)絡(luò)傳輸過(guò)程中。

另外,我們還可以從資源使用率層面來(lái)分析,如果你的應(yīng)用程序操作 Redis 的 OPS 不是很大,但 Redis 實(shí)例的 CPU 使用率卻很高,那么很有可能是使用了復(fù)雜度過(guò)高的命令導(dǎo)致的。

除此之外,我們都知道,Redis 是單線(xiàn)程處理客戶(hù)端請(qǐng)求的,如果你經(jīng)常使用以上命令,那么當(dāng) Redis 處理客戶(hù)端請(qǐng)求時(shí),一旦前面某個(gè)命令發(fā)生耗時(shí),就會(huì)導(dǎo)致后面的請(qǐng)求發(fā)生排隊(duì),對(duì)于客戶(hù)端來(lái)說(shuō),響應(yīng)延遲也會(huì)變長(zhǎng)。

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

針對(duì)這種情況如何解決呢?

答案很簡(jiǎn)單,你可以使用以下方法優(yōu)化你的業(yè)務(wù):

  1. 盡量不使用 O(N) 以上復(fù)雜度過(guò)高的命令,對(duì)于數(shù)據(jù)的聚合操作,放在客戶(hù)端做
  2. 執(zhí)行 O(N) 命令,保證 N 盡量的?。ㄍ扑] N <= 300),每次獲取盡量少的數(shù)據(jù),讓 Redis 可以及時(shí)處理返回

操作bigkey

如果你查詢(xún)慢日志發(fā)現(xiàn),并不是復(fù)雜度過(guò)高的命令導(dǎo)致的,而都是 SET / DEL 這種簡(jiǎn)單命令出現(xiàn)在慢日志中,那么你就要懷疑你的實(shí)例否寫(xiě)入了 bigkey。

Redis 在寫(xiě)入數(shù)據(jù)時(shí),需要為新的數(shù)據(jù)分配內(nèi)存,相對(duì)應(yīng)的,當(dāng)從 Redis 中刪除數(shù)據(jù)時(shí),它會(huì)釋放對(duì)應(yīng)的內(nèi)存空間。

如果一個(gè) key 寫(xiě)入的 value 非常大,那么 Redis 在分配內(nèi)存時(shí)就會(huì)比較耗時(shí)。同樣的,當(dāng)刪除這個(gè) key 時(shí),釋放內(nèi)存也會(huì)比較耗時(shí),這種類(lèi)型的 key 我們一般稱(chēng)之為 bigkey。

此時(shí),你需要檢查你的業(yè)務(wù)代碼,是否存在寫(xiě)入 bigkey 的情況。你需要評(píng)估寫(xiě)入一個(gè) key 的數(shù)據(jù)大小,盡量避免一個(gè) key 存入過(guò)大的數(shù)據(jù)。

如果已經(jīng)寫(xiě)入了 bigkey,那有沒(méi)有什么辦法可以?huà)呙璩鰧?shí)例中 bigkey 的分布情況呢?

答案是可以的。

Redis 提供了掃描 bigkey 的命令,執(zhí)行以下命令就可以?huà)呙璩?,一個(gè)實(shí)例中 bigkey 的分布情況,輸出結(jié)果是以類(lèi)型維度展示的:

$ redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01

...
-------- summary -------

Sampled 829675 keys in the keyspace!
Total key length in bytes is 10059825 (avg len 12.13)

Biggest string found 'key:291880' has 10 bytes
Biggest   list found 'mylist:004' has 40 items
Biggest set found 'myset:2386' has 38 members
Biggest hash found 'myhash:3574' has 37 fields
Biggest   zset found 'myzset:2704' has 42 members

36313 strings with 363130 bytes (04.38% of keys, avg size 10.00)
787393 lists with 896540 items (94.90% of keys, avg size 1.14)
1994 sets with 40052 members (00.24% of keys, avg size 20.09)
1990 hashs with 39632 fields (00.24% of keys, avg size 19.92)
1985 zsets with 39750 members (00.24% of keys, avg size 20.03)

從輸出結(jié)果我們可以很清晰地看到,每種數(shù)據(jù)類(lèi)型所占用的最大內(nèi)存 / 擁有最多元素的 key 是哪一個(gè),以及每種數(shù)據(jù)類(lèi)型在整個(gè)實(shí)例中的占比和平均大小 / 元素?cái)?shù)量。

其實(shí),使用這個(gè)命令的原理,就是 Redis 在內(nèi)部執(zhí)行了 SCAN 命令,遍歷整個(gè)實(shí)例中所有的 key,然后針對(duì) key 的類(lèi)型,分別執(zhí)行 STRLEN、LLEN、HLEN、SCARD、ZCARD 命令,來(lái)獲取 String 類(lèi)型的長(zhǎng)度、容器類(lèi)型(List、Hash、Set、ZSet)的元素個(gè)數(shù)。

這里我需要提醒你的是,當(dāng)執(zhí)行這個(gè)命令時(shí),要注意 2 個(gè)問(wèn)題:

  1. 對(duì)線(xiàn)上實(shí)例進(jìn)行 bigkey 掃描時(shí),Redis 的 OPS 會(huì)突增,為了降低掃描過(guò)程中對(duì) Redis 的影響,最好控制一下掃描的頻率,指定 -i 參數(shù)即可,它表示掃描過(guò)程中每次掃描后休息的時(shí)間間隔,單位是秒
  2. 掃描結(jié)果中,對(duì)于容器類(lèi)型(List、Hash、Set、ZSet)的 key,只能掃描出元素最多的 key。但一個(gè) key 的元素多,不一定表示占用內(nèi)存也多,你還需要根據(jù)業(yè)務(wù)情況,進(jìn)一步評(píng)估內(nèi)存占用情況

那針對(duì) bigkey 導(dǎo)致延遲的問(wèn)題,有什么好的解決方案呢?

這里有兩點(diǎn)可以?xún)?yōu)化:

  1. 業(yè)務(wù)應(yīng)用盡量避免寫(xiě)入 bigkey
  2. 如果你使用的 Redis 是 4.0 以上版本,用 UNLINK 命令替代 DEL,此命令可以把釋放 key 內(nèi)存的操作,放到后臺(tái)線(xiàn)程中去執(zhí)行,從而降低對(duì) Redis 的影響
  3. 如果你使用的 Redis 是 6.0 以上版本,可以開(kāi)啟 lazy-free 機(jī)制(lazyfree-lazy-user-del = yes),在執(zhí)行 DEL 命令時(shí),釋放內(nèi)存也會(huì)放到后臺(tái)線(xiàn)程中執(zhí)行

但即便可以使用方案 2,我也不建議你在實(shí)例中存入 bigkey。

這是因?yàn)?bigkey 在很多場(chǎng)景下,依舊會(huì)產(chǎn)生性能問(wèn)題。例如,bigkey 在分片集群模式下,對(duì)于數(shù)據(jù)的遷移也會(huì)有性能影響,以及我后面即將講到的數(shù)據(jù)過(guò)期、數(shù)據(jù)淘汰、透明大頁(yè),都會(huì)受到 bigkey 的影響。

集中過(guò)期

如果你發(fā)現(xiàn),平時(shí)在操作 Redis 時(shí),并沒(méi)有延遲很大的情況發(fā)生,但在某個(gè)時(shí)間點(diǎn)突然出現(xiàn)一波延時(shí),其現(xiàn)象表現(xiàn)為:變慢的時(shí)間點(diǎn)很有規(guī)律,例如某個(gè)整點(diǎn),或者每間隔多久就會(huì)發(fā)生一波延遲。

如果是出現(xiàn)這種情況,那么你需要排查一下,業(yè)務(wù)代碼中是否存在設(shè)置大量 key 集中過(guò)期的情況。

如果有大量的 key 在某個(gè)固定時(shí)間點(diǎn)集中過(guò)期,在這個(gè)時(shí)間點(diǎn)訪問(wèn) Redis 時(shí),就有可能導(dǎo)致延時(shí)變大。

為什么集中過(guò)期會(huì)導(dǎo)致 Redis 延遲變大?

這就需要我們了解 Redis 的過(guò)期策略是怎樣的。

Redis 的過(guò)期數(shù)據(jù)采用被動(dòng)過(guò)期 + 主動(dòng)過(guò)期兩種策略:

  1. 被動(dòng)過(guò)期:只有當(dāng)訪問(wèn)某個(gè) key 時(shí),才判斷這個(gè) key 是否已過(guò)期,如果已過(guò)期,則從實(shí)例中刪除
  2. 主動(dòng)過(guò)期:Redis 內(nèi)部維護(hù)了一個(gè)定時(shí)任務(wù),默認(rèn)每隔 100 毫秒(1秒10次)就會(huì)從全局的過(guò)期哈希表中隨機(jī)取出 20 個(gè) key,然后刪除其中過(guò)期的 key,如果過(guò)期 key 的比例超過(guò)了 25%,則繼續(xù)重復(fù)此過(guò)程,直到過(guò)期 key 的比例下降到 25% 以下,或者這次任務(wù)的執(zhí)行耗時(shí)超過(guò)了 25 毫秒,才會(huì)退出循環(huán)

注意,這個(gè)主動(dòng)過(guò)期 key 的定時(shí)任務(wù),是在 Redis 主線(xiàn)程中執(zhí)行的。

也就是說(shuō)如果在執(zhí)行主動(dòng)過(guò)期的過(guò)程中,出現(xiàn)了需要大量刪除過(guò)期 key 的情況,那么此時(shí)應(yīng)用程序在訪問(wèn) Redis 時(shí),必須要等待這個(gè)過(guò)期任務(wù)執(zhí)行結(jié)束,Redis 才可以服務(wù)這個(gè)客戶(hù)端請(qǐng)求。

此時(shí)就會(huì)出現(xiàn),應(yīng)用訪問(wèn) Redis 延時(shí)變大。

如果此時(shí)需要過(guò)期刪除的是一個(gè) bigkey,那么這個(gè)耗時(shí)會(huì)更久。而且,這個(gè)操作延遲的命令并不會(huì)記錄在慢日志中。

因?yàn)槁罩局?/span>只記錄一個(gè)命令真正操作內(nèi)存數(shù)據(jù)的耗時(shí),而 Redis 主動(dòng)刪除過(guò)期 key 的邏輯,是在命令真正執(zhí)行之前執(zhí)行的。

所以,此時(shí)你會(huì)看到,慢日志中沒(méi)有操作耗時(shí)的命令,但我們的應(yīng)用程序卻感知到了延遲變大,其實(shí)時(shí)間都花費(fèi)在了刪除過(guò)期 key 上,這種情況我們需要尤為注意。

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

那遇到這種情況,如何分析和排查?

此時(shí),你需要檢查你的業(yè)務(wù)代碼,是否存在集中過(guò)期 key 的邏輯。

一般集中過(guò)期使用的是 expireat / pexpireat 命令,你需要在代碼中搜索這個(gè)關(guān)鍵字。

排查代碼后,如果確實(shí)存在集中過(guò)期 key 的邏輯存在,但這種邏輯又是業(yè)務(wù)所必須的,那此時(shí)如何優(yōu)化,同時(shí)又不對(duì) Redis 有性能影響呢?

一般有兩種方案來(lái)規(guī)避這個(gè)問(wèn)題:

  1. 集中過(guò)期 key 增加一個(gè)隨機(jī)過(guò)期時(shí)間,把集中過(guò)期的時(shí)間打散,降低 Redis 清理過(guò)期 key 的壓力
  2. 如果你使用的 Redis 是 4.0 以上版本,可以開(kāi)啟 lazy-free 機(jī)制,當(dāng)刪除過(guò)期 key 時(shí),把釋放內(nèi)存的操作放到后臺(tái)線(xiàn)程中執(zhí)行,避免阻塞主線(xiàn)程

第一種方案,在設(shè)置 key 的過(guò)期時(shí)間時(shí),增加一個(gè)隨機(jī)時(shí)間,偽代碼可以這么寫(xiě):

# 在過(guò)期時(shí)間點(diǎn)之后的 5 分鐘內(nèi)隨機(jī)過(guò)期掉 redis.expireat(key, expire_time + random(300))

這樣一來(lái),Redis 在處理過(guò)期時(shí),不會(huì)因?yàn)榧袆h除過(guò)多的 key 導(dǎo)致壓力過(guò)大,從而避免阻塞主線(xiàn)程。

第二種方案,Redis 4.0 以上版本,開(kāi)啟 lazy-free 機(jī)制:

# 釋放過(guò)期 key 的內(nèi)存,放到后臺(tái)線(xiàn)程執(zhí)行 lazyfree-lazy-expire yes

另外,除了業(yè)務(wù)層面的優(yōu)化和修改配置之外,你還可以通過(guò)運(yùn)維手段及時(shí)發(fā)現(xiàn)這種情況。

運(yùn)維層面,你需要把 Redis 的各項(xiàng)運(yùn)行狀態(tài)數(shù)據(jù)監(jiān)控起來(lái),在 Redis 上執(zhí)行 INFO 命令就可以拿到這個(gè)實(shí)例所有的運(yùn)行狀態(tài)數(shù)據(jù)。

在這里我們需要重點(diǎn)關(guān)注 expired_keys 這一項(xiàng),它代表整個(gè)實(shí)例到目前為止,累計(jì)刪除過(guò)期 key 的數(shù)量。

你需要把這個(gè)指標(biāo)監(jiān)控起來(lái),當(dāng)這個(gè)指標(biāo)在很短時(shí)間內(nèi)出現(xiàn)了突增,需要及時(shí)報(bào)警出來(lái),然后與業(yè)務(wù)應(yīng)用報(bào)慢的時(shí)間點(diǎn)進(jìn)行對(duì)比分析,確認(rèn)時(shí)間是否一致,如果一致,則可以確認(rèn)確實(shí)是因?yàn)榧羞^(guò)期 key 導(dǎo)致的延遲變大。

實(shí)例內(nèi)存達(dá)到上限

如果你的 Redis 實(shí)例設(shè)置了內(nèi)存上限 maxmemory,那么也有可能導(dǎo)致 Redis 變慢。

當(dāng)我們把 Redis 當(dāng)做純緩存使用時(shí),通常會(huì)給這個(gè)實(shí)例設(shè)置一個(gè)內(nèi)存上限 maxmemory,然后設(shè)置一個(gè)數(shù)據(jù)淘汰策略。

而當(dāng)實(shí)例的內(nèi)存達(dá)到了 maxmemory 后,你可能會(huì)發(fā)現(xiàn),在此之后每次寫(xiě)入新數(shù)據(jù),操作延遲變大了。

這是為什么?

原因在于,當(dāng) Redis 內(nèi)存達(dá)到 maxmemory 后,每次寫(xiě)入新的數(shù)據(jù)之前,Redis 必須先從實(shí)例中踢出一部分?jǐn)?shù)據(jù),讓整個(gè)實(shí)例的內(nèi)存維持在 maxmemory 之下,然后才能把新數(shù)據(jù)寫(xiě)進(jìn)來(lái)。

這個(gè)踢出舊數(shù)據(jù)的邏輯也是需要消耗時(shí)間的,而具體耗時(shí)的長(zhǎng)短,要取決于你配置的淘汰策略:

  • allkeys-lru:不管 key 是否設(shè)置了過(guò)期,淘汰最近最少訪問(wèn)的 key
  • volatile-lru:只淘汰最近最少訪問(wèn)、并設(shè)置了過(guò)期時(shí)間的 key
  • allkeys-random:不管 key 是否設(shè)置了過(guò)期,隨機(jī)淘汰 key
  • volatile-random:只隨機(jī)淘汰設(shè)置了過(guò)期時(shí)間的 key
  • allkeys-ttl:不管 key 是否設(shè)置了過(guò)期,淘汰即將過(guò)期的 key
  • noeviction:不淘汰任何 key,實(shí)例內(nèi)存達(dá)到 maxmeory 后,再寫(xiě)入新數(shù)據(jù)直接返回錯(cuò)誤
  • allkeys-lfu:不管 key 是否設(shè)置了過(guò)期,淘汰訪問(wèn)頻率最低的 key(4.0+版本支持)
  • volatile-lfu:只淘汰訪問(wèn)頻率最低、并設(shè)置了過(guò)期時(shí)間 key(4.0+版本支持)

具體使用哪種策略,我們需要根據(jù)具體的業(yè)務(wù)場(chǎng)景來(lái)配置。

一般最常使用的是 allkeys-lru / volatile-lru 淘汰策略,它們的處理邏輯是,每次從實(shí)例中隨機(jī)取出一批 key(這個(gè)數(shù)量可配置),然后淘汰一個(gè)最少訪問(wèn)的 key,之后把剩下的 key 暫存到一個(gè)池子中,繼續(xù)隨機(jī)取一批 key,并與之前池子中的 key 比較,再淘汰一個(gè)最少訪問(wèn)的 key。以此往復(fù),直到實(shí)例內(nèi)存降到 maxmemory 之下。

需要注意的是,Redis 的淘汰數(shù)據(jù)的邏輯與刪除過(guò)期 key 的一樣,也是在命令真正執(zhí)行之前執(zhí)行的,也就是說(shuō)它也會(huì)增加我們操作 Redis 的延遲,而且,寫(xiě) OPS 越高,延遲也會(huì)越明顯。

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

另外,如果此時(shí)你的 Redis 實(shí)例中還存儲(chǔ)了 bigkey,那么在淘汰刪除 bigkey 釋放內(nèi)存時(shí),也會(huì)耗時(shí)比較久

看到了么?bigkey 的危害到處都是,這也是前面我提醒你盡量不存儲(chǔ) bigkey 的原因。

針對(duì)這種情況,如何解決呢?

我給你 4 個(gè)方面的優(yōu)化建議:

  1. 避免存儲(chǔ) bigkey,降低釋放內(nèi)存的耗時(shí)
  2. 淘汰策略改為隨機(jī)淘汰,隨機(jī)淘汰比 LRU 要快很多(視業(yè)務(wù)情況調(diào)整)
  3. 拆分實(shí)例,把淘汰 key 的壓力分?jǐn)偟蕉鄠€(gè)實(shí)例上
  4. 如果使用的是 Redis 4.0 以上版本,開(kāi)啟 layz-free 機(jī)制,把淘汰 key 釋放內(nèi)存的操作放到后臺(tái)線(xiàn)程中執(zhí)行(配置 lazyfree-lazy-eviction = yes)

fork耗時(shí)嚴(yán)重

為了保證 Redis 數(shù)據(jù)的安全性,我們可能會(huì)開(kāi)啟后臺(tái)定時(shí) RDB 和 AOF rewrite 功能。

但如果你發(fā)現(xiàn),操作 Redis 延遲變大,都發(fā)生在 Redis 后臺(tái) RDB 和 AOF rewrite 期間,那你就需要排查,在這期間有可能導(dǎo)致變慢的情況。

當(dāng) Redis 開(kāi)啟了后臺(tái) RDB 和 AOF rewrite 后,在執(zhí)行時(shí),它們都需要主進(jìn)程創(chuàng)建出一個(gè)子進(jìn)程進(jìn)行數(shù)據(jù)的持久化。

主進(jìn)程創(chuàng)建子進(jìn)程,會(huì)調(diào)用操作系統(tǒng)提供的 fork 函數(shù)。

而 fork 在執(zhí)行過(guò)程中,主進(jìn)程需要拷貝自己的內(nèi)存頁(yè)表給子進(jìn)程,如果這個(gè)實(shí)例很大,那么這個(gè)拷貝的過(guò)程也會(huì)比較耗時(shí)。

而且這個(gè) fork 過(guò)程會(huì)消耗大量的 CPU 資源,在完成 fork 之前,整個(gè) Redis 實(shí)例會(huì)被阻塞住,無(wú)法處理任何客戶(hù)端請(qǐng)求。

如果此時(shí)你的 CPU 資源本來(lái)就很緊張,那么 fork 的耗時(shí)會(huì)更長(zhǎng),甚至達(dá)到秒級(jí),這會(huì)嚴(yán)重影響 Redis 的性能。

那如何確認(rèn)確實(shí)是因?yàn)?fork 耗時(shí)導(dǎo)致的 Redis 延遲變大呢?

你可以在 Redis 上執(zhí)行 INFO 命令,查看 latest_fork_usec 項(xiàng),單位微秒。

# 上一次 fork 耗時(shí),單位微秒 latest_fork_usec:59477

這個(gè)時(shí)間就是主進(jìn)程在 fork 子進(jìn)程期間,整個(gè)實(shí)例阻塞無(wú)法處理客戶(hù)端請(qǐng)求的時(shí)間。

如果你發(fā)現(xiàn)這個(gè)耗時(shí)很久,就要警惕起來(lái)了,這意味在這期間,你的整個(gè) Redis 實(shí)例都處于不可用的狀態(tài)。

除了數(shù)據(jù)持久化會(huì)生成 RDB 之外,當(dāng)主從節(jié)點(diǎn)第一次建立數(shù)據(jù)同步時(shí),主節(jié)點(diǎn)也創(chuàng)建子進(jìn)程生成 RDB,然后發(fā)給從節(jié)點(diǎn)進(jìn)行一次全量同步,所以,這個(gè)過(guò)程也會(huì)對(duì) Redis 產(chǎn)生性能影響。

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

要想避免這種情況,你可以采取以下方案進(jìn)行優(yōu)化:

  1. 控制 Redis 實(shí)例的內(nèi)存:盡量在 10G 以下,執(zhí)行 fork 的耗時(shí)與實(shí)例大小有關(guān),實(shí)例越大,耗時(shí)越久
  2. 合理配置數(shù)據(jù)持久化策略:在 slave 節(jié)點(diǎn)執(zhí)行 RDB 備份,推薦在低峰期執(zhí)行,而對(duì)于丟失數(shù)據(jù)不敏感的業(yè)務(wù)(例如把 Redis 當(dāng)做純緩存使用),可以關(guān)閉 AOF 和 AOF rewrite
  3. Redis 實(shí)例不要部署在虛擬機(jī)上:fork 的耗時(shí)也與系統(tǒng)也有關(guān),虛擬機(jī)比物理機(jī)耗時(shí)更久
  4. 降低主從庫(kù)全量同步的概率:適當(dāng)調(diào)大 repl-backlog-size 參數(shù),避免主從全量同步

開(kāi)啟內(nèi)存大頁(yè)

除了上面講到的子進(jìn)程 RDB 和 AOF rewrite 期間,fork 耗時(shí)導(dǎo)致的延時(shí)變大之外,這里還有一個(gè)方面也會(huì)導(dǎo)致性能問(wèn)題,這就是操作系統(tǒng)是否開(kāi)啟了內(nèi)存大頁(yè)機(jī)制

什么是內(nèi)存大頁(yè)?

我們都知道,應(yīng)用程序向操作系統(tǒng)申請(qǐng)內(nèi)存時(shí),是按內(nèi)存頁(yè)進(jìn)行申請(qǐng)的,而常規(guī)的內(nèi)存頁(yè)大小是 4KB。

Linux 內(nèi)核從 2.6.38 開(kāi)始,支持了內(nèi)存大頁(yè)機(jī)制,該機(jī)制允許應(yīng)用程序以 2MB 大小為單位,向操作系統(tǒng)申請(qǐng)內(nèi)存。

應(yīng)用程序每次向操作系統(tǒng)申請(qǐng)的內(nèi)存單位變大了,但這也意味著申請(qǐng)內(nèi)存的耗時(shí)變長(zhǎng)。

這對(duì) Redis 會(huì)有什么影響呢?

當(dāng) Redis 在執(zhí)行后臺(tái) RDB 和 AOF rewrite 時(shí),采用 fork 子進(jìn)程的方式來(lái)處理。但主進(jìn)程 fork 子進(jìn)程后,此時(shí)的主進(jìn)程依舊是可以接收寫(xiě)請(qǐng)求的,而進(jìn)來(lái)的寫(xiě)請(qǐng)求,會(huì)采用 Copy On Write(寫(xiě)時(shí)復(fù)制)的方式操作內(nèi)存數(shù)據(jù)。

也就是說(shuō),主進(jìn)程一旦有數(shù)據(jù)需要修改,Redis 并不會(huì)直接修改現(xiàn)有內(nèi)存中的數(shù)據(jù),而是先將這塊內(nèi)存數(shù)據(jù)拷貝出來(lái),再修改這塊新內(nèi)存的數(shù)據(jù),這就是所謂的「寫(xiě)時(shí)復(fù)制」。

寫(xiě)時(shí)復(fù)制你也可以理解成,誰(shuí)需要發(fā)生寫(xiě)操作,誰(shuí)就需要先拷貝,再修改。

這樣做的好處是,父進(jìn)程有任何寫(xiě)操作,并不會(huì)影響子進(jìn)程的數(shù)據(jù)持久化(子進(jìn)程只持久化 fork 這一瞬間整個(gè)實(shí)例中的所有數(shù)據(jù)即可,不關(guān)心新的數(shù)據(jù)變更,因?yàn)樽舆M(jìn)程只需要一份內(nèi)存快照,然后持久化到磁盤(pán)上)。

但是請(qǐng)注意,主進(jìn)程在拷貝內(nèi)存數(shù)據(jù)時(shí),這個(gè)階段就涉及到新內(nèi)存的申請(qǐng),如果此時(shí)操作系統(tǒng)開(kāi)啟了內(nèi)存大頁(yè),那么在此期間,客戶(hù)端即便只修改 10B 的數(shù)據(jù),Redis 在申請(qǐng)內(nèi)存時(shí)也會(huì)以 2MB 為單位向操作系統(tǒng)申請(qǐng),申請(qǐng)內(nèi)存的耗時(shí)變長(zhǎng),進(jìn)而導(dǎo)致每個(gè)寫(xiě)請(qǐng)求的延遲增加,影響到 Redis 性能。

同樣地,如果這個(gè)寫(xiě)請(qǐng)求操作的是一個(gè) bigkey,那主進(jìn)程在拷貝這個(gè) bigkey 內(nèi)存塊時(shí),一次申請(qǐng)的內(nèi)存會(huì)更大,時(shí)間也會(huì)更久??梢?jiàn),bigkey 在這里又一次影響到了性能。

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

那如何解決這個(gè)問(wèn)題?

很簡(jiǎn)單,你只需要關(guān)閉內(nèi)存大頁(yè)機(jī)制就可以了。

首先,你需要查看 Redis 機(jī)器是否開(kāi)啟了內(nèi)存大頁(yè):

$ cat /sys/kernel/mm/transparent_hugepage/enabled [always] madvise never

如果輸出選項(xiàng)是 always,就表示目前開(kāi)啟了內(nèi)存大頁(yè)機(jī)制,我們需要關(guān)掉它:

$ echo never > /sys/kernel/mm/transparent_hugepage/enabled 

其實(shí),操作系統(tǒng)提供的內(nèi)存大頁(yè)機(jī)制,其優(yōu)勢(shì)是,可以在一定程序上降低應(yīng)用程序申請(qǐng)內(nèi)存的次數(shù)。

但是對(duì)于 Redis 這種對(duì)性能和延遲極其敏感的數(shù)據(jù)庫(kù)來(lái)說(shuō),我們希望 Redis 在每次申請(qǐng)內(nèi)存時(shí),耗時(shí)盡量短,所以我不建議你在 Redis 機(jī)器上開(kāi)啟這個(gè)機(jī)制。

開(kāi)啟AOF

前面我們分析了 RDB 和 AOF rewrite 對(duì) Redis 性能的影響,主要關(guān)注點(diǎn)在 fork 上。

其實(shí),關(guān)于數(shù)據(jù)持久化方面,還有影響 Redis 性能的因素,這次我們重點(diǎn)來(lái)看 AOF 數(shù)據(jù)持久化。

如果你的 AOF 配置不合理,還是有可能會(huì)導(dǎo)致性能問(wèn)題。

當(dāng) Redis 開(kāi)啟 AOF 后,其工作原理如下:

  1. Redis 執(zhí)行寫(xiě)命令后,把這個(gè)命令寫(xiě)入到 AOF 文件內(nèi)存中(write 系統(tǒng)調(diào)用)
  2. Redis 根據(jù)配置的 AOF 刷盤(pán)策略,把 AOF 內(nèi)存數(shù)據(jù)刷到磁盤(pán)上(fsync 系統(tǒng)調(diào)用)

為了保證 AOF 文件數(shù)據(jù)的安全性,Redis 提供了 3 種刷盤(pán)機(jī)制:

  1. appendfsync always:主線(xiàn)程每次執(zhí)行寫(xiě)操作后立即刷盤(pán),此方案會(huì)占用比較大的磁盤(pán) IO 資源,但數(shù)據(jù)安全性最高
  2. appendfsync no:主線(xiàn)程每次寫(xiě)操作只寫(xiě)內(nèi)存就返回,內(nèi)存數(shù)據(jù)什么時(shí)候刷到磁盤(pán),交由操作系統(tǒng)決定,此方案對(duì)性能影響最小,但數(shù)據(jù)安全性也最低,Redis 宕機(jī)時(shí)丟失的數(shù)據(jù)取決于操作系統(tǒng)刷盤(pán)時(shí)機(jī)
  3. appendfsync everysec:主線(xiàn)程每次寫(xiě)操作只寫(xiě)內(nèi)存就返回,然后由后臺(tái)線(xiàn)程每隔 1 秒執(zhí)行一次刷盤(pán)操作(觸發(fā)fsync系統(tǒng)調(diào)用),此方案對(duì)性能影響相對(duì)較小,但當(dāng) Redis 宕機(jī)時(shí)會(huì)丟失 1 秒的數(shù)據(jù)

下面我們依次來(lái)分析,這幾個(gè)機(jī)制對(duì)性能的影響。

如果你的 AOF 配置為 appendfsync always,那么 Redis 每處理一次寫(xiě)操作,都會(huì)把這個(gè)命令寫(xiě)入到磁盤(pán)中才返回,整個(gè)過(guò)程都是在主線(xiàn)程執(zhí)行的,這個(gè)過(guò)程必然會(huì)加重 Redis 寫(xiě)負(fù)擔(dān)。

原因也很簡(jiǎn)單,操作磁盤(pán)要比操作內(nèi)存慢幾百倍,采用這個(gè)配置會(huì)嚴(yán)重拖慢 Redis 的性能,因此我不建議你把 AOF 刷盤(pán)方式配置為 always。

我們接著來(lái)看 appendfsync no 配置項(xiàng)。

在這種配置下,Redis 每次寫(xiě)操作只寫(xiě)內(nèi)存,什么時(shí)候把內(nèi)存中的數(shù)據(jù)刷到磁盤(pán),交給操作系統(tǒng)決定,此方案對(duì) Redis 的性能影響最小,但當(dāng) Redis 宕機(jī)時(shí),會(huì)丟失一部分?jǐn)?shù)據(jù),為了數(shù)據(jù)的安全性,一般我們也不采取這種配置。

如果你的 Redis 只用作純緩存,對(duì)于數(shù)據(jù)丟失不敏感,采用配置 appendfsync no 也是可以的。

看到這里,我猜你肯定和大多數(shù)人的想法一樣,選比較折中的方案 appendfsync everysec 就沒(méi)問(wèn)題了吧?

這個(gè)方案優(yōu)勢(shì)在于,Redis 主線(xiàn)程寫(xiě)完內(nèi)存后就返回,具體的刷盤(pán)操作是放到后臺(tái)線(xiàn)程中執(zhí)行的,后臺(tái)線(xiàn)程每隔 1 秒把內(nèi)存中的數(shù)據(jù)刷到磁盤(pán)中。

這種方案既兼顧了性能,又盡可能地保證了數(shù)據(jù)安全,是不是覺(jué)得很完美?

但是,這里我要給你潑一盆冷水了,采用這種方案你也要警惕一下,因?yàn)檫@種方案還是存在導(dǎo)致 Redis 延遲變大的情況發(fā)生,甚至?xí)枞麄€(gè) Redis。

這是為什么?我把 AOF 最耗時(shí)的刷盤(pán)操作,放到后臺(tái)線(xiàn)程中也會(huì)影響到 Redis 主線(xiàn)程?

你試想這樣一種情況:當(dāng) Redis 后臺(tái)線(xiàn)程在執(zhí)行 AOF 文件刷盤(pán)時(shí),如果此時(shí)磁盤(pán)的 IO 負(fù)載很高,那這個(gè)后臺(tái)線(xiàn)程在執(zhí)行刷盤(pán)操作(fsync系統(tǒng)調(diào)用)時(shí)就會(huì)被阻塞住。

此時(shí)的主線(xiàn)程依舊會(huì)接收寫(xiě)請(qǐng)求,緊接著,主線(xiàn)程又需要把數(shù)據(jù)寫(xiě)到文件內(nèi)存中(write 系統(tǒng)調(diào)用),但此時(shí)的后臺(tái)子線(xiàn)程由于磁盤(pán)負(fù)載過(guò)高,導(dǎo)致 fsync 發(fā)生阻塞,遲遲不能返回,那主線(xiàn)程在執(zhí)行 write 系統(tǒng)調(diào)用時(shí),也會(huì)被阻塞住,直到后臺(tái)線(xiàn)程 fsync 執(zhí)行完成后,主線(xiàn)程執(zhí)行 write 才能成功返回。

看到了么?在這個(gè)過(guò)程中,主線(xiàn)程依舊有阻塞的風(fēng)險(xiǎn)。

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

所以,盡管你的 AOF 配置為 appendfsync everysec,也不能掉以輕心,要警惕磁盤(pán)壓力過(guò)大導(dǎo)致的 Redis 有性能問(wèn)題。

那什么情況下會(huì)導(dǎo)致磁盤(pán) IO 負(fù)載過(guò)大?以及如何解決這個(gè)問(wèn)題呢?

我總結(jié)了以下幾種情況,你可以參考進(jìn)行問(wèn)題排查:

  1. 子進(jìn)程正在執(zhí)行 AOF rewrite,這個(gè)過(guò)程會(huì)占用大量的磁盤(pán) IO 資源
  2. 有其他應(yīng)用程序在執(zhí)行大量的寫(xiě)文件操作,也會(huì)占用磁盤(pán) IO 資源

對(duì)于情況1,說(shuō)白了就是,Redis 的 AOF 后臺(tái)子線(xiàn)程刷盤(pán)操作,撞上了子進(jìn)程 AOF rewrite!

這怎么辦?難道要關(guān)閉 AOF rewrite 才行?

幸運(yùn)的是,Redis 提供了一個(gè)配置項(xiàng),當(dāng)子進(jìn)程在 AOF rewrite 期間,可以讓后臺(tái)子線(xiàn)程不執(zhí)行刷盤(pán)(不觸發(fā) fsync 系統(tǒng)調(diào)用)操作。

這相當(dāng)于在 AOF rewrite 期間,臨時(shí)把 appendfsync 設(shè)置為了 none,配置如下:

# AOF rewrite 期間,AOF 后臺(tái)子線(xiàn)程不進(jìn)行刷盤(pán)操作 # 相當(dāng)于在這期間,臨時(shí)把 appendfsync 設(shè)置為了 none no-appendfsync-on-rewrite yes

當(dāng)然,開(kāi)啟這個(gè)配置項(xiàng),在 AOF rewrite 期間,如果實(shí)例發(fā)生宕機(jī),那么此時(shí)會(huì)丟失更多的數(shù)據(jù),性能和數(shù)據(jù)安全性,你需要權(quán)衡后進(jìn)行選擇。

如果占用磁盤(pán)資源的是其他應(yīng)用程序,那就比較簡(jiǎn)單了,你需要定位到是哪個(gè)應(yīng)用程序在大量寫(xiě)磁盤(pán),然后把這個(gè)應(yīng)用程序遷移到其他機(jī)器上執(zhí)行就好了,避免對(duì) Redis 產(chǎn)生影響。

當(dāng)然,如果你對(duì) Redis 的性能和數(shù)據(jù)安全都有很高的要求,那么我建議從硬件層面來(lái)優(yōu)化,更換為 SSD 磁盤(pán),提高磁盤(pán)的 IO 能力,保證 AOF 期間有充足的磁盤(pán)資源可以使用。

綁定CPU

很多時(shí)候,我們?cè)诓渴鸱?wù)時(shí),為了提高服務(wù)性能,降低應(yīng)用程序在多個(gè) CPU 核心之間的上下文切換帶來(lái)的性能損耗,通常采用的方案是進(jìn)程綁定 CPU 的方式提高性能。

但在部署 Redis 時(shí),如果你需要綁定 CPU 來(lái)提高其性能,我建議你仔細(xì)斟酌后再做操作。

為什么?

因?yàn)?Redis 在綁定 CPU 時(shí),是有很多考究的,如果你不了解 Redis 的運(yùn)行原理,隨意綁定 CPU 不僅不會(huì)提高性能,甚至有可能會(huì)帶來(lái)相反的效果。

我們都知道,一般現(xiàn)代的服務(wù)器會(huì)有多個(gè) CPU,而每個(gè) CPU 又包含多個(gè)物理核心,每個(gè)物理核心又分為多個(gè)邏輯核心,每個(gè)物理核下的邏輯核共用 L1/L2 Cache。

而 Redis Server 除了主線(xiàn)程服務(wù)客戶(hù)端請(qǐng)求之外,還會(huì)創(chuàng)建子進(jìn)程、子線(xiàn)程。

其中子進(jìn)程用于數(shù)據(jù)持久化,而子線(xiàn)程用于執(zhí)行一些比較耗時(shí)操作,例如異步釋放 fd、異步 AOF 刷盤(pán)、異步 lazy-free 等等。

如果你把 Redis 進(jìn)程只綁定了一個(gè) CPU 邏輯核心上,那么當(dāng) Redis 在進(jìn)行數(shù)據(jù)持久化時(shí),fork 出的子進(jìn)程會(huì)繼承父進(jìn)程的 CPU 使用偏好。

而此時(shí)的子進(jìn)程會(huì)消耗大量的 CPU 資源進(jìn)行數(shù)據(jù)持久化(把實(shí)例數(shù)據(jù)全部掃描出來(lái)需要耗費(fèi)CPU),這就會(huì)導(dǎo)致子進(jìn)程會(huì)與主進(jìn)程發(fā)生 CPU 爭(zhēng)搶?zhuān)M(jìn)而影響到主進(jìn)程服務(wù)客戶(hù)端請(qǐng)求,訪問(wèn)延遲變大。

這就是 Redis 綁定 CPU 帶來(lái)的性能問(wèn)題。

那如何解決這個(gè)問(wèn)題呢?

如果你確實(shí)想要綁定 CPU,可以?xún)?yōu)化的方案是,不要讓 Redis 進(jìn)程只綁定在一個(gè) CPU 邏輯核上,而是綁定在多個(gè)邏輯核心上,而且,綁定的多個(gè)邏輯核心最好是同一個(gè)物理核心,這樣它們還可以共用 L1/L2 Cache。

當(dāng)然,即便我們把 Redis 綁定在多個(gè)邏輯核心上,也只能在一定程度上緩解主線(xiàn)程、子進(jìn)程、后臺(tái)線(xiàn)程在 CPU 資源上的競(jìng)爭(zhēng)。

因?yàn)檫@些子進(jìn)程、子線(xiàn)程還是會(huì)在這多個(gè)邏輯核心上進(jìn)行切換,存在性能損耗。

如何再進(jìn)一步優(yōu)化?

可能你已經(jīng)想到了,我們是否可以讓主線(xiàn)程、子進(jìn)程、后臺(tái)線(xiàn)程,分別綁定在固定的 CPU 核心上,不讓它們來(lái)回切換,這樣一來(lái),他們各自使用的 CPU 資源互不影響。

其實(shí),這個(gè)方案 Redis 官方已經(jīng)想到了。

Redis 在 6.0 版本已經(jīng)推出了這個(gè)功能,我們可以通過(guò)以下配置,對(duì)主線(xiàn)程、后臺(tái)線(xiàn)程、后臺(tái) RDB 進(jìn)程、AOF rewrite 進(jìn)程,綁定固定的 CPU 邏輯核心:

# Redis Server 和 IO 線(xiàn)程綁定到 CPU核心 0,2,4,6 server_cpulist 0-7:2  # 后臺(tái)子線(xiàn)程綁定到 CPU核心 1,3 bio_cpulist 1,3  # 后臺(tái) AOF rewrite 進(jìn)程綁定到 CPU 核心 8,9,10,11 aof_rewrite_cpulist 8-11  # 后臺(tái) RDB 進(jìn)程綁定到 CPU 核心 1,10,11 # bgsave_cpulist 1,10-1 

如果你使用的正好是 Redis 6.0 版本,就可以通過(guò)以上配置,來(lái)進(jìn)一步提高 Redis 性能。

這里我需要提醒你的是,一般來(lái)說(shuō),Redis 的性能已經(jīng)足夠優(yōu)秀,除非你對(duì) Redis 的性能有更加嚴(yán)苛的要求,否則不建議你綁定 CPU。

從上面的分析你也能看出,綁定 CPU 需要你對(duì)計(jì)算機(jī)體系結(jié)構(gòu)有非常清晰的了解,否則謹(jǐn)慎操作。

我們繼續(xù)分析還有什么場(chǎng)景會(huì)導(dǎo)致 Redis 變慢。

使用Swap

如果你發(fā)現(xiàn) Redis 突然變得非常慢,每次的操作耗時(shí)都達(dá)到了幾百毫秒甚至秒級(jí),那此時(shí)你就需要檢查 Redis 是否使用到了 Swap,在這種情況下 Redis 基本上已經(jīng)無(wú)法提供高性能的服務(wù)了。

什么是 Swap?為什么使用 Swap 會(huì)導(dǎo)致 Redis 的性能下降?

如果你對(duì)操作系統(tǒng)有些了解,就會(huì)知道操作系統(tǒng)為了緩解內(nèi)存不足對(duì)應(yīng)用程序的影響,允許把一部分內(nèi)存中的數(shù)據(jù)換到磁盤(pán)上,以達(dá)到應(yīng)用程序?qū)?nèi)存使用的緩沖,這些內(nèi)存數(shù)據(jù)被換到磁盤(pán)上的區(qū)域,就是 Swap。

問(wèn)題就在于,當(dāng)內(nèi)存中的數(shù)據(jù)被換到磁盤(pán)上后,Redis 再訪問(wèn)這些數(shù)據(jù)時(shí),就需要從磁盤(pán)上讀取,訪問(wèn)磁盤(pán)的速度要比訪問(wèn)內(nèi)存慢幾百倍!

尤其是針對(duì) Redis 這種對(duì)性能要求極高、性能極其敏感的數(shù)據(jù)庫(kù)來(lái)說(shuō),這個(gè)操作延時(shí)是無(wú)法接受的。

此時(shí),你需要檢查 Redis 機(jī)器的內(nèi)存使用情況,確認(rèn)是否存在使用了 Swap。

你可以通過(guò)以下方式來(lái)查看 Redis 進(jìn)程是否使用到了 Swap:

# 先找到 Redis 的進(jìn)程 ID $ ps -aux | grep redis-server  # 查看 Redis Swap 使用情況 $ cat /proc/$pid/smaps | egrep '^(Swap|Size)' 

輸出結(jié)果如下:

Size:               1256 kB
Swap:                  0 kB
Size:                  4 kB
Swap:                  0 kB
Size:                132 kB
Swap:                  0 kB
Size:              63488 kB
Swap:                  0 kB
Size:                132 kB
Swap:                  0 kB
Size:              65404 kB
Swap:                  0 kB
Size:            1921024 kB
Swap:                  0 kB
...

這個(gè)結(jié)果會(huì)列出 Redis 進(jìn)程的內(nèi)存使用情況。

每一行 Size 表示 Redis 所用的一塊內(nèi)存大小,Size 下面的 Swap 就表示這塊 Size 大小的內(nèi)存,有多少數(shù)據(jù)已經(jīng)被換到磁盤(pán)上了,如果這兩個(gè)值相等,說(shuō)明這塊內(nèi)存的數(shù)據(jù)都已經(jīng)完全被換到磁盤(pán)上了。

如果只是少量數(shù)據(jù)被換到磁盤(pán)上,例如每一塊 Swap 占對(duì)應(yīng) Size 的比例很小,那影響并不是很大。如果是幾百兆甚至上 GB 的內(nèi)存被換到了磁盤(pán)上,那么你就需要警惕了,這種情況 Redis 的性能肯定會(huì)急劇下降。

此時(shí)的解決方案是:

  1. 增加機(jī)器的內(nèi)存,讓 Redis 有足夠的內(nèi)存可以使用
  2. 整理內(nèi)存空間,釋放出足夠的內(nèi)存供 Redis 使用,然后釋放 Redis 的 Swap,讓 Redis 重新使用內(nèi)存

釋放 Redis 的 Swap 過(guò)程通常要重啟實(shí)例,為了避免重啟實(shí)例對(duì)業(yè)務(wù)的影響,一般會(huì)先進(jìn)行主從切換,然后釋放舊主節(jié)點(diǎn)的 Swap,重啟舊主節(jié)點(diǎn)實(shí)例,待從庫(kù)數(shù)據(jù)同步完成后,再進(jìn)行主從切換即可。

可見(jiàn),當(dāng) Redis 使用到 Swap 后,此時(shí)的 Redis 性能基本已達(dá)不到高性能的要求(你可以理解為武功被廢),所以你也需要提前預(yù)防這種情況。

預(yù)防的辦法就是,你需要對(duì) Redis 機(jī)器的內(nèi)存和 Swap 使用情況進(jìn)行監(jiān)控,在內(nèi)存不足或使用到 Swap 時(shí)報(bào)警出來(lái),及時(shí)處理。

碎片整理

Redis 的數(shù)據(jù)都存儲(chǔ)在內(nèi)存中,當(dāng)我們的應(yīng)用程序頻繁修改 Redis 中的數(shù)據(jù)時(shí),就有可能會(huì)導(dǎo)致 Redis 產(chǎn)生內(nèi)存碎片。

內(nèi)存碎片會(huì)降低 Redis 的內(nèi)存使用率,我們可以通過(guò)執(zhí)行 INFO 命令,得到這個(gè)實(shí)例的內(nèi)存碎片率:

# Memory used_memory:5709194824
used_memory_human:5.32G
used_memory_rss:8264855552
used_memory_rss_human:7.70G
...
mem_fragmentation_ratio:1.45

這個(gè)內(nèi)存碎片率是怎么計(jì)算的?

很簡(jiǎn)單,mem_fragmentation_ratio = used_memory_rss / used_memory。

其中 used_memory 表示 Redis 存儲(chǔ)數(shù)據(jù)的內(nèi)存大小,而 used_memory_rss 表示操作系統(tǒng)實(shí)際分配給 Redis 進(jìn)程的大小。

如果 mem_fragmentation_ratio > 1.5,說(shuō)明內(nèi)存碎片率已經(jīng)超過(guò)了 50%,這時(shí)我們就需要采取一些措施來(lái)降低內(nèi)存碎片了。

解決的方案一般如下:

  1. 如果你使用的是 Redis 4.0 以下版本,只能通過(guò)重啟實(shí)例來(lái)解決
  2. 如果你使用的是 Redis 4.0 版本,它正好提供了自動(dòng)碎片整理的功能,可以通過(guò)配置開(kāi)啟碎片自動(dòng)整理

但是,開(kāi)啟內(nèi)存碎片整理,它也有可能會(huì)導(dǎo)致 Redis 性能下降。

原因在于,Redis 的碎片整理工作是也在主線(xiàn)程中執(zhí)行的,當(dāng)其進(jìn)行碎片整理時(shí),必然會(huì)消耗 CPU 資源,產(chǎn)生更多的耗時(shí),從而影響到客戶(hù)端的請(qǐng)求。

所以,當(dāng)你需要開(kāi)啟這個(gè)功能時(shí),最好提前測(cè)試評(píng)估它對(duì) Redis 的影響。

Redis 碎片整理的參數(shù)配置如下:

# 開(kāi)啟自動(dòng)內(nèi)存碎片整理(總開(kāi)關(guān)) activedefrag yes  # 內(nèi)存使用 100MB 以下,不進(jìn)行碎片整理 active-defrag-ignore-bytes 100mb  # 內(nèi)存碎片率超過(guò) 10%,開(kāi)始碎片整理 active-defrag-threshold-lower 10 # 內(nèi)存碎片率超過(guò) 100%,盡最大努力碎片整理 active-defrag-threshold-upper 100  # 內(nèi)存碎片整理占用 CPU 資源最小百分比 active-defrag-cycle-min 1 # 內(nèi)存碎片整理占用 CPU 資源最大百分比 active-defrag-cycle-max 25  # 碎片整理期間,對(duì)于 List/Set/Hash/ZSet 類(lèi)型元素一次 Scan 的數(shù)量 active-defrag-max-scan-fields 1000

你需要結(jié)合 Redis 機(jī)器的負(fù)載情況,以及應(yīng)用程序可接受的延遲范圍進(jìn)行評(píng)估,合理調(diào)整碎片整理的參數(shù),盡可能降低碎片整理期間對(duì) Redis 的影響。

網(wǎng)絡(luò)帶寬過(guò)載

如果以上產(chǎn)生性能問(wèn)題的場(chǎng)景,你都規(guī)避掉了,而且 Redis 也穩(wěn)定運(yùn)行了很長(zhǎng)時(shí)間,但在某個(gè)時(shí)間點(diǎn)之后開(kāi)始,操作 Redis 突然開(kāi)始變慢了,而且一直持續(xù)下去,這種情況又是什么原因?qū)е拢?/span>

此時(shí)你需要排查一下 Redis 機(jī)器的網(wǎng)絡(luò)帶寬是否過(guò)載,是否存在某個(gè)實(shí)例把整個(gè)機(jī)器的網(wǎng)路帶寬占滿(mǎn)的情況。

網(wǎng)絡(luò)帶寬過(guò)載的情況下,服務(wù)器在 TCP 層和網(wǎng)絡(luò)層就會(huì)出現(xiàn)數(shù)據(jù)包發(fā)送延遲、丟包等情況。

Redis 的高性能,除了操作內(nèi)存之外,就在于網(wǎng)絡(luò) IO 了,如果網(wǎng)絡(luò) IO 存在瓶頸,那么也會(huì)嚴(yán)重影響 Redis 的性能。

如果確實(shí)出現(xiàn)這種情況,你需要及時(shí)確認(rèn)占滿(mǎn)網(wǎng)絡(luò)帶寬 Redis 實(shí)例,如果屬于正常的業(yè)務(wù)訪問(wèn),那就需要及時(shí)擴(kuò)容或遷移實(shí)例了,避免因?yàn)檫@個(gè)實(shí)例流量過(guò)大,影響這個(gè)機(jī)器的其他實(shí)例。

運(yùn)維層面,你需要對(duì) Redis 機(jī)器的各項(xiàng)指標(biāo)增加監(jiān)控,包括網(wǎng)絡(luò)流量,在網(wǎng)絡(luò)流量達(dá)到一定閾值時(shí)提前報(bào)警,及時(shí)確認(rèn)和擴(kuò)容。

其他原因

好了,以上這些方面就是如何排查 Redis 延遲問(wèn)題的思路和路徑。

除了以上這些,還有一些比較小的點(diǎn),你也需要注意一下:

1) 頻繁短連接

你的業(yè)務(wù)應(yīng)用,應(yīng)該使用長(zhǎng)連接操作 Redis,避免頻繁的短連接。

頻繁的短連接會(huì)導(dǎo)致 Redis 大量時(shí)間耗費(fèi)在連接的建立和釋放上,TCP 的三次握手和四次揮手同樣也會(huì)增加訪問(wèn)延遲。

2) 運(yùn)維監(jiān)控

前面我也提到了,要想提前預(yù)知 Redis 變慢的情況發(fā)生,必不可少的就是做好完善的監(jiān)控。

監(jiān)控其實(shí)就是對(duì)采集 Redis 的各項(xiàng)運(yùn)行時(shí)指標(biāo),通常的做法是監(jiān)控程序定時(shí)采集 Redis 的 INFO 信息,然后根據(jù) INFO 信息中的狀態(tài)數(shù)據(jù)做數(shù)據(jù)展示和報(bào)警。

這里我需要提醒你的是,在寫(xiě)一些監(jiān)控腳本,或使用開(kāi)源的監(jiān)控組件時(shí),也不能掉以輕心。

在寫(xiě)監(jiān)控腳本訪問(wèn) Redis 時(shí),盡量采用長(zhǎng)連接的方式采集狀態(tài)信息,避免頻繁短連接。同時(shí),你還要注意控制訪問(wèn) Redis 的頻率,避免影響到業(yè)務(wù)請(qǐng)求。

在使用一些開(kāi)源的監(jiān)控組件時(shí),最好了解一下這些組件的實(shí)現(xiàn)原理,以及正確配置這些組件,防止出現(xiàn)監(jiān)控組件發(fā)生 Bug,導(dǎo)致短時(shí)大量操作 Redis,影響 Redis 性能的情況發(fā)生。

我們當(dāng)時(shí)就發(fā)生過(guò),DBA 在使用一些開(kāi)源組件時(shí),因?yàn)榕渲煤褪褂脝?wèn)題,導(dǎo)致監(jiān)控程序頻繁地與 Redis 建立和斷開(kāi)連接,導(dǎo)致 Redis 響應(yīng)變慢。

3)其它程序爭(zhēng)搶資源

最后需要提醒你的是,你的 Redis 機(jī)器最好專(zhuān)項(xiàng)專(zhuān)用,只用來(lái)部署 Redis 實(shí)例,不要部署其他應(yīng)用程序,盡量給 Redis 提供一個(gè)相對(duì)「安靜」的環(huán)境,避免其它程序占用 CPU、內(nèi)存、磁盤(pán)資源,導(dǎo)致分配給 Redis 的資源不足而受到影響。

總結(jié)

好了,以上就是我總結(jié)的在使用 Redis 過(guò)程中,常見(jiàn)的可能導(dǎo)致延遲、甚至阻塞的問(wèn)題場(chǎng)景,以及如何快速定位和分析這些問(wèn)題,并且針對(duì)性地提供了解決方案。

這里我也匯總成了思維導(dǎo)圖,方便你在排查 Redis 性能問(wèn)題時(shí),快速地去分析和定位。

Redis為什么變慢了?一文講透如何排查Redis性能問(wèn)題 | 萬(wàn)字長(zhǎng)文

這里再簡(jiǎn)單總結(jié)一下,Redis 的性能問(wèn)題,既涉及到了業(yè)務(wù)開(kāi)發(fā)人員的使用方面,也涉及到了 DBA 的運(yùn)維方面。

作為業(yè)務(wù)開(kāi)發(fā)人員,我們需要了解 Redis 的基本原理,例如各個(gè)命令執(zhí)行的時(shí)間復(fù)雜度、數(shù)據(jù)過(guò)期策略、數(shù)據(jù)淘汰策略等,從而更合理地使用 Redis 命令,并且結(jié)合業(yè)務(wù)場(chǎng)景進(jìn)行優(yōu)化。

作為 DBA 和運(yùn)維人員,需要了解 Redis 運(yùn)行機(jī)制,例如數(shù)據(jù)持久化、內(nèi)存碎片整理、進(jìn)程綁核配置。除此之外,還需要了解操作系統(tǒng)相關(guān)知識(shí),例如寫(xiě)時(shí)復(fù)制、內(nèi)存大頁(yè)、Swap 機(jī)制等等。

同時(shí),DBA 在部署 Redis 時(shí),需要提前對(duì)進(jìn)行容量規(guī)劃,預(yù)留足夠的機(jī)器資源,還要對(duì) Redis 機(jī)器和實(shí)例做好完善的監(jiān)控,這樣才能盡可能地保證 Redis 的穩(wěn)定運(yùn)行。

后記

如果你能耐心地看到這里,想必你肯定已經(jīng)對(duì) Redis 的性能調(diào)優(yōu)有了很大的收獲。

你應(yīng)該也發(fā)現(xiàn)了,Redis 的性能問(wèn)題,涉及到的知識(shí)點(diǎn)非常廣,幾乎涵蓋了 CPU、內(nèi)存、網(wǎng)絡(luò)、甚至磁盤(pán)的方方面面,同時(shí),你還需要了解計(jì)算機(jī)的體系結(jié)構(gòu),以及操作系統(tǒng)的各種機(jī)制。

從資源使用角度來(lái)看,包含的知識(shí)點(diǎn)如下:

  • CPU 相關(guān):使用復(fù)雜度過(guò)高命令、數(shù)據(jù)的持久化,都與耗費(fèi)過(guò)多的 CPU 資源有關(guān)
  • 內(nèi)存相關(guān):bigkey 內(nèi)存的申請(qǐng)和釋放、數(shù)據(jù)過(guò)期、數(shù)據(jù)淘汰、碎片整理、內(nèi)存大頁(yè)、內(nèi)存寫(xiě)時(shí)復(fù)制都與內(nèi)存息息相關(guān)
  • 磁盤(pán)相關(guān):數(shù)據(jù)持久化、AOF 刷盤(pán)策略,也會(huì)受到磁盤(pán)的影響
  • 網(wǎng)絡(luò)相關(guān):短連接、實(shí)例流量過(guò)載、網(wǎng)絡(luò)流量過(guò)載,也會(huì)降低 Redis 性能
  • 計(jì)算機(jī)系統(tǒng):CPU 結(jié)構(gòu)、內(nèi)存分配,都屬于最基礎(chǔ)的計(jì)算機(jī)系統(tǒng)知識(shí)
  • 操作系統(tǒng):寫(xiě)時(shí)復(fù)制、內(nèi)存大頁(yè)、Swap、CPU 綁定,都屬于操作系統(tǒng)層面的知識(shí)

沒(méi)想到吧?Redis 為了把性能做到極致,涉及到了這么多項(xiàng)優(yōu)化。

如果這篇文章內(nèi)容,你能吸收 90% 以上,說(shuō)明你對(duì) Redis 原理、計(jì)算機(jī)基礎(chǔ)、操作系統(tǒng)都已經(jīng)有了較為深刻的理解。

如果你能吸收 50% 左右,那你可以好好梳理一下,哪些方面是自己的知識(shí)盲區(qū),這樣可以針對(duì)性地去學(xué)習(xí)。

如果你吸收的只在 30% 以下,那么你可以先從 Redis 的基本原理出發(fā),先了解 Redis 的各種機(jī)制,進(jìn)而思考 Redis 為了提高性能,為什么使用這些機(jī)制?這些機(jī)制又是利用了計(jì)算機(jī)和操作系統(tǒng)的哪些特性去做的?進(jìn)而一步步地去擴(kuò)充你的知識(shí)體系,這是一個(gè)非常高效的學(xué)習(xí)路徑。

由于篇幅限制,關(guān)于 Redis 的很多細(xì)節(jié)無(wú)法全部展開(kāi),其實(shí),這篇文章提到的每一個(gè)導(dǎo)致 Redis 性能問(wèn)題的場(chǎng)景,如果展開(kāi)來(lái)講,都可以寫(xiě)出一篇文章出來(lái)。

例如,關(guān)于 Redis 進(jìn)程綁定 CPU,以及操作系統(tǒng)使用 Swap,其實(shí)這些還涉及到了非一致性?xún)?nèi)存訪問(wèn) NUMA 架構(gòu)的影響,其中也有很多細(xì)節(jié)沒(méi)有展開(kāi)來(lái)講。


免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱(chēng),數(shù)字世界的話(huà)語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉