golang 支付 分布式锁

发布时间:2024-11-24 10:08:59

分布式锁是分布式系统中常用的一种同步机制,主要解决多个进程/线程同时访问共享资源的问题。在Golang中,我们可以使用一些现有的开源库来实现分布式锁,本文将介绍几种常见的Golang支付分布式锁的方式。

Redis分布式锁

Redis是一种常用的内存数据库,它提供了一种简单而强大的方式来实现分布式锁。在Redis中,我们可以使用SETNX命令来将某个键值对设置为锁,如果设置成功,则表示当前进程/线程获得了锁。当获得锁之后,可以执行业务操作,执行完毕后再通过DEL命令来释放锁。

下面是使用Redis实现的一个简单的分布式锁示例:

package main

import (
	"github.com/go-redis/redis"
	"time"
)

func main() {
	redisClient := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",  // 设置密码
		DB:       0,   // 选择数据库
	})

	lockKey := "distributed_lock"

	// 尝试获取锁
	for {
		if val, _ := redisClient.SetNX(lockKey, true, 10*time.Second).Result(); val {
			// 获取锁成功
			defer redisClient.Del(lockKey)
			// 执行业务逻辑
			break
		} else {
			// 获取锁失败,等待一段时间后继续尝试
			time.Sleep(100 * time.Millisecond)
		}
	}
}

Etcd分布式锁

Etcd是一个高可用的分布式键值存储系统,它也可以用来实现分布式锁。和Redis类似,Etcd中的分布式锁也是通过设置某个键值对来实现的,并且Etcd还提供了一些其他功能来增强分布式锁的可用性和灵活性。

下面是使用Etcd实现的一个简单的分布式锁示例:

package main

import (
	"context"
	"github.com/coreos/etcd/clientv3"
	"time"
)

func main() {
	etcdClient, _ := clientv3.New(clientv3.Config{
		Endpoints:   []string{"localhost:2379"},
		DialTimeout: 5 * time.Second,
	})

	lockKey := "distributed_lock"
	leaseTTL := 10 // 锁过期时间

	leaseResp, _ := etcdClient.Grant(context.Background(), int64(leaseTTL))

	for {
		_, err := etcdClient.Get(context.Background(), lockKey) // 判断锁是否已经存在
		if err != nil {
			// 不存在锁,可以获取锁
			_, err = etcdClient.Put(context.Background(), lockKey, "", clientv3.WithLease(leaseResp.ID))
			if err == nil {
				// 获取锁成功
				defer etcdClient.Revoke(context.Background(), leaseResp.ID)
				// 执行业务逻辑
				break
			}
		} else {
			// 锁已经存在,等待一段时间后继续尝试
			time.Sleep(100 * time.Millisecond)
		}
	}
}

Zookeeper分布式锁

Zookeeper是一个分布式的协调服务,也可以用来实现分布式锁。Zookeeper中的分布式锁使用临时有序节点来实现,每个进程/线程都在指定目录下创建一个节点,并通过比较自己是否是最小节点来判断是否获取到了锁。

下面是使用Zookeeper实现的一个简单的分布式锁示例:

package main

import (
	"fmt"
	"github.com/samuel/go-zookeeper/zk"
	"time"
)

func main() {
	zkConn, _, _ := zk.Connect([]string{"localhost:2181"}, 5*time.Second)
	defer zkConn.Close()

	lockPath := "/distributed_lock"

	for {
		lockName, err := zkConn.Create(lockPath+"/lock-", []byte{}, zk.FlagEphemeral|zk.FlagSequence, zk.WorldACL(zk.PermAll))
		if err != nil {
			// 创建节点失败,等待一段时间继续尝试
			time.Sleep(100 * time.Millisecond)
		} else {
			// 创建节点成功
			children, _, _ := zkConn.Children(lockPath)
			minNode := getMinNode(children)
			if lockName == minNode {
				// 获取锁成功
				defer zkConn.Delete(lockName, -1)
				// 执行业务逻辑
				break
			} else {
				// 不是最小节点,等待一段时间继续尝试
				time.Sleep(100 * time.Millisecond)
			}
		}
	}
}

func getMinNode(nodes []string) string {
	if len(nodes) == 0 {
		return ""
	}
	minIndex := 0
	for i := 1; i < len(nodes); i++ {
		if nodes[i] < nodes[minIndex] {
			minIndex = i
		}
	}
	return nodes[minIndex]
}

以上分别介绍了使用Redis、Etcd和Zookeeper实现分布式锁的方式,在实际应用中可以根据具体情况选择适合自己的方案。通过使用分布式锁,可以有效地避免多个进程/线程对共享资源的竞争,保证系统的并发处理能力和数据一致性。

相关推荐