• ADADADADAD

    怎么在MySQL中利用DB实现分布式锁[ mysql数据库 ]

    mysql数据库 时间:2024-11-28 13:27:20

    作者:文/会员上传

    简介:

    表设计首先要明确DB在系统中仍然需要认为是最脆弱的一环,因此在设计时需要考虑压力问题,即能应用实现的逻辑就不要放到DB上实现,也就是尽量少使用DB提供的锁能力,如果是高并发业

    以下为本文的正文内容,内容仅供参考!本站为公益性网站,复制本文以及下载DOC文档全部免费。

    表设计

    首先要明确DB在系统中仍然需要认为是最脆弱的一环,因此在设计时需要考虑压力问题,即能应用实现的逻辑就不要放到DB上实现,也就是尽量少使用DB提供的锁能力,如果是高并发业务则要避免使用DB锁,换成Redis等缓存锁更加有效。如清单1所示,该表中唯一的约束为lock_name,timestamp,version三者组合主键,下文会利用这三者实现悲观锁,乐观锁等业务场景。

    清单1: 分布式锁表结构

    CREATETABLE`lock`(`lock_name`varchar(32)NOTNULLDEFAULT''COMMENT'锁名称',`resource`bigint(20)NOTNULLCOMMENT'业务主键',`version`int(5)NOTNULLCOMMENT'版本',`gmt_create`datetimeNOTNULLCOMMENT'生成时间',PRIMARYKEY(`lock_name`,`resource`,`version`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

    悲观锁实现

    对于悲观锁业务中常见的操作有以下两种:

    针对A:

    A场景当一台机器获取到锁后,其他机器处于排队状态,锁释放后其他机器才能够继续下去,这种应用层面解决是相当麻烦,因此一般使用DB提供的行锁能力,即select xxx from xxx for update。A场景一般都和业务强关联,比如库存增减,使用业务对象作为行锁即可。需要注意的是,该方案本质上锁压力还是在数据库上,当阻塞住的线程过多,且操作耗时,最后会出现大量锁超时现象。

    针对B:

    针对B场景(tryLock)举个具体业务,在集群下每台机器都有定时任务,但是业务上要求同一时刻只能有一台能正常调度。
    解决思路是利用唯一主键约束,插入一条针对TaskA的记录,版本则默认为1,插入成功的算获取到锁,继续执行业务操作。这种方案当机器挂掉就会出现死锁,因此还需要有一个定时任务,定时清理已经过期的锁,清理维度可以根据lock_name设置不同时间清理策略。

    定时任务清理策略会额外带来复杂度,假设机器A获取到了锁,但由于CPU资源紧张,导致处理变慢,此时锁被定时任务释放,因此机器B也会获取到锁,那么此时就出现同一时刻两台机器同时持有锁的现象,解决思路:把超时时间设置为远大于业务处理时间,或者增加版本机制改成乐观锁。

    insertintolocksetlock_name='TaskA',resource='锁住的业务',version=1,gmt_create=now()success:获取到锁failed:放弃操作释放锁

    乐观锁实现

    针对乐观锁场景,举个具体业务,在后台系统中经常使用大json扩展字段存储业务属性,在涉及部分更新时,需要先查询出来,合并数据,写入到DB,这个过程中如果存在并发,则很容易造成数据丢失,因此需要使用锁来保证数据一致性,相应操作如下所示,针对乐观锁,不存在死锁,因此这里直接存放业务id字段,保证每一个业务id有一条对应的记录,并且不需要对应的定时器清除。

    select*fromlockwherelock_name='业务名称',resource='业务id';不存在:insertintolocksetlock_name='业务名称',resource='业务id',version=1;获取版本:version业务操作:取数据,合并数据,写回数据写回到DB:updatelocksetversion=version+1wherelock_name='业务名称'andresource='业务id'andversion=#{version};写回成功:操作成功写回失败:回滚事务,从头操作
    怎么在MySQL中利用DB实现分布式锁.docx

    将本文的Word文档下载到电脑

    推荐度:

    下载
    热门标签: mysqldb