Zanzibar vs MySQL Permission System - 实证性能对比研究

完整的实证研究项目: 对比传统MySQL展开存储和Google Zanzibar风格的元组图遍历权限系统

基于真实测试数据: 5,000用户 | 100,000文档 | 50,000客户 | 生产规模验证

仓库地址: https://github.com/d60-Lab/zanzibar


1️⃣ 业务背景

这是一个典型的企业文档协作系统的权限管理场景:

核心业务实体

  • 用户: 5,000名员工
  • 部门: 500个部门,5级层级结构
  • 客户: 50,000个客户
  • 文档: 100,000个业务文档

权限需求

  1. 用户可以看到自己创建的文档
  2. 用户可以看到自己关注的客户的文档
  3. 部门主管可以看到该部门及所有子部门员工创建的文档
  4. 部门主管可以看到该部门及所有子部门员工关注客户的文档
  5. 超级用户可以看到所有文档

业务挑战

在传统的关系型数据库方案中,这些权限需求导致:

  • 复杂的权限继承: 管理链、多部门归属、客户关注者等多重权限来源
  • 高昂的维护成本: 组织调整(如员工换部门、部门换主管)需要重建大量权限数据
  • 性能问题: 随着数据增长,权限查询和更新性能急剧下降

研究目标: 通过真实数据对比传统MySQL展开存储和Zanzibar元组存储方案,为架构选型提供实证依据。


2️⃣ 表设计对比

方案一:传统MySQL展开存储

核心思想: 写入时计算所有可能的权限,预先展开存储

sql 复制代码
-- 文档权限表(展开存储)
CREATE TABLE document_permissions_mysql (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id VARCHAR(255) NOT NULL,
    document_id VARCHAR(255) NOT NULL,
    permission_type ENUM('viewer', 'editor', 'owner') NOT NULL,
    source_type ENUM('direct', 'creator', 'customer_follower', 'manager_chain', 'superuser') NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_user_doc_permission (user_id, document_id, permission_type),
    KEY idx_user_id (user_id),
    KEY idx_document_id (document_id)
);

特点:

  • ✅ 读取快速: 直接查询已有权限记录
  • ❌ 写入缓慢: 需要计算并插入所有可能的权限来源
  • ❌ 存储膨胀: 一个文档可能产生数千行权限记录
  • ❌ 维护复杂: 组织调整需要重建大量权限数据

权限来源展开示例 :

当用户 user-1 对文档 doc-123 有权限时,需要插入所有来源:

  • 来源1: 直接授权 - INSERT 1 row
  • 来源2: 文档创建者 - INSERT 1 row
  • 来源3: 客户关注者 - INSERT N rows(N = 该客户的所有文档)
  • 来源4: 管理链 - INSERT M rows(M = 递归查找所有下属员工的所有文档)
  • 来源5: 超级用户 - INSERT ALL rows(所有文档!)

方案二:Zanzibar元组存储

核心思想: 只存储"谁有关系",读取时通过图遍历计算权限

sql 复制代码
-- 关系元组表(Zanzibar风格)
CREATE TABLE relation_tuples (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    namespace VARCHAR(255) NOT NULL,
    object_id VARCHAR(255) NOT NULL,
    relation VARCHAR(255) NOT NULL,
    subject_namespace VARCHAR(255) NOT NULL,
    subject_id VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_tuple (namespace, object_id, relation, subject_namespace, subject_id),
    KEY idx_object (namespace, object_id, relation),
    KEY idx_subject (subject_namespace, subject_id)
);

元组示例:

sql 复制代码
-- 用户 user-1 关注客户 customer-456
INSERT INTO relation_tuples VALUES
('customer', 'customer-456', 'follower', 'user', 'user-1');

-- 文档 doc-123 属于客户 customer-456
INSERT INTO relation_tuples VALUES
('document', 'doc-123', 'owner_customer', 'customer', 'customer-456');

-- 文档 doc-123 的创建者是 user-789
INSERT INTO relation_tuples VALUES
('document', 'doc-123', 'creator', 'user', 'user-789');

特点:

  • ✅ 写入高效: 只需插入/删除1条元组
  • ✅ 存储紧凑: 只存储关系,不展开权限
  • ✅ 维护简单: 组织调整只需更新相关元组
  • ✅ 灵活扩展: 通过配置支持复杂的继承规则
  • ⚠️ 读取计算: 需要图遍历(通过缓存优化)

权限检查逻辑 :

