使用redis分布式锁+lua脚本实现分布式定时任务控制demo

分布式系统常常要遇到定时任务执行的问题,不能重复执行,但不少时候又不能统一到一个微服务里面,由于这样就失去了微服务的意义。因为个人系统只有寥寥几个定时任务,并且都是按天执行的,我就弄了这么个小东西来控制分布式定时任务。redis

我使用的redis分布式锁来控制分布式定时任务的方式,实际上适用于定时任务较少的状况,并且不适用于瞬时反复执行的定时任务。这种状况下,若是加上分布式定时任务框架,如Elastic-Job这种,显然就很重了,因此这是一个极轻量级的方式。这种方式显然很难支持做业分片、失效转移、从新触发执行以及执行过程当中服务挂掉以后的从新执行。因此使用这种方式要慎重,若是系统存在后续定时任务大规模扩展、定时任务须要分片或者有瞬时反复执行的定时任务等状况,则这种简单的方式就不适用了。框架

原理其实很简单,各个微服务系统同时向redis申请加锁,因为redis是单线程的,因此只能有一个加锁成功,而后后面的所有得不到锁。获得锁的执行定时任务,得不到的,就放弃执行定时任务。分布式

为啥要用lua脚本呢?由于好用啊,亲,操做的原子性能获得保证。ide

小demo:微服务

@Test
public void testgg(){
   try{
      jedisCluster.del("schedule:lock:sss");
      String dateStr = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
      for (int i=0;i<30;i++){
         Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
               //lua脚本
               String luaScript = "local vals = redis.call('setnx', KEYS[1],'lock') if  vals > 0 then redis.call('expire',KEYS[1], 1) end  if  vals > 0  then return 1 end return 0";
               //执行lua脚本
               Object lockVal = jedisOperationUtils.executeLuaScript(luaScript,1, "schedule:lock:sss");
               System.out.println(lockVal.toString()+"  "+Thread.currentThread().getName());
               if(lockVal!=null && Integer.valueOf(lockVal.toString())>0){
                  //获得锁,执行定时任务的内容
               }
            }
         });
         thread.start();
         Thread.currentThread().sleep(100);
      }
      try{
         Thread.currentThread().sleep(10000);
      }catch (Exception e){
         System.out.println("ooooooooooooooooooooooooooooo");
         e.printStackTrace();
      }
   }catch (Exception e){
      System.out.println("IIIIIIIIIIIIIII");
      e.printStackTrace();
   }
}

这个例子就大概表达了整个思路的意思。其实至关简单。性能

里面的lua

jedisOperationUtils.executeLuaScript(......)

方法是封装的,我不须要ARGV[],因此就没封装进去。线程

/**
 * lua脚本执行
 * @param luaScript
 * @param keyCount
 * @param keys
 * @return
 */
public Object executeLuaScript(String luaScript,int keyCount,String ... keys){
   Object object = null;
   try{
      object = jedisCluster.eval(luaScript,keyCount,keys);
      if(object == null){
         return null;
      }
   }catch(Exception e){
      log.error("执行redislua脚本失败",e);
      return null;
   }
   return object;
}

OVERorm

相关文章
相关标签/搜索