分布式锁和分布式事务和分布式Session

分布式锁和分布式事务

分布式锁

基于MySQL数据库

这种方式一般采用数据库乐观锁,不推荐使用

基于redis
  • 加锁:setnx命令,key是锁的唯一标志,可以为想要加锁的资源设置对应的keyvalue暂时设置为1,即

    • setnx(lock_ID,1)//setnx返回1,原key不存在,加锁成功;返回0,key存在,加锁失败
      
  • 解锁:释放锁,采用del命令

    • del(lockID)
      
  • 锁超时:得到锁的线程挂掉,来不及释放锁,资源将被永久锁住,别的线程无法进入。

    • setnxkey设置一个超时时间,保证即使没有被显式释放,也要在一定时间后自动释放

    • 使用expire(lock_ID,30)来实现

    • if(setnx(lock_sale_商品ID,1) == 1){
               
          expire(lock_sale_商品ID,30)
          try {
               
              do something ......
          } finally {
               
              del(lock_sale_商品ID)
          }
      }
      

存在的问题

setnxexpire两个操作是非原子的,可以使用带可选参数(超时时间)的set来替代

set(lock_ID,1,30,NX)

del误删除,线程A由于执行时间过长,提前被释放了锁,线程B拿到了锁,此时线程A执行完了,进行了del操作,但删除的实际上是B线程的锁

​ 把当前线程的ID当作set操作中的value,每次释放锁时进行判断,看是否是自己占有的锁

​ 判断和删除不是原子性操作,可以使用守护线程来解决

基于zookeeper
  • 在指定locker节点下创建临时顺序节点,释放锁时删除该节点

  • 获取locker下所有的子节点,客户端发现自己创建的子节点序号最小,则获取到了锁

  • 如果非最小,则找到自己的前一个节点,调用exist()方法,注册事件监听器

  • 如果关注的这个节点被删除,客户端的watcher会收到通知,再判断是否为最小,循环往复

获取分布式锁的核心算法流程

​ 下面同个一个流程图来分析获取分布式锁的完整算法,如下:

img

分布式事务

两阶段提交
  • 准备阶段,协调者询问参与者是否执行成功,参与者发回事务执行结果
  • 提交阶段,如果每个参与者都执行成功,协调者发送通知让参与者提交事务,否则,协调者通知参与者回滚
  • 问题
    • 所有事务参与者等待其他参与者响应都是阻塞状态
    • 协调者发生故障影响很大,第二阶段故障会造成所有参与者一直等待
    • 网络异常导致协调者只发送了部分通知,导致数据不一致
补偿事务

对每个操作都要注册一个与其对应的确认和补偿操作。三个阶段

  • try 主要是对业务系统做检测和资源预留
  • confirm 对业务系统做确认提交,try成功,confirm必定成功
  • cancel 业务执行错误,回滚时执行的业务取消,预留资源释放
本地消息表

利用本地事务保证对两个表(本地消息表和业务数据表)操作满足事务性,并使用了消息队列

  • 分布式事务操作的一方完成业务数据操作后向本地消息表发送一个消息,本地事务能保证此消息一定会被写入本地消息表
  • 将本地消息表中的消息转发到kafka等消息队列,转发成功则将消息从本地消息表中删除,否则继续重新转发
  • 分布式事务操作另一方从消息队列中读取消息,执行操作

是一种经典的最终一致性实现方案

MQ事务消息
  • prepare消息:半消息,标志该消息处于“暂时不能投递”状态,不会被consumer消费,等到服务端收到生成者对该消息的commit和rollback后,才会被正常投递或回滚
  • 两阶段提交:
    • 1.生产者向服务器发送prepare消息,服务端确认后回调通知生产者执行本地事务
    • 2.生产者执行完本地事务,根据结果返回commit/rollback/unknown状态玛做出不同回应
  • 事务状态定时回查:服务端如果收不到状态码,回定时回调检查生产者本地事务执行状态,保证最终能和本地事务状态一致

分布式session

  • 粘性session
    • 第一次请求时,负载均衡设置粘性session,以后每次用户请求都转发到存有session的服务器上
  • session复制
    • 任何一个服务器上的session发生改变(增删改),该节点会把这个 session的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要session,以此来保证Session同步。
  • session共享
    • 使用分布式缓存方案比如memcached、Redis,但是要求Memcached或Redis必须是集群
  • 持久化session到数据库

你可能感兴趣的:(分布式)