基因法分庫分表

TY520發表於2024-03-23

問題

假設我們有一張超大的訂單表(N億),裡面有order_id、user_id等欄位。

  1. 能透過order_id快速查詢對應訂單
  2. 能透過user_id快速查詢該使用者具有的訂單列表

像上面這樣的要求改怎樣做呢?透過雜湊訂單ID取模?那如何滿足透過使用者ID快速查詢訂單列表呢?

什麼是基因演算法

理論

He meant that taking number mod 2^n is equivalent to stripping off all but the n lowest-order (right-most) bits of number

即: 一個數取餘2的n次方,那麼餘數就是這個數的二進位制的最後n位數。所有我們可以位運算子把高位清零就可以得到餘數.

image

使用者user_id=666 (666的二進位制表示為:0000 0010 1001 1010)的使用者生成一個訂單步驟

  1. 使用user_id%16分庫,決定這行資料要插入到哪個庫中

  2. 分庫基因是user_id的最後4個bit,即1010

  3. 在生成order_id時,先使用一種分散式ID生成演算法生成前60bit(上圖中淺灰色部分)

  4. 將分庫基因加入到order_id的最後4個bit(上圖中綠色部分)

  5. 拼裝成最終的64bit訂單order_id(上圖中藍色部分)

  6. 這般,保證了同一個使用者釋出的所有訂單的order_id,都落在同一個庫上,order_id的最後4個bit都相同,於是:

    • 透過order_id%16能夠定位到庫

    • 透過user_id%16也能定位到庫

Python程式碼實現

import random

# 假設我們有16個庫,每個庫有16個表
num_databases = 16
num_tables = 16

# 假設我們有一些使用者
user_ids = [random.randint(1, 10000) for _ in range(10)]


def generate_order_id(user_id):
    # 使用分散式ID生成演算法生成前60bit(這裡我們簡化為一個隨機數)
    distributed_id = random.randint(1, 2**60)
    # 從 user_id 中提取基因
    gene = user_id % 16
    # 將基因加入到 order_id 的最後幾個bit
    order_id = (distributed_id << 4) | gene
    return order_id


def get_database_and_table_from_user_id(user_id):
    # 使用 user_id 的最後4位作為基因
    gene = user_id % 16
    # 使用基因決定資料庫和表
    database = gene % num_databases
    table = gene % num_tables
    return database, table


def get_database_and_table_from_order_id(order_id):
    # 從 order_id 中提取基因
    gene = order_id % 16
    # 使用基因決定資料庫和表
    database = gene % num_databases
    table = gene % num_tables
    return database, table


if __name__ == '__main__':

    for user_id in user_ids:
        u_database, u_table = get_database_and_table_from_user_id(user_id)
        # 生成訂單ID
        order_id = generate_order_id(user_id)
        o_database, o_table = get_database_and_table_from_order_id(order_id)
        print(f"user_id: {user_id}, order_id: {order_id} "
              f"user database: {u_database}, user table: {u_table}  "
              f"order database: {o_database} order table: {o_table}")


相關文章