1.分布式锁相关

1.1介绍

  • 在分布式系统中,常常需要去协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
  • 分布式锁是: 控制分布式系统之间同步访问共享资源的一种方式。

    1.2实现分布式锁的几种方案

  • 基于数据库实现: 基于数据库的悲观锁 for update(行锁)实现(写入的并发的太大)

  • 基于zookeeper实现: (CP): 基于zookeeper的文件系统及通知机制
  • 基于redis的实现(推荐): 基于redis单线程模型+setnx

    1.3方案对比

  • 理解的难易程度角度(从低到高)

    • 数据库 > redis > zookeeper
  • 从实现的复杂性角度( 从高到低 )
    • zookeeper > redis(Redisson) > 数据库
  • 性能角度(从高到低)
    • redis > zookeeper > 数据库
  • 可靠性角度(从高到低)

    • zookeeper > redis > 数据库

      1.4为什么选择基于Redis实现?

  • Redis完全基于内存的 ,性能比Zookeeper高很多

  • 另外基于Redission框架的实现已经相对非常高可用,而且api简单很容易整合到项目中。
  • 而且redis也是大部分公司的选择,因为redis在其它的使用场景也很多,公司往往都会搭建redis集群。

    1.5实现分布式锁的思路

  • 实现分布式锁的思路很简单, 创建key成功代表持有锁,失败说明锁被占用,需要等待并尝试继续获取锁, 持有锁的客户端执行完毕业务代码后会释放锁就是删除key, 这样其它的客户端就可以获取到锁

    • 实现一个高可用的分布式锁需要满足很多条件
      • 互斥性:和我们本地锁一样互斥性是最基本的,但是分布式锁需要保证在不同节点的不同线程互斥。
      • 可重入性:同一个节点上的同一个线程如果获取了锁之后,那么也可以再次获取这个锁。
      • 锁超时:和本地锁一样支持锁超时,防止死锁。(redis expiretime)
      • 锁的续约: 当程序响应时间过长时,能够续约锁的时间
      • 高效:高可用:加锁和解锁需要高效,同时也需要保证高可用防止分布式锁失效,可以增加降级。
      • 支持阻塞和非阻塞:和ReentrantLock一样支持Lock和tryLock以及tryLock(long timeout)。
      • 支持公平锁和非公平锁:公平锁的意思是按照请求加锁的顺序获取锁,非公平锁就相反是无序的,这个一般来说实现的比较少。
      • 引出了分布式锁的框架Redisson
    • 使用Redisson框架的方式

      • RLock rlock = redisson.getLock(“likes-lock”); 获取一个锁
      • rLock.lock();代表加锁,加锁成功才会往下执行,否则阻塞
      • rLock.unlock();代表释放锁
      • 释放锁必须在finally中,否则有产生死锁的可能

        1.6分布式锁的原理

        image.png

        2.任务调度

    • 什么是任务调度

      • 任务调度是指系统为了自动完成特定任务,在约定的特定时刻去执行任务的过程。有了任务调度即可解放更多的人力,而是由系统自动去执行任务。
    • corn表达式
      • 秒 分 时 天 月 周 年(可选,一般不谢)
      • /5 * ? 每隔五秒运行一次任务
      • 0 0 23 ? 每天23点运行一次任务
      • 0 0 1 1 * ? 每月一号凌晨1点运行一次任务
      • 0 26,29,33 * ? 在26分,29分,33分运行一次任务
      • 0 0/30 9-17 ? 朝九晚五工作时间内每半小时运行一次任务
      • 0 15 10 ? * 6#3 每个月的第三个星期五上午10:15运行一次任务
    • 什么是分布式任务调度

      • 当前软件的架构已经开始向分布式架构转变,将单体结构拆分为若干服务,服务之间通过网络交互来完成业务处理。在分布式架构下,一个服务往往会部署多个实例来运行我们的业务,如果在这种分布式系统环境下运行任务调度,我们称之为分布式任务调度

        3.分布式任务调度框架XXL-Job

    • 如何使用:

      • 新增执行器

        1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22908560/1638277192067-adf1ea51-d283-40b1-b00f-f7a1a3406e3d.png#clientId=u4ec28ba1-b2b2-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=363&id=u0f887d45&margin=%5Bobject%20Object%5D&name=image.png&originHeight=363&originWidth=611&originalType=binary&ratio=1&rotation=0&showTitle=false&size=16798&status=done&style=none&taskId=u18648565-e89a-49d8-9939-b039edf5121&title=&width=611)<br /> 注意: 手动录入时,需要用逗号分隔
      • 在调度中心中新建任务

image.png

  1. - 执行器:任务的绑定的执行器,任务触发调度时将会自动发现注册成功的执行器, 实现任务自动发现功能; 另一方面也可以方便的进行任务分组。每个任务必须绑定一个执行器, 可在 "执行器管理" 进行设置
  2. - **路由策略:当执行器集群部署时,提供丰富的路由策略,包括**
  3. - FIRST(第一个):固定选择第一个机器;
  4. - LAST(最后一个):固定选择最后一个机器;
  5. - ROUND(轮询):
  6. - RANDOM(随机):随机选择在线的机器;
  7. - CONSISTENT_HASH(一致性HASH):每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上。
  8. - LEAST_FREQUENTLY_USED(最不经常使用):使用频率最低的机器优先被选举;
  9. - LEAST_RECENTLY_USED(最近最久未使用):最久为使用的机器优先被选举;
  10. - FAILOVER(故障转移):按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度;
  11. - BUSYOVER(忙碌转移):按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度;
  12. - SHARDING_BROADCAST(分片广播):广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务;
  13. - Cron:触发任务执行的Cron表达式
  14. - **阻塞处理策略**:调度过于密集执行器来不及处理时的处理策略;
  15. - 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行;
  16. - 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败;
  17. - 覆盖之前调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度任务;
  • 配合代码使用

image.png