Redis 6.0 多執行緒性能測試結果及分析
弄清楚了多執行緒的本質之後,就會有一系列的問題,多執行緒會比單執行緒有多大的提升?設置多少個執行緒合適?見一些大神測試過,其結果也非常理想,但只是看看也不太過癮,決定一試為快,本文將對Redis的多執行緒進行一個粗淺的測試驗證。同時需要思考另外一個問題:面對多執行緒版本的Redis,和Redis cluster,該如何選擇?
多執行緒Redis
redis 6.0 的「多執行緒」特性讓很多標題黨高潮連連,參考圖片源自於:美圖技術團隊侵刪,核心的執行緒(Execute Command)還是單執行緒,多執行緒是指網路IO(socket)讀寫的多執行緒化。
如下圖所示,讀寫網路socket中的數據是可以用多個執行緒,所以Redis的多執行緒也叫做io thread,相關參數:「io-threads」。另一個參數是io-threads-do-reads,這裡涉及另外一個細節:多執行緒IO主要用在請求完成後返回結果集的過程,也就是socket寫操作,至於讀socket,單執行緒本身採用的多路IO復用技術,也不會產生瓶頸,因此Redis給出了一個io-threads-do-reads 參數,決定讀socket的時候是否啟用多執行緒。其實io-threads-do-reads是否啟用,對性能的影響並不大,最後會做一個驗證。
測試策略
本機配置:centos 7,16C+32GB記憶體

Redis版本

翻車
整個測試開始之前,經歷了兩次翻車才得以繼續
centos 7上默認的gcc是4.*版本,無法編譯Redis 6.0,所以需要升級gcc,因為本機不支援yum安裝,參考這裡使用源碼包安裝,gcc編譯的時候那個酸爽,本機16C+32GB記憶體的環境下,因為缺少某些依賴包,導致失敗了幾次,最終編譯成功的一次,花了大概1個小時10分鐘

沒有認真讀配置文件中的說明,設置io-threads後,重啟Redis服務後,上來就用redis-benchmark直接懟,其結果跟單執行緒差不多,令人大跌眼鏡。
最後還是在原始配置文件發現了這段話:
If you want to test the Redis speedup using redis-benchmark, make sure you also run the benchmark itself in threaded mode, using the –threads option to match the number of Redis threads, otherwise you’ll not be able to notice the improvements.

關於Thread IO的說明
################################ THREADED I/O #################################
# Redis is mostly single threaded, however there are certain threaded
# operations such as UNLINK, slow I/O accesses and other things that are
# performed on side threads.
#
# Now it is also possible to handle Redis clients socket reads and writes
# in different I/O threads. Since especially writing is so slow, normally
# Redis users use pipelining in order to speed up the Redis performances per
# core, and spawn multiple instances in order to scale more. Using I/O
# threads it is possible to easily speedup two times Redis without resorting
# to pipelining nor sharding of the instance.
#
# By default threading is disabled, we suggest enabling it only in machines
# that have at least 4 or more cores, leaving at least one spare core.
# Using more than 8 threads is unlikely to help much. We also recommend using
# threaded I/O only if you actually have performance problems, with Redis
# instances being able to use a quite big percentage of CPU time, otherwise
# there is no point in using this feature.
#
# So for instance if you have a four cores boxes, try to use 2 or 3 I/O
# threads, if you have a 8 cores, try to use 6 threads. In order to
# enable I/O threads use the following configuration directive:
#
# io-threads 4
#
# Setting io-threads to 1 will just use the main thread as usual.
# When I/O threads are enabled, we only use threads for writes, that is
# to thread the write(2) syscall and transfer the client buffers to the
# socket. However it is also possible to enable threading of reads and
# protocol parsing using the following configuration directive, by setting
# it to yes:
#
# io-threads-do-reads no
#
# Usually threading reads doesn't help much.
#
# NOTE 1: This configuration directive cannot be changed at runtime via
# CONFIG SET. Aso this feature currently does not work when SSL is
# enabled.
#
# NOTE 2: If you want to test the Redis speedup using redis-benchmark, make
# sure you also run the benchmark itself in threaded mode, using the
# --threads option to match the number of Redis threads, otherwise you'll not
# be able to notice the improvements.
大多數情況下redis是以單執行緒的方式運行的,然而,有一些執行緒操作,如斷開鏈接,耗時的I/O操作(bgsave,expired key清理之類的操作)和其他任務是在side執行緒(主執行緒fork出來的先執行緒)中執行的。
但是,也可以啟用讀寫執行緒,使用以下配置指令進行協議解析,方法是將其設置為「yes」:
測試結果及分析

從中可以看到:
因此在本機環境下,io-threads 4設置成2或者4個都ok,最多不超過8個,超出後性能反而會下降,同時也不能超出cpu的個數,正如配置文件中注釋中說的,至少要留出一個CPU。

關於io-threads-do-reads參數
上文提到過io-threads-do-reads這個參數,它是決定socket讀操作是否開啟多執行緒,Redis的socket讀操作採用多路IO復用技術,本身不會成為瓶頸,所以這個參數對多執行緒下測試影響比較小。依舊參考這裡的這個圖 侵刪,這個io-threads-do-reads在筆者理解起來,就是socket讀的執行緒,是否開啟影響不大。
參考如下截圖,在開啟了兩個執行緒的情況下,分別開啟和禁用io-threads-do-reads,從整體上看,性能影響差別很小。當然專業的大神可以從源碼的角度去分析。
io-threads為2,且啟動io-threads-do-reads
io-threads為2,且禁動io-threads-do-reads
多執行緒版本的Redis和Redis Cluster的選擇
redis集群有兩種模式:sentinel和cluster,這裡暫時先不提sentinel,來思考多執行緒版本的Redis和Redis Cluster的選擇問題。
Redis的Cluster解決的就是擴展性和單節點單執行緒的阻塞隱患,如果Redis支援了多執行緒(目前多執行緒的Redis最對不建議超出8個執行緒),在不考慮單個節點網卡瓶頸的情況下,其實這兩個問題都已經解決了,單節點可以支援多執行緒和充分利用多核CPU,單節點可以支援到25W QPS,還要啥自行車?
同時要考慮到Redis cluster的痛點:
1,不支援multiple操作(第三方插件也不一定穩定)。
2,cluster中每個主節點要掛一個從節點,不管這個節點是不是獨立的物理節點還是單機多實例中的一個節點,終究是增加了維護成本。
3,只能使用一個資料庫
4,集群自身擴容、縮容帶來的一系列slot遷移等性能問題,以及集群的管理問題
這些所謂的痛點也不復存在了,所以這裡就面臨一個重新選擇的問題:是使用多執行緒版本的Redis,還是使用Redis cluster?這是一個需要思考的問題。
疑問
關於redis-benchmark 測試時候 ./bin/redis-benchmark -d 128 -c 200 -n 1000000 -t set -q –threads 2,涉及的兩個參數-c和–threads,個人是不太理解的
-c的解釋是:指定並發連接數
–threads是redis-benchmark的執行緒數?
對此去跟老錢求證了一下,說該參數是redis-benchmark客戶端的epoll,伺服器端的多路IO復用原理已經看得我七葷八素了,客戶端也是帶epoll的,還是不太理解這兩者之間的關係。
redis-benchmark測試現場
如下是redis-benchmark測試過程中部分截圖