###導入###
| 「大容量Redisストレージ - Pikaのすべて」では、pikaの誕生、pikaの特徴、pikaの核心、pikaの使い方について紹介しました。この記事では、pika 同期ロジックの重要なファイル、つまり「write2file」のデータ保存方法と実装原理について詳細に分析しており、非常に読む価値があります。
|
ピカ
pika は、360 Web プラットフォーム部門の DBA とインフラストラクチャ チームによって開発された大容量 Redis ライク ストレージです。pika の登場は、Redis を置き換えるものではなく、Redis シナリオを補完するものです。 Pika は、Redis プロトコルとの完全互換を前提とし、Redis の利便性の高い運用保守設計を継承し、大容量シナリオにおける Redis の課題である復旧時間の遅さ、マスター/スレーブのコストの高さなどを永続ストレージによって解決することを目指しています。同期、比較的壊れやすいシングルスレッド、耐荷重性、データ制限、メモリコストの高さなど。
pika マスター/スレーブ レプリケーション原則の binlog
Binlog 関連ファイルには、マニフェストと write2file の 2 つの部分が含まれています。マニフェストは、現在のログ ファイル番号と現在のログ ファイル オフセットを含むログ メタ情報を記録します。write2file num は、pika が受信したすべての redis 書き込みコマンドとパラメータを記録します。
ファイル形式
マニフェスト ファイル形式:
ログ オフセット (8 バイト)|con_offset (8 バイト、未使用)|要素数 (4 バイト、未使用)|ログ ファイル番号 (4 バイト)。
バイログ ファイル形式:
Binlog ファイルの固定サイズは 100MB です。各 Binlog ファイルは複数のブロックで構成されています。各ブロックのサイズは 64KB に固定されています。各書き込み redis コマンドはレコードと呼ばれます。レコードは複数のブロックに分散できますが、1 つの Binlog ファイルにのみ分散されるため、Binlog ファイルは 100MB より大きくなる可能性があります。
レコード形式: Header|Cmd
ヘッダー: レコード長 (3 バイト) | タイムスタンプ (4 バイト) | レコード タイプ (1 バイト)。
Cmd: 現在のブロックの残りのスペースにレコードを保存できるかどうかに応じて、redis コマンドの一部またはすべて。
実装クラス
ベーシッククラス
バージョン: mmap およびマニフェスト ファイルを通じてマップされたメタ情報クラス。
Binlog: mmap および write2file ファイルを通じてマップされたログ クラス。
PikaBinlogSenderThread: ログ消費クラス。ログ ファイルの内容を順次読み取り、ログを消費します。
基本操作
Binlog の構築
//file_size は構成ファイルで指定できます。デフォルトは 100MBです。
Binlog::Binlog(const std::string& binlog_path, const int file_size)
1.1binlog ファイルのディレクトリを作成します。
1.2 ログディレクトリにマニフェストファイルが存在するか確認し、存在しない場合は新規作成してください。
1.3 マニフェスト ファイルに従って Version クラスを初期化します。
1.4 マニフェスト内の filenum に従って対応するログ ファイルを検索し、pro_offset に従ってファイルの追加位置を特定し、ログ ポインタを初期化し、ログの内容の長さとブロック ブロックの数を記録します。
現在のログ生成ステータスを更新します
//pro_num: ログファイル番号
//pro_offset: ログ ファイルのオフセット
//完全同期が必要な場合に、スレーブ インスタンスに対応するバイナリログ情報を更新するために使用されます
ステータス 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 に初期化し、それをマニフェスト ファイルに更新します。
2.4 現在のファイルサイズと block_offset を初期化します。
現在のログ生成ステータスを更新します
//filenum: 現在のログ番号
//pro_offset: 現在のログ オフセット
ステータス Binlog::GetProducerStatus(uint32_t* filenum, uint64_t* pro_offset)
3.1 version の pro_num と pro_offset を読み取って返します。
制作記録
//Put->Produce->EmitPhysicalRecord
ステータス 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 現在のブロックの残りのサイズが 4.1.3 Produce はループであり、アイテムのサイズが kBlockSize を超えたときに、EmitPhysicalRecord を複数回実行でき、アイテムのすべてのデータが binlog ファイルにドロップされることを保証します。ループが正常に終了するための条件左==0です。
4.1.3.1 left
4.1.3.2 左 > が利用可能な場合は、項目を保存するために複数のブロックが必要であることを意味し、初回 Type=kFirstType で EmitPhysicalRecord を複数回呼び出します。
4.1.3.3 左 > が利用可能で、EmitPhysicalRecord が初めてではない場合、Type=kMiddleType で、EmitPhysicalRecord を複数回呼び出します。
4.1.4物理レコードを送信します。
4.1.4.1 RecordHeader (長さ 3 バイト、時間 4 バイト、タイプ 1 バイト) を結合し、データを書き込み、block_offset と pro_offset を更新します。
消費ログ
//スクラッチ: 消費結果は完全な redis cmd を返します
//Consume->ReadPhysicalRecord、ReadPhysicalRecord は毎回完全なレコードを読み取り、複数のレコードで完全な redis cmd を構成します
ステータス PikaBinlogSenderThread::Consume(std::string &scratch)
5.1Consume はループであり、ReadPhysicalRecord を複数回呼び出す可能性があります。ループ終了の条件は、read Record_type==kFullType または Record_type==kLastType であることです。
5.1.1 読み取られた kBlockSize-last_record_offset_
5.1.2 データを読み取り、last_record_offset_、con_offset を更新します。