一次订单业务问题的排查

前些天遇到一个切换数据源的问题,分析了下给大家分享下

l  【问题】

1.       问题背景

提单数据是分库存储的,分库意味着数据需要根据特定的路由规则路由到不同的库,

切换数据源不可避免;

2.       问题描述

优化版本单品单结,用户订单不能按照路由规则,存储到特定的数据库,而是存储在默认的数据库中,持久层代码如图

 

l  【分析】

1.       提单采用的路由规则很简单,路由key为用户pin,根据用户pin哈希取模决定数据存储到特定的数据库,若不能取得路由key,则存储到默认的数据库中。从结果看数据存储到了默认的数据库,说明路由策略中没有取到对应的路由key

2.       为了Service层与Dao层的分离解耦,路由key,是通过TheadLocal的方式存储到线程中,实现两个层的数据传递,线程内部为串行执行,只需要在Dao层调用之前确定路由key,Dao层便可以根据路由规则,将数据存储到特定的库。代码也确实是这么处理的,将用户pin设置到了线程变量,并且之后调用了Dao层的方法,如下图标识。


3.       问题变的难以琢磨,一切貌似都很正常,但只有优化版本的单品单结业务出现了这样的问题,商超,外卖,秒杀等平行业务没有这样的问题,使用的路由规则和Dao层方法也是一样一样的,在测试环境下,加入打印日志验证

通过日志对比看出在路由策略执行的时,单品单结没有取到路由key,其他业务可以取到路由key,进一步将问题锁定在单品单结业务的代码上,但然而仍然没有什么头绪……

4.       再次对比代码,寻找差异(很反复的过程)抱着宁可错杀一千也不放过一个的态度,最终发现设置路由key的位置,有所不同,其他业务设置路由key为拿到用户pin就立即设置,而单品单结是在调用Dao之前设置路由key,将单品单结的设置路由key的代码,尽可能的前置,部署测试,惊奇的发现正确运行,订单数据可以顺利路由到用户pin对应的数据库了,改动设置路由key的代码位置生效了,距离问题的真正原因又近了一步;继续变换该段代码的位置,不断测试,最终问题慢慢凸显出来在事务内部设置路由key就会有问题,在事务外部设置路由key则正确运行。事务注解@Transactional都做了些什么呢?


5.       进一步的分析,我们知道无论是注解式的事务,还是声明式的事务,最终都是事务管理器处理事务,我们这里使用的是spring默认的DataSourceTransactionManager,

Spring注解事务的传播级别为默认的PROPAGATION_REQUIRED,如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中,所以一旦开启就会在同一事务中。

在事务开启时DataSourceTransactionManager会调用doBegin方法,这个方法会获得该事务使用的数据库连接,结合场景,由于是第一个事务标签所以是新建的事务,所以会通过图中的this.dataSource.getConnection()来获取数据库连接。


我们使用的数据源为下图动态路由数据源,该数据源依赖自定义路由策略

dataSource.getConnection(),分为两步,第一步确定数据源,第二步获取已定数据源的数据库连接;第一步确定数据源的过程依赖我们自定义的路由策略。如下图


我们自定义的数据源实现了父类的方法,并依赖自定义的路由策略,如图


大致流程如下图

也就是说在事务开启阶段,我们已经使用路由规则,选定了数据源并且获取了数据库连接,并且将该连接绑定在线程中,而后续的数据库操作都是使用的是线程绑定的数据库连接(myibatis事务也是spring管理,也会直接使用该连接)。在开启事务之前设置路由key是有效的,而在事务内部设置路由key已经为时已晚,因为后续的操作会一直使用在事务开启阶段绑定的数据库连接。

 【总结】

1.       数据源的切换需要在获取数据库连接之前,获取数据库连接以后,切换数据源不能起作用。

2.       开启数据库事务会提前锁定数据库连接,对于确定数据源的路由key等数据,应该在事务开始之前设置。

