Redis壓縮列表

来源:https://www.cnblogs.com/thomson-fred/archive/2019/02/07/10354357.html
-Advertisement-
Play Games

此篇文章是主要介紹Redis在數據存儲方面的其中一種方式,壓縮列表。本文會介紹1. 壓縮列表(ziplist)的使用場景 2.如何達到節約記憶體的效果?3.壓縮列表的存儲格式 4. 連鎖更新的問題 5. conf文件配置。在實踐上的操作主要是對conf配置文件進行配置,具體上沒有確切的一個值,更多是經 ...


此篇文章是主要介紹Redis在數據存儲方面的其中一種方式,壓縮列表。本文會介紹1. 壓縮列表(ziplist)的使用場景 2.如何達到節約記憶體的效果?3.壓縮列表的存儲格式 4. 連鎖更新的問題  5. conf文件配置。在實踐上的操作主要是對conf配置文件進行配置,具體上沒有確切的一個值,更多是經驗值。也有的項目會直接使用原本的預設值。此篇對於更好地理解一個資料庫底層的存儲邏輯會有一點幫助。修學儲能,既要博,也要淵。希望這篇文章對同樣也是在學習Redis的各位同伴有點用。

 

一、壓縮列表(ziplist)的使用場景:

Redis為了優化數據存儲,節約記憶體,在列表、字典(哈希鍵)和有序集合的底層實現了使用壓縮列表這一優化方案。

例如,假如一個哈希鍵裡面存儲的字元串比較短,那麼Redis就會將它用壓縮列表的格式去存儲,即轉換為位元組數組存儲。而一個哈希鍵內部存儲的整數值比較小,同樣也會把它存儲為壓縮列表的一個節點。同理,列表鍵的對小數據的存儲跟哈希鍵的操作類似。

 

如此說來,壓縮列表並不是開發者可以直接調用的Redis中的一種存儲數據結構,而是Redis中為優化數據存儲而在底層做的一項努力。理解好這點還是比較重要的。

 

二、如何達到節約記憶體的效果?

壓縮列表是一種序列化的數據結構,這種數據結構的功能是將一系列數據與其編碼信息存儲在一塊連續的記憶體區域,這塊記憶體物理上是連續的。但邏輯上被分為多個組成部分,即節點。目的是為了在一定可控的時間複雜度條件下儘可能的減少不必要的記憶體開銷,從而達到節省記憶體的效果。需要理解是怎麼達到節約記憶體作用的,還需要去瞭解壓縮列表的存儲格式。

 

三、壓縮列表的存儲格式:

壓縮列表(ziplist)是Redis列表鍵、哈希鍵和有序集合鍵的底層實現之一,其實質是一種序列化的數據存儲結構。有別於普通情況下,Redis用雙端鏈表表示列表,使用散列表表示哈希鍵,用散列表+跳躍表表示有序集合。當一個列表或者哈希字典/有序集合只包含很少內容,並且每一個列表項或者哈希項/有序集合項如果是小整數,或者比較短的字元串。那麼Redis就會用壓縮列表來做底層的實現。

 

壓縮列表由一系列經Redis特殊編碼的連續記憶體塊組成,每一個記憶體塊稱為一個節點(entry),而一個壓縮列表可以包含很多個節點。每個節點存儲的數據格式可以是位元組數組(中文字元串等都會轉換為位元組數組)或者整數值。

位元組數組的長度可以是以下的其中一種:

1. 長度小於等於63位元組(2的6次方)

2. 長度小於等於16383位元組(2的14次方)

3. 長度小於等於4294967295位元組(2的32次方)

整數值可能是以下六種中的其中一種:

1. 4位長,介於0-12之間的無符號整數

2. 1位元組長的有符號整數

3. 3位元組長的有符號整數

4. int16_t類型整數

5. int32_類型整數

6. int64_t類型整數

 

普通存儲格式下和壓縮列表存儲格式下的不同點:

