当前位置: 首页 > news >正文

【后端开发】goland分布式锁的几种实现方式(mysql,redis,etcd,zookeeper,mq,s3)

【后端开发】goland分布式锁的几种实现方式(mysql,redis,etcd,zookeeper,mq,s3)

文章目录

    • 1、分布式锁实现方案对比(mysql,redis,etcd,zookeeper,mq,s3)
    • 2、锁的常见策略(乐观/悲观,可重入/不可重入,公平/非公平,自旋锁, 读写锁)
    • 3、基于redis,mysql的实现(缓存,AP-高性能)
    • 4、基于etcd,zk的实现(分布式协调系统,CP-强一致性)
    • 5、基于mq,s3等其他中间件的实现(特殊CAP)

1、分布式锁实现方案对比(mysql,redis,etcd,zookeeper,mq,s3)

技术实现复杂度性能可靠性适用场景主要特点
Redis高性能、高并发场景基于内存,高性能;需要处理锁续期问题;可能出现脑裂问题
Etcd中高强一致性要求的场景基于Raft协议,强一致性;自带租约机制;适合云原生环境
ZooKeeper中高复杂协调场景基于ZAB协议,强一致性;watch机制完善;但运维成本较高
MySQL低频、简单场景实现简单;性能瓶颈明显;不适合高并发
MQ中高中高异步、解耦场景通过消息排他性实现;天然支持分布式;但不如专用锁工具直观
S3特殊场景(如跨云)基于对象存储的原子操作;延迟高;适合低频跨地域场景

分布式锁适用场景(排序)

  1. Redis - 最适合大多数场景,性能与功能平衡 (无脑选择)

    • 推荐库: redsync
    • 适用: 电商秒杀、缓存更新等高频场景
  2. Etcd - 强一致性要求的云原生场景首选 (云原生+刚好有etcd)

    • 推荐库: 官方concurrency包
    • 适用: K8s环境、服务注册发现相关锁需求
  3. ZooKeeper - 已有ZK基础设施的复杂协调场景 (刚好有…雾)

    • 推荐库: curator(Java)或go-zookeeper
    • 适用: Hadoop生态、传统分布式系统
  4. MQ - 已使用MQ且需要弱化锁概念的场景 (刚好只有…雾)

    • 推荐: RabbitMQ排他队列/Kafka partition
    • 适用: 异步任务调度、事件驱动架构
  5. MySQL - 简单低频场景的快速实现 (不咋用,刚好只有mysql)

    • 推荐: GET_LOCK函数
    • 适用: 低频管理操作、小型系统
  6. S3 - 特殊跨云/跨地域需求 (刚好只有S3)

    • 推荐: S3原子操作
    • 适用: 多云环境下的协调

特殊场景建议

  • 超高频场景(10万+/秒): Redis集群+Redlock算法
  • 金融级强一致: Etcd或ZooKeeper
  • 云原生环境: 首选Etcd
  • 已有MQ基础设施: 可考虑利用MQ特性实现简化架构
  • 简单低频系统: MySQL实现最方便

参考资料:1, 2

2、锁的常见策略(乐观/悲观,可重入/不可重入,公平/非公平,自旋锁, 读写锁)

CAP定理(一致性Consistency、可用性Availability、分区容错性Partition Tolerance)

用锁的策略考虑

  1. 争用程度:高争用时应减少锁粒度
  2. 持有时间:长时间持有应使用可重入锁
  3. 公平性需求:平衡吞吐量与公平性

悲观锁

  • 特点
    默认认为并发冲突会发生
    访问资源前先加锁
    阻塞其他线程直到锁释放
    实现简单但并发性能较低
  • 适用场景
    冲突频率高的场景
    临界区执行时间较长
    需要强一致性保证

乐观锁

  • 特点
    默认认为冲突不会发生
    不上锁直接操作,提交时检查版本
    非阻塞,冲突时回滚或重试
    高并发性能好
  • 适用场景
    读多写少的环境
    冲突概率低的场景
    需要高吞吐量的系统
--- 乐观锁
--- 初始数据
id | name | version
1  | 张三 | 1场景1:无并发冲突
T1: 服务A读取数据 (version=1)
T2: 服务A更新数据 (version=1 -> 2)
T3: 服务B读取数据 (version=2)
T4: 服务B更新数据 (version=2 -> 3)场景2:有并发冲突
T1: 服务A读取数据 (version=1)
T2: 服务B读取数据 (version=1)
T3: 服务B更新数据 (version=1 -> 2)
T4: 服务A尝试更新数据 (version=1 -> 2) 失败!

