Redis優化建議

Redis優化建議


優化的一些建議

1、儘量使用短的 key

當然在精簡的同時,不要忘了 key 的 “見名知意”。對於 value 有些也可精簡,比如性別使用 0、1。

2、避免使用 keys *

keys *, 這個命令是阻塞的,即操作執行期間,其它任何命令在你的實例中都無法執行。當 redis 中 key 數據量小時到無所謂,數據量大就很糟糕了。所以我們應該避免去使用這個命令。可以去使用 SCAN, 來代替。

3、在存到 Redis 之前先把你的數據壓縮下

redis 為每種數據類型都提供了兩種內部編碼方式,在不同的情況下 redis 會自動調整合適的編碼方式。

4、設置 key 有效期

我們應該儘可能的利用 key 有效期。比如一些臨時數據(短信校驗碼),過了有效期 Redis 就會自動為你清除!

5、選擇回收策略 (maxmemory-policy)

當 Redis 的實例空間被填滿了之後,將會嘗試回收一部分 key。根據你的使用方式,強烈建議使用 volatile-lru(默認) 策略 —— 前提是你對 key 已經設置了超時。但如果你運行的是一些類似於 cache 的東西,並且沒有對 key 設置超時機制,可以考慮使用 allkeys-lru 回收機制,具體講解查看 。maxmemory-samples 3 是說每次進行淘汰的時候 會隨機抽取 3 個 key 從裡面淘汰最不經常使用的(默認選項)

maxmemory-policy 六種方式 :

  • volatile-lru:只對設置了過期時間的 key 進行 LRU(默認值)
  • allkeys-lru : 是從所有 key 裡 刪除 不經常使用的 key
  • volatile-random:隨機刪除即將過期 key
  • allkeys-random:隨機刪除
  • volatile-ttl : 刪除即將過期的
  • noeviction : 永不過期,返回錯誤

6、使用 bit 位級別操作和 byte 字節級別操作來減少不必要的內存使用。

  • bit 位級別操作:GETRANGE, SETRANGE, GETBIT and SETBIT
  • byte 字節級別操作:GETRANGE and SETRANGE

7、儘可能地使用 hashes 哈希存儲。

8、當業務場景不需要數據持久化時,關閉所有的持久化方式可以獲得最佳的性能。

9、想要一次添加多條數據的時候可以使用管道。

10、限制 redis 的內存大小(64 位系統不限制內存,32 位系統默認最多使用 3GB 內存)

數據量不可預估,並且內存也有限的話,儘量限制下 redis 使用的內存大小,這樣可以避免 redis 使用 swap 分區或者出現 OOM 錯誤。(使用 swap 分區,性能較低,如果限制了內存,當到達指定內存之後就不能添加數據了,否則會報 OOM 錯誤。可以設置 maxmemory-policy,內存不足時刪除數據。)

11、SLOWLOG [get/reset/len]

  • slowlog-log-slower-than 它決定要對執行時間大於多少微秒 (microsecond,1 秒 = 1,000,000 微秒) 的命令進行記錄。
  • slowlog-max-len 它決定 slowlog 最多能保存多少條日誌,當發現 redis 性能下降的時候可以查看下是哪些命令導致的。

優化實例分析

管道性能測試

redis 的管道功能在命令行中沒有,但是 redis 是支持管道的,在 java 的客戶端 (jedis) 中是可以使用的:

Redis優化建議


示例代碼

<code>     
     
    @

Test     

public

 

void

 

NOTUsePipeline

 (

) throws Exception

 {         Jedis jedis = JedisUtil.getJedis ();         

long

 start_time = System.currentTimeMillis ();         

for

 (

int

 i = 

0

; i 10000; i++) {             jedis.

set

 (

"aa_"

+i, i+

""

);         }         System.

out

.println (System.currentTimeMillis ()-start_time);     }          @

Test     

public

 

void

 

usePipeline

 (

) throws Exception

 {         Jedis jedis = JedisUtil.getJedis ();         

long

 start_time = System.currentTimeMillis ();         Pipeline pipelined = jedis.pipelined ();         

for

 (

int

 i = 

0

; i 10000; i++) {             pipelined.

set

 (

"cc_"

+i, i+

""

);         }         pipelined.sync ();         System.

out

.println (System.currentTimeMillis ()-start_time);     }/<code>

hash 的應用

示例:我們要存儲一個用戶信息對象數據,包含以下信息: key 為用戶 ID,value 為用戶對象(姓名,年齡,生日等)如果用普通的 key/value 結構來存儲,主要有以下 2 種存儲方式:

  • 將用戶 ID 作為查找 key, 把其他信息封裝成一個對象以序列化的方式存儲 缺點:增加了序列化 / 反序列化的開銷,引入複雜適應系統(Complex adaptive system,簡稱 CAS)修改其中一項信息時,需要把整個對象取回,並且修改操作需要對併發進行保護。
Redis優化建議


  • 用戶信息對象有多少成員就存成多少個 key-value 對 雖然省去了序列化開銷和併發問題,但是用戶 ID 為重複存儲。
