2019独角兽企业重金招聘Python工程师标准>>>

在项目开发中,会经常使用的到定时任务。一般对与定时任务根据需求的不同、程序员的编码习惯,通常会有2种部署方式:

  1. 使用统一的任务调度系统进行管理。在分布式环境下,通过任务调度系统使用锁机制来保证同时只有一条服务器在运行定时任务。
  2. 在项目中直接配置task执行。在单服务器的情况下,此种方式是没有问题的,当在分布式环境下,就会存在多台服务器同时出发task。此时就需要单进行特殊的设置,以保证其同时只有一个服务器在运行task。

本文以讨论第2中情况下怎么解决在分布式环境下出现的问题。讨论的解决方法如下:

  1. 分别请求rpc服务,在服务中通过锁机制,来判断获得执行task权限的服务器
  2. 通过zk创建节点是否成功来进行判断
  3. 通过redis的Hsetnx 、Setnx的特性进行判断。

假设有同一个Task不是在3台服务器中,分别是A、B、C,远程服务S

RPC服务

描述:A、B、C三台服务器在执行task时同时请求远程服务S,在S中,通过一定的机制判定某台服务器具有执行task的权限,其他几台服务器则不具备。

在S服务中,判断机制特性为:先请求的具有执行权限。A\B\C请求时传输task唯一标识名,在S服务中接收到请求时,判断当前task标识是否进行记录,如已记录,则返回flase,表示不具备执行条件;反之不存在记录,对先对task标识进行存储,返回true,表示具有执行条件。在判断时,需要使用同步锁机制,保证同时只有一个请求在处于判断条件中。在请求执行完成后,再次S服务的刷新方法,释放已选择标识。

Zookeeper创建节点的方式(Java举例)

描述:A\B\C三台服务器在执行task时同时通过zk客户端创建同一node,创建成功的服务器则具有执行task的权限,否则不具备。

zk的判断机制为:zk客户端在创建节点时,会判断节点是否存在,如不存在则创建,反之出现异常。因此在执行task时,同时创建节点成功,则具有执行权限。伪代码如下:

