关于分布式锁的一种实现思路

需求语言描述:多个节点竞争同一资源,且只能有一个节点竞争成功;

场景描述:

  最近在做一个数据同步程序,因为es出色的查询性能以及为了减轻与底层数据库的交互,将底层数据库如sqlserver中的数据同步到es。

  在做了定时任务的统一调度和配置之后,由于是多人协同开发,所以各自本地都可能启动一个实例,那么就相当于多个实例。但是同一个同步程序(定时任务)在指定时间内我们只想调度(触发)一次,而多个实例同时触发,由于也没有做es的锁的控制,所以发现es会写入重复的数据。举个栗子,比如一个名为 “jobBondGuarantor”的定时任务,cron表达式设置的4个小时调度一次,那么12点的时候,在没有人修改调度表达式的时候,所有本地实例都会触发定时任务,这样就会造成es写入数据重复(A实例先写,B实例后写),同理,16点,20点,8点等等,都有这样的问题。

解决:

  1.Redis分布锁,本人这次没采用这个,所以自行百度哈;

  2.利用数据库的排他锁,加上幂等解决。

解释:

数据库设计

更新sql(幂等):

  数据库更新时的排他锁,就是当有一个线程(进程)更新这条数据时,那么其他线程就不能更新这条数据了,这个锁一般都是行级锁,其他线程一般会等待获取锁,等拿到锁之后执行相应的更新,如果超时则会取消,这个不绝对,和你用的持久层框架有关,你也可以自己写持久层交互。

  那么为什么要用幂等呢,比如A线程先抢到锁,更新了,将 IS_SYNC更新为1了,返回影响行数1行,这个没问题,B线程在等待A线程更新完数据释放锁之后,获取到锁,执行更新,如果不用幂等,只是update edr_cloud_sync_job set is_sync =1 where job_name = ..., 那么B线程更新返回影响行数也是1,我们无法区分AB线程到底是谁更新了is_sync=1,而用幂等,那么B线程则会查不出数据,因为is_sync已经被A线程更新为1了,所以加上is_sync=0时,B线程更新返回影响行数为0。那么就可以区分到底谁更改了is_sync=1,即有唯一一个线程更改数据成功,那么由他执行此次的任务即可。

  一般而言,市面上数据库默认更新时排他锁,而且为行级锁,如果是表级锁也不是很适合用这个方法(一般也没人会把更新做成表级锁,即使需要,也另外设表),具体的还需要各位亲测。

猜你喜欢

转载自blog.csdn.net/duoduo1636546/article/details/81873725