目錄
- 前言
- 1. 二進制位陣列
- 1.1 位陣列的表示
- 1.2 GETBIT 命令的實作
- 1.3 SETBIT 命令的實作
- 1.4 BITECOUNT 命令的實作
- 1.5 BITOP 命令的實作
- 2. 慢查詢日志
- 2.1 慢查詢記錄的保存
- 2.2 慢查詢日志的閱覽與洗掉
- 2.3 添加新日志
- 3. 監視器
- 最后
前言
參考資料:《Redis設計與實作 第二版》;
第三部分為獨立功能的實作,主要由以下模塊組成:發布訂閱、事務、Lua 腳本、排序、二進制位陣列、慢查詢日志、監視器;
本篇將介紹 Redis 的二進制位陣列、慢查詢日志和監視器,Redis 提供了一些命令操作二進制位陣列;通過 SLOWLOG 相關命令可以對慢查詢日志進行操作;通過 MONITOR 命令可以進入監視器模式;
與本章相關的 Redis 命令總結在下篇文章,歡迎點擊收藏,本篇將不再重復:
《Redis常用命令及示例總結(API)》:https://blog.csdn.net/dlhjw1412/article/details/119713214
1. 二進制位陣列
1.1 位陣列的表示
- Redis 使用字串物件來表示位陣列,因為字串物件使用的 SDS 是二進制安全的;
- 使用逆序保存位陣列,下圖實際為:1111 0000 1100 0011 1010 0101;
- 使用逆序保存位陣列,可以直接在新擴展的二進制位中完成,不必改動位陣列原來已有的二進制位;

1.2 GETBIT 命令的實作
GETBIT key offset命令;- 1)計算 byte=offset / 8;
byte值表示位陣列的哪個位元組; - 2)計算 bit=(offset mod 8)+1;
bit值表示在byte下標位元組的第幾個二進制位; - 3)根據 byte 和 bit 的值定位
offfset偏移量指定的二進制位; - 4)向客戶端回傳二進制位的值;

1.3 SETBIT 命令的實作
-
SETBIT key offset value命令; -
1)計算 len=offset/8+1;
len值表示offset指定的二進制位至少需要多少位元組; -
2)根據 len 值進行擴展新空間,如果原位陣列長度夠則不擴展;
-
3)計算 byte=offset/8;
byte值表示位陣列的哪個位元組; -
4)計算 bit=(offset mod 8)+1;
bit值表示在byte下標位元組的第幾個二進制位; -
5)根據 byte 和 bit 的值定位 offfset 偏移量指定的二進制位
oldvalue,并修改; -
6)向客戶端回傳二進制位
oldvalue的值; -
無擴展操作的 SETBIT 命令示例如下:

-
帶擴展操作的 SETBIT 命令示例如下:

1.4 BITECOUNT 命令的實作
-
遍歷演算法:
- 遍歷位陣列中的每個二進制位,遇到 1 時將計數器值贈 1;
- 實作簡單,效率低;
-
查表法:
- 對于長度有限的位陣列而言,能表示的二進制位有限,而每種排列順序的 1 的個數是確定的;
- 查表法是典型的空間換時間策略,節約時間越多,花費記憶體越大
- 受 CPU 快取限制:創建表越大,能加載進快取的內容越少,快取不命中的情況越高,快取的換入換出操作就越頻繁,最終影響實際效率;

