Redis的內存優化

Redis所有數據都在內存中,用戶自然會想到如何有效的使用內存。Redis的作者已考慮了內存的優化,所以從用戶的角度,Redis內存的優化包括兩個方面,一個是Redis Server本省對內存的優化,一個是應用方面的優化。


Redis Server本身對內存的優化


1.存儲編碼的優化


Redis存儲的數據都使用redisObject結構體來封裝,包括string、hash、list、set和zset在內的所有數據類型。


redisObject結構體如下所示:


redisObject

 type - 對象類型

 encoding - 內部編碼類型

 lru - LRU計時時鐘

 int refcount - 引用計數器

 void *ptr - 數據指針


在redisObject中有個encoding字段,表示Redis內部編碼類型,同一個對象採用不同的編碼實現內存佔用存在明顯差異。


對於編碼優化的配置,可參考redis.conf:


# Lists are also encoded in a special way to save a lot of space.

# The number of entries allowed per internal list node can be specified

# as a fixed maximum size or a maximum number of elements.

# For a fixed maximum size, use -5 through -1, meaning:

# -5: max size: 64 Kb  <-- not recommended for normal workloads

# -4: max size: 32 Kb  <-- not recommended

# -3: max size: 16 Kb  <-- probably not recommended

# -2: max size: 8 Kb   <-- good

# -1: max size: 4 Kb   <-- good

# Positive numbers mean store up to _exactly_ that number of elements

# per list node.

# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size),

# but if your use case is unique, adjust the settings as necessary.

list-max-ziplist-size -2


# Lists may also be compressed.

# Compress depth is the number of quicklist ziplist nodes from *each* side of

# the list to *exclude* from compression.  The head and tail of the list

# are always uncompressed for fast push/pop operations.  Settings are:

# 0: disable all list compression

# 1: depth 1 means "don't start compressing until after 1 node into the list,

#    going from either the head or tail"

#    So: [head]->node->node->...->node->[tail]

#    [head], [tail] will always be uncompressed; inner nodes will compress.

# 2: [head]->[next]->node->node->...->node->[prev]->[tail]

#    2 here means: don't compress head or head->next or tail->prev or tail,

#    but compress all nodes between them.

# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail]

# etc.

list-compress-depth 0


# Hashes are encoded using a memory efficient data structure when they have a

# small number of entries, and the biggest entry does not exceed a given

# threshold. These thresholds can be configured using the following directives.

hash-max-ziplist-entries 512

hash-max-ziplist-value 64


# Sets have a special encoding in just one case: when a set is composed

# of just strings that happen to be integers in radix 10 in the range

# of 64 bit signed integers.

# The following configuration setting sets the limit in the size of the

# set in order to use this special memory saving encoding.

set-max-intset-entries 512


# Similarly to hashes and lists, sorted sets are also specially encoded in

# order to save a lot of space. This encoding is only used when the length and

# elements of a sorted set are below the following limits:

zset-max-ziplist-entries 512

zset-max-ziplist-value 64



2.共享對象池(Java中也存在類似優化)


共享對象池是指Redis內部維護了[0-9999]的整數對象池,用於節約內存。除了整數值對象,其它類型如list、hash、set和zset內部元素也可以使用整數對象池。


但要注意當設置maxmemory,並啓用LRU相關淘汰策略如,volatile-lru,allkeys-lru時,Redis禁止使用共享對象池。LRU算法需要獲取對象最後被訪問時間,以便淘汰最長未訪問數據,每個對象最後訪問時間存儲在redisObject對象的lru字段。對象共享意味着多個引用共享同一個RedisObject,這時lru字段也會被共享,導致無法獲取每個對象的最後訪問時間。



3.字符串優化


Redis沒有采用原生C語言的字符串類型,而是自己實現了字符串結構,簡單動態字符串(simple dynamic string,SDS)。其內部實現空間預分配機制,降低內存再分配次數。但要防止預分配,帶來的內存浪費。儘量減少字符串頻繁修改操作append、setrange,改爲直接使用set修改字符串,降低預分配帶來的內存浪費和內存碎片。



應用方面的優化


1.控制鍵的數量,使用hash代替多個key value。


使用Redis不要進入一個誤區,大量使用get/set這樣的API,把其當成Memcached使用。對於存儲相同的數據內容,利用Redis的數據結構降低外層鍵的數量,也可以節省大量內存。



2.縮減鍵值對象


對key長度,設計鍵時,在完整描述業務情況下,鍵值越短越好。

value長度,值對象縮減比較複雜,常見的做法是把業務對象序列化成二進制數組放入Redis,這時就要選擇更高效的序列化工具。值對象除了存儲二進制數據之外,通常還會使用通用格式存儲數據比如json、xml等作爲字符串存儲在Redis中,可使用通用壓縮算法壓縮json、xml後再存入Redis,從而降低內存佔用。



重點參考2個鏈接:

https://redis.io/topics/data-types-intro

https://redis.io/topics/memory-optimization


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章