Skip to content

Map

含义

Map模式相对于静态分片是类似的,区别就在于静态分片是一开始就配置好分片了,而Map则是根据代码逻辑进行分片

场景

假设现在有一个每日处理数据的需求但是数据量不定,这个时候我们就可以通过Map来进行处理。

假设公司要对明文保存手机号的 User 表进行数据安全审查,数据量不定,通过 snail-job 的Map任务将这些数据按不同范围分片处理。

测试

测试目的

  • 验证是否可以按照代码逻辑进行分片
  • 验证分片后其中一片的数据执行失败会是怎样的结果

测试代码

java
@Component
@JobExecutor(name = "testMapJobExecutor")
public class TestMapJobExecutor {

    private final Integer BATCH_SIZE = 3;

    @MapExecutor
    public ExecuteResult rootMapExecute(MapArgs mapArgs, MapHandler mapHandler) {
        // 此处可以进行自定义的分片逻辑
        List<String> phones = JSON.parseArray(String.valueOf(mapArgs.getJobParams()), String.class);
        List<List<String>> partition = Lists.partition(phones, BATCH_SIZE);
        // 服务端会获取到客户端的节点数量来处理map的各个分片
        // 根据在页面配置的路由策略,把对应的分片分发到不同客户端节点
        // 例如:入参总量为10条,BATCH_SIZE设置为3则每3条一个分组,分组结果(List<T> taskList)为[{0,3}, {4, 6}, {7,9}, {10}],此时就会分为四组
        // 集合中的各个对象都会作为MapArgs的mapResult参数传递到后续的各个Map任务中
        // 此处的nextTaskName即为后续分发的Map任务名称
        return mapHandler.doMap(partition, "SECOND_MAP");
    }

    // 由ROOT_MAP分片分发到SECOND_MAP任务
    @MapExecutor(taskName = "SECOND_MAP")
    public ExecuteResult secondMapExecute(MapArgs mapArgs) {
        SnailJobLog.REMOTE.info(JSON.toJSONString(mapArgs.getMapResult()));
        // mapResult 即为上述分包中分发下来的具体参数
        // 各节点分别处理分片后的业务逻辑
      	// 测试目的2时取消注释
        //List<String> strings = JSON.parseArray(JSON.toJSONString(mapArgs.getMapResult()), String.class);
        //if (strings.contains("5")){
        //    int i = 1/0;
        //}
        return ExecuteResult.success("执行结果");
    }
}

idea启动多个节点配置

shell
server.port=web端口 spring.profiles.active=执行环境
-Dserver.port=9901 -Dspring.profiles.active=dev-one
-Dserver.port=9902 -Dspring.profiles.active=dev-two
-Dserver.port=9903 -Dspring.profiles.active=dev-three

同时启动3个节点

测试结果

目的一结果:开始只有一个Root节点接收到参数,Root节点根据逻辑将数据进行分片再交给Sec节点处理

  • Root节点
  • Sec节点

目的二结果:分片后其中一片的数据执行失败整个批次即为失败

结论

  • Map类型相比静态分片类型会比较动态,可以在代码中将分片逻辑预处理掉,这样就可以避免未知数据量时无法提前进行分片的问题