Redis 延遲考慮

2018-08-03 11:14 更新

1. 盡可能使用批量操作:

  • mget、hmget而不是get和hget,對(duì)于set也是如此。
  • lpush向一個(gè)list一次性導(dǎo)入多個(gè)元素,而不用lset一個(gè)個(gè)添加
  • LRANGE 一次取出一個(gè)范圍的元素,也不用LINDEX一個(gè)個(gè)取出

2. 盡可能的把redis和APP SERVER部署在一個(gè)網(wǎng)段甚至一臺(tái)機(jī)器。

3. 對(duì)于數(shù)據(jù)量較大的集合,不要輕易進(jìn)行刪除操作,這樣會(huì)阻塞服務(wù)器,一般采用重命名+批量刪除的策略:

排序集合:

# Rename the key
newkey = "gc:hashes:" + redis.INCR("gc:index")
redis.RENAME("my.zset.key", newkey)

# Delete members from the sorted set in batche of 100s
while redis.ZCARD(newkey) > 0
  redis.ZREMRANGEBYRANK(newkey, 0, 99)
end

集合:

# Rename the key
newkey = "gc:hashes:" + redis.INCR("gc:index")
redis.RENAME("my.set.key", newkey)

# Delete members from the set in batches of 100
cursor = 0
loop
  cursor, members = redis.SSCAN(newkey, cursor, "COUNT", 100)
  if size of members > 0
redis.SREM(newkey, members)
  end
  if cursor == 0
break
  end
end

列表:

# Rename the key
newkey = "gc:hashes:" + redis.INCR("gc:index")
redis.RENAME("my.list.key", newkey)

# Trim off elements in batche of 100s
while redis.LLEN(newkey) > 0
  redis.LTRIM(newkey, 0, -99)
end

Hash:

# Rename the key
newkey = "gc:hashes:" + redis.INCR( "gc:index" )
redis.RENAME("my.hash.key", newkey)

# Delete fields from the hash in batche of 100s
cursor = 0
loop
  cursor, hash_keys = redis.HSCAN(newkey, cursor, "COUNT", 100)
  if hash_keys count > 0
redis.HDEL(newkey, hash_keys)
  end
  if cursor == 0
break
  end
end

4. 盡可能使用不要超過(guò)1M大小的kv。

5. 減少對(duì)大數(shù)據(jù)集的高時(shí)間復(fù)雜度的操作:根據(jù)復(fù)雜度計(jì)算,如下命令可以優(yōu)化:

6. 盡可能使用pipeline操作:一次性的發(fā)送命令比一個(gè)個(gè)發(fā)要減少網(wǎng)絡(luò)延遲和單個(gè)處理開(kāi)銷。一個(gè)性能測(cè)試結(jié)果為(注意并不是pipeline越大效率越高,注意最后一個(gè)測(cè)試結(jié)果) :

logger@BIGD1TMP:~> redis-benchmark -q -r 100000 -n 1000000 -c 50 
PING_INLINE: 90155.07 requests per second
PING_BULK: 92302.02 requests per second
SET: 85070.18 requests per second
GET: 86184.61 requests per second

logger@BIGD1TMP:~> redis-benchmark -q -r 100000 -n 1000000 -c 50 -P 10
PING_INLINE: 558035.69 requests per second
PING_BULK: 668002.69 requests per second
SET: 275027.50 requests per second
GET: 376647.84 requests per second

logger@BIGD1TMP:~> redis-benchmark -q -r 100000 -n 1000000 -c 50 -P 20
PING_INLINE: 705716.25 requests per second
PING_BULK: 869565.25 requests per second
SET: 343406.59 requests per second
GET: 459347.72 requests per second

logger@BIGD1TMP:~> redis-benchmark -q -r 100000 -n 1000000 -c 50 -P 50
PING_INLINE: 940733.81 requests per second
PING_BULK: 1317523.00 requests per second
SET: 380807.31 requests per second
GET: 523834.47 requests per second

logger@BIGD1TMP:~> redis-benchmark -q -r 100000 -n 1000000 -c 50 -P 100
PING_INLINE: 999000.94 requests per second
PING_BULK: 1440922.12 requests per second
SET: 386996.88 requests per second
GET: 602046.94 requests per second

logger@BIGD1TMP:~> redis-benchmark -q -r 100000 -n 1000000 -c 50 -P 200
PING_INLINE: 1078748.62 requests per second
PING_BULK: 1381215.50 requests per second
SET: 379218.81 requests per second
GET: 537634.38 requests per second

一個(gè)場(chǎng)景是一個(gè)購(gòu)物車的設(shè)計(jì),一般的設(shè)計(jì)思路是:

 

在獲取購(gòu)物車內(nèi)部貨品時(shí),不使用pipeline會(huì)很低效: 

可以修改為:

 

7. 如果出現(xiàn)頻繁對(duì)string進(jìn)行append操作,則請(qǐng)使用list進(jìn)行push操作,取出時(shí)使用pop。這樣避免string頻繁分配內(nèi)存導(dǎo)致的延時(shí)。

8. 如果要sort的集合非常大的話排序就會(huì)消耗很長(zhǎng)時(shí)間。由于redis單線程的,所以長(zhǎng)時(shí)間的排序操作會(huì)阻塞其他client的 請(qǐng)求。解決辦法是通過(guò)主從復(fù)制機(jī)制將數(shù)據(jù)復(fù)制到多個(gè)slave上。然后我們只在slave上做排序操作。把可能的對(duì)排序結(jié)果緩存。另外就是一個(gè)方案是就是采用sorted set對(duì)需要按某個(gè)順序訪問(wèn)的集合建立索引。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)