Go Engineer System Course 013 [Study Notes]

Order transactions, whether deducting inventory first or later, will both affect inventory and orders. Therefore, distributed transactions must be used to address business issues (e.g., unpaid orders). One approach is to deduct inventory only after successful payment (e.g., an order was placed, but there was no inventory at the time of payment). Another common method is to deduct inventory when the order is placed, but if payment isn't made, the order is returned/released upon timeout.

Transactions and Distributed Transactions
1. What is a transaction?
A transaction is an important concept in database management systems. It is a collection of database operations, which either all execute successfully, or all...

Table of Contents

Order Transactions

  • Whether inventory is deducted before or after, it will affect both inventory and orders, so distributed transactions must be used.
  • Business (order placed but not paid) business problem.
  • Deduct inventory after successful payment (order placed, but out of stock at payment time).
  • Order deduction, no payment (order timeout and return) [common method].

Transactions and Distributed Transactions

1. What is a Transaction?

A transaction is an important concept in database management systems. It is a collection of database operations that are either all successfully executed or all rolled back upon failure.

1.1 ACID Properties of Transactions

  • Atomicity: All operations within a transaction either succeed completely or fail completely; there is no partial success.
  • Consistency: A transaction transforms the database from one consistent state to another consistent state before and after its execution.
  • Isolation: Concurrent transactions are isolated from each other; the execution of one transaction should not affect other transactions.
  • Durability: Once a transaction is committed, its results are permanently stored in the database.

1.2 Transaction Isolation Levels

  1. Read Uncommitted: The lowest level, may read dirty data.
  2. Read Committed: Can only read committed data.
  3. Repeatable Read: Multiple reads within the same transaction yield consistent results.
  4. Serializable: The highest level, transactions are executed completely serially.

2. What is a Distributed Transaction?

A distributed transaction refers to transaction operations involving multiple databases or services, requiring data consistency across multiple nodes.

2.1 Challenges of Distributed Transactions

  • Network Partition: Network failures lead to communication interruptions between nodes.
  • Node Failure: A node crashes or restarts.
  • Clock Skew: Inconsistent times across different nodes.
  • Data Consistency: How to ensure data consistency across nodes.

2.2 CAP Theorem

  • Consistency: All nodes see the same data at the same time (after an update returns to the client).
  • Availability: The system remains continuously available and operations do not fail.
  • Partition Tolerance: The system can tolerate network partition failures.

CAP Theorem: In a distributed system, it is impossible to simultaneously satisfy all three of Consistency, Availability, and Partition Tolerance.

2.3 BASE Theory (Engineering Trade-offs with CAP)

  • Basically Available: In the event of a failure, the system is allowed to degrade and provide limited functionality (e.g., slower response, partial unavailability).
  • Soft state: The system state is allowed to exist in an intermediate state for a period of time (not strongly consistent).
  • Eventual consistency: Data eventually reaches consistency after a period of time (or through retries/compensations).

In engineering practice: most internet businesses choose AP → guided by BASE theory, sacrificing strong consistency for high availability and scalability, achieving eventual consistency through "compensation, retries, deduplication, and reconciliation".

3. Distributed Transaction Solutions

3.1 Two-Phase Commit (2PC)

Principle:

  1. Prepare Phase: The coordinator asks all participants if they can commit.
  2. Commit Phase: Decides to commit or roll back based on participant responses.

Advantages: Strong consistency
Disadvantages: Poor performance, single point of failure, blocking issues

Detailed Process (示意):

  1. The coordinator sends a prepare request to participants. Each participant reserves resources, writes pre-commit logs, and returns yes/no.
  2. The coordinator aggregates: all yes → sends commit; any no/timeout → sends rollback.
  3. Participants commit or roll back according to the instruction and acknowledge the coordinator.

Common issues: single point of failure for the coordinator, participant blocking (holding locks for a long time), complex recovery during network partitions.

sequenceDiagram
  participant C as 协调者(Coordinator)
  participant P1 as 参与者1
  participant P2 as 参与者2

  C->>P1: prepare
  C->>P2: prepare
  P1-->>C: yes/预提交成功
  P2-->>C: yes/预提交成功
  alt 全部yes
    C->>P1: commit
    C->>P2: commit
    P1-->>C: ack
    P2-->>C: ack
  else 任一no/超时
    C->>P1: rollback
    C->>P2: rollback
  end

3.2 Three-Phase Commit (3PC)

Adds a pre-commit phase on top of 2PC to reduce blocking time, but still suffers from single point of failure issues.

3.3 TCC (Try-Confirm-Cancel)

Principle:

  • Try: Attempt to execute business, reserve resources.
  • Confirm: Confirm business execution, commit resources.
  • Cancel: Cancel business execution, release resources.

Advantages: Good performance, non-blocking
Disadvantages: Complex implementation, requires business compensation

Key Implementation Points (taking order-inventory-payment as an example):

  • Try: Create order pre-status, pre-occupy inventory (deduct available inventory, increase pre-occupied inventory), pre-order payment.
  • Confirm (payment success callback or asynchronous confirmation): Order status changes to paid, inventory moves from pre-occupied to formally deducted.
  • Cancel (payment failure/timeout): Order cancelled, pre-occupied inventory released.

