分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业分片

elastic-job分片介绍 分片 ElasticJob 中任务分片项的概念,使得任务可以在分布式的环境下运行,每台任务服务器只运行分配给该服务器的分片。 随着服务器的增加或宕机,ElasticJob 会近乎实时的感知服务器数量的变更,从而重新为分布式的任务服务器分配更加合理的任务分片项,使得任务可以随着资源的增加而提升效率。 任务的分布式执行,需要将一个任务拆分为多个独立的任务项,然后由分布式的服务器分别执行某一个或几个分片项。 举例说明,如果作业分为 4 片,用两台服务器执行,则每个服务器分到 2 片,分别负责作业的 50% 的负载 阅读详情

摘要: 原创出处 http://www.iocoder.cn/Elastic-Job/job-sharding/ 「芋道源码」欢迎转载,保留摘要,谢谢!

本文基于 Elastic-Job V2.1.5 版本分享


������关注微信公众号:【芋道源码】有福利:
1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
4. 新的源码解析文章实时收到通知。每周更新一篇左右。

> 5. 认真的源码交流微信群。

1. 概述

本文主要分享 Elastic-Job-Lite 作业分片。

涉及到主要类的类图如下( 打开大图 ):

  • 粉色的类在 com.dangdang.ddframe.job.lite.internal.sharding 包下,实现了 Elastic-Job-Lite 作业分片。
  • ShardingService,作业分片服务。
  • ShardingNode,作业分片数据存储路径。
  • ShardingListenerManager,作业分片监听管理器。

你行好事会因为得到赞赏而愉悦
同理,开源项目贡献者会因为 Star 而更加有动力
为 Elastic-Job 点赞!传送门

2. 作业分片条件

当作业满足分片条件时,不会立即进行作业分片分配,而是设置需要重新进行分片的标记,等到作业分片获取时,判断有该标记后执行作业分配。

设置需要重新进行分片的标记的代码如下:

// ShardingService.java
/**
* 设置需要重新分片的标记.
*/
public void setReshardingFlag() {
   jobNodeStorage.createJobNodeIfNeeded(ShardingNode.NECESSARY);
}

// JobNodeStorage.java
/**
* 如果存在则创建作业节点.
* 如果作业根节点不存在表示作业已经停止, 不再继续创建节点.
* 
* @param node 作业节点名称
*/
public void createJobNodeIfNeeded(final String node) {
   if (isJobRootNodeExisted() && !isJobNodeExisted(node)) {
       regCenter.persist(jobNodePath.getFullPath(node), "");
   }
}
  • 调用 #setReshardingFlag() 方法设置需要重新分片的标记 /${JOB_NAME}/leader/sharding/necessary。该 Zookeeper 数据节点是永久节点,存储空串( "" ),使用 zkClient 查看如下:

    [zk: localhost:2181(CONNECTED) 2] ls /elastic-job-example-lite-java/javaSimpleJob/leader/sharding
    [necessary]
    [zk: localhost:2181(CONNECTED) 3] get /elastic-job-example-lite-java/javaSimpleJob/leader/sharding/necessary
     
  • 设置标记之后,通过调用 #isNeedSharding() 方法即可判断是否需要重新分片。

    // ShardingService.java
    /**
    * 判断是否需要重分片.
    * 
    * @return 是否需要重分片
    */
    public boolean isNeedSharding() {
       return jobNodeStorage.isJobNodeExisted(ShardingNode.NECESSARY);
    }
    
    // JobNodeStorage.java
    /**
    * 判断作业节点是否存在.
    * 
    * @param node 作业节点名称
    * @return 作业节点是否存在
    */
    public boolean isJobNodeExisted(final String node) {
       return regCenter.isExisted(jobNodePath.getFullPath(node));
    }

设置需要重新进行分片有 4 种情况

第一种,注册作业启动信息时。

// SchedulerFacade.java
public void registerStartUpInfo(final boolean enabled) {
   // ... 省略无关代码
   // 设置 需要重新分片的标记
   shardingService.setReshardingFlag();
  // ... 省略无关代码
}

第二种,作业分片总数( JobCoreConfiguration.shardingTotalCount )变化时。

