欢迎光临
我们一直在努力

【任务调度:框架】5、分片能力天花板!Elastic-Job搞定1000万级数据批处理

在这里插入图片描述

分片能力天花板!Elastic-Job搞定1000万级数据批处理

引言

当业务数据量从百万级跃升到千万级甚至亿级时,传统的单机定时任务和基于中心化调度的框架(如XXL-JOB)开始显得力不从心。面对海量数据批处理场景,如用户画像计算、日志清洗、积分兑换等,我们需要一个能够将任务弹性分片、去中心化执行的调度框架。Elastic-Job正是为解决这类问题而生。

本文将深入解析Elastic-Job的核心优势、架构原理,并通过完整的实操教程和实战案例,带您掌握如何利用Elastic-Job高效处理千万级数据。最后,我们将对比XXL-JOB,帮助您在不同场景下做出正确选型。


1. Elastic-Job核心优势:去中心化架构+弹性分片

Elastic-Job是由当当网开源的一款分布式调度解决方案,它有两个主要特性:去中心化和弹性分片。

1.1 去中心化架构

与XXL-JOB这类中心化调度框架不同,Elastic-Job没有独立的调度中心节点。每个执行器节点都是对等的,通过注册中心(ZooKeeper或ETCD)协调任务分片和状态同步。这种架构的好处是:

  • 无单点故障:任何一个节点宕机,其他节点自动接管其分片。
  • 水平扩展性极佳:增加节点只需启动新实例,注册中心自动感知并重新分片。

1.2 弹性分片

Elastic-Job的核心能力是分片。它将一个任务逻辑上划分为多个“分片项”(sharding items),每个分片项代表一部分数据或工作。执行器集群中的每个节点领取一定数量的分片项,并行执行。当节点数量变化时,Elastic-Job自动重新分配分片项,实现弹性伸缩。

分片 vs 并行执行:普通并行执行只是将任务简单复制到多个节点,每个节点执行相同逻辑,可能导致重复处理。而分片是将数据/任务切分成互斥的片段,每个节点只处理属于自己的分片,保证数据不重复不遗漏。


2. 架构原理:ZooKeeper/ETCD在分片协调中的作用

Elastic-Job依赖于ZooKeeper(或ETCD)实现分布式协调。下面我们以ZooKeeper为例,说明其核心数据结构和工作流程。

2.1 ZooKeeper数据节点结构

Elastic-Job在ZooKeeper中为每个任务创建一个命名空间,结构如下:

/your-job-namespace
├── job1
│ ├── instances
│ │ ├── instance-ip1:port
│ │ ├── instance-ip2:port
│ ├── sharding
│ │ ├── 0
│ │ │ ├── instance
│ │ │ └── status
│ │ ├── 1
│ │ │ ├── instance
│ │ │ └── status
│ │ └── …
│ ├── leader
│ │ ├── election
│ │ └── failover
│ └── config
└── job2
└── …

  • instances:记录当前所有运行中的执行器实例节点(临时节点)。
  • sharding:记录每个分片项(0,1,2…)被哪个实例持有,以及运行状态。
  • leader:用于主节点选举,处理任务分片、故障转移等控制逻辑。
  • config:存储任务的配置信息,如分片总数、cron表达式等。

