1. 程式人生 > 程式設計 >一文搞懂 Redis降低記憶體佔用方式

一文搞懂 Redis降低記憶體佔用方式

前言

Redis是當前比較熱門的NOSQL資料庫之一,和Memcache一樣,資料都是快取在計算機記憶體中。完全開源免費,遵守BSD協議,是一個高效能的key-value資料庫。通過在記憶體中讀寫資料,大大提高了資料讀寫速度,可以說Redis是實現網站高併發不可或缺的一部分。

降低Redis的記憶體佔用有助於減少建立快照和載入快照所需的時間、提升載入AOF檔案和重寫AOF檔案時的效率、縮短從伺服器進行同步所需的時間”,並且能讓Redis儲存更多的資料而無需新增額外的硬體。

本文將介紹以下3種非常有價值的降低Redis記憶體佔用的方法。

  • 短結構( short structure )
  • 分片結構( shared structure )
  • 打包儲存二進位制位和位元組

短結構

Redis為列表、集合、雜湊、有序集合提供了一組配置選項,這些選項可以讓redis以更節約的方式儲存較短的結構。

ziplist壓縮列表(列表、雜湊、有序集合)

通常情況下使用的儲存方式:

當列表、雜湊、有序集合的長度較短或者體積較小的時候,redis將會採用一種名為ziplist的緊湊儲存方式來儲存這些結構。

ziplist是列表、雜湊、有序集合這三種不同型別的物件的一種非結構化表示,它會以序列化的方式儲存資料,這些序列化的資料每次被讀取的時候都需要進行解碼,每次寫入的時候也要進行編碼。

雙向列表與壓縮列表的區別:

為了瞭解壓縮列表比其他資料結構更加節約記憶體,我們以列表結構為例進行深入研究。

典型的雙向列表

在典型雙向列表裡面,每個值都都會有一個節點表示。每個節點都會帶有指向連結串列前一個節點和後一個節點的指標,以及一個指向節點包含的字串值的指標。

每個節點包含的字串值都會分為三部分進行儲存。包括字串長度、字串值中剩餘可用位元組數量、以空字元結尾的字串本身。

例子:

假若一個某個節點儲存了’abc’字串,在32位的平臺下保守估計需要21個位元組的額外開銷(三個指標+兩個int+空字元即:3*4+2*4+1=21)

由例子可知儲存一個3位元組字串就需要付出至少21個位元組的額外開銷。

ziplist

壓縮列表是由節點組成的序列,每個節點包含兩個長度和一個字串。第一個長度記錄前一個節點的長度(用於對壓縮列表從後向前遍歷);第二個長度是記錄本當前點的長度;被儲存的字串。

例子:

儲存字串’abc’,兩個長度都可以用1位元組來儲存,因此所帶來的額外開銷為2位元組(兩個長度即1+1=2)

結論:

壓縮列表是通過避免儲存額外的指標和元資料,從而達到降低額外的開銷。

intset整數集合(集合)

前提條件,集合中包含的所有member都可以被解析為十進位制整數。

以有序陣列的方式儲存集合不僅可以降低記憶體消耗,還可以提升集合操作的執行速度。

配置:

1 set-max-intset-entries 512 #限制集合中member個數,超出則不採取intset儲存複製程式碼

效能問題

不管列表、雜湊、有序集合、集合,當超出限制的條件後,就會轉換為更為典型的底層結構型別。因為隨著緊湊結構的體積不斷變大,操作這些結構的速度將會變得越來越慢。 

分片結構

分片的本質就是基於簡單的規則將資料劃分為更小的部分,然後根據資料所屬的部分來決定將資料傳送到哪個位置上。很多資料庫使用這種技術來擴充套件儲存空間,並提高自己所能處理的負載量。

結合前面講到的,我們不難發現分片結構對於redis的重要意義。因此我們需要在配置檔案中關於ziplist以及intset的相關配置做出適當的調整。

回到頂部

分片式雜湊

雜湊分片主要是根據基礎鍵以及雜湊包含的鍵計算出分片鍵ID,然後再與基礎鍵拼接成一個完整的分片鍵。在執行hset與hget以及大部分hash命令時,都需要先將key(field)通過shardKey方法處理,得到分片鍵才能夠進行下一步操作。

分片式集合

如何構造分片式集合才能夠讓它更節省記憶體,效能更加強大呢?主要的思路就是,將集合裡面的儲存的資料儘量在不改變其原有功能的情況下轉換成可以被解析為十進位制的資料。根據前面所講到的,當集合中的所有成員都能夠被解析為十進位制資料時,將會採用intset儲存方式,這不僅能夠節省記憶體,而且還可以提高響應的效能。

例子:

假若要某個大型網站需要儲存每一天的唯一使用者訪問量。那麼就可以使用將使用者的唯一識別符號轉化成十進位制數字,再存入分片式set中。

打包儲存二進位制位和位元組

結合前面所講的分片技術,採用string分片結構為大量連續的ID使用者儲存資訊。

使用定長字串,為每一個ID分配n個位元組進行儲存相應的資訊。

接下來我們將採用儲存使用者國家、省份的例子進行講解:

假若某個使用者需要儲存中國、廣東省這兩個資訊,採用utf8字符集,那麼至少需要消耗5*3=15個位元組。如果網站的使用者量大的話,這樣的做法將會佔用很多資源。接下來我們採用的方法每個使用者僅僅只需要佔用兩個位元組就可以完成儲存資訊。

具體思路步驟:

  1. 首先我們為國家、以及各國家的省份資訊建立相應的’資訊表格’
  2. 將’資訊表格’建好後,也意味著每個國家,省份都有相應的索引號
  3. 看到這裡大家應該都想到了吧,對就是使用兩個索引作為使用者儲存的資訊,不過需要注意的是我們還需要對這兩個索引進行相應的處理
  4. 將索引當做ASCII碼,將其轉換為對應ASCII(0~255)所指定的字元
  5. 使用前面所講的分片技術,定長分片string結構,將使用者的儲存位置找出來(redis中一個string不能超過512M)
  6. 實現資訊的寫入以及取出(getrange、setrange)


由於平臺篇幅限制,為了大家更好的閱讀,關於Redis的檔案小編已經打包整理好了,有感興趣的程式猿(媛),可以加 QQ群 538700182 私聊群主 免費獲取