分布式锁的实现与探索

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

一、背景

   分布式场景下的数据一致性问一直是一个非常重要的话题,在很多场景中,我们需要使用各种技术方案来保证数据的一致性,比如分布式事务、分布式存储、分布式锁等。有些业务场景中,我们需要保证一个方法在同一时间内只能被一个线程执行,来解决一些譬如商品超卖,我们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缓存实践经验分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312408.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

matlab 角度转四元数_基于Matlab的机械臂路径规划

什么是 trajectory(路径)规划中文路径在英语中可能有两种翻译:1. path2. trajectory首先告诉大家,我们所说的“路径”是后者——trajectory。我们看一下这两种“路径”在机械臂的世界里有什么区别。设想机械臂的 end-effector 要从 A 点运动到 B 点&…

ASP.NET Core 中间件的几种实现方式

前言ASP.NET Core 中 HTTP 管道使用中间件组合处理的方式,换句人话来说,对于写代码的人而言,一切皆中间件.业务逻辑/数据访问/等等一切都需要以中间件的方式来呈现.那么我们必须学会如何实现自定义中间件 这里划重点,必考这里我们介绍下中间件的几种实现方式...匿名函数通常新建…

cookies默认过期时间_「图」Chrome Canary新版已启动“增强版cookies控制”预览测试...

近日谷歌承诺将于今年晚些时候在Chrome浏览器启动“增强版cookies控制”的预览测试。在今年的I/O开发者大会上,谷歌宣布携手Mozilla等开发者耗时3年多时间制定了名为“same-site cookies”的IETF 标准,而该功能就是建立在same-site cookies的基础上&…

【原创】StackOverflow 20万关注的问题:如何实现异步Task超时的处理?

前文传送门 dotNET开发系列收藏!推荐12个超实用的Visual Studio插件程序员:这10种糟糕的程序命名,你遇到过几个?使用Vistual Studio N年,推荐2个异常捕获的技巧面试官:你连RESTful都不知道我怎么敢要你&…

C# WPF 表单更改提示

微信公众号:Dotnet9,网站:Dotnet9,问题或建议,请网站留言; 如果您觉得Dotnet9对您有帮助,欢迎赞赏Dotnet9.com内容目录实现效果业务场景编码实现本文参考源码下载1.实现效果未做修改的表单展示 …

XRPC接口双向调用

一般远程接口调用的服务都是基于客户端主动调用服务端,由服务端来提供相关的接口服务;在新版本的XRPC中引入了一个新的功能,即接口双向通讯,组件提供服务创建客户会话的接口代理并调用客户提供的接口服务。接下来介绍如何通过XRPC…

电机控制pid_微电机控制如此简单,揭秘微电机调速的控制,PID控制之双环调速...

​​在微型电机应用中,由于各种应用产品的不同会用到不同的调速方式,在调速中可能会遇到各种不同的问题,下面天孚电机对最近客户对微电机PID调速遇到的双环控制问题来讲一讲。智能小车TFMOTOR-N30减速电机​客户是做智能小车的采用的是tfn30微…

简单的01背包和完全背包

2020.12.30开始学习AcWing算法《算法竞赛进阶指南》&#xff1b; 上传博客方便复习。 01背包&#xff08;每种物品只能使用一次&#xff09;&#xff1a; //Wecccccccc //2020.12.31 #include <iostream> using namespace std; int n,m,v[1010],w[1010],dp[1010]; int…

图片上传组件_配置Django-TinyMCE组件 实现上传图片功能

Django自带的Admin后台&#xff0c;好用&#xff0c;TinyMCE作为富文本编辑器&#xff0c;也蛮好用的&#xff0c;这两者结合起来在做博客的时候很方便&#xff08;当然博客可能更适合用Markdown来写&#xff09;&#xff0c;但是Django-TinyMCE这个组件默认没有图片上传功能的…

.NET Core 3.1之深入源码理解HealthCheck(二)

写在前面前文讨论了HealthCheck的理论部分&#xff0c;本文将讨论有关HealthCheck的应用内容。可以监视内存、磁盘和其他物理服务器资源的使用情况来了解是否处于正常状态。运行状况检查可以测试应用的依赖项&#xff08;如数据库和外部服务终结点&#xff09;以确认是否可用和…