// ShardingTotalCountChangedJobListener.java
class ShardingTotalCountChangedJobListener extends AbstractJobListener {

   @Override
   protected void dataChanged(final String path, final Type eventType, final String data) {
       if (configNode.isConfigPath(path)
               && 0 != JobRegistry.getInstance().getCurrentShardingTotalCount(jobName)) {
           int newShardingTotalCount = LiteJobConfigurationGsonFactory.fromJson(data).getTypeConfig().getCoreConfig().getShardingTotalCount();
           if (newShardingTotalCount != JobRegistry.getInstance().getCurrentShardingTotalCount(jobName)) { // 作业分片总数变化
               // 设置需要重新分片的标记
               shardingService.setReshardingFlag();
               // 设置当前分片总数
               JobRegistry.getInstance().setCurrentShardingTotalCount(jobName, newShardingTotalCount);
           }
       }
   }
}

第三种,服务器变化时。

// ShardingListenerManager.java
class ListenServersChangedJobListener extends AbstractJobListener {

   @Override
   protected void dataChanged(final String path, final Type eventType, final String data) {
       if (!JobRegistry.getInstance().isShutdown(jobName)
               && (isInstanceChange(eventType, path)
                   || isServerChange(path))) {
           shardingService.setReshardingFlag();
       }
   }

   private boolean isInstanceChange(final Type eventType, final String path) {
       return instanceNode.isInstancePath(path) && Type.NODE_UPDATED != eventType;
   }

   private boolean isServerChange(final String path) {
       return serverNode.isServerPath(path);
   }
}
  • 服务器变化有两种情况。
  • 第一种,#isServerChange(...) 服务器被开启或禁用。
  • 第二种,#isInstanceChange(...) 作业节点新增或者移除。

第四种,在《Elastic-Job-Lite 源码解析 —— 自诊断修复》详细分享。

3. 分配作业分片项

调用 ShardingService#shardingIfNecessary() 方法,如果需要分片且当前节点为主节点, 则作业分片。

总体流程如下顺序图:( 打开大图 ):

实现代码如下:

// ShardingService.java
/**
* 如果需要分片且当前节点为主节点, 则作业分片.
* 
* 如果当前无可用节点则不分片.
*/
public void shardingIfNecessary() {
   List availableJobInstances = instanceService.getAvailableJobInstances();
   if (!isNeedSharding() // 判断是否需要重新分片
           || availableJobInstances.isEmpty()) {
       return;
   }
   // 【非主节点】等待 作业分片项分配完成
   if (!leaderService.isLeaderUntilBlock()) { // 判断是否为【主节点】
       blockUntilShardingCompleted();
       return;
   }
   // 【主节点】作业分片项分配
   // 等待 作业未在运行中状态
   waitingOtherJobCompleted();
   //
   LiteJobConfiguration liteJobConfig = configService.load(false);
   int shardingTotalCount = liteJobConfig.getTypeConfig().getCoreConfig().getShardingTotalCount();
   // 设置 作业正在重分片的标记
   log.debug("Job '{}' sharding begin.", jobName);
   jobNodeStorage.fillEphemeralJobNode(ShardingNode.PROCESSING, "");
   // 重置 作业分片项信息
   resetShardingInfo(shardingTotalCount);
   // 【事务中】设置 作业分片项信息
   JobShardingStrategy jobShardingStrategy = JobShardingStrategyFactory.getStrategy(liteJobConfig.getJobShardingStrategyClass());
   jobNodeStorage.executeInTransaction(new PersistShardingInfoTransactionExecutionCallback(jobShardingStrategy.sharding(availableJobInstances, jobName, shardingTotalCount)));
   log.debug("Job '{}' sharding complete.", jobName);
}
  • 调用 #isNeedSharding() 方法判断是否需要重新分片。
  • 调用 LeaderService#isLeaderUntilBlock() 方法判断是否为主节点。作业分片项的分配过程:
  • 调用 #blockUntilShardingCompleted() 方法【非主节点】等待作业分片项分配完成。

    private void blockUntilShardingCompleted() {
       while (!leaderService.isLeaderUntilBlock() // 当前作业节点不为【主节点】
               && (jobNodeStorage.isJobNodeExisted(ShardingNode.NECESSARY) // 存在作业需要重分片的标记
                   || jobNodeStorage.isJobNodeExisted(ShardingNode.PROCESSING))) { // 存在作业正在重分片的标记
           log.debug("Job '{}' sleep short time until sharding completed.", jobName);
           BlockUtils.waitingShortTime();
       }
    }
    • 调用 #LeaderService#isLeaderUntilBlock() 方法判断是否为主节点。为什么上面判断了一次,这里又判断一次?主节点作业分片项分配过程中,不排除自己挂掉了,此时【非主节点】若选举成主节点,无需继续等待,当然也不能等待,因为已经没节点在执行作业分片项分配,所有节点都会卡在这里。
    • 当 作业需要重分片的标记、作业正在重分片的标记 都不存在时,意味着作业分片项分配已经完成,下文 PersistShardingInfoTransactionExecutionCallback 类里我们会看到。
  • 调用 #waitingOtherJobCompleted() 方法等待作业未在运行中状态。作业是否在运行中需要 LiteJobConfiguration.monitorExecution = true,《Elastic-Job-Lite 源码分析 —— 作业执行》「4.6 执行普通触发的作业」有详细分享。

  • 调用 ConfigurationService#load(...) 方法从注册中心获取作业配置( 非缓存 ),避免主节点本地作业配置可能非最新的,主要目的是获得作业分片总数( shardingTotalCount )。
  • 调用 jobNodeStorage.fillEphemeralJobNode(ShardingNode.PROCESSING, "") 设置作业正在重分片的标记 /${JOB_NAME}/leader/sharding/processing。该 Zookeeper 数据节点是临时节点,存储空串( "" ),仅用于标记作业正在重分片,无特别业务逻辑。
  • 调用 #resetShardingInfo(...) 方法重置作业分片信息。

    private void resetShardingInfo(final int shardingTotalCount) {
      // 重置 有效的作业分片项
      for (int i = 0; i < shardingTotalCount; i++) {
          jobNodeStorage.removeJobNodeIfExisted(ShardingNode.getInstanceNode(i)); // 移除 `/${JOB_NAME}/sharding/${ITEM_ID}/instance`
          jobNodeStorage.createJobNodeIfNeeded(ShardingNode.ROOT + "/" + i); // 创建 `/${JOB_NAME}/sharding/${ITEM_ID}`
      }
      // 移除 多余的作业分片项
      int actualShardingTotalCount = jobNodeStorage.getJobNodeChildrenKeys(ShardingNode.ROOT).size();
      if (actualShardingTotalCount > shardingTotalCount) {
          for (int i = shardingTotalCount; i < actualShardingTotalCount; i++) {
              jobNodeStorage.removeJobNodeIfExisted(ShardingNode.ROOT + "/" + i); // 移除 `/${JOB_NAME}/sharding/${ITEM_ID}`
          }
      }
    }
  • 调用 JobShardingStrategy#sharding(...) 方法计算每个节点分配的作业分片项。《Elastic-Job-Lite 源码分析 —— 作业分片策略》有详细分享。

  • 调用 JobNodeStorage#executeInTransaction(...) + PersistShardingInfoTransactionExecutionCallback#execute() 方法实现在事务中设置每个节点分配的作业分片项。

    // PersistShardingInfoTransactionExecutionCallback.java
    class PersistShardingInfoTransactionExecutionCallback implements TransactionExecutionCallback {
    
       /**
        * 作业分片项分配结果
        * key:作业节点
        * value:作业分片项
        */
       private final Map> shardingResults;
    
       @Override
       public void execute(final CuratorTransactionFinal curatorTransactionFinal) throws Exception {
           // 设置 每个节点分配的作业分片项
           for (Map.Entry> entry : shardingResults.entrySet()) {
               for (int shardingItem : entry.getValue()) {
                   curatorTransactionFinal.create().forPath(jobNodePath.getFullPath(ShardingNode.getInstanceNode(shardingItem))
                           , entry.getKey().getJobInstanceId().getBytes()).and();
               }
           }
           // 移除 作业需要重分片的标记、作业正在重分片的标记
           curatorTransactionFinal.delete().forPath(jobNodePath.getFullPath(ShardingNode.NECESSARY)).and();
           curatorTransactionFinal.delete().forPath(jobNodePath.getFullPath(ShardingNode.PROCESSING)).and();
       }
    }
    
    // JobNodeStorage.java
    /**
    * 在事务中执行操作.
    * 
    * @param callback 执行操作的回调
    */
    public void executeInTransaction(final TransactionExecutionCallback callback) {
       try {
           CuratorTransactionFinal curatorTransactionFinal = getClient().inTransaction().check().forPath("/").and();
           callback.execute(curatorTransactionFinal);
           curatorTransactionFinal.commit();
       } catch (final Exception ex) {
           RegExceptionHandler.handleException(ex);
       }
    }
    • 设置临时数据节点 /${JOB_NAME}/sharding/${ITEM_ID}/instance 为分配的作业节点的作业实例主键( jobInstanceId )。使用 zkClient 查看如下:
    [zk: localhost:2181(CONNECTED) 0] get /elastic-job-example-lite-java/javaSimpleJob/sharding/0/instance
    192.168.3.2@-@31492

