Distributed System Design
理解 CAP 理论,掌握分布式事务、一致性协议、数据分片策略。
1// Saga 模式实现2type Saga struct {3 steps []SagaStep4}5 6type SagaStep struct {7 Name string8 Action func(ctx context.Context) error9 Compensate func(ctx context.Context) error10}11 12func (s *Saga) Execute(ctx context.Context) error {13 executed := make([]SagaStep, 0)14 15 for _, step := range s.steps {16 if err := step.Action(ctx); err != nil {17 // 执行补偿18 for i := len(executed) - 1; i >= 0; i-- {19 if compErr := executed[i].Compensate(ctx); compErr != nil {20 log.Printf("compensate %s failed: %v", executed[i].Name, compErr)21 }22 }23 return fmt.Errorf("step %s failed: %w", step.Name, err)24 }25 executed = append(executed, step)26 }27 return nil28}29 30// 示例:NFT 购买 Saga31func NewNFTPurchaseSaga(order *Order) *Saga {32 return &Saga{33 steps: []SagaStep{34 {35 Name: "LockNFT",36 Action: func(ctx context.Context) error { return lockNFT(order.NFTID) },37 Compensate: func(ctx context.Context) error { return unlockNFT(order.NFTID) },38 },39 {40 Name: "DeductBalance",41 Action: func(ctx context.Context) error { return deductBalance(order) },42 Compensate: func(ctx context.Context) error { return refundBalance(order) },43 },44 {45 Name: "TransferNFT",46 Action: func(ctx context.Context) error { return transferNFT(order) },47 Compensate: func(ctx context.Context) error { return revertNFTTransfer(order) },48 },49 },50 }51}1type DistributedLock struct {2 client *redis.Client3 key string4 value string5 ttl time.Duration6}7 8func (l *DistributedLock) Lock(ctx context.Context) (bool, error) {9 l.value = uuid.New().String()10 return l.client.SetNX(ctx, l.key, l.value, l.ttl).Result()11}12 13func (l *DistributedLock) Unlock(ctx context.Context) error {14 script := redis.NewScript(`15 if redis.call("GET", KEYS[1]) == ARGV[1] then16 return redis.call("DEL", KEYS[1])17 else18 return 019 end20 `)21 _, err := script.Run(ctx, l.client, []string{l.key}, l.value).Result()22 return err23}24 25// 看门狗续期26func (l *DistributedLock) StartWatchdog(ctx context.Context) {27 ticker := time.NewTicker(l.ttl / 3)28 go func() {29 for {30 select {31 case <-ticker.C:32 l.client.Expire(ctx, l.key, l.ttl)33 case <-ctx.Done():34 return35 }36 }37 }()38}