
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
分布式锁的应用在许多软件开发项目中是会经常见到的一个功能,而本文我们就通过案例分析来简单了解一下,分布式锁的实现方案都有哪些类型。
在单进程的系统中,当存在多个线程可以同时改变某个变量时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量。而同步本质上通过锁来实现。为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记。
而在分布式环境下,数据一致性问题一直是难点。相比于单进程,分布式环境的情况更加复杂。分布式与单机环境大的不同在于其不是多线程而是多进程。多线程由于可以共享堆内存,因此可以简单的采取内存作为标记存储位置。而进程之间甚至可能都不在同一台物理机上,因此需要将标记存储在一个所有进程都能看到的地方。
常见的是秒杀场景,订单服务部署了多个服务实例。如秒杀商品有4个,一个用户购买3个,二个用户购买2个,理想状态下一个用户能购买成功,二个用户提示购买失败,反之亦可。而实际可能出现的情况是,两个用户都得到库存为4,一个用户买到了3个,更新库存之前,二个用户下了2个商品的订单,更新库存为2,导致业务逻辑出错。
在上面的场景中,商品的库存是共享变量,面对高并发情形,需要保证对资源的访问互斥。在单机环境中,比如Java语言中其实提供了很多并发处理相关的API,但是这些API在分布式场景中就无能为力了,由于分布式系统具备多线程和多进程的特点,且分布在不同机器中,synchronized和lock关键字将失去原有锁的效果,。仅依赖这些语言自身提供的API并不能实现分布式锁的功能,因此需要我们想想其它方法实现分布式锁。
常见的锁方案如下:
基于数据库实现分布式锁
基于Zookeeper实现分布式锁
基于缓存实现分布式锁,如redis、etcd等
下面我们简单介绍下这几种锁的实现,并重点介绍etcd实现锁的方法。
基于数据库的锁
基于数据库的锁实现也有两种方式,一是基于数据库表,另一种是基于数据库的排他锁。
基于数据库表的增删
基于数据库表增删是简单的方式,先创建一张锁的表主要包含下列字段:方法名,时间戳等字段。
具体使用的方法为:当需要锁住某个方法时,往该表中插入一条相关的记录。需要注意的是,方法名有性约束。如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,可以执行方法体内容。执行完毕,需要删除该记录。
对于上述方案可以进行优化,如应用主从数据库,数据之间双向同步。一旦主库挂掉,将应用服务快速切换到从库上。除此之外还可以记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查到的话,直接把锁分配给该线程,实现可重入锁。
基于数据库排他锁
我们还可以通过数据库的排他锁来实现分布式锁。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!更多内容请加danei456学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。