-
variable-precision SWAR 演算法:
-
又稱:計算漢明重量法;
-
一個處理 32 位長度位數的演算法示例:
uint32_t swar(unit32_t i){ //步驟1:按每2個二進制位為一組分組,各組的十進制為漢明重量 i = (i & 0x55555555) + ((i >> 1) & 0x55555555); //步驟2:按每4個二進制位為一組分組,各組的十進制為漢明重量 i = (i & 0x33333333) + ((i >> 2) & 0x33333333); //步驟3:按每8個二進制位為一組分組,各組的十進制為漢明重量 i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F); //步驟4 i = (i*(0x01010101) >> 24); return i; } -
一個示例如下:
-


- Redis 的實作:
- BITCOUNT 命令使用查表法和 variable-precision SWAR 法兩種;
- 查表法:使用鍵長為 8 位的表,記錄 0000 0000 到 1111 1111 在內的二進制位的漢明重量;
- variable-precision SWAR 法:每次回圈中載入 128 個二進制位,呼叫 4 次 32 位的variable-precision SWAR 法計算 128 位二進制位的漢明重量;
- 程式根據未處理的二進制位的數量決定使用哪種演算法:
- 未處理二進制位大于等于 128 位:variable-precision SWAR 法;
- 未處理二進制位小于 128 位:查表法;
- BITCOUNT 命令使用查表法和 variable-precision SWAR 法兩種;
- 演算法的時間復雜度為:O(n),n 為輸入二進制位的數量;
1.5 BITOP 命令的實作
-
BITOP 命令的所有操作都是使用 C 語言內置的位操作來實作的;
BITOP 命令 C語言操作 說明 BITOP AND & 邏輯與 BITOP OR | 邏輯或 BITOP XOR ^ 邏輯異或 BITOP NOT ~ 邏輯非
2. 慢查詢日志
-
Redis 的慢查詢日志功能用于記錄執行時間超過給定時長的命令請求,用戶可以通過這個功能產生的例子來監視和優化查詢速度;
-
服務器配置有兩個和慢查詢日志相關的選項:
slowlog-log-slower-than選項:指定執行時間超過多少毫秒的命令請求會被記錄到日志上;slowlog-max-len選項:指定服務器最多保存多少條慢查詢日志,采用先進先出的方式;
-
使用 SLOWLOG 相關命令可以操作慢查詢日志;
2.1 慢查詢記錄的保存
-
服務器狀態中包含與慢查詢日志功能相關的屬性:
struct redisServer{ //... // 下一條慢查詢日志的 ID long long slowlog_entry_id; // 保存了所有慢查詢日志的鏈表 list *slowlog; // 服務器配置 slow_log_slower_than 選項的值 long long slow_log_slower_than; // 服務器配置 slowlog_max_len 選項的值 unsigned long slowlog_max_len; };

-
slowlog鏈表結構如下:typedef struct slowlogEntry{ // 唯一識別符號 long long id; // 命令執行時的時間,格式為 UNIX 時間戳 time_t time; // 執行命令消耗的時間,以微秒為單位 long long duration; // 命令與命令引數 robj **argv; // 命令與命令引數的數量 int argc; } slowlogEntry;

2.2 慢查詢日志的閱覽與洗掉
SLOWLOG GET [number];列印所有 slow log ,最大長度取決于 slowlog-max-len 選項的值;SLOWLOG LEN;查看當前日志的數量,其值為 slowlog 鏈表的長度;SLOWLOG RESET;清除所有慢查詢日志;
2.3 添加新日志
- 每次執行命令的之前和之后,程式會記錄微秒格式的當前 UNIX 時間戳,兩個時間戳之間的差值就是服務器執行命令所消耗的時長;
- 新的慢查詢日志會被添加到 slowlog 鏈表的表頭,如果日志的數量超過
slowlog-max-len選項的值,那么多出來的日志會被洗掉;
3. 監視器
- 執行 MONITOR 命令,客戶端可以將自己變為一個監視器,實時列印服務器當前處理的命令請求相關資訊;
- 當一個客戶端從普通客戶端變為監視器時,該客戶端的
REDIS_MONITOR標識會被打開,該客戶端會被添加到monitors鏈表的表尾; - 所有監視器都記錄在
monitors鏈表里; - 每次處理命令請求時,服務器會遍歷
monitors鏈表,將相關資訊發送給監視器;

最后

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/374466.html
標籤:其他
上一篇:Redis | 第9章 Lua 腳本與排序《Redis設計與實作》
下一篇:MySQL常見問題
