Skip to content

Latest commit

 

History

History
348 lines (244 loc) · 7.02 KB

File metadata and controls

348 lines (244 loc) · 7.02 KB

5.2 一致性模型

📍 导航返回目录 | 上一节:CAP定理 | 下一节:分布式ID


一致性级别

从强到弱排序:

强一致性 → 顺序一致性 → 因果一致性 → 最终一致性 → 弱一致性

强一致性(Strong Consistency)

定义

任何时刻,所有节点看到的数据完全一致。

特点

  • 读操作总能读到最新写入的值
  • 就像只有一个副本

实现方式

1. 同步复制

func WriteWithStrongConsistency(key, value string, replicas []Node) error {
    var wg sync.WaitGroup
    errChan := make(chan error, len(replicas))
    
    // 并发写入所有副本
    for _, node := range replicas {
        wg.Add(1)
        go func(n Node) {
            defer wg.Done()
            if err := n.Write(key, value); err != nil {
                errChan <- err
            }
        }(node)
    }
    
    wg.Wait()
    close(errChan)
    
    // 只要有一个失败,回滚所有
    if len(errChan) > 0 {
        rollback(key, replicas)
        return <-errChan
    }
    
    return nil
}

2. Paxos / Raft

  • 通过共识算法保证强一致性
  • 牺牲部分性能

典型系统:etcd, ZooKeeper, Spanner


顺序一致性(Sequential Consistency)

定义

所有节点看到的操作顺序一致,但不保证实时性。

示例

进程1: Write(X, 1) → Write(X, 2)
进程2:                           Read(X) → Read(X)

顺序一致: Read可能返回 (1,2) 或 (2,2),但不能是 (2,1)

因果一致性(Causal Consistency)

定义

有因果关系的操作必须按顺序可见。

示例

用户A: 发帖子 → 删除帖子
用户B:         看到帖子 → 帖子消失 ✅

错误: 用户B先看到帖子消失,后看到帖子出现 ❌

实现:Vector Clock

type VectorClock map[string]int

type CausalStore struct {
    data  map[string]string
    clock VectorClock
    mu    sync.RWMutex
}

func (cs *CausalStore) Write(key, value string, clientID string) {
    cs.mu.Lock()
    defer cs.mu.Unlock()
    
    cs.clock[clientID]++
    cs.data[key] = value
}

func (cs *CausalStore) Read(key string) (string, VectorClock) {
    cs.mu.RLock()
    defer cs.mu.RUnlock()
    
    return cs.data[key], cs.clock
}

最终一致性(Eventual Consistency)

定义

停止写入后,经过一段时间,所有副本最终达到一致。

典型场景

DNS系统

# 更新DNS记录
# 全球DNS服务器最终(几小时)会同步

社交网络点赞数

func IncrementLikes(postID string) {
    // 本地计数器递增
    localCounter.Incr(postID)
    
    // 异步同步到数据库
    go func() {
        db.IncrBy(postID, 1)
    }()
}

// 定期合并
func MergeLikes() {
    ticker := time.NewTicker(10 * time.Second)
    for range ticker.C {
        for postID, count := range localCounter.GetAll() {
            db.IncrBy(postID, count)
            localCounter.Reset(postID)
        }
    }
}

会话一致性(Session Consistency)

定义

同一会话内保证读到自己的写入。

实现:Sticky Session

type SessionStore struct {
    sessions map[string]*Session
    mu       sync.RWMutex
}

type Session struct {
    lastWriteTime time.Time
    lastWriteNode string
}

func (ss *SessionStore) Write(sessionID, key, value string, node string) {
    // 写入数据
    node.Write(key, value)
    
    // 记录会话信息
    ss.mu.Lock()
    ss.sessions[sessionID] = &Session{
        lastWriteTime: time.Now(),
        lastWriteNode: node,
    }
    ss.mu.Unlock()
}

func (ss *SessionStore) Read(sessionID, key string) string {
    ss.mu.RLock()
    session := ss.sessions[sessionID]
    ss.mu.RUnlock()
    
    // 如果刚写入,从同一节点读取
    if session != nil && time.Since(session.lastWriteTime) < time.Second {
        return session.lastWriteNode.Read(key)
    }
    
    // 否则随机选择节点
    return randomNode().Read(key)
}

应用:Web应用中的用户会话


Quorum机制

NWR模型

  • N:副本数
  • W:写入确认数
  • R:读取节点数

一致性保证:W + R > N

示例

N = 3, W = 2, R = 2

副本: [A, B, C]

写入:
  Client → A ✅
  Client → B ✅  (W=2, 成功)
  Client → C (异步)

读取:
  Client → A (value=1, version=5)
  Client → B (value=1, version=5)
  返回: value=1 (两个节点达成一致)

灵活配置

type QuorumConfig struct {
    N int  // 副本数
    W int  // 写确认数
    R int  // 读节点数
}

// 强一致性
strongConsistency := QuorumConfig{N: 3, W: 3, R: 1}

// 最终一致性
eventualConsistency := QuorumConfig{N: 3, W: 1, R: 1}

// 平衡
balanced := QuorumConfig{N: 3, W: 2, R: 2}

一致性级别对比

模型 延迟 可用性 实现复杂度 应用场景
强一致性 金融、订单
顺序一致性 分布式锁
因果一致性 社交网络
最终一致性 DNS、点赞
会话一致性 Web应用

实战:电商订单

需求分析

  1. 下单:强一致性(不能重复扣款)
  2. 订单列表:会话一致性(看到自己的订单)
  3. 商品浏览量:最终一致性(允许误差)

实现

type OrderService struct {
    strongDB   *StrongConsistentDB  // 订单、支付
    cacheDB    *CacheDB             // 商品信息
    searchDB   *SearchDB            // 搜索引擎
}

// 创建订单(强一致性)
func (os *OrderService) CreateOrder(order Order) error {
    // 写入主库,等待多副本确认
    return os.strongDB.WriteWithQuorum(order, W=3)
}

// 查询订单(会话一致性)
func (os *OrderService) GetOrder(userID, orderID string) (Order, error) {
    // 优先从主库读取
    return os.strongDB.Read(orderID)
}

// 更新浏览量(最终一致性)
func (os *OrderService) IncrementViews(productID string) {
    // 异步更新,不阻塞用户
    go os.cacheDB.Incr(productID)
}

本章小结

关键要点

  • ✅ 一致性有多种级别,根据场景选择
  • ✅ 强一致性牺牲性能,最终一致性牺牲实时性
  • ✅ Quorum机制提供灵活的一致性配置
  • ✅ 同一系统可对不同数据使用不同一致性模型

扩展阅读


💡 思考题

  1. 为什么W + R > N能保证一致性?
  2. 因果一致性如何实现?
  3. 电商系统哪些数据需要强一致性?

⏮️ 上一节:CAP定理 | ⏭️ 下一节:分布式ID