作业分片项分配整体流程有点长,耐着心看,毕竟是核心代码哟。如果中间有任何疑问,欢迎给我公众号:芋道源码 留言。

4. 获取作业分片上下文集合

在《Elastic-Job-Lite 源码分析 —— 作业执行的》「4.2 获取当前作业服务器的分片上下文」中,我们可以看到作业执行器( AbstractElasticJobExecutor ) 执行作业时,会获取当前作业服务器的分片上下文进行执行。获取过程总体如下顺序图( 打开大图 ):

实现代码如下:

// LiteJobFacade.java
@Override
public ShardingContexts getShardingContexts() {
   // 【忽略,作业失效转移详解】获得 失效转移的作业分片项
   boolean isFailover = configService.load(true).isFailover();
   if (isFailover) {
       List failoverShardingItems = failoverService.getLocalFailoverItems();
       if (!failoverShardingItems.isEmpty()) {
           return executionContextService.getJobShardingContext(failoverShardingItems);
       }
   }
   // 作业分片,如果需要分片且当前节点为主节点
   shardingService.shardingIfNecessary();
   // 获得 分配在本机的作业分片项
   List shardingItems = shardingService.getLocalShardingItems();
   // 【忽略,作业失效转移详解】移除 分配在本机的失效转移的作业分片项目
   if (isFailover) {
       shardingItems.removeAll(failoverService.getLocalTakeOffItems());
   }
   // 移除 被禁用的作业分片项
   shardingItems.removeAll(executionService.getDisabledItems(shardingItems));
   // 获取当前作业服务器分片上下文
   return executionContextService.getJobShardingContext(shardingItems);
}
  • 调用 ShardingService#shardingIfNecessary() 方法,如果需要分片且当前节点为主节点,作业分片项分配。不是每次都需要作业分片,必须满足「2. 作业分片条件」才执行作业分片。
  • 调用 ShardingService#getLocalShardingItems()方法,获得分配在本机的作业分片项,即 /${JOB_NAME}/sharding/${ITEM_ID}/instance 为本机的作业分片项。

    // ShardingService.java
    /**
    * 获取运行在本作业实例的分片项集合.
    * 
    * @return 运行在本作业实例的分片项集合
    */
    public List getLocalShardingItems() {
       if (JobRegistry.getInstance().isShutdown(jobName) || !serverService.isAvailableServer(JobRegistry.getInstance().getJobInstance(jobName).getIp())) {
           return Collections.emptyList();
       }
       return getShardingItems(JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId());
    }
    
    /**
    * 获取作业运行实例的分片项集合.
    *
    * @param jobInstanceId 作业运行实例主键
    * @return 作业运行实例的分片项集合
    */
    public List getShardingItems(final String jobInstanceId) {
       JobInstance jobInstance = new JobInstance(jobInstanceId);
       if (!serverService.isAvailableServer(jobInstance.getIp())) {
           return Collections.emptyList();
       }
       List result = new LinkedList<>();
       int shardingTotalCount = configService.load(true).getTypeConfig().getCoreConfig().getShardingTotalCount();
       for (int i = 0; i < shardingTotalCount; i++) {
           // `/${JOB_NAME}/sharding/${ITEM_ID}/instance`
           if (jobInstance.getJobInstanceId().equals(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(i)))) {
               result.add(i);
           }
       }
       return result;
    }
  • 调用 shardingItems.removeAll(executionService.getDisabledItems(shardingItems)),移除被禁用的作业分片项,即 /${JOB_NAME}/sharding/${ITEM_ID}/disabled 存在的作业分片项。

    // ExecutionService.java
    /**
    * 获取禁用的任务分片项.
    *
    * @param items 需要获取禁用的任务分片项
    * @return 禁用的任务分片项
    */
    public List getDisabledItems(final List items) {
       List result = new ArrayList<>(items.size());
       for (int each : items) {
           // /${JOB_NAME}/sharding/${ITEM_ID}/disabled
           if (jobNodeStorage.isJobNodeExisted(ShardingNode.getDisabledNode(each))) {
               result.add(each);
           }
       }
       return result;
    }
  • 调用 ExecutionContextService#getJobShardingContext(...) 方法,获取当前作业服务器分片上下文。

