首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

FriendFeed 如何用 MySQL 實現無模式數據存儲(上)

     編輯:MySQL 綜合教學

FriendFeed 如何用 MySQL 實現無模式數據存儲(上)

背景與動機

FriendFeed 早期使用 MySQL 存儲所有數據,隨用戶增長數據超 2.5 億條。傳統 RDBMS 面臨擴展瓶頸:

  • DDL 變更(加索引、改 Schema)鎖表數小時,嚴重阻礙新功能上線。
  • 刪除舊索引同樣耗時,保留則佔用緩存、拖慢寫入。
  • 分庫分表後 Join 失效,關係型特性幾乎無用。

評估 CouchDB 等 NoSQL 方案後,因穩定性、成熟度不足,團隊決定在 MySQL 上構建無模式存儲層,保留 MySQL 可靠的復制、備份生態,僅放棄關係特性。

核心架構設計

  1. 實體表:僅存 id (BINARY(16) PK)、body (MEDIUMBLOB)、updated (TIMESTAMP)、自增 added_id(物理順序寫入優化)。
    實體屬性集(JSON/字典)經 zlib 壓縮後存入 body。
  2. 索引表:每個需查詢的屬性建一張獨立索引表,如 index_user_id(user_id, entity_id PK)。
    查詢時:先在分片上查索引表得 entity_id 列表,再回實體表取 body 反序列化。
  3. 動態索引管理:
    • 新增索引:建表 → 啟動異步「清潔工」回填歷史數據 → 切換流量,零停機、無主從切換。
    • 刪除索引:停寫入 → 可選異步刪表。
  4. 分片策略:索引表按 shard_on 屬性哈希分片(如 user_id % num_shards),實體表同樣分片。

關鍵代碼示例

實體表

CREATE TABLE entities (
  added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  id BINARY(16) NOT NULL,
  updated TIMESTAMP NOT NULL,
  body MEDIUMBLOB,
  UNIQUE KEY (id),
  KEY (updated)
) ENGINE=InnoDB;

索引表(以 user_id 為例)

CREATE TABLE index_user_id (
  user_id BINARY(16) NOT NULL,
  entity_id BINARY(16) NOT NULL UNIQUE,
  PRIMARY KEY (user_id, entity_id)
) ENGINE=InnoDB;

Python 伪代碼:寫入與查詢

# 定義索引
user_id_index = Index(table="index_user_id", properties=["user_id"], shard_on="user_id")
datastore = DataStore(mysql_shards=["shard1:3306", "shard2:3306"], indexes=[user_id_index])

# 寫入實體(自動維護所有索引)
entity = {"id": uuid, "user_id": uid, "title": "Hello", ...}
datastore.put(entity)

# 查詢:先命中索引表,再回實體表
entities = user_id_index.get_all(datastore, user_id=uid)

新增 link 索引(零停機)

CREATE TABLE index_link (
  link VARCHAR(735) NOT NULL,
  entity_id BINARY(16) NOT NULL UNIQUE,
  PRIMARY KEY (link, entity_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 代碼加入新索引
link_index = Index(table="index_link", properties=["link"], shard_on="link")
datastore = DataStore(..., indexes=[user_id_index, link_index])

# 異步回填歷史數據(不影響線上服務)
./rundatastorecleaner.py --index=index_link

設計優勢總結

  • Schema-less:新增屬性無需 ALTER TABLE,直接寫入 body 並建索引表。
  • 索引增減敏捷:新索引一日內上線,舊索引隨時下線。
  • 利用 MySQL 成熟生態:復制、備份、監控、工具鏈零成本復用。
  • 性能可控:InnoDB 聚簇索引 + 自增主鍵保證寫入順序;壓縮 body 節省空間與 I/O。

下集預告: 深入剖析「清潔工」回填算法、分片一致性、故障恢復與容量規劃細節。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved