源宝导读:大型的信息化系统对数据准确性的要求很高,所以经常会使用事务、锁、队列等技术,保障高并发下的数据一致性问题。本文将讨论在分布式部署模式下,如何利用锁机制保证业务数据准确的技术探索与实践。

一、背景

分布式场景下的数据一致性问一直是一个非常重要的话题,在很多场景中,我们需要使用各种技术方案来保证数据的一致性,比如分布式事务、分布式存储、分布式锁等。有些业务场景中,我们需要保证一个方法在同一时间内只能被一个线程执行,来解决一些譬如商品超卖,我们ERP中的一房多卖、财务票据号跳票重复等问题。在单机环境中,各种语言其实提供了较多并发处理相关的特性,比如.Net中的lock、Monitor、Mutex等,但是这些特性在分布式场景中就有问题了。针对分布式锁的实现,目前比较常用的有这样几种:数据库实现、缓存实现(redis,memcached)、Zookeeper实现、以及etcd等。

二、利用数据库实现分布式锁

基于数据库唯一约束

应该是分布式锁最简单的方式之一,创建一张锁表,通过数据库的唯一约束,当我们需要锁住某个场景时,插入一条数据,插入成功则获锁成功可以执行后续操作,操作完成后删除记录来释放锁资源。我们老系统即提供了此种类型的锁来处理各类锁场景。

数据库约束实现的锁问题:

  • 强依赖数据库,单点无高可用,数据库宕掉则业务不可用。

  • 并发支撑不够,单点的数据库成为瓶颈。

  • 非阻塞的,没有获得锁的无法排队直接失败。

  • 非重入的,同一线程无法再次获取已经得到的锁。

  • 没有失效时间,如果解锁失败则业务受阻。

利用数据库特性实现
    利用SQL Server提供的应用锁来实现锁定,使用sp_getapplock加锁,sp_releaseappLock释放锁,随事务提交或回滚:

相对于数据库唯一约束实现来说,更加简便,好控制,不占用数据库空间,而且支持阻塞特性实现排队等待,且业务失败自动释放(回滚),目前ERP使用此方案来实现锁控制,开箱即用,不依赖其他服务。

三、利用缓存实现分布式锁

相比于数据库实现,基于缓存的锁实现性能更好,可以支撑更高的并发,同时缓存的集群部署可以保证高可用。
MemCached
    利用Memcached的原子命令add操作,只有add成功才表示获取到锁。由于MemCached采用LUR置换策略,可能导致并未过期的锁信息被删除,且无持久化。

Redis
    同样利用其原子操作,来处理锁定场景,官方也提供了Relock的dotnet实现。

RedLock算法提出通过N/2 + 1(半数以上实例)获取到锁并且获取时间小于锁过期时间则认为获取到锁,来解决Master-Slave模式下主从同步失败导致的锁安全问题,但实际上还是可能由于某一节点未落盘宕机或则时钟不同步导致多客户端获锁成功的问题,本身AP,想完全CP就比较别扭了,这也是RedLock被质疑的地方。

同时通过retry机制实现阻塞(间隔一段时间,重试获锁过程),不过重试间隔不好把握,这一点java的实现Redisson提供了另外的方式,在申请锁失败后,阻塞线程,通过订阅解锁消息来释放阻塞并重试获锁过程,同时也可以利用watch dog来实现锁延时。

四、利用Zookeeper实现分布式锁

可以通过其有序临时节点+监听节点删除来实现分布式锁,通过仅监听上一个节点的删除事件避免羊群效应,具体流程如下图:

可基于Zookeeper的客户端,按照上述流程实现:

也可以使用ZookeeperNet.Recipes提供的锁:

相比于redis,性能弱于redis,但健壮性更好(更能保障数据一致)。

五、利用etcd实现分布式锁

etcd可能没有ZK那么被大众熟知,但说它为K8s提供状态配置存储就明白了。

和ZK功能相似,使用Raft保证数据一致性,相较于zookeeper,ecd使用GO编写更加轻便,其效率也更高,在etcd v3版本中已提供了lock的封装。

官方推荐的dotnet的客户端如下:

dotnet-etcd使用google的gRPC框架封装了客户端各操作,包括V3提供的锁:

六、总结

没有完美的技术,只有合适的选择,就如CAP原则最多只能同时满足两种特性一样,复杂性、高可用、高性能等方面很难同时满足,选择适合当前业务要求的即可。怕的是没有意识到并发情况会产生数据不一致的问题,导致的超卖现象以及跳号重复等问题的产生,之前处理过比较多的反馈,希望通过此篇文章让大家意识到分布式环境下可能出现的数据不一致的问题,并选择合适的方案来解决。

------ END ------

作者简介

王同学: 架构师,目前负责售楼产品的相关架构规划和设计工作。

也许您还想看

.NET Core MVC扩展实践

如何使用有序GUID提升数据库读写性能

.Net最小工作线程对应用程序性能的影响