Implementation details: idempotent interfaces (deduplication table/unique business key), handling null rollback/hanging, transaction log recording and retry tasks.

sequenceDiagram
  participant Order as 订单服务
  participant Inv as 库存服务
  participant Pay as 支付服务

  rect rgb(230,250,230)
  Note over Order,Inv: Try 阶段(预留资源)
  Order->>Inv: Try 预占库存
  Order->>Pay: Try 预下单/冻结
  end

  alt 支付成功
    rect rgb(230,230,255)
    Note over Order,Inv: Confirm 阶段
    Pay-->>Order: 支付成功回调
    Order->>Inv: Confirm 扣减库存
    Order->>Pay: Confirm 确认扣款
    end
  else 失败/超时
    rect rgb(255,230,230)
    Note over Order,Inv: Cancel 阶段
    Order->>Inv: Cancel 释放预占
    Order->>Pay: Cancel 解冻/撤销
    end
  end

3.4 Message-Based Eventual Consistency

Principle:

  1. Execute local transaction.
  2. Send message to message queue.
  3. Consumer processes message, ensuring eventual consistency.

Advantages: Good performance, relatively simple implementation
Disadvantages: Only guarantees eventual consistency

3.4.1 Local Message Table (Outbox Pattern)

Process: Write business data and outbox message table within the same local transaction → background forwarder polls and delivers to MQ → consumer processes and persists to database → sends confirmation/reconciliation.

Key points:

  • Strong consistency on the producer side (business + message in the same database transaction)
  • Idempotent forwarding (deliver by message ID, consumer deduplication)
  • Failure retry and dead-letter queue, manual reconciliation and repair
flowchart LR
  A[应用/业务服务] -->|同库同事务| B[(业务表 + Outbox表)]
  B -->|后台转发器扫描/拉取| MQ[消息队列]
  MQ --> C[下游服务]
  C --> D[(消费落库/去重表)]

  subgraph 重试与对账
    E[失败重投/死信队列]
    F[对账/人工修复]
  end
  MQ --> E
  E --> F
3.4.2 Reliable Message-Based Eventual Consistency (Common)

Process:

  1. The business requests a "prepare message/half message" from MQ.
  2. After the local business commit is successful, it calls MQ to confirm (commit), otherwise it rolls back.
  3. MQ suspends unconfirmed half messages and queries (check) the business's final status to decide whether to commit or discard.

Key points:

  • Relies on MQ's transaction message/callback capabilities (RocketMQ, etc.)
  • Both producer and consumer sides need idempotent processing.
sequenceDiagram
  participant Biz as 业务服务
  participant MQ as MQ(事务消息)
  participant D as 下游服务

  Biz->>MQ: 发送半消息(Prepare)
  Biz->>Biz: 执行业务本地事务
  alt 成功
    Biz->>MQ: Commit 确认
  else 失败
    Biz->>MQ: Rollback 撤销
  end
  MQ->>D: 投递正式消息
  D-->>MQ: Ack/重试

  MQ->>Biz: 事务回查(Check) 未确认半消息
  Biz-->>MQ: 返回最终状态(提交/回滚)
3.4.3 Best-Effort Notification

Process: After an event occurs, a notification is sent to downstream systems (HTTP/MQ). If it fails, it retries several times according to a strategy. If the threshold is exceeded, it enters manual processing.

Applicable: Scenarios with relatively relaxed consistency requirements (e.g., SMS, in-app messages, point issuance).

flowchart LR
  A[事件源] --> B{通知}
  B -->|HTTP/MQ| C[下游]
  B --> R1[重试1]
  R1 --> R2[重试2]
  R2 --> R3[重试N]
  R3 --> DLQ[死信/人工补偿]
  C --> Idem[去重/幂等处理]

4. Transaction Processing in Order Systems

4.1 Inventory Deduction Issue

In an order system, inventory deduction is a critical operation:

