分布式事务 #

一、事务概述 #

1.1 ACID保证 #

text
ACID 特性
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   Atomicity (原子性)                                        │
│   └── 事务要么全部成功,要么全部失败                       │
│                                                             │
│   Consistency (一致性)                                      │
│   └── 事务前后数据保持一致状态                             │
│                                                             │
│   Isolation (隔离性)                                        │
│   └── 并发事务互不干扰                                     │
│                                                             │
│   Durability (持久性)                                       │
│   └── 事务提交后数据永久保存                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 分布式事务挑战 #

text
分布式事务挑战
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   网络分区:                                                 │
│   ├── 节点间通信可能失败                                   │
│   └── 需要容错机制                                         │
│                                                             │
│   节点故障:                                                 │
│   ├── 节点可能随时宕机                                     │
│   └── 需要故障恢复机制                                     │
│                                                             │
│   数据分布:                                                 │
│   ├── 数据分布在多个节点                                   │
│   └── 需要协调多个节点                                     │
│                                                             │
│   性能问题:                                                 │
│   ├── 跨节点事务延迟高                                     │
│   └── 需要优化事务处理                                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

二、事务模型 #

2.1 事务生命周期 #

sql
-- 基本事务
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

-- 带参数的事务
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE, PRIORITY HIGH;
-- SQL语句
COMMIT;

-- 只读事务
BEGIN TRANSACTION READ ONLY;
SELECT * FROM accounts;
COMMIT;

2.2 事务状态 #

text
事务状态机
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   ┌─────────┐                                              │
│   │ Pending │  事务开始                                    │
│   └────┬────┘                                              │
│        │                                                    │
│        ▼                                                    │
│   ┌─────────┐                                              │
│   │ Staging │  准备提交                                    │
│   └────┬────┘                                              │
│        │                                                    │
│        ├─────────────────────┐                             │
│        ▼                     ▼                             │
│   ┌─────────┐          ┌─────────┐                         │
│   │Committed│          │ Aborted │                         │
│   └─────────┘          └─────────┘                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

三、两阶段提交 #

3.1 2PC流程 #

text
两阶段提交流程
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   Phase 1: Prepare                                          │
│                                                             │
│   Coordinator                                               │
│       │                                                     │
│       ├──► Range 1: Prepare                                │
│       │       │                                             │
│       │       └── 锁定资源                                 │
│       │       └── 返回 Ready                               │
│       │                                                     │
│       ├──► Range 2: Prepare                                │
│       │       │                                             │
│       │       └── 锁定资源                                 │
│       │       └── 返回 Ready                               │
│       │                                                     │
│       └──► Range 3: Prepare                                │
│               │                                             │
│               └── 锁定资源                                 │
│               └── 返回 Ready                               │
│                                                             │
│   Phase 2: Commit                                           │
│                                                             │
│   Coordinator (所有参与者 Ready)                            │
│       │                                                     │
│       ├──► Range 1: Commit                                 │
│       ├──► Range 2: Commit                                 │
│       └──► Range 3: Commit                                 │
│                                                             │
│   返回成功                                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.2 事务记录 #

sql
-- 查看事务记录
SELECT * FROM crdb_internal.cluster_transactions;

-- 查看特定事务
SELECT * FROM crdb_internal.cluster_transactions
WHERE id = 'transaction-id';

-- 事务字段说明
SELECT 
    id,                    -- 事务ID
    status,                -- 状态
    start,                 -- 开始时间
    num_retries,           -- 重试次数
    num_statements,        -- 语句数量
    last_error,            -- 最后错误
    priority               -- 优先级
FROM crdb_internal.cluster_transactions;

四、隔离级别 #

4.1 支持的隔离级别 #

sql
-- READ COMMITTED (默认)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- SERIALIZABLE
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- 查看当前隔离级别
SHOW TRANSACTION ISOLATION LEVEL;

4.2 隔离级别对比 #