分布式锁

  • 特性
    跨进程/跨机器互斥
    高可用性(避免单点故障)
    自动释放(防死锁)
    可重入性(可选)
  • 实现对比
    Redis:AP系统,高性能但不保证强一致
    Zookeeper/Etcd:CP系统,强一致但性能较低

可重入锁(递归锁)

  • 特点
    同一线程可重复获取已持有的锁
    需要记录持有线程和重入次数
    避免自死锁
  • 实现:
    etcd默认 concurrency包

不可重入锁

  • 特点
    严格互斥,即使同一线程也不能重复获取
    实现简单但易引发死锁

死锁

  • 四大条件与预防
    1 互斥条件, 破坏互斥
    2 请求与保持,破坏请求保持,资源有序分配法
    3 不可剥夺,允许资源抢占
    4 循环等待, 破坏循环等待
  • 实现措施
    设置超时时间(Redis锁的expire)
    资源有序申请(按固定顺序获取锁)
    使用tryLock而非lock

公平锁

  • 特点
    按申请顺序分配锁
    避免线程饥饿
    性能较低(需要维护队列)

非公平锁

  • 特点
    允许插队获取锁
    吞吐量更高
    可能导致线程饥饿

自旋锁

  • 适用场景:临界区非常小且CPU资源充足
// C++原子操作实现自旋锁
std::atomic_flag lock = ATOMIC_FLAG_INIT;void lock() {while(lock.test_and_set(std::memory_order_acquire));
}void unlock() {lock.clear(std::memory_order_release);
}

读写锁

  • 特点:读共享,写互斥
// Java读写锁
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();// 读操作
rwLock.readLock().lock();
try {// 并发读
} finally {rwLock.readLock().unlock();
}// 写操作
rwLock.writeLock().lock();
try {// 独占写
} finally {rwLock.writeLock().unlock();
}

3、基于redis,mysql的实现(缓存,AP-高性能)

Redis实现

  • AP系统:高可用和分区容忍优先,牺牲强一致性(如Redis集群可能出现脑裂)
  • 高性能:基于内存操作,TPS可达10万+级别
  • Redis集群脑裂是指在一个Redis集群中,由于网络分区导致集群被分裂成两个或多个部分,每个部分都认为自己是主节点(Master)的情况。
  • redsync/v4(Redsync)
    Redis 官方推荐的分布式锁库,基于 Redlock 算法 实现,支持单节点、多节点 Redis 模式,具备自动续期、容错处理等特性。
  • 特点
    支持单实例和 多实例(Redlock) 模式,多实例模式下通过多数节点加锁提升可靠性。
    自动处理锁的续期(Renewal),避免业务执行时间超过锁有效期导致的误释放。
    提供 Lock 和 RLock(可重入锁)接口,支持上下文取消(context.Context)。 Redlock参考:1, 2, 3
// Redlock算法示例(多节点Redis)
err := redsync.New(redisPools).NewMutex("resource_lock").Lock()// 使用 SET NX 命令
lockKey := "sync_lock"
lockValue := "server_id"
success, err := redis.SetNX(ctx, lockKey, lockValue, 5*time.Minute).Result()

手动实现