// 库存扣减示例
func (s *InventoryServer) Sell(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {
    // 开启事务
    tx := global.DB.Begin()
    if tx.Error != nil {
        return nil, status.Error(codes.Internal, "开启事务失败")
    }

    // 遍历所有商品
    for _, goodsInfo := range req.GoodsInvInfo {
        var inv model.Inventory
        // 使用行锁查询
        result := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
            Where("goods_id = ?", goodsInfo.GoodsId).
            First(&inv)

        // 检查库存是否充足
        if inv.Stock < goodsInfo.Num {
            tx.Rollback()
            return nil, status.Error(codes.ResourceExhausted, "库存不足")
        }

        // 使用乐观锁更新库存
        updateResult := tx.Model(&model.Inventory{}).
            Where("goods_id = ? AND version = ?", goodsInfo.GoodsId, inv.Version).
            Updates(map[string]interface{}{
                "stock":   inv.Stock - goodsInfo.Num,
                "version": inv.Version + 1,
            })
    }

    // 提交事务
    if err := tx.Commit().Error; err != nil {
        return nil, status.Error(codes.Internal, "提交事务失败")
    }
    return &emptypb.Empty{}, nil
}

4.2 Distributed Locks to Solve Concurrency Issues

// 基于Redis的分布式锁
func (s *InventoryServer) SellWithDistributedLock(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {
    // 获取分布式锁
    lockKey := fmt.Sprintf("inventory_lock_%d", req.GoodsInvInfo[0].GoodsId)
    lock := s.redisClient.NewMutex(lockKey, time.Second*10)

    if err := lock.Lock(); err != nil {
        return nil, status.Error(codes.Internal, "获取锁失败")
    }
    defer lock.Unlock()

    // 执行库存扣减逻辑
    return s.Sell(ctx, req)
}

5. Business Scenario Analysis

5.1 Order Placement Without Payment Issue

Problem: Users place orders but do not pay, leading to inventory being held.

Solutions:

  1. Order Timeout Mechanism: Set an order timeout period, after which the order is automatically canceled.
  2. Inventory Pre-occupation: Pre-occupy inventory when an order is placed, confirm deduction after successful payment.
  3. Scheduled Task: Periodically clean up timed-out orders and release inventory.

5.2 Insufficient Inventory During Payment Issue

Problem: Inventory is sufficient when the order is placed, but insufficient at the time of payment.

Solutions:

  1. Inventory Pre-occupation: Pre-occupy inventory when an order is placed to prevent overselling.
  2. Re-check at Payment: Re-verify inventory before payment.
  3. Compensation Mechanism: Provide alternative solutions when inventory is insufficient.

6. Best Practices

  1. Judicious Use of Transactions: Avoid long transactions to reduce lock contention.
  2. Choose Appropriate Isolation Levels: Select based on business requirements.
  3. Use Optimistic Locking: Reduce lock contention and improve concurrency performance.
  4. Implement Retry Mechanisms: Handle transient failures.
  5. Monitoring and Alerting: Timely detection and handling of issues.

7. Summary

Transactions and distributed transactions are important mechanisms for ensuring data consistency. In a microservice architecture,

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/4786

(0)
Walker的头像Walker
上一篇 Mar 10, 2026 00:00
下一篇 Mar 8, 2026 15:40

Related Posts

  • Node: In-depth Yet Easy to Understand (Shengsi Garden Education) 003 [Study Notes]

    WebSocket and SSE Overview WebSocket Basics Definition: WebSocket is a full-duplex connection upgraded after an HTTP handshake, allowing clients and servers to push data bidirectionally over the same TCP channel, eliminating the need for repeated polling. Handshake Process: The client initiates an HTTP request with the Upgrade: websocket header; The server responds with 101 Switching Protocols, and both parties agree...

    Personal Nov 24, 2025
    39700
  • Nuxt3: Beginner's Guide and Principles Introduction [Learning Notes]

    Nuxt 3: Getting Started and Principles 💡 What is Nuxt 3? Nuxt 3 is a full-stack frontend framework built on Vue 3 and Vite, supporting: Server-Side Rendering (SSR) Static Site Generation (SSG) Single-Page Applications (SPA) Building full-stack applications (with API support) Nuxt 3 is an "enhanced version" of Vue, helping you simplify project structure and development workflow. 🔧 Core Principles Feature How Nuxt Handles It ✅ Page Routing Automatic root...

    Personal Apr 6, 2025
    2.2K00
  • In-depth Understanding of ES6 012 [Study Notes]

    Proxy and Reflection API
    A Proxy is a wrapper that can intercept and modify underlying JavaScript engine operations. It exposes internal operational objects, enabling developers to create custom built-in objects.

    Proxy Traps
    Overridden Features | Default Behavior
    get Reads a property value | Reflect.get()
    set Writes a property value | Reflect.set()
    has `in` operator | Reflect...

    Personal Mar 8, 2025
    1.2K00
  • Go Engineer Systematic Course 002 [Study Notes]

    Differences between GOPATH and Go Modules 1. Concept GOPATH was Go's early dependency management mechanism. All Go projects and dependency packages must be placed within the GOPATH directory (default is ~/go). GO111MODULE=off must be set. Project paths must be organized according to the src/package_name structure. Version control is not supported, and dependency management needs to be handled manually (e.g., go get). The order for finding dependency packages is g...

    Nov 25, 2025
    29300
  • Go Engineer Systematic Course 008 [Study Notes]

    Orders and Shopping Cart
    First, copy the service code framework of 'srv' from the inventory service, then find and replace the corresponding name (order_srv).

    Fundamentals of Encryption Technology
    Symmetric Encryption
    Principle:
    Uses the same key for encryption and decryption.
    Like a single key that can both lock and unlock a door.
    Fast encryption speed, suitable for large data transfers.
    Use cases:
    Local file encryption
    Database content encryption
    Content encryption during large data transfers
    Fast communication between internal systems...

    Personal Nov 25, 2025
    26500
EN
简体中文 繁體中文 English