text
隔离级别对比
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   问题          │ READ COMMITTED │ SERIALIZABLE            │
│   ────────────────────────────────────────────────────────  │
│   脏读          │      ✗         │      ✗                 │
│   不可重复读    │      ✓         │      ✗                 │
│   幻读          │      ✓         │      ✗                 │
│   写偏斜        │      ✓         │      ✗                 │
│                                                             │
│   性能          │     较高       │     较低               │
│   一致性        │     较弱       │     最强               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.3 隔离级别示例 #

sql
-- READ COMMITTED 示例
-- 会话1
BEGIN ISOLATION LEVEL READ COMMITTED;
SELECT balance FROM accounts WHERE id = 1;  -- 1000

-- 会话2
BEGIN;
UPDATE accounts SET balance = 500 WHERE id = 1;
COMMIT;

-- 会话1
SELECT balance FROM accounts WHERE id = 1;  -- 500 (不可重复读)
COMMIT;

-- SERIALIZABLE 示例
-- 会话1
BEGIN ISOLATION LEVEL SERIALIZABLE;
SELECT balance FROM accounts WHERE id = 1;  -- 1000

-- 会话2
BEGIN;
UPDATE accounts SET balance = 500 WHERE id = 1;
COMMIT;

-- 会话1
SELECT balance FROM accounts WHERE id = 1;  -- 1000 (可重复读)
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 可能触发重试
COMMIT;

五、并发控制 #

5.1 乐观并发控制 #

text
乐观并发控制
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   阶段:                                                     │
│                                                             │
│   1. 读取阶段                                               │
│      ├── 读取数据到本地                                    │
│      └── 记录读取的时间戳                                  │
│                                                             │
│   2. 验证阶段                                               │
│      ├── 检查是否有冲突                                    │
│      └── 冲突则重试                                        │
│                                                             │
│   3. 写入阶段                                               │
│      ├── 提交事务                                          │
│      └── 写入新版本数据                                    │
│                                                             │
│   优点:                                                     │
│   ├── 无锁开销                                             │
│   ├── 适合读多写少                                         │
│   └── 高并发性能好                                         │
│                                                             │
│   缺点:                                                     │
│   ├── 冲突时需要重试                                       │
│   └── 写多读少性能差                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

5.2 冲突检测 #

sql
-- 冲突检测示例
-- 两个事务同时更新同一行

-- 事务1
BEGIN;
SELECT balance FROM accounts WHERE id = 1;  -- 1000

-- 事务2
BEGIN;
SELECT balance FROM accounts WHERE id = 1;  -- 1000
UPDATE accounts SET balance = 900 WHERE id = 1;
COMMIT;  -- 成功

-- 事务1
UPDATE accounts SET balance = 800 WHERE id = 1;
COMMIT;  -- 可能失败,需要重试
-- Error: restart transaction

5.3 重试机制 #

sql
-- 自动重试示例
DO $$
BEGIN
    DECLARE
        retry_count INT DEFAULT 0;
    BEGIN
        WHILE retry_count < 3 LOOP
            BEGIN
                -- 事务逻辑
                UPDATE accounts SET balance = balance - 100 WHERE id = 1;
                UPDATE accounts SET balance = balance + 100 WHERE id = 2;
                COMMIT;
                EXIT;  -- 成功退出
            EXCEPTION WHEN serialization_failure THEN
                retry_count := retry_count + 1;
                ROLLBACK;
                -- 可以添加延迟
                -- PERFORM pg_sleep(0.1);
            END;
        END LOOP;
        
        IF retry_count >= 3 THEN
            RAISE EXCEPTION 'Transaction failed after 3 retries';
        END IF;
    END;
END;
$$;

六、事务优先级 #

6.1 设置优先级 #

sql
-- 高优先级
SET TRANSACTION PRIORITY HIGH;

-- 低优先级
SET TRANSACTION PRIORITY LOW;

-- 正常优先级 (默认)
SET TRANSACTION PRIORITY NORMAL;

-- 在事务开始时设置
BEGIN TRANSACTION PRIORITY HIGH;
-- SQL语句
COMMIT;