获取当前作业服务器分片上下文

调用 ExecutionContextService#getJobShardingContext(...) 方法,获取当前作业服务器分片上下文:

// ExecutionContextService.java
public ShardingContexts getJobShardingContext(final List shardingItems) {
   LiteJobConfiguration liteJobConfig = configService.load(false);
   // 移除 正在运行中的作业分片项
   removeRunningIfMonitorExecution(liteJobConfig.isMonitorExecution(), shardingItems);
   //
   if (shardingItems.isEmpty()) {
       return new ShardingContexts(buildTaskId(liteJobConfig, shardingItems), liteJobConfig.getJobName(), liteJobConfig.getTypeConfig().getCoreConfig().getShardingTotalCount(), 
               liteJobConfig.getTypeConfig().getCoreConfig().getJobParameter(), Collections.emptyMap());
   }
   // 解析分片参数
   Map shardingItemParameterMap = new ShardingItemParameters(liteJobConfig.getTypeConfig().getCoreConfig().getShardingItemParameters()).getMap();
   // 创建 分片上下文集合
   return new ShardingContexts(buildTaskId(liteJobConfig, shardingItems), //
           liteJobConfig.getJobName(), liteJobConfig.getTypeConfig().getCoreConfig().getShardingTotalCount(),
           liteJobConfig.getTypeConfig().getCoreConfig().getJobParameter(),
           getAssignedShardingItemParameterMap(shardingItems, shardingItemParameterMap)); // 获得当前作业节点的分片参数
}
  • 调用 #removeRunningIfMonitorExecution() 方法,移除正在运行中的作业分片项。

    private void removeRunningIfMonitorExecution(final boolean monitorExecution, final List shardingItems) {
       if (!monitorExecution) {
           return;
       }
       List runningShardingItems = new ArrayList<>(shardingItems.size());
       for (int each : shardingItems) {
           if (isRunning(each)) {
               runningShardingItems.add(each); // /${JOB_NAME}/sharding/${ITEM_ID}/running
           }
       }
       shardingItems.removeAll(runningShardingItems);
    }
    
    private boolean isRunning(final int shardingItem) {
       return jobNodeStorage.isJobNodeExisted(ShardingNode.getRunningNode(shardingItem));
    }
  • 使用 ShardingItemParameters 解析作业分片参数。例如作业分片参数( JobCoreConfiguration.shardingItemParameters="0=Beijing,1=Shanghai,2=Guangzhou" ) 解析结果:

    • ShardingItemParameters 代码清晰易懂,点击链接直接查看。
  • 调用 #buildTaskId(...) 方法,创建作业任务ID( ShardingContexts.taskId ):

    private String buildTaskId(final LiteJobConfiguration liteJobConfig, final List shardingItems) {
       JobInstance jobInstance = JobRegistry.getInstance().getJobInstance(jobName);
       return Joiner.on("@-@").join(liteJobConfig.getJobName(), Joiner.on(",").join(shardingItems), "READY", 
               null == jobInstance.getJobInstanceId() ? "127.0.0.1@-@1" : jobInstance.getJobInstanceId()); 
    }
    • taskId = ${JOB_NAME} + @-@ + ${SHARDING_ITEMS} + @-@ + READY + @-@ + ${IP} + @-@ + ${PID}。例如:javaSimpleJob@-@0,1,2@-@READY@-@192.168.3.2@-@38330。
  • 调用 #getAssignedShardingItemParameterMap(...) 方法,获得当前作业节点的分片参数。

    private Map getAssignedShardingItemParameterMap(final List shardingItems, final Map shardingItemParameterMap) {
       Map result = new HashMap<>(shardingItemParameterMap.size(), 1);
       for (int each : shardingItems) {
           result.put(each, shardingItemParameterMap.get(each));
       }
       return result;
    }
  • ShardingContexts,分片上下文集合。

    public final class ShardingContexts implements Serializable {
    
        private static final long serialVersionUID = -4585977349142082152L;
    
        /**
         * 作业任务ID.
         */
        private final String taskId;
        /**
         * 作业名称.
         */
        private final String jobName;
        /**
         * 分片总数.
         */
        private final int shardingTotalCount;
        /**
         * 作业自定义参数.
         * 可以配置多个相同的作业, 但是用不同的参数作为不同的调度实例.
         */
        private final String jobParameter;
        /**
         * 分配于本作业实例的分片项和参数的Map.
         */
        private final Map shardingItemParameters;
        /**
         * 作业事件采样统计数.
         */
        private int jobEventSamplingCount;
        /**
         * 当前作业事件采样统计数.
         */
        @Setter
        private int currentJobEventSamplingCount;
        /**
         * 是否允许可以发送作业事件.
         */
        @Setter
        private boolean allowSendJobEvent = true;
    }
    • jobEventSamplingCount,currentJobEventSamplingCount 在 Elastic-Job-Lite 暂未还使用,在 Elastic-Job-Cloud 使用。