2.2 工作流程

  • 实例注册:每个执行器启动时,在/instances下创建自己的临时节点,表示在线。
  • 主节点选举:所有实例竞争成为leader,leader负责分片分配。leader选举通过ZooKeeper的临时顺序节点实现,序号最小的成为leader。
  • 分片分配:leader根据当前在线实例列表和分片总数,计算每个实例应持有的分片项(默认平均分配)。分配结果写入/sharding下每个分片项的instance节点。
  • 任务执行:每个执行器监听/sharding下自己负责的分片项,当分片项被分配给自己时,开始执行对应的任务逻辑。
  • 弹性伸缩:当有实例宕机,其对应的临时节点消失,leader重新触发分片;当新实例加入,同样触发重新分片。
  • Mermaid流程图:

    Leader(Executor1)ZooKeeperExecutor2Executor1Leader(Executor1)ZooKeeperExecutor2Executor1#mermaid-svg-Za5CS685IUOZekt8{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Za5CS685IUOZekt8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Za5CS685IUOZekt8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Za5CS685IUOZekt8 .error-icon{fill:#552222;}#mermaid-svg-Za5CS685IUOZekt8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Za5CS685IUOZekt8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Za5CS685IUOZekt8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Za5CS685IUOZekt8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Za5CS685IUOZekt8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Za5CS685IUOZekt8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Za5CS685IUOZekt8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Za5CS685IUOZekt8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Za5CS685IUOZekt8 .marker.cross{stroke:#333333;}#mermaid-svg-Za5CS685IUOZekt8 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Za5CS685IUOZekt8 p{margin:0;}#mermaid-svg-Za5CS685IUOZekt8 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Za5CS685IUOZekt8 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Za5CS685IUOZekt8 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Za5CS685IUOZekt8 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Za5CS685IUOZekt8 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Za5CS685IUOZekt8 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Za5CS685IUOZekt8 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Za5CS685IUOZekt8 .sequenceNumber{fill:white;}#mermaid-svg-Za5CS685IUOZekt8 #sequencenumber{fill:#333;}#mermaid-svg-Za5CS685IUOZekt8 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Za5CS685IUOZekt8 .messageText{fill:#333;stroke:none;}#mermaid-svg-Za5CS685IUOZekt8 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Za5CS685IUOZekt8 .labelText,#mermaid-svg-Za5CS685IUOZekt8 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Za5CS685IUOZekt8 .loopText,#mermaid-svg-Za5CS685IUOZekt8 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Za5CS685IUOZekt8 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Za5CS685IUOZekt8 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Za5CS685IUOZekt8 .noteText,#mermaid-svg-Za5CS685IUOZekt8 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Za5CS685IUOZekt8 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Za5CS685IUOZekt8 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Za5CS685IUOZekt8 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Za5CS685IUOZekt8 .actorPopupMenu{position:absolute;}#mermaid-svg-Za5CS685IUOZekt8 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Za5CS685IUOZekt8 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Za5CS685IUOZekt8 .actor-man circle,#mermaid-svg-Za5CS685IUOZekt8 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Za5CS685IUOZekt8 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}当Executor2宕机创建临时节点 /instances/executor1创建临时节点 /instances/executor2通知instances变化通知instances变化尝试创建/leader/election节点,成为leader读取所有instances,计算分片分配写入分片分配信息到/sharding/*监听到分片分配,获取自己的分片项监听到分片分配,获取自己的分片项执行分片任务执行分片任务临时节点/instances/executor2消失重新分片,更新/sharding/*监听到分片变化,获取新的分片项执行新增的分片项


    3. 实操教程:从零搭建Elastic-Job环境

    3.1 环境准备

    • JDK 1.8+
    • Maven 3.5+
    • ZooKeeper 3.4.6+(集群或单机)
    • IDE(如IntelliJ IDEA)

    3.2 部署ZooKeeper集群(可选单机)

    单机模式(测试用):

    wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
    tar -zxvf zookeeper-3.4.14.tar.gz
    cd zookeeper-3.4.14
    cp conf/zoo_sample.cfg conf/zoo.cfg
    # 修改dataDir为自定义路径
    bin/zkServer.sh start

    集群模式(生产推荐):
    至少三台机器,每台修改zoo.cfg:

    server.1=192.168.1.10:2888:3888
    server.2=192.168.1.11:2888:3888
    server.3=192.168.1.12:2888:3888

    并在dataDir目录下创建myid文件,内容为对应序号。

    3.3 创建Spring Boot项目整合Elastic-Job

    我们将使用Elastic-Job-Lite,它是轻量级无中心化版本。

    Maven依赖:

    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.12.RELEASE</version>
    </parent>

    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>elasticjob-lite-spring-boot-starter</artifactId>
    <version>3.0.4</version>
    </dependency>
    </dependencies>

    application.yml配置:

    elasticjob:
    reg-center:
    server-lists: localhost:2181 # ZooKeeper地址
    namespace: elasticjobexample # ZooKeeper命名空间
    jobs:
    dataCleanJob:
    elasticJobClass: com.example.job.DataCleanJob
    cron: 0 0 2 * * ? # 每天凌晨2点执行
    sharding-total-count: 5 # 分片总数
    sharding-item-parameters: 0=beijing,1=shanghai,2=guangzhou,3=shenzhen,4=others # 分片参数
    overwrite: true

    3.4 编写第一个分片任务

    创建任务类,实现SimpleJob接口:

    package com.example.job;

    import org.apache.shardingsphere.elasticjob.api.ShardingContext;
    import org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;
    import org.springframework.stereotype.Component;

    @Component
    public class DataCleanJob implements SimpleJob {

    @Override
    public void execute(ShardingContext shardingContext) {
    int shardingItem = shardingContext.getShardingItem();
    String shardingParameter = shardingContext.getShardingParameter();

    System.out.println("分片项:" + shardingItem + ",参数:" + shardingParameter + " 开始处理数据…");

    // 模拟根据分片参数处理不同地域的数据
    switch (shardingParameter) {
    case "beijing":
    // 处理北京的数据
    cleanDataByRegion("beijing");
    break;
    case "shanghai":
    cleanDataByRegion("shanghai");
    break;
    // … 其他地域
    default:
    cleanDataByRegion("others");
    }
    }

    private void cleanDataByRegion(String region) {
    // 实际业务:从数据库查询该地域的数据并清洗
    System.out.println("正在清洗 " + region + " 的数据…");
    // 模拟耗时
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }

    3.5 分片策略配置

    Elastic-Job内置了三种分片策略:

    • 平均分配策略(默认):AverageAllocationJobShardingStrategy,将分片项尽可能平均分配给所有实例。
    • 轮询分配策略:RoundRobinAllocationJobShardingStrategy,按顺序轮流分配。
    • 根据作业名称哈希分配:OdevitySortByNameJobShardingStrategy,根据作业名称的哈希值奇偶决定。

    我们可以在配置中指定策略:

    elasticjob:
    jobs:
    dataCleanJob:
    jobShardingStrategyType: AVG_ALLOCATION # 或 ROUND_ROBIN

    3.6 启动验证

    分别启动两个或多个应用实例(通过不同端口或命令行参数),观察控制台输出。每个实例会打印自己负责的分片项及参数,并且当停止一个实例后,剩余实例会自动接管其分片。

    弹性伸缩验证:

  • 启动实例A(端口8080),观察分片分配:假设分片总数为5,只有一个实例,则它负责所有分片0-4。
  • 启动实例B(端口8081),此时ZooKeeper检测到新实例,触发重新分片,实例A和B会平均分配分片(如A负责0,1,2;B负责3,4)。
  • 停止实例B,实例A重新接管所有分片。
  • 通过日志可清晰看到分片变化。


    4. 优缺点分析

    4.1 优点

    • 分片能力极强:支持灵活的分片策略,适合海量数据并行处理。
    • 弹性伸缩:执行器节点动态增减,任务自动重新分片,无需人工干预。
    • 去中心化:无调度中心,避免单点故障,系统更健壮。
    • 与Spring生态集成良好:提供Spring Boot Starter,配置简单。
    • 支持分布式事务(通过补偿):虽然不直接提供事务,但可通过幂等和重试保证最终一致性。

    4.2 缺点

    • 需要维护ZooKeeper:引入额外的中间件,增加运维复杂度。
    • 学习曲线稍陡:对分片概念、ZooKeeper原理需要一定理解。
    • 不支持复杂DAG工作流:Elastic-Job主要面向单任务分片,如果需要复杂依赖编排,需结合其他框架(如Apache DolphinScheduler)或自行实现。
    • 无内置监控界面:虽然可通过ZooKeeper查看状态,但缺乏友好的可视化控制台(社区有第三方扩展,但非官方)。

    5. 实战案例:1000万条数据清洗分片执行

    假设我们有一个用户行为日志表,记录了近千万条数据,需要每天凌晨进行清洗(过滤无效数据、格式转换、脱敏等),并存入数仓。使用Elastic-Job分片处理,可以大幅提升效率。

    5.1 数据分片策略

    按用户ID取模分片是最常见的方式。例如,分片总数为10,每个分片处理用户ID % 10 == 固定值的数据。这样能保证同一用户的所有数据进入同一分片,便于后续聚合计算。

    配置分片参数:

    elasticjob:
    jobs:
    logCleanJob:
    sharding-total-count: 10
    # 分片参数可传递每个分片对应的用户ID模值,但通常业务中直接使用分片项序号取模

    5.2 任务实现

    @Component
    public class LogCleanJob implements SimpleJob {

    @Autowired
    private LogDao logDao;

    @Override
    public void execute(ShardingContext context) {
    int shard = context.getShardingItem();
    int totalShards = context.getShardingTotalCount();

    // 计算当前分片需要处理的用户ID范围(按ID取模)
    // 假设用户ID为数字,清洗最近一周的数据
    Date startTime = DateUtils.addDays(new Date(), 7);
    Date endTime = new Date();

    List<Long> userIds = logDao.findUserIdsByMod(shard, totalShards, startTime, endTime);

    // 分批处理,防止一次加载过多
    for (Long userId : userIds) {
    List<LogEntity> logs = logDao.findLogsByUserId(userId, startTime, endTime);
    for (LogEntity log : logs) {
    // 清洗逻辑:过滤、脱敏、转换
    cleanLog(log);
    // 写入清洗后的表或发送到MQ
    logDao.insertCleanedLog(log);
    }
    // 每处理完一个用户,更新进度(可选)
    }
    }

    private void cleanLog(LogEntity log) {
    // 模拟清洗:脱敏IP、过滤敏感词等
    log.setIp(maskIp(log.getIp()));
    // … 其他处理
    }
    }

    5.3 性能对比

    假设单机处理1000万条数据需要10小时,采用10个分片(10台机器并行)理论上可将时间缩短到1小时左右。实际中受数据库瓶颈、网络等影响,但提升依然显著。


    6. 对比XXL-JOB:什么时候选Elastic-Job而非XXL-JOB?

    XXL-JOB是目前国内使用最广泛的分布式任务调度框架,它采用中心化架构(调度中心+执行器)。两者对比如下:

    维度Elastic-JobXXL-JOB
    架构 去中心化,依赖ZooKeeper协调 中心化,调度中心负责触发和分配
    分片能力 原生支持弹性分片,动态分配 支持分片(广播模式),但分片逻辑需自行实现
    可扩展性 节点增减自动重新分片 执行器增减需调度中心感知,但任务分片需手动配置
    运维复杂度 需要维护ZooKeeper集群 只需维护调度中心数据库(MySQL),更简单
    监控界面 无官方UI,需通过ZooKeeper查看 自带功能丰富的Web控制台
    任务依赖 不支持DAG工作流 支持简单依赖(通过子任务)
    多语言支持 Java为主 Java为主,但有HTTP任务可支持其他语言
    适用场景 海量数据批处理,需要弹性分片 常规定时任务,中小团队,简单分片需求

    何时选择Elastic-Job?

    • 数据量巨大,需要将数据切分到多台机器并行处理,且节点数量会动态变化。
    • 追求高可用,希望避免调度中心单点(虽然XXL-JOB调度中心可集群,但依赖数据库锁)。
    • 团队有ZooKeeper运维能力,愿意承担额外中间件成本。

    何时选择XXL-JOB?

    • 任务数量不多,对分片要求不高。
    • 需要可视化管理和快速部署。
    • 团队规模小,希望降低运维复杂度。

    7. 适用场景:海量数据批处理

    Elastic-Job特别适合以下场景:

    • 用户画像计算:每天根据用户行为日志计算标签,数据量千万级,需要按用户ID分片并行计算。
    • 数据清洗/ETL:日志清洗、数据标准化,可按日期或地域分片。
    • 批处理作业:如积分兑换、优惠券发放,需扫描全量用户,分片处理避免数据库压力。
    • 定时报表生成:按区域、渠道分片生成报表,再合并结果。
    • 索引/缓存重建:大规模数据重建Elasticsearch索引或Redis缓存,可分片并行。

    总结

    Elastic-Job凭借其去中心化架构和强大的弹性分片能力,成为海量数据批处理场景的首选方案。虽然需要维护ZooKeeper增加了一定复杂度,但换来的高可用性和伸缩性在数据量爆炸的今天极具价值。

    本文从原理到实战,带您完整体验了Elastic-Job的魅力。下篇我们将探讨PowerJob——新一代支持工作流和多语言的调度框架,敬请期待!

    您的业务是否遇到过千万级数据处理的挑战?欢迎留言分享!


    附录:完整Mermaid图汇总

    1. Elastic-Job架构图

    #mermaid-svg-DTXqSi3SVObr1f8J{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DTXqSi3SVObr1f8J .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DTXqSi3SVObr1f8J .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DTXqSi3SVObr1f8J .error-icon{fill:#552222;}#mermaid-svg-DTXqSi3SVObr1f8J .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DTXqSi3SVObr1f8J .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DTXqSi3SVObr1f8J .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DTXqSi3SVObr1f8J .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DTXqSi3SVObr1f8J .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DTXqSi3SVObr1f8J .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DTXqSi3SVObr1f8J .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DTXqSi3SVObr1f8J .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DTXqSi3SVObr1f8J .marker.cross{stroke:#333333;}#mermaid-svg-DTXqSi3SVObr1f8J svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DTXqSi3SVObr1f8J p{margin:0;}#mermaid-svg-DTXqSi3SVObr1f8J .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-DTXqSi3SVObr1f8J .cluster-label text{fill:#333;}#mermaid-svg-DTXqSi3SVObr1f8J .cluster-label span{color:#333;}#mermaid-svg-DTXqSi3SVObr1f8J .cluster-label span p{background-color:transparent;}#mermaid-svg-DTXqSi3SVObr1f8J .label text,#mermaid-svg-DTXqSi3SVObr1f8J span{fill:#333;color:#333;}#mermaid-svg-DTXqSi3SVObr1f8J .node rect,#mermaid-svg-DTXqSi3SVObr1f8J .node circle,#mermaid-svg-DTXqSi3SVObr1f8J .node ellipse,#mermaid-svg-DTXqSi3SVObr1f8J .node polygon,#mermaid-svg-DTXqSi3SVObr1f8J .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DTXqSi3SVObr1f8J .rough-node .label text,#mermaid-svg-DTXqSi3SVObr1f8J .node .label text,#mermaid-svg-DTXqSi3SVObr1f8J .image-shape .label,#mermaid-svg-DTXqSi3SVObr1f8J .icon-shape .label{text-anchor:middle;}#mermaid-svg-DTXqSi3SVObr1f8J .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DTXqSi3SVObr1f8J .rough-node .label,#mermaid-svg-DTXqSi3SVObr1f8J .node .label,#mermaid-svg-DTXqSi3SVObr1f8J .image-shape .label,#mermaid-svg-DTXqSi3SVObr1f8J .icon-shape .label{text-align:center;}#mermaid-svg-DTXqSi3SVObr1f8J .node.clickable{cursor:pointer;}#mermaid-svg-DTXqSi3SVObr1f8J .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DTXqSi3SVObr1f8J .arrowheadPath{fill:#333333;}#mermaid-svg-DTXqSi3SVObr1f8J .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DTXqSi3SVObr1f8J .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DTXqSi3SVObr1f8J .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DTXqSi3SVObr1f8J .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DTXqSi3SVObr1f8J .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DTXqSi3SVObr1f8J .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DTXqSi3SVObr1f8J .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DTXqSi3SVObr1f8J .cluster text{fill:#333;}#mermaid-svg-DTXqSi3SVObr1f8J .cluster span{color:#333;}#mermaid-svg-DTXqSi3SVObr1f8J div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DTXqSi3SVObr1f8J .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DTXqSi3SVObr1f8J rect.text{fill:none;stroke-width:0;}#mermaid-svg-DTXqSi3SVObr1f8J .icon-shape,#mermaid-svg-DTXqSi3SVObr1f8J .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DTXqSi3SVObr1f8J .icon-shape p,#mermaid-svg-DTXqSi3SVObr1f8J .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DTXqSi3SVObr1f8J .icon-shape rect,#mermaid-svg-DTXqSi3SVObr1f8J .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DTXqSi3SVObr1f8J .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DTXqSi3SVObr1f8J .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DTXqSi3SVObr1f8J :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    执行器集群

    ZooKeeper集群

    ZK节点1

    ZK节点2

    ZK节点3

    执行器1

    执行器2

    执行器3

    数据库

    2. 分片重新分配流程图

    #mermaid-svg-RW0tekOusDyvtCtz{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RW0tekOusDyvtCtz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RW0tekOusDyvtCtz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RW0tekOusDyvtCtz .error-icon{fill:#552222;}#mermaid-svg-RW0tekOusDyvtCtz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RW0tekOusDyvtCtz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RW0tekOusDyvtCtz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RW0tekOusDyvtCtz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RW0tekOusDyvtCtz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RW0tekOusDyvtCtz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RW0tekOusDyvtCtz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RW0tekOusDyvtCtz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RW0tekOusDyvtCtz .marker.cross{stroke:#333333;}#mermaid-svg-RW0tekOusDyvtCtz svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RW0tekOusDyvtCtz p{margin:0;}#mermaid-svg-RW0tekOusDyvtCtz .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-RW0tekOusDyvtCtz .cluster-label text{fill:#333;}#mermaid-svg-RW0tekOusDyvtCtz .cluster-label span{color:#333;}#mermaid-svg-RW0tekOusDyvtCtz .cluster-label span p{background-color:transparent;}#mermaid-svg-RW0tekOusDyvtCtz .label text,#mermaid-svg-RW0tekOusDyvtCtz span{fill:#333;color:#333;}#mermaid-svg-RW0tekOusDyvtCtz .node rect,#mermaid-svg-RW0tekOusDyvtCtz .node circle,#mermaid-svg-RW0tekOusDyvtCtz .node ellipse,#mermaid-svg-RW0tekOusDyvtCtz .node polygon,#mermaid-svg-RW0tekOusDyvtCtz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RW0tekOusDyvtCtz .rough-node .label text,#mermaid-svg-RW0tekOusDyvtCtz .node .label text,#mermaid-svg-RW0tekOusDyvtCtz .image-shape .label,#mermaid-svg-RW0tekOusDyvtCtz .icon-shape .label{text-anchor:middle;}#mermaid-svg-RW0tekOusDyvtCtz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RW0tekOusDyvtCtz .rough-node .label,#mermaid-svg-RW0tekOusDyvtCtz .node .label,#mermaid-svg-RW0tekOusDyvtCtz .image-shape .label,#mermaid-svg-RW0tekOusDyvtCtz .icon-shape .label{text-align:center;}#mermaid-svg-RW0tekOusDyvtCtz .node.clickable{cursor:pointer;}#mermaid-svg-RW0tekOusDyvtCtz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RW0tekOusDyvtCtz .arrowheadPath{fill:#333333;}#mermaid-svg-RW0tekOusDyvtCtz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RW0tekOusDyvtCtz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RW0tekOusDyvtCtz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RW0tekOusDyvtCtz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RW0tekOusDyvtCtz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RW0tekOusDyvtCtz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RW0tekOusDyvtCtz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RW0tekOusDyvtCtz .cluster text{fill:#333;}#mermaid-svg-RW0tekOusDyvtCtz .cluster span{color:#333;}#mermaid-svg-RW0tekOusDyvtCtz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RW0tekOusDyvtCtz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RW0tekOusDyvtCtz rect.text{fill:none;stroke-width:0;}#mermaid-svg-RW0tekOusDyvtCtz .icon-shape,#mermaid-svg-RW0tekOusDyvtCtz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RW0tekOusDyvtCtz .icon-shape p,#mermaid-svg-RW0tekOusDyvtCtz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RW0tekOusDyvtCtz .icon-shape rect,#mermaid-svg-RW0tekOusDyvtCtz .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RW0tekOusDyvtCtz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RW0tekOusDyvtCtz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RW0tekOusDyvtCtz :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    实例启动/停止

    ZooKeeper触发

    Leader选举

    重新计算分片分配

    写入ZooKeeper

    各实例监听到变化

    执行新分片任务

    赞(0)
    未经允许不得转载:171主机测评 » 【任务调度:框架】5、分片能力天花板!Elastic-Job搞定1000万级数据批处理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址