/*** 使用zk在分布式部署情况下确保并发情况中只有一台服务在执行* 利用zk的创建node机制:当节点存在,则返回异常,否则创建成功。* @author aiyungui* @create 2016-09-27-11:24**/
public class ZkDistributedUtil {private CuratorFramework client;private String defaultName = "ink";private boolean isExecute = true;public ZkDistributedUtil(String connectStr){this(connectStr,null);}/*** 初始化zk* @param connectStr* @param namespace*/public ZkDistributedUtil(String connectStr,String namespace){if (StringUtils.isBlank(namespace)){namespace = defaultName;}CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder();client = builder.connectString(connectStr).sessionTimeoutMs(30000).connectionTimeoutMs(30000).canBeReadOnly(true).namespace(namespace).retryPolicy(new ExponentialBackoffRetry(1000, Integer.MAX_VALUE)).defaultData(null).build();client.start();}/*** 创建节点* @param nodePath* @throws Exception*/public void createNode(String nodePath) throws Exception {client.create().creatingParentsIfNeeded().forPath(nodePath);}/*** 删除节点* @param nodePath* @throws Exception*/public void deleteNode(String nodePath) throws Exception {client.delete().forPath(nodePath);}public static void main(String args[]){//调用示例try {ZkDistributedUtil watcherService = new ZkDistributedUtil("10.1.5.217:2181");watcherService.createNode("/timer/node");System.out.println("execute module ....");watcherService.deleteNode("/timer/node");} catch (Exception e) {System.out.println("创建节点失败");}}
}

redis判断方式

描述:A\B\C三台服务器在执行task时同时请求远程服务器S,在S中,通过redis的Hsetnx、setnx命令的特性,返回1则具有执行task的权限,否则不具备

redis的判断机制特性:redis的Hsetnx、setnx命令会在执行时判断是否存在对应的key,如存在则返回0,不存在则创建key,并进行赋值操作,返回1。此时可根据返回值为1或0来判定是否具有执行权限。伪代码如下:

/***使用Redis在分布式部署情况下确保并发情况中只有一台服务在执行*利用redis的hsetnx命令特性:当key存在则返回0,反之创建成功并返回1* @author aiyungui* @create 2016-09-27-10:44**/
public class RedisDistributedUtil {private JedisPool jedisPool;/*** 初始化redis pool*/public void init(){if (jedisPool == null)jedisPool = (JedisPool) SpringApplicationContext.getBean("jedisPool");}/***是否获取执行权限 true为是,false为否* @param key* @param fieldId* @param value* @return*/public boolean isCanExecute(String key,String fieldId,String value){boolean isExecute = true;Jedis jedis = null;try{if (jedisPool == null){init();}jedis = jedisPool.getResource();value = value==null?"1":value;Long result = jedis.hsetnx(key,fieldId,value);if (result == 0){isExecute = false;}}catch (Exception e){e.printStackTrace();}finally {if (jedis != null){jedis.close();}}return isExecute;}/*** 释放锁定的key信息* @param key* @param fieldId*/public void refreshKey(String key,String fieldId){Jedis jedis = null;try{if (jedisPool == null){init();}jedis = jedisPool.getResource();jedis.hdel(key,fieldId);}catch (Exception e){e.printStackTrace();}finally {if (jedis != null){jedis.close();}}}public static void main(String args[]){RedisDistributedUtil distributedUtil = new RedisDistributedUtil();boolean result = distributedUtil.isCanExecute("task","ink.test","1");if (result) {System.out.println("execute module ....");distributedUtil.refreshKey("task","ink.test");}}
}

上述3种方式能保证在分布式部署的环境下同时只有一台服务器具有task执行权限。但task的执行又主要分为一些两种:

  1. 每隔多长时间执行
  2. 在某个时间点执行

对于2,则上述方式能完全满足,对于1,则会因服务器启动时间的不同,出现在不同的时间点执行task,此时需要根据业务再进行区分,如A\B\C服务执行的task是否在不同时间执行都对业务数据的操作是否具有冥等性。如果具有冥等性,则不受影响。否则需要根据业务进行特殊处理。处理方式可有:

  • 在获得task执行权限的服务器在task任务执行完成后,休眠一段时间再通知zookeeper删除节点、redis删除key,RPC服务刷新,已保证task的执行是有效的
  • 对第一个获得执行task权限的服务器进行记录,下次执行依然使用该服务器,直至此服务器出现异常。出现异常后,再次选择最先获得task执行权限的服务器

转载于:https://my.oschina.net/aiyungui/blog/751882

任务调度在分布式部署环境下保证task的正确运行相关推荐

  1. WIN10环境下配置hadoop+spark并运行实例的教程

    WIN10环境下配置 hadoop + spark 并运行开发实例的教程 前期准备 基本环境配置 虚拟机的安装 配置虚拟机中的静态网络 关闭并禁用防火墙 配置主机名 编辑host文件 使用ssh传输文 ...

  2. 解析ThreadPoolExecutor类是如何保证线程池正确运行的

    摘要:对于线程池的核心类ThreadPoolExecutor来说,有哪些重要的属性和内部类为线程池的正确运行提供重要的保障呢? 本文分享自华为云社区<[高并发]通过源码深度解析ThreadPoo ...

  3. elastic-job 是如何保证分布式环境下任务只有一个实例运行

    本文适合使用过elastic-job的人,不会介绍如何使用elastic-job,因为如何使用已经有官方文档介绍了. 最近研究了几个分布式作业调度框架,最终从xxl-job elastic-job l ...

  4. spark集群环境下Lost task 0.0 in stage 10.0 (TID 17, 10.28.23.202): java.io.FileNotFoundException