666. 彩蛋

旁白君:小伙伴,更新了干货嘛,双击 666。
芋道君:那必须的嘛,而且这么勤快更新!是不是应该分享一波朋友圈。

道友,赶紧上车,分享一波朋友圈!


������关注微信公众号:【芋道源码】有福利:
1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
4. 新的源码解析文章实时收到通知。每周更新一篇左右。
5. 认真的源码交流微信群。

混沌系统在图像加密中的应用(二维离散Hénon混沌映射) Hénon映射是一种二维离散时间动力系统,由美国数学家Michel Hénon在1976年引入。它是混沌动力系统中的经典模型之一,具有简单的形式和复杂的行为。 阅读详情

相关推荐

Unity2020 发布Android包,下载安装配置JDK、SDK、NDK详细教程

配置成功页面 JDK、SDK、NDK

qq_41263535的博客 1万+

Elastic-Job:Elastic-Job作业分片是什么、Elastic-Job作业分片策略及源码分析、Elastic-Job自定义分片策略、Elastic-Job作业分片配置方式

某些场景需要实现自定义的作业分片策略。// 实现逻辑 } }实现后,配置实现类的全路径到 Lite作业配置( LiteJobConfiguration )的 jobShardingStrategyClass 属性。

郝开的博客 2926

详解如何用爬虫工具批量采集阿里巴巴批发网商品数据

本文主要介绍如何使用后羿采集器的智能模式,免费采集阿里巴巴批发网商品的批发价格、发货时间、是否代发等信息。 采集字段: 商品标题、商品链接、图片链接、标签1、标签2、标签3、价格、30天成交数、 评价、店铺 功能点目录: 如何对采集字段进行配置 如何采集列表+详情页类型网页 采集结果预览: 下面我们来详细介绍一下如何免费采集1688批发网的商品数据,我们以“羽绒服女”为例,具体步骤如下: 步骤一...

weixin_43777427的博客 1万+

Elastic-Job原理

概述Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。 Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务。 功能列表分布式调度协调弹性扩容缩容失效转移错过执行作业重触发作业分片一致性,保证同一分片在分布式环境中仅一个执行实例自诊断并修复...

