《Redis官方教程》-基準測試
Redis有多快?
Redis 包含了工具程序redis-benchmark,它可以模擬運行命令,相當於模擬N個客戶端同時發送總數M個查詢(和apache的ab工具程序類似)。下麵是在linux係統上執行benchemark後的完整輸出,支持的選項如下:
Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]
-h <hostname> Server hostname (default 127.0.0.1)
-p <port> Server port (default 6379)
-s <socket> Server socket (overrides host and port)
-a <password> Password for Redis Auth
-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 2)
-dbnum <db> SELECT the specified db number (default 0)
-k <boolean> 1=keep alive 0=reconnect (default 1)
-r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD
Using this option the benchmark will expand the string __rand_int__
inside an argument with a 12 digits number in the specified range
from 0 to keyspacelen-1. The substitution changes every time a command
is executed. Default tests use this to hit random keys in the
specified range.
-P <numreq> Pipeline <numreq> requests. Default 1 (no pipeline).
-q Quiet. Just show query/sec values
–csv Output in CSV format
-l Loop. Run the tests forever
-t <tests> Only run the comma separated list of tests. The test
names are the same as the ones produced as output.
-I Idle mode. Just open N idle connections and wait.
啟動benchmark之前你得有個正在運行的Redis實例。運行benchmark典型示例如下:
redis-benchmark -q -n 100000
使用這個工具比較簡單,你也可以實現你自己的benchmark,但是有些坑不要踩。
隻運行一部分測試
不是每次運行redis-benchmark時,都要運行所有默認的測試。選擇一部分來測試,隻要簡單地使用-t選項,如下:
$ redis-benchmark -t set,lpush -n 100000 -q
SET: 74239.05 requests per second
LPUSH: 79239.30 requests per second
上麵的例子中,在安靜模式下(參見-q選項),我們隻測試了SET和LPUSH命令。也可以直接給benchmark指定命令,如下:
$ redis-benchmark -n 100000 -q script load “redis.call(‘set’,’foo’,’bar’)”
script load redis.call(‘set’,’foo’,’bar’): 69881.20 requests per second
選擇key空間的大小
默認情況下,benchmark隻針對單一個key測試。在人為測試環境和真實使用環境下,Redis表現出來的差別不是很大,因為它是一個內存係統。但如果使用更大範圍的key,則可以測試緩存命中,並模擬一個更真實的工作負載。
使用-r選項就可以達到此目的,比如我想運行一百萬次SET操作,每次操作從10萬個key裏麵隨機選一個,可以使用下麵的命令:
$ redis-cli flushall
OK$ redis-benchmark -t set -r 100000 -n 1000000
====== SET ======
1000000 requests completed in 13.86 seconds
50 parallel clients
3 bytes payload
keep alive: 199.76% `<=` 1 milliseconds
99.98% `<=` 2 milliseconds
100.00% `<=` 3 milliseconds
100.00% `<=` 3 milliseconds
72144.87 requests per second$ redis-cli dbsize
(integer) 99993
管道化
默認情況下,每個模擬的客戶端(如果不指定選項-c,benchmark模擬50個客戶端)需要等待,隻有收到前一條命令的響應之後才會發送下一條命令。這意味著,客戶端發送的每條命令,服務器都需要一次read調用才能獲得。當然,等待時間也得算上RTT的時間。
Redis支持/topics/pipelining即管道化,因此是可以一次發送多條命令的。現實中的應用經常用到這個特性。Redis在管道化模式下能夠大幅提高服務器的每秒操作數。
下麵的例子中,使用由16條命令的組成的管道,在一台MacBook Air 11″上運行benchmark:
$ redis-benchmark -n 1000000 -t set,get -P 16 -q
SET: 403063.28 requests per second
GET: 508388.41 requests per second
使用管道化可以大大地提高性能。
一些坑和誤區
第一點很明顯: benmark測試的黃金法則是隻比較相互有可比性的東西。例如基於相同的工作負載比較不同版本的Redis。或者使用相同版本的Redis,但是使用不同的選項運行。如果你打算把Redis和其他什麼東西進行比較,評估和考慮他們功能上和技術上的差異非常重要。
- Redis是個服務器:所有的命令在網絡和IPC的之間都需要經過一個來回的過程。把redis和內嵌數據存儲(embedded data stores)比如SQLite,Berkeley DB,Tokyo/Kyoto Cabinet等等進行比較沒有意義,因為redis大多數操作的代價花在網絡/協議管理上了。
- redis對所有常用命令都會返回一個確認。其他的數據存儲未必這樣,比如MongoDB就不確認寫操作。把redis和單向查詢的存儲比較用處不大。
- 簡單地迭代同步的Redis命令並不是測試redis,而是測算你的網絡(或者IPC)延遲。要想真正測試redis,你需要多個連接(像redis-benchmark那樣),使用多線程或多進程,使用管道化以便一次發多條命令。
- redis是一個內存數據存儲(in-memory data store),也帶一些持久化功能。如果打算把它和事務類服務器(MySQL, PostgreSQL等)進行比較,你得激活AOF,並且確定合適的fsync策略。
- redis是個單線程服務器,沒有設計成利用多核cpu獲得更多性能。如果需要的話,應該啟動多個redis實例來利用多核。將單個redis實例和多線程的數據存儲(multi-threaded data store)不大公平。
一種常見的誤區是redis-benchmark被設計成使得redis性能看上去更好,redis-benchmark的吞吐量似乎有點假,而不是由真實應用輸出的。這種認識實際是不對的。
要獲得和評估一個redis實例在給定硬件上的性能,使用redis-benchmark程序是一種快速且有用的方式。然而,默認情況下,redis-benmark並不能測出一個redis實例所能承受的最大吞吐量。實際上,通過使用管道化和快速客戶端(hiredis),寫一個吞吐量比redis-benchmark更高的程序是相當容易的。redis-benchmark的默認行為僅僅是利用並發性來達成吞吐量(即創建了好幾個連接到服務器),並沒有使用管道化或者任何並行操作(每個連接上最多一條等待處理的查詢,也沒有多線程)。
要使用管道化運行一個benchmark獲得更大吞吐量,你需要加上-P選項。注意,這樣比較切實,因為很多基於redis的應用積極使用管道化來提高性能。
最後,進行多個數據存儲比較時,benchmark應該處在相同的工作模式下,使用相同的操作。把redis-benchmark的測試結果和其他benchmark程序的結果比較和推斷,沒什麼意義。
例如,可以對redis和單線程模式的memcached基於GET/SET操作進行比較。兩個都是內存數據存儲,協議層幾乎是一樣的工作方式。如果各自的benchmark程序以同樣的方式(管道化)匯集多條查詢,並使用差不多的連接數,這樣的比較才有意義。
Redis (antirez) 和memcached (dormando) 的開發人員之間的對話就是最好的例子。
antirez 1 – On Redis, Memcached, Speed, Benchmarks and The Toilet (校對注:歡迎在ifeve.com翻譯發表此文)
dormando – Redis VS Memcached (slightly better bench) (校對注:不能訪問)
antirez 2 – An update on the Memcached/Redis benchmark
從最後的結果可以看到,考慮所有技術相關的方麵,這兩種解決方案之間的差異並沒有大得讓人出乎意料。注意,在這些性能測試之後,redis和memcached已經又進一步優化了。
最後,在測試那些高效的服務器時(redis和memcache肯定屬於這一類),其實很難讓服務達到滿負荷。有時性瓶頸在客戶端這邊,而不是服務器那邊。這種情況下,要讓服務器達到最大吞吐量,客戶端(也就是benchmark程序本身)必須得修複或擴展。
影響redis性能的因素
有多種因素會直接影響redis的性能。這裏,我們分析一些,因為它們可以改變所有benchmark測試的結果。但請注意,一個典型的redis實例,運行在低速、未調優過的係統上,提供的性能對大多數應用來說也是夠好的。
- 網絡帶寬和延遲常常是直接影響性能。啟動benchmark程序前,使用ping程序快速檢查客戶端和服務器之間的延遲是一種好習慣。關於帶寬,一般用Gbit/s來評估吞吐量,並和網絡的理論帶寬比較。例如,一個benchmark以每秒100000次設置4KB的string到redis中,將消耗2Gbit/s的帶寬,一般需要帶寬為10Gbit/s的鏈接,而不是1Gbit/s的鏈接。在很多現實的場景中,redis吞吐量先受到網絡限製,然後才是CPU。要在一台機器上整合多個高性能的redis實例,要考慮裝一塊10Gbit/s或者多塊1Gbit/s的TCP/IP網卡。
- CPU是另一個重要的因素。作為單線程的,redis喜歡高速有大緩存而不是有多個核的cpu。這場較量中,intel cpu是贏家。redis使用AMD Operon CPU時的性能隻達到使用Nehalem EP/Westmere EP/Sandy Bridge Intel CPUs時的一半,這並不稀奇。當客戶端和服務器運行在同一個係統上,cpu就是redis-benchmark的限製因素。
- ram的速度和內存帶寬對全局性能的影響則次要多了,尤其是小數據對象時。對大對象(大於10KB)而言,影響會明顯一些。一般來說,買昂貴的快速內存來優化redis並不是很經濟的做法。
- 相同的硬件上,運行在虛擬機上的redis會比運行在真實係統上的redis慢。如果可以在物理機上運行redis是最好的。當然,這並不意味著,在虛擬環境下redis就慢,處理性能依然很好,虛擬環境下,可能遇到的大多數性能問題是由於預留空間(over-provisioning),高延遲的非本地磁盤(non-local disks with high latency),或者哪些使用低速fork係統調用實現的舊管理程序(hypervisor)。
- 當服務器和客戶端benchmark程序運行同一係統上時,TCP/IP回路和unix域套接字都可使用。取決於平台,使用unix域套接字可以比使用TCP/IP回路多大約15%的吞吐量(比如在linux上)。redis-benchmark默認使用TCP/IP回路。
- 大量使用管道化(即長管道)時,比起使用TCP/IP,unix域套接字的性能提升會有所下降。
- 使用以太網訪問redis,數據大小保持小於以太網報文大小(大約1500字節),使用管道化匯集多條命令特別有效。實際上,處理10字節,100字節,1000字節的查詢幾乎是一樣的吞吐量。如下圖。
- 在有多個CPU插口的服務器上,redis的性能依賴於NUMA配置和進程位置。最明顯的是,redis-benchmark的結果似乎無法確定,因為客戶端和服務器進程隨機分配在這些核上。要得到確定性的結果,得使用進程安置工具(linux上是taskset或numactl)。最有效的組合是,總是把客戶端和服務器進程放在cpu不同的核上,充分利用起L3緩存。使用4KB的SET命令,在不同的進程安置組合下, benchmark測試三個CPU(AMD Istanbul, Intel Nehalem EX, and Intel Westmere)的結果如下。請注意,這個benchmark測試並不是為了比較CPU型號本身(這裏並未標出CPU的準確型號和頻率)。
- 使用高級配置,客戶端連接數也是很重要的因素。基於epoll/kqueue,redis的事件循環伸縮性較好。redis已經測試過超過60000連接,這些條件下,仍然能承受每秒50000次請求。經驗告訴我們,有30000連接的redis,隻能處理100連接時一半的吞吐量。下麵的例子中顯示各連接數下,redis實例對應的吞吐量:
- 在高級配置上,通過調優NIC的配置和對應的中斷,可能會獲得更高的吞吐量。通過設置和CPU核數相近的網卡隊列數,並激活RPS(Receive Packet Steering),則可以獲得最大吞吐量。更多內容清參考這裏。傳送大對象時,使用大容量幀(Jumbo frames)也可以提升性能。
- 看平台支持情況,redis可以在編譯時指定使用不同的內存分配器(libc malloc, jemalloc, tcmalloc),從原始速度(raw speed),內部和外部碎片這些方麵看,行為表現會有不同。如果不是自己編譯的redis,可以使用命令INFO查看內存分配器。和生產環境的redis相比,benchmark運行的時間不夠長,無法產生足夠多的外部碎片。
其他要考慮的事情
benchmark的一個重要目的是得到可重複的結果,這樣才能和其他測試的結果進行比較。
- 好的做法是盡可能地在孤立的硬件上運行測試。如果沒條件,則必須監控係統確保benchmark沒有受外界活動影響。
- 某些機器(桌麵和筆記本肯定支持,有些服務器也支持)支持可變的cpu 核心頻率。控製策略可以在OS層設置。某些CPU型號在改變CPU頻率適應工作負載方麵比其他型號更快。要得到可重複的結果,在測試時,最好把所有CPU核的頻率固定設在最高值。
- 根據benchmark測試,調整係統也是很重要的。係統必須要有足夠的RAM,不使用SWAP。在LINUX上不要忘記正確設置overcommit_memory參數。注意32位和64位的redis使用的內存空間是不一樣的。
- 如果打算使用RDB或AOF,請確保係統中沒有其他I/O活動。避免把RDB或AOF文件在NAS或NFS上共享,或放在其他影響網絡帶寬或延遲的設備上(比如Amazon EC2的EBS)。
- 設置redis的日誌級別(參數loglevel)為warning 或notice。避免把日誌放在遠程文件係統上。
- 避免使用影響benchmark結果的監控工具。比如,定期使用INFO收集統計信息是可以的,但MONITOR則會對測試的性能結果有較大影響。
不同虛擬機和裸機上的benchmark結果
- 同時使用50個客戶端發送2百萬請求進行測試
- 所有測試使用版本6.14
- 使用回路接口測試
- 使用1百萬的key空間測試
- 使用管道化(匯集16條命令)和不使用管道化分別測試
Intel(R) Xeon(R) CPU E5520 @ 2.27GHz (with pipelining)
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -P 16 -q
SET: 552028.75 requests per second
GET: 707463.75 requests per second
LPUSH: 767459.75 requests per second
LPOP: 770119.38 requests per second
Intel(R) Xeon(R) CPU E5520 @ 2.27GHz (without pipelining)
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q
SET: 122556.53 requests per second
GET: 123601.76 requests per second
LPUSH: 136752.14 requests per second
LPOP: 132424.03 requests per second
Linode 2048 instance (with pipelining)
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q -P 16
SET: 195503.42 requests per second
GET: 250187.64 requests per second
LPUSH: 230547.55 requests per second
LPOP: 250815.16 requests per second
Linode 2048 instance (without pipelining)
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q
SET: 35001.75 requests per second
GET: 37481.26 requests per second
LPUSH: 36968.58 requests per second
LPOP: 35186.49 requests per second
更多未使用管道化的詳細測試
$ redis-benchmark -n 100000
====== SET ======
100007 requests completed in 0.88 seconds
50 parallel clients
3 bytes payload
keep alive: 158.50% <= 0 milliseconds
99.17% <= 1 milliseconds
99.58% <= 2 milliseconds
99.85% <= 3 milliseconds
99.90% <= 6 milliseconds
100.00% <= 9 milliseconds
114293.71 requests per second====== GET ======
100000 requests completed in 1.23 seconds
50 parallel clients
3 bytes payload
keep alive: 143.12% <= 0 milliseconds
96.82% <= 1 milliseconds
98.62% <= 2 milliseconds
100.00% <= 3 milliseconds
81234.77 requests per second====== INCR ======
100018 requests completed in 1.46 seconds
50 parallel clients
3 bytes payload
keep alive: 132.32% <= 0 milliseconds
96.67% <= 1 milliseconds
99.14% <= 2 milliseconds
99.83% <= 3 milliseconds
99.88% <= 4 milliseconds
99.89% <= 5 milliseconds
99.96% <= 9 milliseconds
100.00% <= 18 milliseconds
68458.59 requests per second====== LPUSH ======
100004 requests completed in 1.14 seconds
50 parallel clients
3 bytes payload
keep alive: 162.27% <= 0 milliseconds
99.74% <= 1 milliseconds
99.85% <= 2 milliseconds
99.86% <= 3 milliseconds
99.89% <= 5 milliseconds
99.93% <= 7 milliseconds
99.96% <= 9 milliseconds
100.00% <= 22 milliseconds
100.00% <= 208 milliseconds
88109.25 requests per second====== LPOP ======
100001 requests completed in 1.39 seconds
50 parallel clients
3 bytes payload
keep alive: 154.83% <= 0 milliseconds
97.34% <= 1 milliseconds
99.95% <= 2 milliseconds
99.96% <= 3 milliseconds
99.96% <= 4 milliseconds
100.00% <= 9 milliseconds
100.00% <= 208 milliseconds
71994.96 requests per second
注意:修改包的載荷分別為256,1024,4096字節,並沒有明顯改變結果數字(但應答包被合在一起直到1024字節,因此大數據包時GET會慢些)。客戶端數量從50變到256時,結果數字是一樣的。隻有10個客戶端時,則慢一點。
不同的係統上會有不同結果。比如一個低配主機,CPU是主頻為1.66GHz 的intel coreT5500,運行著linux 2.6,測試結果如下:
$ ./redis-benchmark -q -n 100000
SET: 53684.38 requests per second
GET: 45497.73 requests per second
INCR: 39370.47 requests per second
LPUSH: 34803.41 requests per second
LPOP: 37367.20 requests per second
另一個CPU為2.5GHz Xeon L5420的64位主機上,結果如下:
$ ./redis-benchmark -q -n 100000
PING: 111731.84 requests per second
SET: 108114.59 requests per second
GET: 98717.67 requests per second
INCR: 95241.91 requests per second
LPUSH: 104712.05 requests per second
LPOP: 93722.59 requests per second
在優化過的高端服務硬件上的測試結果示例
- 版本為redis 2.4.2
- 默認數量的連接數,數據載荷為256字節
- linux主機運行著SLES10 SP3 2.6.16.60-0.54.5-smp,配備2 個主頻為93GHz的Intel X5670 CPU
- benchmark客戶端和redis運行在同一個CPU上,但在不同的核上進行測試
使用UNIX域套接字:
$ numactl -C 6 ./redis-benchmark -q -n 100000 -s /tmp/redis.sock -d 256
PING (inline): 200803.22 requests per second
PING: 200803.22 requests per second
MSET (10 keys): 78064.01 requests per second
SET: 198412.69 requests per second
GET: 198019.80 requests per second
INCR: 200400.80 requests per second
LPUSH: 200000.00 requests per second
LPOP: 198019.80 requests per second
SADD: 203665.98 requests per second
SPOP: 200803.22 requests per second
LPUSH (again, in order to bench LRANGE): 200000.00 requests per second
LRANGE (first 100 elements): 42123.00 requests per second
LRANGE (first 300 elements): 15015.02 requests per second
LRANGE (first 450 elements): 10159.50 requests per second
LRANGE (first 600 elements): 7548.31 requests per second
使用TCP回路:
$ numactl -C 6 ./redis-benchmark -q -n 100000 -d 256
PING (inline): 145137.88 requests per second
PING: 144717.80 requests per second
MSET (10 keys): 65487.89 requests per second
SET: 142653.36 requests per second
GET: 142450.14 requests per second
INCR: 143061.52 requests per second
LPUSH: 144092.22 requests per second
LPOP: 142247.52 requests per second
SADD: 144717.80 requests per second
SPOP: 143678.17 requests per second
LPUSH (again, in order to bench LRANGE): 143061.52 requests per second
LRANGE (first 100 elements): 29577.05 requests per second
LRANGE (first 300 elements): 10431.88 requests per second
LRANGE (first 450 elements): 7010.66 requests per second
LRANGE (first 600 elements): 5296.61 requests per second
最後更新:2017-05-22 09:31:59
上一篇:
《Redis官方文檔》用Redis構建分布式鎖
下一篇:
《Redis官方文檔》分區
Clojure世界:利用HouseMD診斷clojure
最小生成樹-prime-jobdu-1017
圖片移動並進行邊界判斷
控製迭代過程 防止業務流程管理失敗
???????????????Elasticsearch????????????2????????????2.2.3????????????????????????-??????-????????????-?????????
《創業在路上》賦能聯合辦公企業,做有溫度的創業社區
笛卡爾積
為什麼數據庫事務會出現未知狀態,如何處理
HTAP數據庫 PostgreSQL 場景與性能測試之 8 - (OLTP) 多值類型(數組)含索引實時寫入
nginx.conf 配置文件中文說明