分布式锁:不同实现方式实践测评(下)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
注册配置 MSE Nacos/ZooKeeper,182元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 分布式锁:不同实现方式实践测评(下)

2 分布式锁引入

2.1 分布式锁的概念

先说锁

线程是进程的一个实体,同一进程下的多个线程可以进行资源的共享,多个线程共享一个资源时则会进行资源的竞争进而引发线程异常。

基于此类问题,我们引入锁这个概念,锁,是一种线程中的一种同步机制。通过加锁我们就可以实现对共享资源的互斥访问。

为什么会出现分布式锁?

因为集群环境下,无法避免要把一个项目部署成多个节点,但是数据的一致性导致每个节点访问的数据都是一样的,至此我们可以把每一个项目节点都当做一个线程,整个分布式集群当做一个进程,数据就是多个节点共享的资源,因此难免会引发分布式环境下的多线程问题。

网络异常,图片无法展示
|


2.2 Redis实现分布式锁

package redis_lock
import (
   "github.com/go-redis/redis/v8"
   "github.com/go-redsync/redsync/v4"
   "github.com/go-redsync/redsync/v4/redis/goredis/v8"
   "time"
)
type RLock struct {
   Mutex *redsync.Mutex
}
func NewRLock(key string, expire ...time.Duration) *RLock {
   client := redis.NewClient(&redis.Options{
      Addr: "localhost:6379",
   })
   pool := goredis.NewPool(client)
   rs := redsync.New(pool)
   option := redsync.WithExpiry(time.Second * 5)
   if len(expire) == 1 {
      option = redsync.WithExpiry(expire[0])
   }
   mutex := rs.NewMutex(key, option)
   return &RLock{Mutex: mutex}
}
func (r *RLock) Lock() error {
   return r.Mutex.Lock()
}
func (r *RLock) Unlock() error {
   if ok, err := r.Mutex.Unlock(); !ok || err != nil {
      return err
   }
   return nil
}
复制代码

2.3 etcd实现分布式锁

package etcd_lock
import (
   "context"
   "fmt"
   "go.etcd.io/etcd/client/v3"
   "go.etcd.io/etcd/client/v3/concurrency"
   "time"
)
type EtcdLock struct {
   Mutex *concurrency.Mutex
}
func NewEtcdLock(key string, expire ...time.Duration) *EtcdLock {
   timeOut := time.Second * 5
   if len(expire) == 1 {
      timeOut = expire[0]
   }
   cli, err := clientv3.New(clientv3.Config{
      Endpoints:   []string{"127.0.0.1:2379"},
      DialTimeout: time.Second * 5,
   })
   if err != nil {
      fmt.Println(err)
   }
   s1, err := concurrency.NewSession(cli, concurrency.WithTTL(int(timeOut/time.Second)))
   if err != nil {
      fmt.Println(err)
   }
   return &EtcdLock{Mutex: concurrency.NewMutex(s1, key)}
}
func (r *EtcdLock) Lock(ctx context.Context) error {
   return r.Mutex.Lock(ctx)
}
func (r *EtcdLock) Unlock(ctx context.Context) error {
   return r.Mutex.Unlock(ctx)
}
复制代码

2.4 Zookeeper实现分布式锁

package zk_lock
import (
   "fmt"
   "time"
   "github.com/go-zookeeper/zk"
)
type ZkLock struct {
   ZLock *zk.Lock
}
func NewZkLock(key string, expire ...time.Duration) *ZkLock {
   timeOut := time.Second * 5
   if len(expire) == 1 {
      timeOut = expire[0]
   }
   c, _, err := zk.Connect([]string{"127.0.0.1:2181"}, timeOut)
   if err != nil {
      fmt.Println(err)
   }
   lock := zk.NewLock(c, fmt.Sprintf("/zkLock/lock-%s", key), zk.WorldACL(zk.PermAll))
   return &ZkLock{ZLock: lock}
}
func (z *ZkLock) Lock() error {
   return z.ZLock.Lock()
}
func (z ZkLock) Unlock() error {
   return z.ZLock.Unlock()
}
复制代码

3 实践测评过程与需要注意的问题

以Zookeeper加锁的代码举例:

func RunServer() {
  http.HandleFunc("/buyBook", func(w http.ResponseWriter, r *http.Request) {
    username := r.URL.Query().Get("name")
    buyNum := r.URL.Query().Get("num")
    zkLock := zk_lock.NewZkLock(username, time.Second*3)
    err := zkLock.Lock()
    if err != nil {
      fmt.Errorf("Lock err = %s",err)
      w.Write([]byte("购买失败"))
      return
    }
    defer func() {
      err = zkLock.Unlock()
      if err != nil {
        fmt.Errorf("UnLock err = %s",err)
      }
    }()
    resp := service.BuyBook(username, cast.ToInt64(buyNum))
    _, err = w.Write([]byte(resp))
    if err != nil {
      fmt.Errorf("write err %s", err)
    }
  })
  err := http.ListenAndServe(":8081", nil)
  if err != nil {
    fmt.Errorf("Http run err %s ", err)
  }
}
复制代码

实践过程就不是很难了,就是一个加锁和解锁的过程,但是要注意的一些问题:

  • 锁过期时间。分布式锁设置过期时间可以确保在未来的一定时间内,无论获得锁的节点发生了什么问题,最终锁都能被释放掉。但是时间也不能过短,防止业务还没有执行完锁就失效了。
  • 锁的全局唯一标识。
  • 锁的合理释放。我们要考虑在业务执行完成或发生异常时锁也能得到释放。

4 结论

经过Jmeter的分析报告,我们汇总成了一张表格:

网络异常,图片无法展示
|


依照表格我们可以得出结论:

Redis是三者中吞吐量、平均响应时间最优的一种方式,但是相对而言不如Zookeeper更加稳定,etcd在虽然在各个维度都不如Redis和Zookeeper,但是它仍然是一款比较优秀的云原生领域分布式注册中心,在集群环境中,Redis会产生脑裂、主从同步失败等安全问题,etcd则可以很大程度上屏蔽此类问题,所以我们不能只关注表面的数据,同时也要兼顾每个组件背后的原理和安全性。

最后,做一个小总结,分布式锁是一个相对复杂的组件,除了本文所讲述的以外,如果想要更好的使用分布式锁,还需要考虑其背后的诸多问题,比如锁操作的原子性、一致性、可重入性等,这些当然也与不同组件背后的算法相关,由于篇幅有限就没有一一详解,当然除了etcd、Redis、Zookeeper等组件之外,还有许多方式可以实现分布式锁,比如高性能的关系型数据库、MySQL乐观锁等等,都需要我们针对自身的业务进行选择。其实无论是一般的线程锁,还是分布式锁的作用都是一样的,只是作用的范围大小不同。只是范围越大技术复杂度就越大。


