1.分布式锁是保证任一时刻只有一个线程持有锁。
1.1 mysql数据库实现
create table dss_lock {id,lock_name,lock_status,start_time,expire_time};
优势:数据库可以保证高可用。
设置expire_time可以避免一个线程获取锁后出现异常后,锁一直占用。
劣势:线程执行时间超长问题。到expire_time后仍然没有执行完成。解决:在应用中自己去判断前一个任务是否还在执行,如果是就不再执行,如job,将运行日志插入job_log表,在job中每次查询是否有在运行中的该job。需要继续执行需要手动线下调整,否则也无意义。
任务调度实例重启任务捞取的开始时间。应该以expire_time开始,即上一次结束时间,如果当前时间小于expire_time
执行端多实例。解决直接封装成api,调用时直接调用网关通过注册中心负载
1.2 redis实现
redisTemplate.opsForValue().setIfAbsent("dsslock",111,3, TimeUnit.MINUTES);
优势:缓存数据库性能有保障。
保证可用性AP.
劣势:在集群模式下极端情况下会有数据一致性问题(redis RedLock)。当一个master挂掉后,slave拉起的过程中,锁信息没有同步,导致第二个线程也持有锁。解决,采用redssion或者保障最终一致性,即,1.1任务超长的解决方案。
2 并发更新
CAScompare and set
更新库存或扣费,0时不能操作
乐观锁:update store_amount=
(store_amount-#{amount}) where
store_amount >#{amount}
and store_amount=#{before_amount}
悲观锁:
select for update ;
update store_amount=(store_amount-#{amount}) where for update
commit;