<think>好的,我需要帮助用户排查线上问题A的产品相关原因。首先,根据用户提供的引用内容,特别是引用[1]、[2]、[3],线上问题排查通常需要按照一定的步骤来进行。用户提到要关注产品原因、日志和故障定位,所以需要围绕这些方面展开。 首先,确定问题现象。用户的问题A具体表现是什么?比如是功能异常、性能下降还是数据错误?这一步可能需要用户提供更多信息,但假设用户已经知道问题现象,接下来需要收集相关日志和监控数据。产品相关的日志可能包括用户操作日志、业务逻辑处理日志、API调用日志等,这些有助于了解用户行为和数据流转情况。 然后是分析可能的产品原因。比如是否存在产品设计缺陷、业务流程漏洞、配置错误或者需求实现偏差。例如,如果某个功能最近有更新,可能存在代码逻辑错误或配置未正确生效的情况。此外,用户权限设置不当也可能导致问题。 接下来需要逐步排查。比如检查最近的版本变更,是否有相关功能的发布;验证业务流程是否符合预期,是否存在逻辑错误;检查产品配置是否正确;分析用户操作路径是否与设计一致。同时,结合日志中的错误信息和用户行为数据,定位具体环节的问题。 最后,解决问题后需要验证修复效果,并进行复盘,优化产品设计或流程。此外,用户可能需要生成相关问题,比如如何分析用户行为日志,或者产品配置检查的方法,这些可以作为后续问题。 需要注意的是,回答中要引用提供的参考文献,尤其是在步骤说明时,自然地添加引用标识。同时,按照用户的要求,使用中文,数学公式用$...$格式,独立公式用$$...$$,但当前问题不涉及数学公式,可能不需要使用。另外,代码块部分如果有的话需要用正确格式,但这里可能不需要代码。 总结步骤应该是:确定现象、收集日志、分析产品原因、逐步排查、解决验证。每个步骤结合引用内容进行说明,并生成相关问题。</think>排查线上问题A的产品相关原因需遵循系统化分析流程,结合日志分析和业务逻辑验证,以下是具体步骤: ### 一、明确问题现象(引用[1][2]) 1. 记录用户反馈的核心异常点,例如: - 功能失效(如支付失败率突增) - 业务流程中断(如订单状态卡在待审核) - 数据显示异常(如库存数量出现负数) 2. 确认问题影响范围: - 特定用户群体/区域/设备类型 - 特定业务场景触发 ### 二、收集产品相关日志(引用[3]) 1. **关键日志类型**: ```markdown - 用户行为日志:`user_behavior.log`(含操作路径、点击事件) - 业务流水日志:`biz_transaction.log`(记录核心业务状态变更) - 接口调用日志:`api_access.log`(包含请求参数和响应结果) - 错误跟踪日志:`error_trace.log`(异常堆栈和上下文信息) ``` 2. **日志筛选技巧**: - 使用时间窗口过滤(如`grep "2023-08-20T14:" error_trace.log`) - 按用户ID/订单号等业务主键追踪全链路日志 - 组合查询(如`状态=失败 AND 操作类型=支付`) ### 三、定位产品原因(引用[1][3]) 1. **常见产品维度问题**: - 业务流程设计缺陷(如缺少状态校验环节) - 功能配置错误(如营销活动规则配置冲突) - 用户权限体系漏洞(如越权访问未授权功能) - 需求实现偏差(如开发未按PRD实现交互逻辑) 2. **分析方法论**: ```mermaid graph TD A[问题现象] --> B{是否涉及业务流程变更?} B -->|是| C[检查最近3次版本发布说明] B -->|否| D[检查系统配置变更记录] C --> E[验证需求文档与实际实现差异] D --> F[分析用户角色权限配置] ``` ### 四、典型排查场景示例 **场景:用户无法领取优惠券** 1. 检查风控规则表达式:`WHERE condition = '新用户' AND $create_time > '2023-08-01'` 2. 验证优惠券发放接口:响应码`500`时检查参数校验逻辑 3. 分析用户标签系统:确认用户是否被错误标记为`黑名单` ### 五、验证与修复 1. 通过`A/B测试`验证修复方案 2. 添加监控指标:如`异常操作率=异常操作次数/总操作次数` 3. 更新产品文档:补充边界条件说明(如`单用户每日最多领取3次`)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值