相关文章
|
2月前
|
人工智能 安全 Java
分布式 Multi Agent 安全高可用探索与实践
在人工智能加速发展的今天,AI Agent 正在成为推动“人工智能+”战略落地的核心引擎。无论是技术趋势还是政策导向,都预示着一场深刻的变革正在发生。如果你也在探索 Agent 的应用场景,欢迎关注 AgentScope 项目,或尝试使用阿里云 MSE + Higress + Nacos 构建属于你的 AI 原生应用。一起,走进智能体的新世界。
523 40
|
2月前
|
关系型数据库 Apache 微服务
《聊聊分布式》分布式系统基石:深入理解CAP理论及其工程实践
CAP理论指出分布式系统中一致性、可用性、分区容错性三者不可兼得,必须根据业务需求进行权衡。实际应用中,不同场景选择不同策略:金融系统重一致(CP),社交应用重可用(AP),内网系统可选CA。现代架构更趋向动态调整与混合策略,灵活应对复杂需求。
|
4月前
|
数据采集 消息中间件 监控
单机与分布式:社交媒体热点采集的实践经验
在舆情监控与数据分析中,单机脚本适合小规模采集如微博热榜,而小红书等大规模、高时效性需求则需分布式架构。通过Redis队列、代理IP与多节点协作,可提升采集效率与稳定性,适应数据规模与变化速度。架构选择应根据实际需求,兼顾扩展性与维护成本。
117 2
|
7月前
|
人工智能 安全 应用服务中间件
阿里巴巴 MCP 分布式落地实践:快速转换 HSF 到 MCP server
本文分享了阿里巴巴内部将大规模HSF服务快速转换为MCP Server的实践经验,通过Higress网关实现MCP协议卸载,无需修改代码即可接入MCP生态。文章分析了MCP生态面临的挑战,如协议快速迭代和SDK不稳定性,并详细介绍了操作步骤及组件功能。强调MCP虽非终极解决方案,但作为AI业务工程化的起点具有重要意义。最后总结指出,MCP只是AI原生应用发展的第一步,未来还有更多可能性值得探索。
1195 48
|
3月前
|
消息中间件 缓存 监控
中间件架构设计与实践:构建高性能分布式系统的核心基石
摘要 本文系统探讨了中间件技术及其在分布式系统中的核心价值。作者首先定义了中间件作为连接系统组件的"神经网络",强调其在数据传输、系统稳定性和扩展性中的关键作用。随后详细分类了中间件体系,包括通信中间件(如RabbitMQ/Kafka)、数据中间件(如Redis/MyCAT)等类型。文章重点剖析了消息中间件的实现机制,通过Spring Boot代码示例展示了消息生产者的完整实现,涵盖消息ID生成、持久化、批量发送及重试机制等关键技术点。最后,作者指出中间件架构设计对系统性能的决定性影响,
|
7月前
|
监控 Linux 应用服务中间件
Linux多节点多硬盘部署MinIO:分布式MinIO集群部署指南搭建高可用架构实践
通过以上步骤,已成功基于已有的 MinIO 服务,扩展为一个 MinIO 集群。该集群具有高可用性和容错性,适合生产环境使用。如果有任何问题,请检查日志或参考MinIO 官方文档。作者联系方式vx:2743642415。
2267 57
|
7月前
|
安全 JavaScript 前端开发
HarmonyOS NEXT~HarmonyOS 语言仓颉:下一代分布式开发语言的技术解析与应用实践
HarmonyOS语言仓颉是华为专为HarmonyOS生态系统设计的新型编程语言,旨在解决分布式环境下的开发挑战。它以“编码创造”为理念,具备分布式原生、高性能与高效率、安全可靠三大核心特性。仓颉语言通过内置分布式能力简化跨设备开发,提供统一的编程模型和开发体验。文章从语言基础、关键特性、开发实践及未来展望四个方面剖析其技术优势,助力开发者掌握这一新兴工具,构建全场景分布式应用。
711 35
|
8月前
|
存储 负载均衡 测试技术
ACK Gateway with Inference Extension:优化多机分布式大模型推理服务实践
本文介绍了如何利用阿里云容器服务ACK推出的ACK Gateway with Inference Extension组件,在Kubernetes环境中为多机分布式部署的LLM推理服务提供智能路由和负载均衡能力。文章以部署和优化QwQ-32B模型为例,详细展示了从环境准备到性能测试的完整实践过程。
|
9月前
|
并行计算 PyTorch 算法框架/工具
融合AMD与NVIDIA GPU集群的MLOps:异构计算环境中的分布式训练架构实践
本文探讨了如何通过技术手段混合使用AMD与NVIDIA GPU集群以支持PyTorch分布式训练。面对CUDA与ROCm框架互操作性不足的问题,文章提出利用UCC和UCX等统一通信框架实现高效数据传输,并在异构Kubernetes集群中部署任务。通过解决轻度与强度异构环境下的挑战,如计算能力不平衡、内存容量差异及通信性能优化,文章展示了如何无需重构代码即可充分利用异构硬件资源。尽管存在RDMA验证不足、通信性能次优等局限性,但该方案为最大化GPU资源利用率、降低供应商锁定提供了可行路径。源代码已公开,供读者参考实践。
742 3
融合AMD与NVIDIA GPU集群的MLOps:异构计算环境中的分布式训练架构实践
|
9月前
|
人工智能 运维 监控
领先AI企业经验谈:探究AI分布式推理网络架构实践
当前,AI行业正处于快速发展的关键时期。继DeepSeek大放异彩之后,又一款备受瞩目的AI智能体产品Manus横空出世。Manus具备独立思考、规划和执行复杂任务的能力,其多智能体架构能够自主调用工具。在GAIA基准测试中,Manus的性能超越了OpenAI同层次的大模型,展现出卓越的技术实力。

热门文章

最新文章