weixin_30929011的博客 411

430单片机实现三人投票表决器_基于单片机的五人表决器的设计

姚海云+马野摘要:本设计利用51单片机,按键开关模块,数码管显示模块和LED模块来实现一个简单的五人表决器的功能。按键开关模块中的键2~键6表示五个人,由5个人来投票,当同意的票数大于或者等于3人时,数码管显示同意的人数,说明表决通过。当表决的人数小于3时,数码管显示同意的人数。关键词:表决器;单片机;流水灯;数码管;矩阵键盘;时钟中图分类号:TP391 文献标识码:A 文章编号:1009-304...

weixin_33277215的博客 2559

防止通达信公式被盗?手把手教你用DLL加密+互联网验证(含易语言后台管理)

本文详细介绍了如何通过DLL加密与互联网验证技术保护通达信公式安全。从DLL加密实现、设备绑定到易语言后台管理,提供了一套完整的防护方案,有效防止公式被盗用。重点讲解了互联网验证登录和绑定设备等核心技术,帮助量化交易者守护核心资产。

weixin_29323551的博客 503

elastic-job 实现的分片案例5

作业分片是指例如:Elastic-Job快速入门中文件备份的例子,现有2台服务器,每台服务器分别跑一个应用实例。为了快速的执行作业,那么可以将作业分成4片,每个应用实例个执行2片。可以看到,通过对任务合理的分片化,从而达到任务并行处理的效果,最大限度的提高执行作业的吞吐量。

健康平安的活着的专栏 1830

STM32F030C8烧录实战:用J-Link Commander实现一键批量烧写(附完整脚本)

本文详细介绍了如何使用J-Link Commander工具链实现STM32F030C8的一键批量烧录,包括环境配置、批处理脚本设计、命令脚本解析以及生产环境实战技巧。通过自动化烧录流程,显著提升效率并降低人为错误,特别适合量产和频繁迭代的开发场景。

weixin_30505225的博客 462

elastic-job详解(一):数据分片

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

weixin_34306676的博客 900

Amber实战:小分子配体MD模拟全流程避坑指南(附磷酸基团处理技巧)

本文提供了一份基于Amber软件进行小分子配体分子动力学模拟的实战避坑指南。详细解析了从晶体结构预处理、配体参数化(重点探讨AM1-BCC与RESP电荷选择)、复合物体系构建到模拟稳定性调试的全流程。特别针对磷酸基团等特殊官能团处理中常见的模拟崩溃问题,给出了系统性的诊断与解决方案,旨在帮助研究者获得稳定可靠的模拟结果。

weixin_29237635的博客 682

人形机器人电源系统硬件开发:从原理图设计到PCB布局的完整流程

人形机器人是“移动的智能终端”,其电源系统如同“心脏+血管”:既要为大脑(主控)、肌肉(电机)、感官(传感器)提供稳定能量,又要在有限体积内应对高动态负载(如跳跃时电机瞬间大电流)。本文聚焦“硬件开发”维度,覆盖从需求分析到PCB制板的完整流程,适合硬件工程师、机器人爱好者快速掌握工程实战方法。

AI天才研究院 2177

分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业分片策略

点击上方“芋道源码”,选择“置顶公众号”技术文章第一时间送达!源码精品专栏 精尽 Dubbo 原理与源码 69 篇精尽 Netty 原理与源码 61 篇中文详细注释的开源...

芋道源码 456

Quartus II编译时出现Error (119013): Current license file does not support the EP4CE6E22C6 device

Quartus II编译时出现Error (119013): Current license file does not support the EP4CE6E22C6 device, Quartus的安装过程不同于ISE/vivado的安装。“Current license file does not support”这种情况多出现在高版本的quartus中综合很久以前的代码,使用很早型号的FPGA或是CPLD。对于这种情况,就得在官网或是其他网站上下载包含所需Device的库文件。

夜半少年的博客 1万+

分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业失效转移

点击上方“芋道源码”,选择“置顶公众号”技术文章第一时间送达!源码精品专栏 精尽 Dubbo 原理与源码 69 篇精尽 Netty 原理与源码 61 篇中文详细注释的开源...