列表存儲結構典型的為雙端鏈表,每一個值都是用一個節點來表示,每個節點都會有指向前一個節點和後一個節點的指針,以及指向節點包含的字元串值的指針。而字元串值又分為3個部分存儲,第一部分存儲字元串長度,第二部分存儲字元串值中剩餘可用的位元組量,第三部分存儲的則是字元串數據本身。所以一個節點往往都需要存儲3個指針、2個記錄字元串信息的整數、字元串本省和一個額外的位元組。總體上額外的開銷是很大的(21位元組)。

 

壓縮列表節點的格式:

每一個節點都有previous_entry_length,encoding,content三個部分組成,在遍歷壓縮列表的時候是從後往前遍歷的。

1. previous_entry_length記錄了前一個節點的長度,只要用當前指針減去這個值就可以達到前一個節點的起始地址。

2. encoding記錄了節點content屬性所保存數據的類型和長度

3. content記錄了一個節點的值

 

顯然壓縮列表這種方式節約了不少存儲空間。但同時也會引發下麵的問題。

 

四、連鎖更新的問題:

一般而言如果前一個節點的整體長度小於254位元組,previous_entry_length屬性只需要1個位元組的空間來保存這個長度值。而當前一個節點大於254位元組的時候,previous_entry_length屬性要用5個位元組長的空間來記錄長度值。

當長度為254位元組左右的節點前插入一個新的節點的時候,需要增加previous_entry_length來記錄這個節點到新節點的偏移量。這個時候,這個節點的長度肯定就大於254位元組了。所以這個節點的後一個節點就不能只用一個位元組的previous_entry_length來記錄這個節點的信息了,而是需要5個位元組來記錄。如果連續多個節點的長度都為254位元組左右,在其中的某一個節點前/後發生節點的插入和刪除(刪除的推理與插入相反,原本用5位元組記錄前一節點的可能變為1位元組),都可能引發連鎖的更新,顯然,這樣對系統地運行效率是很不利的。不過,在實際應用中這種情況還是比較少發生的。

    而雙端鏈表在節點的更新、增加和刪除上顯得就會“輕鬆”很多了。 因為每一個節點存儲的信息都是相對獨立的。  

 

實踐意義:

要預估一個節點大概占據多少位元組的存儲空間,適當地調整欄位的存儲格式而不要使存儲的欄位值占據存儲空間落在254位元組(除去encoding屬性和previous_entry_length屬性)左右。

 

Redis中查看字元串和哈希鍵值的長度相關命令:

1. 查詢字元串鍵對應的值長度

命令:

Strlen

例如:

127.0.0.1:6379> strlen m_name

(integer) 8

 

2. 查詢哈希鍵某一個域長度

命令:

Hstrlen

例如:

127.0.0.1:6379> hstrlen good_list good_list1

(integer) 226

 

 

五、Conf文件配置:

通過修改配置文件,可以控制是否使用壓縮列表存儲相關鍵的最大元素個數和最大元素的大小

Conf文件中的配置:
1.

[] -max-ziplist-entries : 表示對於鍵的最大元素個數,即一個鍵中在該指定值下的數量的節點個數都會用壓縮列表來儲存

[] -max-ziplist-value :表示壓縮列表中每個節點的最大體積是多少位元組

實際使用中,一個列表鍵/哈希鍵的某一個元素往往存儲著比較大的信息量,會大於64位元組,所以配置時很有可能會比64大,同時考慮到實際存儲數據的容量大小以及上面談到的previous_entry_length的大小問題,對[] -max-ziplist-value進行合理的配置。

 

配置文件內容:

############## ADVANCED CONFIG ##########################
哈希鍵
# 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

有序集合鍵
# 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 128
zset-max-ziplist-value 64

列表鍵,比較特殊,直接使用制定大小kb位元組數表示(有些conf文件的列表鍵與hash鍵的表達式沒太大區別)
# 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

 

案例:

修改配置前使用預設配置:

hash-max-ziplist-entries 512

hash-max-ziplist-value 64

 