package mainimport ("context""log""math/rand""time""github.com/go-redis/redis/v9"
)type DistLock struct {rdb        *redis.Clientkey        stringvalue      string // 唯一标识(如 UUID)expiration time.Durationctx        context.Context
}// 新建分布式锁
func NewDistLock(rdb *redis.Client, key string, expiration time.Duration) *DistLock {return &DistLock{rdb:        rdb,key:        key,value:      rand.String(16), // 生成随机 UUID(示例简化)expiration: expiration,ctx:        context.Background(),}
}// 加锁
func (l *DistLock) Lock() (bool, error) {ok, err := l.rdb.SetNX(l.ctx, l.key, l.value, l.expiration).Result()if err != nil {return false, err}return ok, nil
}// 释放锁
func (l *DistLock) Unlock() (bool, error) {script := `if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end`result, err := l.rdb.Eval(l.ctx, script, []string{l.key}, l.value).Result()if err != nil {return false, err}return result.(int64) == 1, nil
}func main() {rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379",})lock := NewDistLock(rdb, "my-lock", 5*time.Second)// 尝试加锁ok, err := lock.Lock()if err != nil || !ok {log.Fatal("获取锁失败")return}defer lock.Unlock() // 确保释放锁// 模拟业务执行(可能超过锁过期时间,需手动处理续期)log.Println("执行业务...")time.Sleep(6 * time.Second) // 超过 5s 锁过期时间,可能导致其他进程获取锁
}

MySQL实现

  • 基于唯一索引或乐观锁(CAS)
  • 简单但性能低(TPS通常<1K)
  • 适用场景:低频管理操作、传统单体架构过渡期。
-- 悲观锁
SELECT * FROM table WHERE id=1 FOR UPDATE;-- 乐观锁
UPDATE table SET stock=stock-1, version=version+1 
WHERE id=1 AND version=5;

4、基于etcd,zk的实现(分布式协调系统,CP-强一致性)

基于etcd的分布式锁实现

  • etcd是一个分布式、高可用的键值存储系统,主要用于共享配置和服务发现。由CoreOS开发,现为CNCF(云原生计算基金会)项目。
    etcd采用Raft一致性算法保证数据一致性,支持分布式锁、观察者模式、TTL(生存时间)等特性,广泛应用于Kubernetes等云原生系统中。
  • etcd实现锁的核心是通过Create操作在KV存储中创建临时键值对。如果创建成功即获取锁,否则监听该键变化。锁释放时自动删除键值对。 1 2
  • 优点:
    强一致性
    自动过期
    适合分布式系统
// etcd 手动实现
// etcd客户端初始化
cli, err := clientv3.New(clientv3.Config{Endpoints:   []string{"localhost:2379"},DialTimeout: 5 * time.Second,
})// 尝试获取锁
lease := clientv3.NewLease(cli)
leaseGrantResp, err := lease.Grant(context.TODO(), 10) // 10秒租约
_, err = cli.Put(context.TODO(), "/lock/key", "", clientv3.WithLease(leaseGrantResp.ID))// 锁续约
keepAliveCh, err := lease.KeepAlive(context.TODO(), leaseGrantResp.ID)// 释放锁
lease.Revoke(context.TODO(), leaseGrantResp.ID)
// etcd的concurrency包
func main() {// 创建一个etcd客户端client, err := clientv3.New(clientv3.Config{Endpoints:   []string{"localhost:2379"},DialTimeout: 5 * time.Second,})if err != nil {panic(err)}defer client.Close()// 创建一个分布式锁mutex := concurrency.NewMutex(client, "/lock/key")// 尝试获取锁err = mutex.Lock(context.Background())if err != nil {panic(err)}defer mutex.Unlock(context.Background())// 执行需要互斥访问的代码// ...
}

etcdctl工具 1

brew install etcd
etcdctl get --prefix foo# 创建租约(TTL为10秒)
etcdctl lease grant 10
# 输出示例:lease 32695410dcc0ca06 granted with TTL(10s)# 使用租约持有锁(写入一个键并绑定租约)
etcdctl put --lease=32695410dcc0ca06 /lock/resource "holder1"# 续租
etcdctl lease keep-alive 32695410dcc0ca06
# 释放锁(删除键或撤销租约)
etcdctl lease revoke 32695410dcc0ca06

基于Zookeeper的分布式锁实现

// 创建连接
ZooKeeper zk = new ZooKeeper("localhost:2181", 3000, null);// 创建临时有序节点
String lockPath = zk.create("/lock/key-", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);// 检查是否为最小节点
List<String> children = zk.getChildren("/lock", false);
Collections.sort(children);// 监听前一个节点
String watchNode = "/lock/" + children.get(Collections.binarySearch(children, lockPath)-1);
zk.exists(watchNode, new Watcher() {public void process(WatchedEvent event) {// 节点删除时重新检查锁状态}
});// 释放锁
zk.delete(lockPath, -1);

etcd和zk对比
1,

应用场景etcdZookeeper细节差异
发布与订阅(配置中心)etcd API 简洁轻量;Zookeeper 需处理会话超时等细节,Java 生态适配好
软负载均衡etcd 客户端主动拉取负载;Zookeeper 靠监听节点变化实现,传统架构适配性强
命名服务etcd 查询高效,适配灵活场景;Zookeeper 适合强层级结构,如传统中间件集成
服务发现etcd 天然适配云原生(如 K8s );Zookeeper 是 Dubbo 等传统框架默认依赖
分布式通知 / 协调etcd 多 Key 监听、原子性优;Zookeeper 适合复杂协调逻辑,如集群状态同步
集群管理与 Master 选举etcd 基于 Raft 算法,选主高效自动;Zookeeper 靠临时 / 有序节点,Java 生态成熟
分布式锁etcd 轻量级、无锁竞争性能优;Zookeeper 阻塞锁易实现,高并发下节点创建开销略大
分布式队列etcd 可扩展延时队列(结合 Lease );Zookeeper 天然支持阻塞队列,客户端完善

etcd和redis的对比 1

对比维度etcdRedis
定位分布式系统元数据存储、配置中心内存数据库、高性能缓存、实时数据处理
数据存储仅磁盘持久化(WAL + 快照)内存为主(支持 RDB/AOF 持久化)
数据一致性强一致性(Raft 共识算法)最终一致性(可配置强一致性)
数据类型仅简单键值对(String-Byte)丰富数据类型(String/Hash/List 等)
分布式能力原生支持(Raft 集群)需手动配置(Cluster/Sentinel)
典型场景Kubernetes 集群、分布式锁、配置管理缓存、排行榜、消息队列、实时分析
读写性能低频操作(数百次 / 秒,受磁盘限制)高频内存操作(数万次 / 秒)
扩展性节点数建议 3-5 个(Raft 限制)支持动态扩缩容(数千节点)
生态集成深度集成 Kubernetes 生态通用型,适配多种框架(如 Spring、Node.js)

5、基于mq,s3等其他中间件的实现(特殊CAP)

MQ实现

  • 原理
    利用消息队列的排他性消费特性
    通过创建唯一队列或独占消费者实现互斥
    基于消息的ACK机制实现锁释放
  • 示例
    RabbitMQ: 使用排他队列(exclusive queue)或单活跃消费者
    Kafka: 使用partition的单一消费者机制
    RocketMQ: 使用MessageGroup保证同一分组消息被同一消费者处理
  • 优点:
    天然分布式特性
    与业务消息系统集成方便
    自带重试和持久化机制
  • 缺点:
    没有专门为锁设计,功能不直观
    锁释放依赖于消费者生命周期
    性能通常低于专用锁服务

S3实现:

  • 方案1:去s3持久化文件,在文件中记录当前锁的状态
  • 方案2:
    通过 PutObject 尝试创建一个唯一的锁文件(如以锁名称为键的对象),利用 IfNoneMatch 条件确保只有当文件不存在时才能创建成功(即获取锁)
    通过 DeleteObject 删除锁文件,利用 IfMatch 条件确保只有持有锁的客户端(通过存储在元数据中的唯一标识)才能删除,避免误删其他客户端的锁
  • 适用场景
    轻量级分布式锁需求:如简单的任务调度、资源编排等。
    跨云或多云环境:S3 兼容接口(如 MinIO)可统一不同云厂商的实现
    低成本场景:避免引入 Redis、ZooKeeper 等复杂中间件
优点缺点
1. 利用 S3 原生接口,无需额外组件1. 依赖 S3 服务的可用性和延迟
2. 支持跨区域分布式场景2. 高频操作时 API 调用成本较高(需付费)
3. 天然支持持久化(锁状态存储在 S3 中)3. 强一致性依赖 S3 的读一致性模型
4. 实现简单,适合轻量级场景4. 不支持可重入锁

相关文章:

  • 2025-0604学习记录17——文献阅读与分享(2)
  • 使用PyInstaller将Python脚本打包成可执行文件
  • Java转Go日记(五十七):gin 中间件
  • 《仿盒马》app开发技术分享-- 商品搜索页(顶部搜索bar热门搜索)(端云一体)
  • 300道GaussDB(WMS)题目及答案。
  • 解析“与此站点的连接不安全”警告:成因与应对策略
  • OD 算法题 B卷【查找舆情热词】
  • AI 时代下语音与视频伪造的网络安全危机
  • 区块链安全攻防战:51% 攻击与 Sybil 攻击的应对策略
  • AlphaFold3服务器安装与使用(非docker)(1)
  • window 显示驱动开发-提供视频解码功能(三)
  • C++课设:银行账户管理系统
  • 智慧货运飞船多维度可视化管控系统
  • 华为设备OSPF配置与实战指南
  • 内网穿透之Linux版客户端安装(神卓互联)
  • Docker 常用命令详解
  • 大模型高效提示词Prompt编写指南
  • 电脑频繁黑屏怎么办
  • 探索分布式存储与通信:去中心化共享及通訊(DSAC)
  • 以人类演示视频为提示,学习可泛化的机器人策略
  • 网站建设公司前十名/如何进行网络推广营销
  • 微信网站域名/北京百度推广排名优化
  • 黑龙江做网站找谁/网络优化工程师有前途吗
  • 网站免费备案/山东一级造价师
  • 客服电话/网店seo名词解释
  • 行政事业单位网站建设/seo黑帽技术工具