6.2 优先级影响 #

text
事务优先级影响
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   HIGH:                                                     │
│   ├── 优先执行                                             │
│   ├── 较少重试                                             │
│   └── 可能导致其他事务重试                                 │
│                                                             │
│   NORMAL:                                                   │
│   ├── 默认优先级                                           │
│   └── 公平竞争                                             │
│                                                             │
│   LOW:                                                      │
│   ├── 最后执行                                             │
│   ├── 更多重试                                             │
│   └── 适合后台任务                                         │
│                                                             │
│   使用场景:                                                 │
│   ├── HIGH: 重要业务事务                                   │
│   ├── NORMAL: 普通事务                                     │
│   └── LOW: 后台批处理任务                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

七、分布式事务最佳实践 #

7.1 设计原则 #

text
事务设计原则
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   1. 保持事务简短                                           │
│      ├── 减少事务持有时间                                  │
│      └── 降低冲突概率                                      │
│                                                             │
│   2. 避免热点                                               │
│      ├── 分散写入                                          │
│      └── 使用UUID代替自增ID                                │
│                                                             │
│   3. 合理设置隔离级别                                       │
│      ├── 默认READ COMMITTED                                │
│      └── 需要强一致性用SERIALIZABLE                        │
│                                                             │
│   4. 实现重试逻辑                                           │
│      ├── 捕获serialization_failure                         │
│      └── 设置合理重试次数                                  │
│                                                             │
│   5. 使用合适的优先级                                       │
│      ├── 重要事务HIGH                                      │
│      └── 后台任务LOW                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

7.2 事务模式 #

sql
-- 模式1: 简单事务
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

-- 模式2: 带重试的事务
DO $$
BEGIN
    DECLARE
        retry INT DEFAULT 0;
    BEGIN
        WHILE retry < 3 LOOP
            BEGIN
                -- 事务逻辑
                COMMIT;
                EXIT;
            EXCEPTION WHEN serialization_failure THEN
                retry := retry + 1;
                ROLLBACK;
            END;
        END LOOP;
    END;
END;
$$;

-- 模式3: 只读事务
BEGIN TRANSACTION READ ONLY;
SELECT * FROM accounts;
COMMIT;

-- 模式4: 时间旅行查询
SELECT * FROM accounts
AS OF SYSTEM TIME '-10s';

八、事务监控 #

8.1 监控指标 #

sql
-- 查看活跃事务
SELECT * FROM crdb_internal.cluster_transactions
WHERE status = 'pending';

-- 查看事务统计
SELECT 
    database,
    COUNT(*) as transaction_count,
    AVG(num_statements) as avg_statements,
    AVG(num_retries) as avg_retries
FROM crdb_internal.cluster_transactions
GROUP BY database;

-- 查看长时间运行的事务
SELECT 
    id,
    start,
    NOW() - start AS duration,
    num_statements
FROM crdb_internal.cluster_transactions
WHERE status = 'pending'
ORDER BY duration DESC;

8.2 事务问题排查 #

sql
-- 查看重试次数多的事务
SELECT 
    id,
    num_retries,
    last_error
FROM crdb_internal.cluster_transactions
WHERE num_retries > 0
ORDER BY num_retries DESC;

-- 查看锁等待
SELECT * FROM crdb_internal.cluster_locks;

-- 查看阻塞的事务
SELECT 
    blocked.id AS blocked_txn,
    blocking.id AS blocking_txn,
    blocked.num_retries
FROM crdb_internal.cluster_transactions blocked
JOIN crdb_internal.cluster_transactions blocking
    ON blocked.id != blocking.id
WHERE blocked.num_retries > 0;

九、总结 #

分布式事务要点:

特性 说明
ACID 完整的事务保证
两阶段提交 分布式事务协调
隔离级别 READ COMMITTED, SERIALIZABLE
并发控制 乐观并发控制
重试机制 自动重试

下一步,让我们学习数据复制!

最后更新:2026-03-27