整车解决问题举例

news/2025/2/25 5:05:01

一,调度中心

业务流程优化

1,JOB 地址解析/库存校验/承运商分配

导致问题:日志表量多大,高德调用量过大,频繁调用第三方接口,接口处理慢

处理方案:降量,处理历史数据从时间维度,近三个月;多线程+分批,一个线程处理20条数据

2,针对库存匹配失败,状态29,单独拉出来JOB,降低JOB执行频率1h一次

3,延迟出库问题,导致dps到达状态没有更新成功

原因:正常先出库后发运,但是由于一批车统一做出库,就先发运了,导致后续到达无法更新成功

bug处理

1,dps偶发无法分配问题

20一批,一个线程处理一批,其中部门订单无法分配

原因:开始怀疑库存问题,实际不是。单个线程处理一批数据时,有个查询逻辑selectOne,但是匹配到多条数据,导致异常,该线程的后续数据,则无法进行分配处理,关键时,没有打印异常日志

处理方案

1,降量一批处理50,改成20

2,selectOne 改成limit

3,捕获异常

skywalking优化

根据订单履历,更新订单告警信息

订单报警巡检定时器 
orderAlarmWithParamsJobHandler
/**
 * 报警业务逻辑
 * 1,分配成功1小时后仍未收到承运商的调度信息 30/33
 * 2,调度生效后48小时未反馈出库 6020/6050
 * 3,库存匹配失败(出发地仓库与实车所在仓库不一致)29
 * 4,地址解析失败 26
 * 5,分配失败(39):履历31 没有匹配到有效的分配规则
 * 6,分配失败(39):履历170 订单分配失败,VIN在途
 * 7,地址解析成功后,长时间未分配承运商。履历中22,主表中未记录状态。待添加
 */

问题所在

1,全量获取订单数据

2,在for循环中,查询订单履历

方案

1,查询最近一个月订单

2,根据订单ID查询履历,避免for循环中查询

问题

分配失败

分配规则没有维护好,需要在某个维度增加车型,仓库信息

二,运单中心

死锁:

原因:一个地方,根据主键更新运单里程;另外一个地方进行范围更新

网络异常:更新承运商失败,调用用户中心失败

详细:另外一个地方进行范围更新

DpTaskPanicBuyingPoolCreate 

做了几件事
1,运单池扫描运单定时器

 2,关闭超时自动抢单运单

3,关闭不符合条件的已扫描任务(补偿操作,运单包含配件单,配件单未下发被扫描)

<select id="selectIdsByGrabbingStatus" resultType="java.lang.Long">
    SELECT id
    FROM tt_task
    where grabbing_status = '79501010'
      and relation_parts_count > 0
</select>
//3.关闭不符合条件的已扫描任务(补偿操作,运单包含配件单,配件单未下发被扫描)
List<Long> ids = ttTaskService.selectIdsByGrabbingStatus();
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(ids)) {
    ttTaskService.batchUpdateGrabbingStatus(ids, GrabbingStatusEnum.unScanned.getStatusCode());
}
public enum GrabbingStatusEnum {
    //
    unScanned("0","未扫描"),
    endScanned("79501010","已扫描"),
    inFleet("79501020","进入车队抢单池"),
    inPublic("79501030","进入公共抢单池");

解决方案

1,缩短大事务,把这个范围更新逻辑拉出来,单独job跑

2,改成ID更新

大表

车联网

