【GHS】基于数据库、redis和zookeeper实现的分布式

编程开发   © 文章版权由 admin 解释,禁止匿名转载

#楼主# 2020-12-30

基于数据库
基于数据库(MySQL)的方案,一般分为3类:基于表记录、乐观锁和悲观锁

基于表记录
用表主键或表字段加唯一性索引便可实现,如下;

CREATE TABLE `database_lock` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`resource` int NOT NULL COMMENT '锁定的资源',
`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');
解锁删除数据:

DELETE FROM database_lock WHERE resource=1;
这种实现方式非常的简单,但是需要注意以下几点:

这种锁没有失效时间,一旦释放锁的操作失败就会导致锁记录一直在数据库中,其它线程无法获得锁。这个缺陷也很好解决,比如可以做一个定时任务去定时清理。
这种锁的可靠性依赖于数据库。建议设置备库,避免单点,进一步提高可靠性。
这种锁是非阻塞的,因为插入数据失败之后会直接报错,想要获得锁就需要再次操作。如果需要阻塞式的,可以弄个for循环、while循环之类的,直至INSERT成功再返回。
这种锁也是非可重入的,因为同一个线程在没有释放锁之前无法再次获得锁,因为数据库中已经存在同一份记录了。想要实现可重入锁,可以在数据库中添加一些字段,比如获得锁的主机信息、线程信息等,那么在再次获得锁的时候可以先查询数据,如果当前的主机信息和线程信息等能被查到的话,可以直接把锁分配给它。
在 MySQL 数据库中采用主键冲突防重,在大并发情况下有可能会造成锁表现象
基于乐观锁
可基于MVCC机制实现

优点:在检测数据冲突时并不依赖数据库本身的锁机制,不会影响请求的性能,当产生并发且并发量较小的时候只有少部分请求会失败

缺点: 唯一癿问题就是对数据表侵入较大,我们
要为每个表设计一个版本号字段,然后写一条判断 sql 每次进行判断,增加了数据库操作的次数,在高并发要求下,对数据库连接的开销也是无法忍受的。

基于悲观锁
在查询语句后面增加for update, 数据库会在查询过程中给数据库表增加排他锁, 当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁。

我们可以任务获得排他锁的线程即可获得分布式锁,当获取到锁之后,可以执行方法的业务逻辑,执行完方法后,通过connection.commit()操作来释放锁注意:在加锁的时候,只有明确地指定主键(或索引)的才会执行行锁,否则MySQL 将会执行表锁

加锁前注意取消自动提交

优点:

简单易于理解
严格保证数据访问的安全
缺点:

MySQL会对查询进行优化,如果任务全表扫描效率更高,便使用表锁,导致性能问题
如果一个排他锁长时间不提交,就会占用数据库连接,类似连接变多,就可能把连接池撑爆
悲观锁使用不当还可能产生死锁的情况
每次请求都会额外产生加锁的开销且未获取到锁的请求将会阻塞等待锁的获取,在高并发环境下,容易造成大量请求阻塞,影响系统可用性

成为第一个回答人

评论

登录后才可发表内容
  • 主题

    10

  • 帖子

    48

  • 关注者

    0

Copyright © 2019 凯特网.   Powered by HYBBS 2.3.4  

Runtime:2.4879s Mem:2060Kb