Redis Performance Optimization

Posted by Joe's Notes on Tuesday, December 31, 2019

TOC

1. 使用Pipeline

Redis client跟server之間的溝通是透過TCP來傳輸。每一次的command都有TCP連線傳輸的代價。因此如果有多個command要執行,可以藉由pipeline來減少TCP的overhead.

<?php
$pipe = $redis->multi(Redis::PIPELINE);   
for ($i = 0; $i <  10000; $i++) {   
    $pipe->set("key::$i", str_pad($i, 4, '0', 0));   
    $pipe->get("key::$i");   
}   
$replies = $pipe->exec(); 

2. 使用 multi-argument commands

因為Redis是single process的程式,因此當一瞬間湧入大量的command時,你會發現平均的latency變長了。這是因為command必須等待前面的command被執行完才輪的到他。因此很明顯的,當如果同時有大量的操作時,使用可同時對多個key/filed操作的command將可以改善這個問題。 例如

set key1 val1
set key2 val2

改成更有效率的方式

mset key1 val1 key2 val2

下面條列出原始和對應優化的方案:

SingleArgumentCommand Single-Argument Description Multi-Argument Alternative Multi-Argument Description
SET set the value of key MSET Set multiple keys to multiple values
GET get the value of key MGET Get the values of all the given keys
LSET set value of an element in a list LPUSH/RPUSH Prepend/append multiple values to a list
LINDEX get an element from a list LRANGE Get a range of elements from a list
HSET set the string value of a hash HMSET Set multiple hash fields to multiple values
HGET get the value of a hash field HMGET Get the values of all the given hash fields

3. 避免 slow commands for large sets

除了command個數會影響Redis的效能,高時間複雜度的command會大量的使用CPU資源而直接的影響Redis效能。要記得Redis是single process的程式,而且Redis本身scale out是非常麻煩的。因此當使用大量消耗CPU的command的時候,將會影響Redis的整體表現甚至出現服務中斷。 因此,避免使用這類的command會是比較好的作法。

如果真的要使用的話,盡量減少操作的key數或者是資料的大小。另外由於List是double linked list的結構,因此對index的操作是沒有效率的。

Command Description Improve Performance By
ZINTERSTORE 取得多個sorted set的交集並存到新的key 降低set的大小或key的個數
SINTERSTORE 取得多個set的交集並存到新的key 降低set的大小或key的個數
SINTER 取得多個set的交集 降低set的大小或key的個數
MIGRATE 將key從某個redis轉移到新的redis 降低該key的大小
DUMP 取得key值得serialized value 降低大小
ZREM 刪除一個或多個sorted set的element 降低sorted set的element個數
ZUNIONSTORE 將多個sorted set的element聯集存到新的key 降低聯集的key數或sorted set的大小
SORT 將list/set排序 降低list/set大小
SDIFFSTORE 取得多個sorted set間的差集並存到新的key 降低key數或sorted set的大小
SDIFF 取得多個sorted set間的差集 降低key數或sorted set的大小
SUNION 取得多個sorted set間的聯集 降低key數或sorted set的大小
LSET 設置list裡某個index的值 降低list大小
LREM 刪除某個list的某個index 降低list大小
LRANGE 取得list某個區間內的值 降低list大小

4. Special encoding of small aggregate data types

Redis 的Set的結構在值比較小的時候(entry 小於 hash-max-ziplist-entries及element 小於 hash-max-ziplist-value)會使用zipmap儲存,而zipmap佔用的memory非常的少。所以舉例來說,如果使用hash來取代key/value的方式紀錄譬如使用者是否要收到通知可以得到更好的memory效率(這個是以計算換取空間,消耗多一點的計算量來降低記憶體的使用,必須自己權衡)。 e.g. 使用key/value紀錄

for($uid=0;$uid<1000000,$uid++){
    $redis->set($uid,1);
}

使用set紀錄

for($uid=0;$uid<1000000,$uid++){
    $key=(int)($uid/100);
    $redis->hset($key,$uid,1);
}

使用set儲存可以節省100倍以上的空間(200MB->20MB)

5. 縮短你的key

別忘記key也是需要消耗記憶體的,當你的key一多,加成效應是很恐怖的。例如你的key是 user_access_token:{uid}, 想像一下如果你有一百萬個用戶,這麼多key要耗掉多少記憶體啊?所以縮短一下key名稱會是個好主意。

「您的支持是創作的原動力」

Joe's Notes

您的支持是創作的原動力

使用Wechat(微信))掃描QR Code贊助我吧!


comments powered by Disqus