 执行时间15min

问题:之前取全量,取了多余的数据,JOB频率

方案:取最近3个月数据,只需地跑,10min一次

三,订单中心

1,运单重复生成问题,调度中心重复出库

问题:运单重复生成问题,调度中心重复出库

如何发现的:忘记了,安吉反馈重新出库了吗?

表现:taskmq 消费记录有两条,order发送两次

原因:order没控制住,通过查询订单表,根据外部订单号,并发情况下,拦不住短时间重复下发

解决方法:order接收订单时,加分布式锁,维度外部订单号,过期时间1min

根本原因:调用中心,job重新下发了,为什么会重新下发?-》中间表更新失败

老的记录:

// 先查询,没有再写入
// 实际结果 还没有执行新增订单,就查到了
// 后续都执行完成了,订单创建了,运单也异步创建了,这个再抛出一个异常,导致dps中间表状态更新失败,是2
// 然后再重试,这时候订单是真有了,再重新下发,重试9次,依然失败

2,调度中心偶发调度失败问题

原因1:订单中心,调用调度中心,调用失败

解决方案:增加重试机制,从500ms增加到3s,还是依然存在

最终方案:把查询订单方法上的注解去掉

为什么生效了

解决方案解释1:
移除事务注解:通过移除 @Transactional 注解,taskStatusChangeMessagePush 方法不再创建新的事务上下文,而是直接读取数据库中的最新数据,避免了事务隔离带来的延迟问题。
确保一致性:确保 commonCreatOrder 方法在写入订单时已经提交事务,使得后续的 taskStatusChangeMessagePush 方法能够立即读取到最新的订单数据

解释2:

删除 @Transactional(rollbackFor = Throwable.class) 注解后,taskStatusChangeMessagePush 方法不再参与事务管理,从而解决了偶发查询不到订单的问题。原因如下:
事务隔离问题:当方法被标记为事务时,数据库操作会在事务提交之前处于未提交状态。如果 commonCreatOrder 和 taskStatusChangeMessagePush 不在同一个事务中,但 taskStatusChangeMessagePush 自身是一个事务,则它会创建一个新的事务上下文,导致无法看到其他事务尚未提交的数据。

解释3

为什么查询方法上注解@Transactional(rollbackFor = Throwable.class) 去掉,问题解决了,可以查询到订单了

如果去掉查询方法上的 @Transactional(rollbackFor = Throwable.class) 注解后,问题解决了(可以查询到订单了),这说明问题与 事务的传播行为 或 事务的隔离级别 有关。以下是可能的原因分析和解决方案:


1. 事务传播行为的影响

  • 原因@Transactional 注解默认的传播行为是 Propagation.REQUIRED,即如果当前存在事务,则加入该事务;如果不存在事务,则创建一个新事务。

    • 如果查询方法上加了 @Transactional,而调用查询方法的地方已经在一个事务中,那么查询方法会加入该事务。

    • 如果该事务尚未提交(例如,新增订单的事务还未提交),那么查询方法会读取到未提交的数据(取决于隔离级别),或者被阻塞(如果隔离级别较高)。

  • 解决方案

    • 如果查询方法不需要事务,可以去掉 @Transactional 注解。

    • 如果查询方法需要事务,但希望独立于其他事务,可以将传播行为设置为 Propagation.REQUIRES_NEW

    • 示例代码:

      java

      复制

      @Transactional(propagation = Propagation.REQUIRES_NEW)
      public Order queryOrder(Long orderId) {
          return orderRepository.findById(orderId);
      }

2. 事务隔离级别的影响

  • 原因@Transactional 注解默认的隔离级别是数据库的默认隔离级别(通常是 READ COMMITTED)。

    • 如果查询方法上加了 @Transactional,并且隔离级别较高(如 REPEATABLE READ 或 SERIALIZABLE),可能会导致查询方法无法立即看到其他事务提交的数据。

    • 如果去掉 @Transactional 注解,查询方法会以非事务方式执行,直接读取数据库的最新数据。

  • 解决方案

    • 如果查询方法需要事务,但希望读取已提交的数据,可以将隔离级别设置为 READ COMMITTED

    • 示例代码:

      java

      复制

      @Transactional(isolation = Isolation.READ_COMMITTED)
      public Order queryOrder(Long orderId) {
          return orderRepository.findById(orderId);
      }

3. 事务超时或锁等待

  • 原因:如果查询方法上加了 @Transactional,并且当前事务持有锁(例如,新增订单的事务锁定了某些行),查询方法可能会被阻塞,直到锁释放。

    • 如果去掉 @Transactional 注解,查询方法会以非事务方式执行,不会被阻塞。

  • 解决方案

    • 检查新增订单的事务是否持有锁,并确保事务尽快提交。

    • 如果查询方法需要事务,可以设置较短的事务超时时间。

    • 示例代码:

      java

      复制

      @Transactional(timeout = 5) // 设置事务超时时间为5秒
      public Order queryOrder(Long orderId) {
          return orderRepository.findById(orderId);
      }

4. Spring 事务管理的上下文问题

  • 原因:如果查询方法上加了 @Transactional,Spring 会为该方法的执行创建一个事务上下文。如果调用查询方法的地方已经在一个事务中,可能会导致事务上下文冲突。

    • 去掉 @Transactional 注解后,查询方法会以非事务方式执行,避免了上下文冲突。

  • 解决方案

    • 确保事务的传播行为和上下文管理符合业务需求。