多重背包问题以及二进制优化

2020.12.30开始学习AcWing算法《算法竞赛进阶指南》&#xff1b; 上传博客方便复习。 多重背包问题&#xff08;N< 100): //Wecccccccc //2020.12.31 #include <iostream> using namespace std; int n,m,dp[110]; int main() {cin>>n>>m;for(int i0;i&…

UnitTest in .NET(Part 2)

Photo &#xff1a;Unit Test in Visual Studio文 | Edison Zhou上一篇我们学习基本的单元测试基础知识和入门实例。但是&#xff0c;如果我们要测试的方法依赖于一个外部资源&#xff0c;如文件系统、数据库、Web服务或者其他难以控制的东西&#xff0c;那又该如何编写测试呢&…

二维费用的背包问题

2020.12.30开始学习AcWing算法《算法竞赛进阶指南》&#xff1b; 上传博客方便复习。 //Wecccccccc //2020.12.31 #include <iostream> using namespace std; int n, v, m, dp[120][120];int main() {cin >> n >> v >> m;for (int i 0; i < n; i) …

UnitTest in .NET(Part 1)

Photo &#xff1a;Unit Test in Visual Studio文 | Edison Zhou2015年看了Roy Osherove的《单元测试的艺术》一书&#xff0c;颇有收获。因此&#xff0c;我在当时就将我的学习笔记过程记录了下来&#xff0c;并分为四个部分分享成文&#xff0c;与各位Share。本篇作为入门&am…

找出一个字符串中出现次数最多的字_Day34:第一个只出现一次的字符

剑指Offer_编程题——第一个只出现一次的字符题目描述&#xff1a;在一个字符串(0<字符串长度<10000&#xff0c;全部由字母组成)中找到第一个只出现一次的字符&#xff0c;并返回它的位置&#xff0c;如果没有则返回-1&#xff0c;需要区分大小写。(从0开始计数)。具体要…

2020 WTM 继续向前

WTM3.1 正式发布在过去的2019年&#xff0c;承蒙各位的厚爱&#xff0c;WTM从零开始一年的时间在GitHub上收获了将近1600星&#xff0c;nuget上的下载量累计超过10万。WTM所坚持的低码开发&#xff0c;快速实现的理念受到了越来越多.netcore使用者的喜爱。在2020年&#xff0c;…

使用ASP.NET Core 3.x 构建 RESTful API - 4.3 HTTP 方法的安全性和幂等性

什么样的HTTP方法是安全的&#xff1f; 如果一个方法不会改变资源的表述&#xff0c;那么这个方法就被认为是安全的。 例如 HTTP GET 和 HTTP HEAD 就被认为是安全的&#xff0c;但需要注意的是&#xff0c;这并不意味着执行GET请求就不会引起其它的资源操作&#xff0c;在表面…

混合背包问题

2020.12.30开始学习AcWing算法《算法竞赛进阶指南》&#xff1b; 上传博客方便复习。 //Wecccccccc //2020.12.31 #include <iostream> using namespace std; #include <vector>struct note {int kind;int v, w; };vector <note> kinds; int n, v, v1, w, dp…

.NET Core 3.1通用主机原理及使用

一、前言只是讲asp.net core 3.x通用主机的大致原理&#xff0c;这些东西是通过查看源码以及自己根据经验总结得来的&#xff0c;在文章中不会深入源码&#xff0c;因为个人觉得懂原理就晓得扩展点&#xff0c;后期碰到有需求的时候再仔细去研究源码也不迟。阅读前你应该先去了…

火焰效果材质实现_「游戏开发」使用Unity实现魔法火焰效果

*本文转载自公众号“Unity官方平台”。本文由视觉效果艺术家Evgeny Starostin分享如何使用Unity制作魔法火焰效果的过程&#xff0c;让我们一起学习和制作魔法火焰吧。下面是魔法火焰效果图。项目下载本文提供项目工程及着色器下载。本文为转载文章&#xff0c;请关注公众号“U…