[AI 協作筆記] gRPC 傳輸優化:基於 Flattening 與 Bitset 的高效方案

[AI 協作筆記] gRPC 傳輸優化:基於 Flattening 與 Bitset 的高效方案

本篇文章記錄了在開發高效能資料庫中間件 (hypool) 時,針對 gRPC 傳輸效率與型別限制所採用的優化方案。該方案由 AI 協助提出,借鑑了資料庫底層儲存原理,解決了傳統 gRPC 在傳輸大量資料庫結果集時面臨的兩個主要挑戰。

1. 背景與技術挑戰

在設計資料庫中間件的 API 時,我們通常需要回傳多行的查詢結果。若採用傳統的 gRPC 定義方式,會面臨以下效能與實作上的問題。

1.1 Payload 冗餘問題 (Key Repetition)

最直觀的 Protobuf 定義通常是將每一行資料定義為一個 Map 或 Object:

message Row {
    map<string, string> data = 1;
}
message Response {
    repeated Row rows = 1;
}

問題分析
這種結構會導致嚴重的 Payload 膨脹。假設查詢結果有 10,000 筆資料,且包含欄位 customer_id, created_at, status。在傳輸過程中,這些欄位名稱 (Key) 會被重複傳輸 10,000 次,佔用了大量的頻寬資源。

1.2 Protobuf 對 NULL 值的限制

Protobuf (proto3) 的設計哲學將純量型別 (Scalar Types) 視為不可為空。

  • string 欄位若為 NULL,傳輸時會被序列化為空字串 ""
  • Client 端無法區分這是「空值」還是「原始資料庫中的 NULL」。

雖然可以使用 google.protobuf.StringValue 等 Wrapper 類型解決,但這會增加額外的 Message 嵌套層級與處理開銷。

2. 解決方案:類資料庫底層架構

針對上述挑戰,AI 建議跳脫傳統的 API 物件思維,轉而參考 資料庫底層 (Columnar Storage)ODBC/JDBC 驅動 的實作方式。

核心優化策略包含以下兩個部分:

A. 陣列扁平化 (Flattening)

主要用於解決 Key-Value 冗餘問題。

我們不再傳輸「物件陣列 (Array of Objects)」,而是將資料結構扁平化

  1. Header (Metadata):單獨傳輸一次欄位定義 (columns)。
  2. Body (Values):將所有資料值攤平成一個巨大的一維陣列 (values)。

這種設計完全移除了每行資料中的 Key 傳輸,顯著降低 Payload 大小。

B. Bitset (Bitmap) 機制

主要用於解決 NULL 值標記問題。

既然 string 用來傳輸「值」,我們便引入一個額外的二進位欄位 (bytes) 來專門記錄「狀態」:

  • 使用 Bitset 來標記每一個值是否為 NULL。
  • 1 個 bit 對應 1 個值

    • Bit = 1: 表示該值為 NULL。
    • Bit = 0: 表示該值有效。

空間效率
每 8 個欄位值僅需消耗 1 byte 的額外空間。對於 1,000 行 x 8 欄的資料,僅需約 1 KB 的 Overhead 即可精確記錄所有 NULL 狀態。

3. 實作細節 (Implementation Essentials)

本節將展示 Server 端如何「壓縮」與 Client 端如何「還原」的關鍵程式碼。

3.1 Protobuf 定義 (proto/query.proto)

message QueryResponse {
    repeated string values = 3;   // 扁平化數值
    repeated Column columns = 4;  // 欄位定義
    bytes null_bitmap = 7;        // NULL 標記位元流
    int32 row_count = 6;
}

3.2 Server 端:編碼與壓縮 (Encoding)

Server 端的任務是一次性遍歷資料庫結果,同時完成「數值扁平化」與「Bitmap 生成」。

// $result['rows'] 是資料庫回傳的二維陣列
$values = [];
$packedBytes = "";
$currentByte = 0;
$bitIndex = 0;

foreach ($result['rows'] as $row) {
    foreach ($row as $value) {
        if ($value === null) {
            $values[] = "";             // 值放空字串佔位
            $currentByte |= (1 << $bitIndex); // 標記 NULL (Bit設為1)
        } else {
            $values[] = (string)$value; // 存入實際值
            // 非 NULL,Bit 保持 0
        }

        // 每滿 8 個 bits 就寫入一個 byte
        if (++$bitIndex === 8) {
            $packedBytes .= chr($currentByte);
            $currentByte = 0;
            $bitIndex = 0;
        }
    }
}
// 寫入剩餘的 bits
if ($bitIndex > 0) {
    $packedBytes .= chr($currentByte);
}

3.3 Client 端:解碼與還原 (Decoding)

Client 端收到資料後,需要根據 columns 數量進切割,並參考 null_bitmap 將 NULL 還原回來。

$fetchedRows = [];
$columns = $response->getColumns();
$colCount = count($columns);
$values = $response->getValues();     // 取得扁平化陣列
$bitmap = $response->getNullBitmap(); // 取得 Bitmap string

$rowCount = $response->getRowCount();

for ($r = 0; $r < $rowCount; $r++) {
    $row = [];
    for ($c = 0; $c < $colCount; $c++) {
        // 計算在一維陣列中的絕對索引
        $flatIndex = ($r * $colCount) + $c;

        // [精華] Bitset 查表法
        // 1. 找到對應的 Byte 位置
        $bytePos = (int)($flatIndex / 8); 
        // 2. 找到 Byte 中的 Bit 位置
        $bitPos = $flatIndex % 8;

        // 3. 檢查該 Bit 是否為 1
        $isNull = (ord($bitmap[$bytePos]) >> $bitPos) & 1;

        if ($isNull) {
            $row[] = null; // 精確還原 NULL
        } else {
            $row[] = $values[$flatIndex];
        }
    }
    $fetchedRows[] = $row;
}

透過上述兩段對稱的邏輯,我們即可以極低的運算成本完成資料的壓縮與還原。

4. 優化效益分析

採用此架構後,我們獲得了以下具體效益:

  1. 極致的傳輸效率

    • 透過扁平化設計,Payload 大小與資料量呈線性單純增長,不受欄位名稱長度影響。在大數據量查詢中,頻寬節省效果極為顯著。
  2. 精確的型別還原

    • Client 端可透過讀取 null_bitmap 精確還原資料庫的 NULL 狀態,解決了 gRPC 預設型別的限制。
  3. 解析效能提升

    • 對於 PHP 與其他語言而言,處理扁平的一維陣列 (Indexed Array) 通常比處理大量複雜的巢狀物件 (Nested Objects) 擁有更好的 CPU Cache 命中率與更低的記憶體碎片。

5. 總結

這個優化案例展示了在現代分散式系統中,適度引入底層系統設計思維的重要性。透過與 AI 的協作,我們跳脫了單純的 API 設計框架,利用 位元運算資料結構優化,以極低的成本解決了 gRPC/Protobuf 在資料庫應用場景下的先天限制。

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

Welcome to the Quality Caption Contest #3!

Next Post
how-data-and-ai-are-reshaping-the-work-of-aerospace-quality-engineers

How Data and AI Are Reshaping the Work of Aerospace Quality Engineers

Related Posts