Go语言分布式系统实战:分布式锁与一致性协议
引言
分布式系统开发面临诸多挑战,其中分布式锁和数据一致性是核心问题。Go语言凭借其并发特性和丰富的生态,成为构建分布式系统的优秀选择。本文将深入探讨分布式锁的实现和一致性协议的应用。
一、分布式锁基础
1.1 分布式锁的需求
// 单进程锁
var mu sync.Mutex
func processOrder(orderID int) {
mu.Lock()
defer mu.Unlock()
// 处理订单逻辑
}
// 多进程/分布式环境需要分布式锁
1.2 分布式锁特性
| 特性 | 说明 |
|---|---|
| 互斥性 | 同一时刻只有一个客户端持有锁 |
| 死锁避免 | 锁必须有超时机制 |
| 容错性 | 锁服务宕机后能自动释放 |
| 公平性 | 保证请求顺序 |
二、基于Redis的分布式锁
2.1 基础实现
import (
"context"
"github.com/go-redis/redis/v8"
)
type RedisLock struct {
client *redis.Client
key string
value string
ttl time.Duration
}
func NewRedisLock(client *redis.Client, key string, ttl time.Duration) *RedisLock {
return &RedisLock{
client: client,
key: key,
value: uuid.New().String(),
ttl: ttl,
}
}
func (l *RedisLock) Lock(ctx context.Context) (bool, error) {
result, err := l.client.SetNX(ctx, l.key, l.value, l.ttl).Result()
if err != nil {
return false, err
}
return result, nil
}
func (l *RedisLock) Unlock(ctx context.Context) error {
script := `
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
`
_, err := l.client.Eval(ctx, script, []string{l.key}, l.value).Result()
return err
}
2.2 锁续约机制
func (l *RedisLock) LockWithRenewal(ctx context.Context) (bool, error) {
success, err := l.Lock(ctx)
if !success || err != nil {
return success, err
}
go l.startRenewal(ctx)
return true, nil
}
func (l *RedisLock) startRenewal(ctx context.Context) {
ticker := time.NewTicker(l.ttl / 3)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
_, err := l.client.Expire(ctx, l.key, l.ttl).Result()
if err != nil {
return
}
}
}
}
三、基于ZooKeeper的分布式锁
3.1 Curator框架
go get github.com/go-zookeeper/zk
import (
"github.com/go-zookeeper/zk"
)
type ZookeeperLock struct {
conn *zk.Conn
path string
lock *zk.Lock
}
func NewZookeeperLock(conn *zk.Conn, path string) *ZookeeperLock {
return &ZookeeperLock{
conn: conn,
path: path,
lock: zk.NewLock(conn, path, zk.WorldACL(zk.PermAll)),
}
}
func (l *ZookeeperLock) Lock(ctx context.Context) error {
return l.lock.LockWithContext(ctx)
}
func (l *ZookeeperLock) Unlock(ctx context.Context) error {
return l.lock.Unlock()
}
四、一致性协议
4.1 CAP理论
┌─────────────────────────────────────────────────────────────┐
│ CAP理论 │
├─────────────────────────────────────────────────────────────┤
│ Consistency (一致性) │
│ - 所有节点同时看到相同的数据 │
├─────────────────────────────────────────────────────────────┤
│ Availability (可用性) │
│ - 每个请求都能收到响应 │
├─────────────────────────────────────────────────────────────┤
│ Partition Tolerance (分区容错) │
│ - 网络分区时系统仍能继续工作 │
└─────────────────────────────────────────────────────────────┘
4.2 两阶段提交(2PC)
type TransactionCoordinator struct {
participants []Participant
}
type Participant interface {
Prepare() error
Commit() error
Rollback() error
}
func (tc *TransactionCoordinator) Commit() error {
// Phase 1: Prepare
for _, p := range tc.participants {
if err := p.Prepare(); err != nil {
tc.Rollback()
return err
}
}
// Phase 2: Commit
for _, p := range tc.participants {
if err := p.Commit(); err != nil {
// 处理提交失败
return err
}
}
return nil
}
func (tc *TransactionCoordinator) Rollback() {
for _, p := range tc.participants {
p.Rollback()
}
}
4.3 三阶段提交(3PC)
Phase 1: CanCommit
┌──────────────┐ CanCommit? ┌──────────────┐
│ Coordinator │ ─────────────────→ │ Participant │
└──────────────┘ └──────────────┘
←────────────── Yes/No ────────────────
Phase 2: PreCommit
┌──────────────┐ PreCommit ┌──────────────┐
│ Coordinator │ ─────────────────→ │ Participant │
└──────────────┘ └──────────────┘
←────────────── ACK ──────────────────
Phase 3: DoCommit
┌──────────────┐ Commit ┌──────────────┐
│ Coordinator │ ─────────────────→ │ Participant │
└──────────────┘ └──────────────┘
←────────────── Done ──────────────────
五、分布式事务解决方案
5.1 Saga模式
type Saga struct {
steps []SagaStep
}
type SagaStep interface {
Execute() error
Compensate() error
}
func (s *Saga) Execute() error {
for i, step := range s.steps {
if err := step.Execute(); err != nil {
// 回滚已执行的步骤
for j := i - 1; j >= 0; j-- {
s.steps[j].Compensate()
}
return err
}
}
return nil
}
5.2 TCC模式
type TCCService interface {
Try(ctx context.Context, params interface{}) error
Confirm(ctx context.Context, params interface{}) error
Cancel(ctx context.Context, params interface{}) error
}
type TCCTransaction struct {
services []TCCService
}
func (t *TCCTransaction) Execute(ctx context.Context) error {
// Try阶段
for _, service := range t.services {
if err := service.Try(ctx, nil); err != nil {
// Cancel所有已Try的服务
for _, s := range t.services {
s.Cancel(ctx, nil)
}
return err
}
}
// Confirm阶段
for _, service := range t.services {
if err := service.Confirm(ctx, nil); err != nil {
// 处理Confirm失败
return err
}
}
return nil
}
六、分布式ID生成
6.1 Snowflake算法
type Snowflake struct {
mu sync.Mutex
timestamp int64
workerID int64
sequence int64
}
func NewSnowflake(workerID int64) *Snowflake {
return &Snowflake{
workerID: workerID,
}
}
func (s *Snowflake) NextID() int64 {
s.mu.Lock()
defer s.mu.Unlock()
now := time.Now().UnixMilli()
if now == s.timestamp {
s.sequence = (s.sequence + 1) & 0x1F
if s.sequence == 0 {
for now <= s.timestamp {
now = time.Now().UnixMilli()
}
}
} else {
s.sequence = 0
}
s.timestamp = now
return (now-1288834974657)<<22 | (s.workerID << 12) | s.sequence
}
6.2 Redis自增
func GenerateID(ctx context.Context, client *redis.Client, key string) (int64, error) {
return client.Incr(ctx, key).Result()
}
七、实战:分布式订单系统
type OrderService struct {
redisClient *redis.Client
db *sql.DB
}
func (s *OrderService) CreateOrder(ctx context.Context, order *Order) error {
lock := NewRedisLock(s.redisClient, "order:"+order.ID, 30*time.Second)
success, err := lock.Lock(ctx)
if err != nil {
return err
}
if !success {
return errors.New("order is being processed")
}
defer lock.Unlock(ctx)
// 检查库存
if err := s.checkStock(ctx, order.Items); err != nil {
return err
}
// 创建订单
if err := s.createOrderRecord(ctx, order); err != nil {
return err
}
// 扣减库存
if err := s.deductStock(ctx, order.Items); err != nil {
// 回滚订单
s.rollbackOrder(ctx, order.ID)
return err
}
return nil
}
结论
分布式系统开发面临诸多挑战,分布式锁和一致性协议是其中的核心问题。Go语言凭借其并发特性和丰富的生态,成为构建分布式系统的优秀选择。在实际项目中,需要根据业务需求选择合适的分布式锁实现和一致性方案,平衡性能和一致性要求。

1065

被折叠的 条评论
为什么被折叠?