ERP缓存实践经验分享

分布式锁的实现与探索相关推荐

  1. 快来学习Redis 分布式锁的背后原理

    以前在学校做小项目的时候,用到Redis,基本也只是用来当作缓存.可阿粉在工作中发现,Redis在生产中并不只是当作缓存这么简单.在阿粉接触到的项目中,Redis起到了一个分布式锁的作用,具体情况是这 ...

  2. 分布式锁的三种实现方式_基于 redis 的分布式锁实现

    云龙 资深运维开发工程师,负责游戏系统配置管理平台的设计和开发,目前专注于新 CMDB 系统的开发,平时也关注运维自动化,devops,python 开发等技术. 背景 CMDB 系统里面的机器数据会 ...

  3. 灵活运用分布式锁解决数据重复插入问题

    作者:快应用服务器研发团队-Lin Yupan 一.业务背景 许多面向用户的互联网业务都会在系统后端维护一份用户数据,快应用中心业务也同样做了这件事.快应用中心允许用户对快应用进行收藏,并在服务端记录 ...

  4. Redisson 是如何实现分布式锁的?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | bravoban 来源 | tech.lede ...

  5. Apache ZooKeeper - 使用ZK实现分布式锁(非公平锁/公平锁/共享锁 )

    文章目录 什么是分布式锁 分布式死锁 分类 排他锁 共享锁 实现 创建锁 获取锁 释放锁 Demo Jmeter配置 方案零 缺陷版本 方案一 非公平锁方案 缺陷 (羊群效应) 方案二 公平锁方案 方 ...

  6. 还不知道 Redis 分布式锁的背后原理?还不赶快学习一下

    前言 以前在学校做小项目的时候,用到Redis,基本也只是用来当作缓存.可阿粉在工作中发现,Redis在生产中并不只是当作缓存这么简单.在阿粉接触到的项目中,Redis起到了一个分布式锁的作用,具体情 ...

  7. redis 分布式锁 看门狗_漫谈分布式锁之Redis实现

    笔耕墨耘,深研术道. 01写在前面Redis是一个高性能的内存数据库,常用于数据库.缓存和消息中间件.它提供了丰富的数据结构,更适合各种业务场景:基于AP模型,Redis保证了其高可用和高性能. 本文 ...

  8. Redis分布式锁—SETNX+Lua脚本实现篇

    前言 平时的工作中,由于生产环境中的项目是需要部署在多台服务器中的,所以经常会面临解决分布式场景下数据一致性的问题,那么就需要引入分布式锁来解决这一问题. 针对分布式锁的实现,目前比较常用的就如下几种 ...

  9. 万字长文!不为人所知的分布式锁实现全都在这里了

    1. 引入业务场景 首先来由一个场景引入: 最近老板接了一个大单子,允许在某终端设备安装我们的APP,终端设备厂商日活起码得几十万到百万级别,这个APP也是近期产品根据市场竞品分析设计出来的,几个小码 ...

最新文章

  1. 选择性模糊及其算法的实现。
  2. Java的知识点21——String类、StringBuffer和StringBuilder、不可变和可变字符序列使用陷阱
  3. 战略配售基金成热点,它或成为入局CDR的最优选择
  4. [javaSE] 多线程(守护线程)
  5. javaweb学习总结(十八)——JSP属性范围
  6. C语言程序设计--输入与输出
  7. java pkcs1转pkcs8_pkcs1与pkcs8格式RSA私钥互相转换
  8. VB6-改造ComUnit(免除用例名称注册)
  9. Shell脚本学习-阶段六-密钥的批量分发与执行
  10. 《python源代码分析》笔记 pythonVM一般表达式
  11. 新版Excel和Word全屏打印预览的设定方法
  12. 计算机专业毕业论文题目大全集
  13. roc曲线spss怎么做_如何用SPSS做ROC曲线分析?看这1篇就够了!
  14. Transforms的使用
  15. 【Codeforces思维题】20220728
  16. CNN中的小tips
  17. android卡通头像,Face V(卡通头像制作)
  18. 北京邮电大学计算机考研英语,我的考研心得——北京邮电大学计算机专业
  19. 用友U9 SOA引领企业IT架构全面升级
  20. 用c语言将2048的分数存档,利用C语言实现2048小游戏的方法

热门文章

  1. CXF小窥:知道服务器端wsdl地址,如何本地测试服务接口
  2. CN Erlounge IV 讲师名单公布及Call For Topic
  3. python多任务编程_python线程的多任务编程
  4. JavaScript 开发的45个经典技巧
  5. 思科三层交换机充当路由器实现全网互通
  6. Scala具体解释---------Scala是什么?可伸展的语言!
  7. 腾讯大湘网某处csrf(city.hn.qq.com)可投诉刷留言
  8. [BOOST] BOOST::Format
  9. 设计模式之Builder
  10. Zune 3.0与XNA GS 3.0 Beta