芋道源码 590

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业数据存储

点击上方“芋道源码”,选择“置顶公众号”技术文章第一时间送达!源码精品专栏 精尽 Dubbo 原理与源码 69 篇精尽 Netty 原理与源码 61 篇中文详细注释的开源...

芋道源码 410

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业执行

点击上方“芋道源码”,选择“置顶公众号”技术文章第一时间送达!源码精品专栏 精尽 Dubbo 原理与源码专栏( 已经完成 69+ 篇,预计总共 75+ 篇 )中文详细注释...

芋道源码 430

贝叶斯统计 [韦来生编]

贝叶斯(Bayes)统计是近几十年来迅速发展起来的数理统计的一个重要分支。贝叶斯方法与经典统计方法的主要不同之处是进行统计推断时除了利用样本信息外,还要利用参数的先验信息,因此可以提高统计推断或统计决策的效果。它在经济、金融、生物、医学、自然科学和社会科学等许多领域具有广泛的应用。贝叶斯方法的研究已渗透到了统计学的几乎所有领域。作者在给中国科学技术大学概率论与数理统计专业本科生开设的“数理统计”课程中有一章专门讲授“贝叶斯方法和统计决策理论”,近十年来也给中国科学技术大学概率统计专业研究生开设过几次“贝叶斯分析”课。本书是在对过去讲稿的内容作了适当的增减和调整的基础上完成的。  本书共分六章。第1章是绪论,介绍了贝叶斯统计的若干基本概念,同时对必要的数理统计的基础知识有重点地作了回顾。第二章介绍了确定先验分布的若干可供选择的方法。第三章介绍了几类常见统计模型参数的后验分布的主要结果和计算方法。第四章和第五章分别介绍了“贝叶斯统计推断”和“贝叶斯统计决策”的内容。第六章介绍了贝叶斯统计计算的若干方法,包括蒙特卡洛方法和马尔可夫链蒙特卡洛(MCMC)方法以及相关统计软件的简介。本书的每一章附右大量的例题和习题,书末附有常用的几个表格和部分习题解答供读者查用。  大约可在54学时内讲授本书的第1章至第六章的主要内容,教师可根据学时需要选讲本书第1章至第六章的部分内容。书中标“*”号的章节可略去不讲,留给读者作为阅读材料。第六章例题中的R代码和部分例题的数据文件等可从作者个人主页下载。  作者在编写本书的过程中参考了J.O.Berger教授的《统计决策论及贝叶斯分析》和茆诗松教授编写的《贝叶斯统计》等书中的一些内容,以及《贝叶斯分析》一书中由张伟平博士编写的有关贝叶斯统计计算的一些内容。在此表示衷心感谢。  本书编写准备过程中,中国科学技术大学统计与金融系的几个研究生帮助完成了本书部分中文的录入和排版,作者对他们的辛勤工作表示真诚的感谢。高等教育出版社为本书的出版给予了大力支持。在此一并致谢。

分布式作业系统 Elastic-Job-Lite 源码分析 —— 自诊断修复

点击上方“芋道源码”,选择“置顶公众号”技术文章第一时间送达!源码精品专栏 精尽 Dubbo 原理与源码 69 篇精尽 Netty 原理与源码 61 篇中文详细注释的开源...

芋道源码 520

分布式作业系统 Elastic-Job-Lite 源码分析 —— 运维平台

点击上方“芋道源码”,选择“置顶公众号”技术文章第一时间送达!源码精品专栏精尽 Dubbo 原理与源码69 篇精尽 Netty 原理与源码61 篇中文详细注释的开源项目Java 并...

芋艿V 325

分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业监听器

点击上方“芋道源码”,选择“置顶公众号”技术文章第一时间送达!源码精品专栏 精尽 Dubbo 原理与源码 69 篇精尽 Netty 原理与源码 61 篇中文详细注释的开源...

芋道源码 501
上一篇: 【Netty 专栏】Netty源码分析之服务启动
下一篇: 沉思录:一个堕落上进者的自我救赎
公众号-芋道源码
博客等级 码龄10年 1635粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值