Redis優化建議


  • Redis 提供的 Hash 很好的解決了這個問題,提供了直接存取這個 Map 成員的接口。Key 仍然是用戶 ID, value 是一個 Map,這個 Map 的 key 是成員的屬性名,value 是屬性值。( 內部實現:Redis Hashd 的 Value 內部有 2 種不同實現,Hash 的成員比較少時 Redis 為了節省內存會採用類似一維數組的方式來緊湊存儲,而不會採用真正的 HashMap 結構,對應的 value redisObject 的 encoding 為 zipmap, 當成員數量增大時會自動轉成真正的 HashMap, 此時 encoding 為 ht )。
Redis優化建議

Instagram 內存優化

Instagram 可能大家都已熟悉,當前火熱的拍照 App,月活躍用戶 3 億。四年前 Instagram 所存圖片 3 億多時需要解決一個問題:想知道每一張照片的作者是誰(通過圖片 ID 反查用戶 UID),並且要求查詢速度要相當的快,如果把它放到內存中使用 String 結構做 key-value:

<code>

HSET

 

"mediabucket:1155"

 

"1155315"

 

"939"

HGET 

"mediabucket:1155"

 

"1155315"

"939"

/<code>

測試:1 百萬數據會用掉 70MB 內存,3 億張照片就會用掉 21GB 的內存。當時 (四年前) 最好是一臺 EC2 的 high-memory 機型就能存儲(17GB 或者 34GB 的,68GB 的太浪費了), 想把它放到 16G 機型中還是不行的。

Instagram 的開發者向 Redis 的開發者之一 Pieter Noordhuis 詢問優化方案,得到的回覆是使用 Hash 結構。具體的做法就是將數據分段,每一段使用一個 Hash 結構存儲.

由於 Hash 結構會在單個 Hash 元素在不足一定數量時進行壓縮存儲,所以可以大量節約內存。這一點在上面的 String 結構裡是不存在的。而這個一定數量是由配置文件中的 hash-zipmap-max-entries 參數來控制的。經過實驗,將 hash-zipmap-max-entries 設置為 1000 時,性能比較好,超過 1000 後 HSET 命令就會導致 CPU 消耗變得非常大。

<code>

HSET

 

"mediabucket:1155"

 

"1155315"

 

"939"

HGET 

"mediabucket:1155"

 

"1155315"

"939"

/<code>

測試:1 百萬消耗 16MB 的內存。總內存使用也降到了 5GB。當然我們還可以優化,去掉 mediabucket:key 長度減少了 12 個字節。

<code>

HSET

 

"1155"

 

"315"

 

"939"

HGET 

"1155"

 

"315"

"939"

/<code>

啟動時 WARNING 優化

在我們啟動 redis 時,默認會出現如下三個警告:

Redis優化建議


  • 一、修改 linux 中 TCP 監聽的最大容納數量
<code>WARNING: The TCP backlog setting of 511 cannot be enforced because 
/proc/sys/net/core/somaxconn is 

set

 

to

 the 

lower

 

value

 

of

 

128.

/<code>

在高併發環境下你需要一個高 backlog 值來避免慢客戶端連接問題。注意 Linux 內核默默地將這個值減小到 /proc/sys/net/core/somaxconn 的值,所以需要確認增大 somaxconn 和 tcp_max_syn_backlog 兩個值來達到想要的效果。

<code>echo 

511

 > 

/proc/sys

/net/core

/somaxconn

/<code>

注意:這個參數並不是限制 redis 的最大鏈接數。如果想限制 redis 的最大連接數需要修改 maxclients,默認最大連接數為 10000

  • 二、修改 linux 內核內存分配策略
<code>錯誤日誌:WARNING overcommit_memory is 

set

 

to

 

0

! Background 

save

 may fail 

under

 

low

 

memory

 condition. 

To

 fix this issue 

add

 

'vm.overcommit_memory = 1'

 

to

 /etc/sysctl.conf 

and

 

then

 reboot 

or

  run the command

'sysctl vm.overcommit_memory=1'

/<code>

原因: redis 在備份數據的時候,會 fork 出一個子進程,理論上 child 進程所佔用的內存和 parent 是一樣的,比如 parent 佔用的內存為 8G,這個時候也要同樣分配 8G 的內存給 child, 如果內存無法負擔,往往會造成 redis 服務器的 down 機或者 IO 負載過高,效率下降。所以內存分配策略應該設置為 1(表示內核允許分配所有的物理內存,而不管當前的內存狀態如何)。

內存分配策略有三種

可選值:0、1、2。

  • 0, 表示內核將檢查是否有足夠的可用內存供應用進程使用;如果有足夠的可用內存,內存申請允許;否則,內存申請失敗,並把錯誤返回給應用進程。
  • 1, 不管需要多少內存,都允許申請。
  • 2, 只允許分配物理內存和交換內存的大小 (交換內存一般是物理內存的一半)。
  • 三、關閉 Transparent Huge Pages (THP)

THP 會造成內存鎖影響 redis 性能,建議關閉

<code>Transparent HugePages :用來提高內存管理的性能
Transparent Huge Pages 在 

32

 位的 RHEL 

6

 中是不支持的 執行命令 echo never > 

/sys/kernel

/mm/transparent

_hugepage/enabled 把這條命令添加到這個文件中 /etc/rc.local/<code>


分享到:


相關文章: