加入收藏 | 设为首页 | 会员中心 | 我要投稿 宁德站长网 (https://www.0593zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

为什么Zookeeper天生就是一副分布式锁的胚子?

发布时间:2020-03-15 20:31:17 所属栏目:MySql教程 来源:站长网
导读:副标题#e# 【金融特辑】光大****科技部DBA女神带你从0到1揭秘MGR 什么是分布式锁?分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。 图片来自 Pexels 如果不同的系统或是同一个系统的不同主机之间共享了

`description` varchar(1024) NOT NULL DEFAULT "" COMMENT '描述', 

PRIMARY KEY (`id`), 

UNIQUE KEY `uiq_idx_resource` (`resource`) 

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据库分布式锁表'; 

①获得锁

我们可以插入一条数据:

INSERT INTO database_lock(resource, description) VALUES (1, 'lock'); 

因为表 database_lock 中 resource 是唯一索引,所以其他请求提交到数据库,就会报错,并不会插入成功,只有一个可以插入。插入成功,我们就获取到锁。

②删除锁

INSERT INTO database_lock(resource, description) VALUES (1, 'lock'); 

这种实现方式非常的简单,但是需要注意以下几点:

①这种锁没有失效时间,一旦释放锁的操作失败就会导致锁记录一直在数据库中,其他线程无法获得锁。这个缺陷也很好解决,比如可以做一个定时任务去定时清理。

②这种锁的可靠性依赖于数据库。建议设置备库,避免单点,进一步提高可靠性。

③这种锁是非阻塞的,因为插入数据失败之后会直接报错,想要获得锁就需要再次操作。

如果需要阻塞式的,可以弄个 for 循环、while 循环之类的,直至 INSERT 成功再返回。

④这种锁也是非可重入的,因为同一个线程在没有释放锁之前无法再次获得锁,因为数据库中已经存在同一份记录了。

想要实现可重入锁,可以在数据库中添加一些字段,比如获得锁的主机信息、线程信息等。

那么在再次获得锁的时候可以先查询数据,如果当前的主机信息和线程信息等能被查到的话,可以直接把锁分配给它。

乐观锁

顾名思义,系统认为数据的更新在大多数情况下是不会产生冲突的,只在数据库更新操作提交的时候才对数据作冲突检测。如果检测的结果出现了与预期数据不一致的情况,则返回失败信息。

为什么Zookeeper天生就是一副分布式锁的胚子?

乐观锁大多数是基于数据版本(version)的记录机制实现的。何谓数据版本号?

即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个 “version”字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号加 1。

在更新过程中,会对版本号进行比较,如果是一致的,没有发生改变,则会成功执行本次操作;如果版本号不一致,则会更新失败。

为了更好的理解数据库乐观锁在实际项目中的使用,这里也就举了业界老生常谈的库存例子。

一个电商平台都会存在商品的库存,当用户进行购买的时候就会对库存进行操作(库存减 1 代表已经卖出了一件)。

如果只是一个用户进行操作数据库本身就能保证用户操作的正确性,而在并发的情况下就会产生一些意想不到的问题。

比如两个用户同时购买一件商品,在数据库层面实际操作应该是库存进行减 2 操作。

但是由于高并发的情况,第一个用户购买完成进行数据读取当前库存并进行减 1 操作,由于这个操作没有完全执行完成。

第二个用户就进入购买相同商品,此时查询出的库存可能是未减 1 操作的库存导致了脏数据的出现【线程不安全操作】。

数据库乐观锁也能保证线程安全,通常代码层面我们都会这样做:

(编辑:宁德站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读