    spark从当前目录加载文件报错,Lost task 0.0 in stage 10.0 (TID 17, 10.28.23.202): java.io.FileNotFoundException,明 ...

  5. Linux环境下用vim编写编译运行C/C++程序

    在Linux环境下编写编译运行C程序 首先在终端下输入命令进入编写 vim hello.c #include <stdio.h> int main() {printf("hell ...

  6. 在redhat/centos的linux环境下安装配置java web运行环境

    2019独角兽企业重金招聘Python工程师标准>>> 环境安装配置: 1.jdk的安装配置     ①下载jdk,地址 http://www.oracle.com/technetw ...

  7. 面试官:分布式环境下,如何实现session共享

    点击关注公众号,实用技术文章及时了解 先了解一下为什么会出现这种session共享的解决方案? 随着互联网公司的项目在微服务和分布式的环境下进行的搭建,导致一个项目可能分别部署在几个甚至很多的服务器集 ...

  8. Dapper--Google生产环境下的分布式跟踪系统

    Dapper--Google生产环境下的分布式跟踪系统 概述 当代的互联网的服务,通常都是用复杂的.大规模分布式集群来实现的.互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发 ...

  9. JAVA中useDrlimiter方法_今天来讲讲分布式环境下,怎么达到对象共享,以及实现原子性(atomic),以Redis中的Redisson为例(实现分布式锁、分布式限流等)...

    相信各位对redis肯定是不陌生的,一个高吞吐量的内存型结构存储数据库.可用用于很多业务场景,能够有效的解决很多复杂的并发问题,分布式问题. 下面粘一下中文官网介绍: 关于解决对象共享问题,很多方式, ...

  10. 基于Java技术的Web环境下分布式数据库互操作性的实现

                作者:李炽明 莫倩 徐明 1 JDBC工作原理 JDBC(Java Database Connectivity)是1个Sun公司注册了的商标,代表用来执行SQL语句的Java语 ...

最新文章

  1. 百度之星试题每周一练
  2. 【PAT】A1074 Reversing Linked List ***
  3. Mysql 8主从复制配置图解
  4. ctsc2009 移民站选址
  5. python做自动化控制postman_python自动化测试入门篇-postman
  6. [LeetCode]题解(python):012-Integer to Roman
  7. asp.net 安装element ui_vue入门003~vue项目引入element并创建一个登录页面
  8. 阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_15_常用的函数式接口_Predicate接口练习-集合信息的筛选...
  9. 易用性软件测试用例,软件性能测试规定——易用性测试规定
  10. C语言——(乘法口诀表)
  11. LabVIEW与Microsoft Windows的兼容性
  12. Android屏幕适配很难嘛?其实也就那么回事,吐血整理
  13. Python pip distribute
  14. 普通人学会Python到底具体能做什么呢?
  15. 基于PHP+MySQL音乐相册网站的设计与实现
  16. python文件下载
  17. GPS的相关指标的意思
  18. 信号与系统、数字信号处理、滤波、傅里叶变换、数字信号模拟信号采样信号、滤波器零阶保持器
  19. 账号共享风险大 恐泄漏用户信息
  20. (最新react-native-0.59.5) 如何将ReactNative项目集成到现有得Android项目中(两种实现方法之一)

热门文章

  1. 内层元素设置position:relative后父元素overflow:hidden overflow:scroll失效 解决方法
  2. We7从这里开始---认识we7
  3. 在.NET 对XML的一些基本操作
  4. JS取得RadioButtonList的Value,Text及选中值等信息
  5. 部分苹果 macOS Monterey 用户遇到“内存泄漏”问题,应用后台运行消耗上百 GB 内存
  6. Mac电脑上怎么添加密码提示?操作教程来啦!
  7. 最新消息:苹果M1芯片为何如此之快?
  8. 如何通过iMazing导出Safari浏览器的历史记录
  9. 基于神经网络的实体识别和关系抽取联合学习
  10. WordPress: 使用 wp_insert_attachment 上传附件