    • 如果查询方法不需要事务,可以去掉 @Transactional 注解。


5. 事务的只读属性

  • 原因:如果查询方法上加了 @Transactional,但没有设置 readOnly = true,Spring 会将其视为一个读写事务,可能会导致额外的锁或事务管理开销。

    • 去掉 @Transactional 注解后,查询方法会以非事务方式执行,避免了这些问题。

  • 解决方案

    • 如果查询方法需要事务,可以将其设置为只读事务。

    • 示例代码:

      java

      复制

      @Transactional(readOnly = true)
      public Order queryOrder(Long orderId) {
          return orderRepository.findById(orderId);
      }

总结

去掉查询方法上的 @Transactional 注解后问题解决,说明查询方法不需要事务,或者事务的传播行为、隔离级别等配置导致了问题。以下是建议的解决方案:

  1. 如果查询方法不需要事务

    • 直接去掉 @Transactional 注解。

  2. 如果查询方法需要事务

    • 设置合适的传播行为(如 Propagation.REQUIRES_NEW)。

    • 设置合适的隔离级别(如 Isolation.READ_COMMITTED)。

    • 设置 readOnly = true,避免不必要的锁开销。

通过调整事务配置,可以确保查询方法既能正确执行,又能避免与其他事务的冲突。如果问题仍然存在,可以提供更多上下文信息,我可以进一步帮助你分析!


http://www.niftyadmin.cn/n/5864980.html

相关文章

XML DOM4J 二、document对象

DOM4J获取Document对象&#xff1a; 使用DOM4J来加载XML文档&#xff0c;需要先获取SAXReader对象&#xff0c;然后通过SAXReader对象的read()方法来加载XML文档&#xff1a; SAXReader reader new SAXReader(); // reader.setValidation(true);Document doc reader.read(&…

C语言多人聊天室 ---s(服务端)

head.h #ifndef __HEAD_H #define __HEAD_H// 常用头文件 #include <stdio.h> #include <stdlib.h> #include <string.h>// 网络编程涉及的头文件 #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h>#include <…

Linux 高级篇 日志管理、定制自己的Linux系统、备份与恢复

一、日志管理 &#xff08;1&#xff09;基本介绍 日志文件是重要的系统信息文件&#xff0c;记录了如用户登录、系统启动、系统安全、邮件及各种服务等相关重要系统事件在安全方面&#xff0c;日志也至关重要&#xff0c;它能记录系统日常发生的各类事情&#xff0c;可用于检…

C#最新语言特性

C#最新语言特性 近几年持续引入多个新特性以提升开发效率和代码质量&#xff0c;截至今年2025年2月&#xff0c;C#的最新稳定版本是C#13&#xff0c;它是在2024年11月发布的&#xff0c;下方是一些C#13中的新特性以及近期版本特性。 C#13版本 params集合增强 params关键字得…

中间件专栏之redis篇——redis基本原理、概念及其相关命令介绍

一、redis是什么 redis是remote dictionary service的简称&#xff0c;中文翻译为远程字典服务&#xff1b; redis是一种数据库&#xff0c;若按照类型来归类&#xff0c;则其可以被归入三个类型数据库&#xff0c;分别为&#xff1a;内存数据库、KV数据库、数据结构数据库&a…

8.日常英语笔记

ribs 排骨 he broke a few ribs in the accident we had barbecued ribs for dinner 我们晚餐吃了排骨烤排骨 肋条&#xff0c;辐条 The ribs of the umbrella are made of metal pan 平底锅 I used a pan to fry the eggs 烤盘 Put the cake pan in the oven 把蛋糕烤盘放到烤…

C#初级教程(4)——流程控制:从基础到实践

1.为什么需要流程控制 有时候&#xff0c;需要根据程序运行时的具体环境&#xff0c;有选择地执行不同代码段&#xff1b;而有时候&#xff0c;则需要反复执行同一段代码。这时候&#xff0c;流程控制中的分支和循环就发挥了关键作用。分支能让代码根据条件判断结果来决定执行路…

欢乐力扣:同构字符串

文章目录 1、题目描述2、 代码 1、题目描述 同构字符串。给定两个字符串 s 和 t &#xff0c;判断它们是否是同构的。如果 s 中的字符可以按某种映射关系替换得到 t &#xff0c;那么这两个字符串是同构的。  每个出现的字符都应当映射到另一个字符&#xff0c;同时不改变字符…