首頁  >  文章  >  系統教程  >  Pika: 補充大容量類 Redis 儲存的適用場景

Pika: 補充大容量類 Redis 儲存的適用場景

WBOY
WBOY轉載
2024-01-08 22:14:34759瀏覽
導讀 我們在《大容量類 Redis 儲存 — 有關 pika 的一切》裡介紹過pika的誕生、pika的特點、pika的核心以及pika的使用。文章中非常詳細的解析了pika同步邏輯中的重要文件:「write2file」的資料儲存方式及實作原理,非常值得一看!
pika

pika 是 360 Web 平台部 DBA 與基礎架構組合作開發的大容量類 Redis 存儲,pika 的出現並不是為了替代 Redis,而是 Redis 的場景補充。 pika 力求在完全相容Redis 協定、繼承Redis 便捷運維設計的前提下透過持久化儲存的方式解決Redis 在大容量場景下的問題,如復原時間慢、主從同步代價高、單執行緒相對脆弱、承載資料較有限、記憶體成本高昂等。

pika主從複製原理之binlog

#binlog相關的檔案包含兩部分: manifest和write2file,其中manifest記錄了日誌元信息,包括當前日誌檔案編號、當前日誌檔案偏移量,write2file num記錄了pika接收到的所有redis寫命令、參數。

檔案格式

#manifest檔案格式:

日誌偏移量(8位元組)|con_offset(8字節,未使用)|元素個數(4字節,未使用)|日誌檔案編號(4位元組)。

Binlog檔案格式:

#Binlog檔案固定大小為100MB,每個Binlog檔案由多個Block組成,每個Block大小固定為64KB,每一個寫redis指令稱為一個Record。一個Record可以分佈在多個Block中,但只會分佈在一個Binlog檔案裡,所以Binlog檔案有可能大於100MB。

Record格式:Header|Cmd 

##Header: Record Length(3位元組)|時間戳(4位元組)|記錄類型(1位元組)。

Cmd: redis指令的一部分或全部,取決於目前Block剩餘空間是否可以存放該Record。

實作類別

基本類別

Version: 元資訊類,透過mmap與manifest檔案映射。

Binlog: 日誌類,透過mmap與write2file檔案映射。

PikaBinlogSenderThread: 日誌消費性,順序讀取日誌檔案內容,消費日誌。

基本運算

建構Binlog

#//file_size可以在設定檔指定,預設為100MB

Binlog::Binlog(const std::string& binlog_path, const int file_size)

1.1建立binlog檔案目錄。

1.2檢查log目錄下manifest檔案是否存在,不存在則新建。

1.3根據manifest檔初始化Version類別。

1.4根據manifest中的filenum找到對應的日誌文件,根據pro_offset定位到文件append的位置,初始化日誌指標、記錄日誌內容長度、Block區塊數量。

更新目前日誌生產狀態

#//pro_num: 日誌檔案編號

//pro_offset: 日誌檔案偏移量

//用在需要全量同步時更新slave實例對應的binlog資訊

Status Binlog::SetProducerStatus(uint32_t pro_num, uint64_t pro_offset)

2.1 刪除write2file0。

2.2 刪除write2file pro_num。

2.3 建構新的write2file pro_num文件,填入pro_offset個空格,初始化version->pro_num為pro_num,version->pro_offset為pro_offset,並刷新到manifest文件中。

2.4 初始化目前filesize、block_offset。

更新目前日誌生產狀態

#//filenum: 目前日誌編號

//pro_offset: 目前日誌偏移量

Status Binlog::GetProducerStatus(uint32_t* filenum, uint64_t* pro_offset)

3.1 讀取version中的pro_num、pro_offset並回傳。

生產日誌

//Put->Produce->EmitPhysicalRecord

Status Binlog::Put(const std::string &item)

4.1檢查目前日誌檔案是否符合切割條件,如果滿足則進行切割。

4.1.1 pro_num自增加1,初始化新的日誌文件,version->pro_num=pro_num,version->pro_offset = 0,binlog->filesize = 0,binlog->block_offset = 0。

4.1.2 如果目前block剩餘大小

4.1.3 Produce是一個循環,保證在item大小超過kBlockSize時,可以進行多次EmitPhysicalRecord,完成item全部資料落入binlog文件,循環正常退出的條件是left==0。

4.1.3.1 如果left

4.1.3.2 如果left > avail,代表需要多個Block存放item,則第一次Type=kFirstType,呼叫EmitPhysicalRecord多次。

4.1.3.3 如果left > avail,且不是第一次EmitPhysicalRecord,則Type=kMiddleType,呼叫EmitPhysicalRecord多次。

4.1.4EmitPhysicalRecord。

4.1.4.1 拼接RecordHeader(3位元組長度 4位元組時間 1位元組Type),寫入數據,更新block_offset、pro_offset。

消費日誌

//scratch: 消費結果回傳一個完整的redis cmd

#//Consume->ReadPhysicalRecord,ReadPhysicalRecord每次讀取一個完整的Record,多個Record構成一個完整的redis cmd

Status PikaBinlogSenderThread::Consume(std::string &scratch)

5.1Consume是一個循環,可能多次呼叫ReadPhysicalRecord,循環退出的條件是讀取到的record_type==kFullType或record_type==kLastType。

5.1.1如果讀取到的kBlockSize-last_record_offset_ <= kHeaderSize代表讀到了Block的末尾,且為填充數據,skip掉。

5.1.2讀取數據,更新last_record_offset_,con_offset。

以上是Pika: 補充大容量類 Redis 儲存的適用場景的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:linuxprobe.com。如有侵權,請聯絡admin@php.cn刪除