wangguangwu
wangguangwu
发布于 2024-12-20 / 18 阅读
0
0

推送模型优化

1. 背景与需求

在系统中,我们需要处理案件的推送流程,包括以下主要阶段:

  1. 报案:向外部系统推送案件的报案信息。
  2. 影像件推送:推送影像件信息。
  3. 理算推送:推送理算信息。

案件的状态需要按照顺序流转,流程分为以下几步:

  • 初始化 -> 报案成功 -> 影像件推送成功 -> 保司影像件上传成功 -> 理算推送成功 -> 保司理算成功。

1.1 需求痛点

  1. 同步处理性能问题:每个阶段通过轮询处理,效率低,无法充分利用系统资源。
  2. 逻辑耦合度高:状态判断逻辑集中在一个模块中,不易扩展。
  3. 缺乏动态触发机制:影像件推送完成后需要等待保司的回调,但原始模型中没有合适的触发机制。
  4. 扩展性差:增加新的状态或流程需要修改大量代码。
  5. 内存风险:一次性查询过多数据可能占用大量内存,影响系统稳定性。

2. 原始推送模型

2.1 原始模型设计

原始模型采用 while 循环与定时任务相结合的方式,通过状态判断批量处理案件:

流程逻辑

  1. 定时查询数据库,获取 初始化 状态的案件,批量执行 报案推送
  2. 查询 报案成功 状态的案件,批量执行 影像件推送
  3. 查询 影像件推送成功 状态的案件,等待保司的回调完成后,执行 理算推送

核心代码逻辑

while (true) {
    // 查询初始化案件并推送报案
    List<Task> initTasks = fetchTasksByStatus("初始化");
    pushRegist(initTasks);

    // 查询报案成功案件并推送影像件
    List<Task> registSuccessTasks = fetchTasksByStatus("报案成功");
    pushImage(registSuccessTasks);

    // 查询影像件推送成功案件并推送理算
    List<Task> imageSuccessTasks = fetchTasksByStatus("影像件推送成功");
    pushClaim(imageSuccessTasks);
}

2.2 原始模型的问题

  1. 轮询效率低
    • while 循环不断查询数据库,消耗资源,增加数据库压力。
  2. 同步阻塞
    • 所有任务同步执行,不能充分利用多线程并发能力。
  3. 缺乏动态触发机制
    • 影像件推送完成后无法主动监听保司的回调事件。
  4. 难以扩展
    • 状态和逻辑耦合度高,新增状态或流程需要修改现有代码。
  5. 内存占用问题
    • 一次性查询过多数据可能导致内存不足,甚至引发 OOM(OutOfMemoryError)。

3. 优化后的推送模型

针对上述问题,优化后的模型采用 分段式任务处理 + 事件驱动机制,并通过 分页查询流式处理 优化数据加载方式。

3.1 优化模型设计

第一段任务

  • 处理 报案推送影像件推送
  • 通过定时任务批量处理,完成状态流转。

第二段任务

  • 基于事件驱动机制,监听保司的回调事件。
  • 动态触发 理算推送 流程。

3.2 优化模型的核心架构

任务调度器

  • 定时调度,查询数据库中各阶段的任务,并提交给线程池处理。

任务状态机

  • 每个阶段对应一个处理模块(如报案推送、影像件推送、理算推送)。
  • 状态独立实现,逻辑解耦。

事件驱动机制

  • 使用 Spring 事件监听器监听保司的回调事件,动态触发理算推送。

数据查询优化

  • 分页查询:限制每次查询数据量。
  • 流式处理:逐条读取数据,避免一次性加载过多数据。

3.3 优化后的任务处理流程

第一段任务

public void executeFirstSegment(Task task) {
    if ("初始化".equals(task.getStatus())) {
        taskManager.processTask(task, "报案成功");
    }

    if ("报案成功".equals(task.getStatus())) {
        taskManager.processTask(task, "影像件推送成功");
    }
}

第二段任务

@EventListener
public void handleImageUploadSuccessEvent(ImageUploadSuccessEvent event) {
    String caseId = event.getCaseId();
    Task task = taskManager.getTaskById(caseId);
    if (task != null && "保司影像件上传成功".equals(task.getStatus())) {
        taskManager.processTask(task, "理算推送成功");
    }
}

数据查询优化

分页查询:

public List<Task> fetchTasksByStatus(String status, int page, int size) {
    return jdbcTemplate.query(
            "SELECT * FROM tasks WHERE status = ? LIMIT ?, ?",
            new Object[]{status, page * size, size},
            new BeanPropertyRowMapper<>(Task.class)
    );
}

流式处理:

jdbcTemplate.query(
    "SELECT * FROM tasks WHERE status = ?",
    new Object[]{status},
    rs -> {
        while (rs.next()) {
            Task task = mapRowToTask(rs);
            threadPool.execute(() -> processTask(task));
        }
    }
);

3.4 优化模型的特点

  1. 解耦逻辑

    • 每个状态独立实现,逻辑清晰。
    • 状态流转由任务管理器统一管理,避免嵌套复杂判断。
  2. 性能提升

    • 第一段任务批量处理,利用线程池并发执行。
    • 第二段任务通过事件监听器触发,避免轮询消耗。
  3. 动态响应

    • 保司的回调通过事件触发,理算推送任务即时响应。
  4. 内存优化

    • 分页查询和流式处理,降低内存占用。

4. 模型对比

对比项原始模型优化模型
任务处理方式同步轮询分段式任务 + 异步事件
逻辑解耦状态判断集中,耦合度高每个阶段独立实现,逻辑解耦
性能单线程处理,数据库压力大线程池并发处理,减少资源消耗
动态触发不支持动态触发,需要轮询数据库基于事件机制,支持动态触发
内存优化一次性加载所有数据,可能导致内存不足分页查询 + 流式处理,降低内存使用
扩展性增加新状态需要修改核心逻辑新增状态只需实现对应的处理逻辑

5. 总结

优化后的模型优势

  1. 性能提升:线程池并发处理批量任务,提升推送效率。
  2. 逻辑清晰:各阶段职责单一,降低耦合度,易于维护。
  3. 动态响应:事件驱动机制实现动态任务触发,无需频繁轮询。
  4. 内存稳定性:分批处理和流式查询减少内存占用,提升系统稳定性。

适用场景

  • 复杂任务流转场景。
  • 需要与外部系统交互并等待回调的场景。
  • 对性能和扩展性有较高要求的场景。

优化后的推送模型不仅解决了原始模型的痛点,还为系统的扩展和高效运行提供了可靠的基础。


评论