检查 user-1 是否有 doc-123viewer 权限:

  1. 查询: document:doc-123#viewer@user:user-1(直接授权)
  2. 查询: document:doc-123#creator@user:user-1(创建者)
  3. 查询: document:doc-123#owner_customer → 递归查找 customer:*#follower@user:user-1(客户关注者)
  4. 查询: document:doc-123#creator → 查找创建者的部门 → 递归查找管理链(主管权限)
  5. 查询: system:root#admin@user:user-1(超级用户)

核心业务表结构

sql 复制代码
-- 用户表
CREATE TABLE users (
    id VARCHAR(255) PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL UNIQUE,
    primary_department_id VARCHAR(255),
    is_superuser BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL
);

-- 部门表(支持5级层级)
CREATE TABLE departments (
    id VARCHAR(255) PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    parent_id VARCHAR(255),
    level INT NOT NULL,
    manager_id VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (parent_id) REFERENCES departments(id),
    FOREIGN KEY (manager_id) REFERENCES users(id)
);

-- 用户-部门关联表(支持多部门归属)
CREATE TABLE user_departments (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id VARCHAR(255) NOT NULL,
    department_id VARCHAR(255) NOT NULL,
    role ENUM('member', 'manager') NOT NULL,
    is_primary BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_user_dept (user_id, department_id),
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (department_id) REFERENCES departments(id)
);

-- 管理关系表(预计算管理链)
CREATE TABLE management_relations (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    manager_user_id VARCHAR(255) NOT NULL,
    subordinate_user_id VARCHAR(255) NOT NULL,
    department_id VARCHAR(255) NOT NULL,
    management_level INT NOT NULL COMMENT '1=直接上级, 2=二级上级, ...',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_manager_subordinate_dept (manager_user_id, subordinate_user_id, department_id),
    FOREIGN KEY (manager_user_id) REFERENCES users(id),
    FOREIGN KEY (subordinate_user_id) REFERENCES users(id),
    FOREIGN KEY (department_id) REFERENCES departments(id)
);

-- 客户表
CREATE TABLE customers (
    id VARCHAR(255) PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL
);