127.0.0.1:6379> hstrlen good_list good_list1

(integer) 226

127.0.0.1:6379> object encoding good_list

"hashtable"

 

修改配置:

hash-max-ziplist-entries 512

hash-max-ziplist-value 254

註意:修改配置後需要重啟伺服器

127.0.0.1:6379> hstrlen good_list good_list1

(integer) 226

127.0.0.1:6379> object encoding good_list

"ziplist"

 

可以看到存儲方式已將變為ziplist

 

較官方的壓力測試和指導建議:

當一個壓縮列表的元素數量上升到幾千(實際使用可能遠小於這個值)的時候,壓縮列表的性能可能會下降,因為Redis在操作這種結構的時候,編解碼會出現一定的壓力。

壓縮列表的長度限制在500-2000之內,每個元素體積限制在128位元組或以下,壓縮列表的的性能都會處於合理範圍之內。

 

參考資料:

《redis設計與實現》

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 以前折騰的時候禁用過,現在已經忘記目錄了,結果今天手賤把系統從 18.04 升級到了 18.10 ,很多東西都要重新搞過,而且用慣了 mac 已經不熟悉 linux 上瞎折騰的那一套了,簡直坑爹。。 由於已經手動裝了 和 兩個擴展,所以預設的已經沒用啦,考慮把它們禁掉,首先要找到它們所在的目錄: 只 ...
  • 簡單對客戶端加域埠做彙總操作,希望對大家有幫助。之前有對服務埠做彙總,具體請參照:Windows Server 2016-Active Directory域服務埠彙總:http://blog.51cto.com/wenzhongxiang/2088693 協議埠埠類型備註 TCP/UDP5... ...
  • 最近在學習Linux操作系統。學到了關於定時任務的章節,作為一個總結寫下這篇文章。在Linux中,我們可以將耗時大的任務如複製大文件,壓縮、解壓縮大文件等放進定時任務中(深夜執行,因為工作時間訪問量大,這類操作會影響系統運行)。 Linux操作系統中關於定時任務主要有種操作方式: 1. at 一次性 ...
  • 目錄 1. 單用戶模式 2. 救援模式 3. 總結 1、 單用戶模式 單用戶模式可以對系統進行修複,如:修改root密碼,修改因配置不正確而導致系統啟動失敗的配置文件等。 (1) Centos7進入單用戶模式 1) 進入grub2菜單時按 ‘e’ 進入編輯模式 2) 在編輯模式中下翻,在指定行修改 ...
  • 在內核分析網路分組時,底層協議的數據將傳輸到跟高的層。而發送數據的時候順序是相反的。每一層都是通過加(首部+凈荷)傳向跟底層,直至最終發送。 這些操作決定了網路的的性能。 就如下圖所示 linux因此設計了一個結構體 如下代碼 套接字換從區在各個層交換數據,就不用複製數據了。 從以上欄位和註釋可以看 ...
  • 1. HDFS Shell基礎 [root@master hadoop]# hadoop fsUsage: hadoop fs [generic options] [-appendToFile <localsrc> ... <dst>] [-cat [-ignoreCrc] <src> ...] [ ...
  • 一、關係查詢處理和查詢優化 關係資料庫系統的查詢處理 查詢處理的步驟分為4個階段:查詢分析、查詢檢查、查詢優化和查詢執行。 查詢語句(由此語句進行查詢) 1、查詢分析 首先對查詢語句進行掃描、詞法分析和語法分析。對SQL關鍵字、屬性名和關係名等,進行語法檢查和語法分析 ,即判斷查詢語句是否符合SQL ...
  • SqlServer中的系統資料庫有五個,平時寫代碼不太關註,今天一時興起研究了一下。 1. master 記錄SQL Server系統的所有系統級信息,例如:登陸賬戶信息、鏈接伺服器和系統配置設置、記錄其他所有資料庫的存在、數據文件的位置、SQL Server的初始化信息等。如果master資料庫不 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...