redis預估記憶體應用案例

2021-08-26 08:33:53 字數 2681 閱讀 5033

要估算redis中的資料佔據的記憶體大小,需要對redis的記憶體模型有比較全面的了解,包括前面介紹的hashtable、sds、redisobject、各種物件型別的編碼方式等。

下面以最簡單的字串型別來進行說明。

假設有90000個鍵值對,每個key的長度是7個位元組,每個value的長度也是7個位元組(且key和value都不是整數);下面來估算這90000個鍵值對所占用的空間。在估算佔據空間之前,首先可以判定字串型別使用的編碼方式:embstr。

90000個鍵值對佔據的記憶體空間主要可以分為兩部分:

一部分是90000個dictentry佔據的空間;一部分是鍵值對所需要的bucket空間。

每個dictentry佔據的空間包括:

1) 乙個dictentry,24位元組,jemalloc會分配32位元組的記憶體塊

2) 乙個key,7位元組,所以sds(key)需要7+9=16個位元組,jemalloc會分配16位元組的記憶體塊

3) 乙個redisobject,16位元組,jemalloc會分配16位元組的記憶體塊

4) 乙個value,7位元組,所以sds(value)需要7+9=16個位元組,jemalloc會分配16位元組的記憶體塊

5) 綜上,乙個dictentry需要32+16+16+16=80個位元組。

bucket空間:bucket陣列的大小為大於90000的最小的2^n,是131072;每個bucket元素為8位元組(因為64位系統中指標大小為8位元組)。

因此,可以估算出這90000個鍵值對佔據的記憶體大小為:90000*80 + 131072*8 = 8248576。

public

class redistest

public

static

void

insertdata()

}  public

static string getmemory()

}

預估答案8248576。

執行結果:8247552

理論值與結果值誤差在萬分之1.2,對於計算需要多少記憶體來說,這個精度已經足夠了。之所以會存在誤差,是因為在我們插入90000條資料之前redis已分配了一定的bucket空間,而這些bucket空間尚未使用。

作為對比將key和value的長度由7位元組增加到8位元組,則對應的sds變為17個位元組,jemalloc會分配32個位元組,因此每個dictentry占用的位元組數也由80位元組變為112位元組。此時估算這90000個鍵值對佔據記憶體大小為:90000*112 + 131072*8 = 11128576。

在redis中驗證**如下(只修改插入資料的**):

public

static

void

insertdata()

}

執行結果:11128576;估算準確。

對於字串型別之外的其他型別,對記憶體占用的估算方法是類似的,需要結合具體型別的編碼方式來確定。

了解redis的記憶體模型,對優化redis記憶體占用有很大幫助。下面介紹幾種優化場景。

上一小節所講述的90000個鍵值便是乙個例子。由於jemalloc分配記憶體時數值是不連續的,因此key/value字串變化乙個位元組,可能會引起占用記憶體很大的變動;在設計時可以利用這一點。

例如,如果key的長度如果是8個位元組,則sds為17位元組,jemalloc分配32位元組;此時將key長度縮減為7個位元組,則sds為16位元組,jemalloc分配16位元組;則每個key所占用的空間都可以縮小一半。

如果是整型/長整型,redis會使用int型別(8位元組)儲存來代替字串,可以節省更多空間。因此在可以使用長整型/整型代替字串的場景下,盡量使用長整型/整型。

利用共享物件,可以減少物件的建立(同時減少了redisobject的建立),節省記憶體空間。目前redis中的共享物件只包括10000個整數(0-9999);可以通過調整redis_shared_integers引數提高共享物件的個數;例如將redis_shared_integers調整到20000,則0-19999之間的物件都可以共享。

考慮這樣一種場景:論壇**在redis中儲存了每個帖子的瀏覽數,而這些瀏覽數絕大多數分布在0-20000之間,這時候通過適當增大redis_shared_integers引數,便可以利用共享物件節省記憶體空間。

然而需要注意的是,不論是哪種優化場景,都要考慮記憶體空間與設計複雜度的權衡;而設計複雜度會影響到**的複雜度、可維護性。

如果資料量較小,那麼為了節省記憶體而使得**的開發、維護變得更加困難並不划算;還是以前面講到的90000個鍵值對為例,實際上節省的記憶體空間只有幾mb。但是如果資料量有幾千萬甚至上億,考慮記憶體的優化就比較必要了。

記憶體碎片率是乙個重要的引數,對redis 記憶體的優化有重要意義。

如果記憶體碎片率過高(jemalloc在1.03左右比較正常),說明記憶體碎片多,記憶體浪費嚴重;這時便可以考慮重啟redis服務,在記憶體中對資料進行重排,減少記憶體碎片。

如果記憶體碎片率小於1,說明redis記憶體不足,部分資料使用了虛擬記憶體(即swap);由於虛擬記憶體的訪問速度比物理記憶體差很多(2-3個數量級),此時redis的訪問速度可能會變得很慢。因此必須設法增大物理記憶體(可以增加伺服器節點數量,或提高單機記憶體),或減少redis中的資料。

要減少redis中的資料,除了選用合適的資料型別、利用共享物件等,還有一點是要設定合理的資料**策略(maxmemory-policy),當記憶體達到一定量後,根據不同的優先順序對記憶體進行**。

redis樂觀鎖應用案例實踐

專車系統給司機派單時,需要過濾掉已經派單的司機,防止出現將不同訂單派單給同個司機的情況發生。以下讀寫操作均是指redis進行讀寫。目前系統裡以城市維度儲存了每個城市已經處於服務中 已派過訂單 的司機列表,但讀取城市服務中司機列表和寫服務中司機列表時,未進行同步,可能由於高併發,會導致讀的司機列表在執...

redis使用案例

1.計數器 string 單執行緒,避免併發問題,保證不會出錯,毫秒級效能 命令 incrby incrby 2.佇列 list 簡單訊息佇列 使用者第幾個訪問 新聞列表排序 由於redis把資料新增到佇列是返回新增元素在佇列的第幾位,所以可以做判斷使用者是第幾個訪問這種業務 新聞列表頁面最新的新聞...

linux eventfd 應用案例

include include include include include include include include int evfd void f void p printf pid d exit n pthread self int main int argc,char argv ev...