-- 客户关注者表
CREATE TABLE customer_followers (
    customer_id VARCHAR(255) NOT NULL,
    user_id VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (customer_id, user_id),
    FOREIGN KEY (customer_id) REFERENCES customers(id),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- 文档表
CREATE TABLE documents (
    id VARCHAR(255) PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    customer_id VARCHAR(255) NOT NULL,
    creator_id VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,
    FOREIGN KEY (customer_id) REFERENCES customers(id),
    FOREIGN KEY (creator_id) REFERENCES users(id)
);

存储空间对比

方案 存储行数 说明
MySQL展开存储 9,034,281 行 每个用户-文档-权限组合都需要一行
Zanzibar元组存储 1,071,700 条 只存储关系,不展开权限
存储节省 88.1% Zanzibar节省了8.4倍存储空间 ⚡⚡⚡

3️⃣ 真实测试结果

测试环境配置

指标 数值
用户 5,000 人
文档 100,000 个
客户 50,000 个
部门 500 个 (5级层级)
客户关注者 764,837 条 (Zipfian分布)
文档已读记录 4,761,837 条
MySQL权限表 9,034,281 行 (9百万!) 🚨
Zanzibar元组 1,071,700 条 (107万)
存储节省 88.1% (8.4倍差距) ⚡⚡⚡

关键特性:

  • Zipfian分布: 前10%大客户50-100关注者, 前40%中等客户10-30关注者
  • 多部门归属: 员工可属于1-5个部门
  • 管理链展开: 最多5级管理关系递归展开
  • 真实业务场景: 文档已读/未读状态跟踪

性能对比数据 (9百万行MySQL权限数据)

操作类型 MySQL Zanzibar 性能提升
客户新增文档
平均耗时 50,656.364 ms 🚨🚨 1.992 ms 25,434x ⚡⚡⚡
中位数 50,649.058 ms 2.028 ms 24,975x
P95 50,775.474 ms 🚨 2.132 ms 23,815x
更换客户关注者
平均耗时 1,615.621 ms 🚨 3.630 ms 445x ⚡⚡⚡
中位数 1,670.670 ms 3.504 ms 477x
P95 1,821.098 ms 🚨 4.784 ms 381x
部门换主管
平均耗时 223.676 ms 3.987 ms 56x ⚡⚡
中位数 216.630 ms 4.067 ms 53x
P95 272.286 ms 4.533 ms 60x
用户文档列表 (分页)
平均耗时 89.934 ms 🚨 6.105 ms 15x ⚡⚡⚡
中位数 67.379 ms 2.468 ms 27x
P95 (高负载) 215.430 ms 53.333 ms 4x
单次权限检查
平均耗时 0.574 ms 5.252 ms MySQL快 9x
中位数 0.565 ms 3.544 ms MySQL快 6x
P95 0.700 ms 30.341 ms MySQL快 43x
批量权限检查 (50文档)
平均耗时 2.277 ms 4.816 ms MySQL快 2.1x
中位数 2.163 ms 4.337 ms MySQL快 2x
P95 3.471 ms 9.015 ms MySQL快 2.6x
直接授权操作
平均耗时 3.006 ms 2.355 ms Zanzibar快 1.3x
P95 47.512 ms 7.036 ms Zanzibar快 6.8x
撤销超级用户权限
平均耗时 7.213 ms 2.109 ms Zanzibar快 3.4x
中位数 7.213 ms 2.012 ms Zanzibar快 3.6x
P95 7.213 ms 3.663 ms Zanzibar快 2x
员工加入部门
平均耗时 5.037 ms 3.599 ms Zanzibar快 1.4x
中位数 1.983 ms 3.908 ms MySQL快 2x
P95 11.354 ms 4.010 ms Zanzibar快 2.8x
并发权限检查
平均耗时 0.930 ms 3.594 ms MySQL快 3.9x

测试时间: 2025-12-30 18:27:54

关键发现

✅ Zanzibar 优势场景 (数据规模越大优势越明显)
  1. 写入密集型操作 - Zanzibar 快 445倍 (更换客户关注者)

    • MySQL: 1,616ms → Zanzibar: 3.6ms
    • 客户新增文档 - MySQL: 50秒!!! → Zanzibar: 2ms (快 25,434倍)
  2. 列表查询场景 - Zanzibar 快 15-27倍

    • 用户文档列表: 90ms → 6ms (平均), 67ms → 2.5ms (中位数)
  3. 组织结构调整 - Zanzibar 快 56倍 (部门换主管)

    • MySQL: 224ms → Zanzibar: 4ms
✅ MySQL 优势场景 (但优势有限)
  1. 单次权限检查 (冷启动) - MySQL快 6-9倍

    • MySQL: 0.57ms vs Zanzibar: 3.5-5.3ms
    • 但差异仅在5ms级别, 对用户体验影响小
  2. 批量权限检查 (50文档) - MySQL快 2倍

    • MySQL: 2.3ms vs Zanzibar: 4.8ms
    • 经过优化后, 差距从92倍缩小到2倍, 已非常接近

扩展性对比

指标 2.6M MySQL数据 9M MySQL数据 变化趋势
数据规模 1x 3.5x
MySQL写入性能 (更换关注者) 73ms 1,616ms ↑22x (严重恶化) 🚨
Zanzibar写入性能 2.3ms 3.6ms ↑1.6x (稳定) ✅
MySQL列表查询 22ms 90ms ↑4.1x (恶化) 🚨
Zanzibar列表查询 2.3ms 6.1ms ↑2.7x (稳定) ✅
MySQL批量检查 (50文档) 2.7ms 2.3ms ↓0.9x (稳定) ✅
Zanzibar批量检查 (50文档) 15.9ms 4.8ms ↓0.3x (优化后) ✅

结论:

  • 数据规模越大, Zanzibar写入和列表查询优势越明显
  • 批量权限检查经过优化后, 性能提升3.3倍 (15.9ms → 4.8ms), 已接近MySQL水平

4️⃣ 如何复现测试

前置要求

  • Go 1.21+
  • MySQL 8.0+

步骤 1: 克隆仓库

bash 复制代码
git clone https://github.com/d60-Lab/zanzibar.git
cd zanzibar

步骤 2: 创建数据库

bash 复制代码
# 创建数据库
mysql -u root -p123456 -h 127.0.0.1 -e "CREATE DATABASE zanzibar_permission;"

# 运行迁移脚本
mysql -u root -p123456 -h 127.0.0.1 zanzibar_permission < migrations/001_permission_comparison_schema.sql

# 验证表创建
mysql -u root -p123456 -h 127.0.0.1 zanzibar_permission -e "SHOW TABLES;"

预期输出:

复制代码
+-------------------------------------------+
| Tables_in_zanzibar_permission             |
+----------------------------------+
| customers                        |
| customer_followers               |
| departments                      |
| document_permissions_mysql       |
| documents                        |
| management_relations             |
| relation_tuples                  |
| user_departments                 |
| users                            |
+----------------------------------+

步骤 3: 清空现有数据 (可选)

如果之前运行过测试,先清空数据:

bash 复制代码
mysql -u root -p123456 -h 127.0.0.1 zanzibar_permission -e "
SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE document_reads;
TRUNCATE TABLE relation_tuples;
TRUNCATE TABLE document_permissions_mysql;
TRUNCATE TABLE documents;
TRUNCATE TABLE customer_followers;
TRUNCATE TABLE customers;
TRUNCATE TABLE management_relations;
TRUNCATE TABLE user_departments;
TRUNCATE TABLE departments;
TRUNCATE TABLE users;
SET FOREIGN_KEY_CHECKS=1;
"

步骤 4: 生成测试数据并运行Benchmark

bash 复制代码
# 1. 生成测试数据 (约30分钟)
go run cmd/production-test/main.go generate

# 2. 运行性能测试 (约30秒)
go run cmd/production-test/main.go benchmark

测试完成后,结果会保存在 benchmark-results-production/ 目录。

查看测试结果

bash 复制代码
# 查看生成的结果文件
ls -lh benchmark-results-production/

# 查看摘要报告
cat benchmark-results-production/summary_*.md

# 查看详细数据
cat benchmark-results-production/detailed_results_*.csv

💡 结论与建议

基于9百万行MySQL权限数据的真实测试:

强烈推荐使用 Zanzibar 的场景

任何写入操作 (更换关注者、组织调整、权限变更)

  • 写入性能提升 445倍 (1,616ms vs 3.6ms)
  • 客户新增文档提升 25,434倍 (50秒 vs 2ms)
  • 数据增长时, MySQL性能持续恶化, Zanzibar性能稳定

用户文档列表查询 (最常用接口!)

  • 性能提升 15-27倍 (90ms vs 6ms)
  • 用户体验明显改善

组织结构调整 (部门换主管、员工换部门)

  • 性能提升 56倍 (224ms vs 4ms)
  • 维护成本降低 100-100,000倍
  • 只需更新1条元组 vs 数千/数万行展开权限

需要支持未来增长

  • MySQL扩展性差 (数据↑3.5x, 写入性能↓22x) 🚨
  • Zanzibar性能稳定 ✅

可以考虑 MySQL 的场景 (仅限特定场景)

⚠️ 单次权限检查密集型应用

  • MySQL快 6-9倍 (0.57ms vs 3.5-5.3ms)
  • 但差异仅在5ms级别, 对用户体验影响小

⚠️ 批量权限检查 (50文档)

  • MySQL快 2倍 (2.3ms vs 4.8ms)
  • 经过优化后差距已非常小, 且可进一步优化

⚠️ 100%只读场景, 永不修改权限

  • 初始化后完全静态, 无任何写入
  • 但这种情况在实际业务中几乎不存在

📁 项目结构

复制代码
zanzibar/
├── cmd/
│   ├── production-test/           # 生产规模测试工具
│   └── benchmark/                 # 小规模Benchmark工具
├── internal/
│   ├── api/handler/               # HTTP处理器
│   ├── repository/                # MySQL和Zanzibar引擎实现
│   └── service/                   # Benchmark套件和数据生成器
├── migrations/
│   └── 001_permission_comparison_schema.sql  # 数据库schema
├── benchmark-results-production/  # 生产测试结果
└── README.md                      # 本文件

📖 相关资源


项目状态 : ✅ 完成 (100%) - 生产规模(9M行)数据验证完成

测试时间:

  • 数据生成: 约30分钟
  • Benchmark执行: 约30秒
  • 总计约30分钟获得完整的生产级测试结果

这是一个完整、生产级、经过9百万行真实数据验证的实证研究项目。🎉

相关推荐
Greyscarf2 小时前
人大金仓服务启动
数据库
是娇娇公主~2 小时前
快速了解MySQL索引(什么是索引,分类)
mysql
张较瘦_2 小时前
MySQL | 文本数据类型(CHAR/VARCHAR/TEXT/BLOB):区别、场景与实战
数据库·mysql
悄悄敲敲敲2 小时前
MySQL内置函数
数据库·mysql
小北方城市网3 小时前
第 5 课:后端工程化进阶 ——Python 分层架构 + 中间件 + 日志 / 异常统一处理(打造企业级高可用后端)
数据库·人工智能·python·mysql·数据库架构
m0_598177233 小时前
SQL(5)- 事务
java·数据库·sql
郝学胜-神的一滴3 小时前
Qt重复添加控件问题探析:现象、原理与解决方案
开发语言·数据库·c++·qt·程序人生
星空椰3 小时前
Windows 安装 Oracle 19c Instant Client
数据库·windows·oracle
万象.3 小时前
redis通用命令与数据结构
数据结构·数据库·redis