我的订单详情查询 祸端就此埋下了——没事找事前几天的
2022-09-21 02:00:22 欢乐点

事情起因

耗子逗猫 —— 没事找事

前几天,在工作不太忙的时候,为了展示我在工作中积极主动,技术能力较强,并给领导留个好印象,我就去翻翻项目代码有没有可优化的空间。

没想到,我真让我找着啦。

祸端就此埋下了!

有用户反馈查询订单列表接口有点慢,我就去打印每一步的耗时信息。发现查询订单之前,需要先根据用户ID查询用户信息,而查询用户信息接口需要调用用户团队提供的服务,有时候网络较慢的时候,耗时达到200毫秒。

而查询订单接口层层调用的时候,调用了好几次查询用户信息接口。当然可以改成再最上层查询一次,然后层层往下传递,这样一来改的地方比较多,也很麻烦。

我琢磨着能不能加个本地缓存,把用户信息缓存起来,这样就不用每次去调用用户服务查询了。刚好就想到了使用,听说高级程序员都用,我也想用一下试试。

是线程私有的,调用结束后,线程销毁了,里面数据也跟着没了。

听着是线程安全的,应该没什么问题。

动手实践

我先写一个的工具类,用来存储和获取用户信息:

/**

* @ 本地缓存用户信息

**/

class {

// 使用存储用户信息

final = new ();

/**

* 获取用户信息

*/

User () {

// 如果中没有用户信息,就从请求解析出来放进去

if (.get() == null) {

.set(.());

}

.get();

}

}

然后在查询订单接口里面,调用这个工具类的方法获取用户信息,最后根据用户信息查询订单信息,完美。

/**

* 获取订单列表方法

*/

List () {

// 1. 从缓存中获取用户信息

User user = .();

// 2. 根据用户信息,调用用户服务获取订单列表

.(user);

}

自测、提测、验收、上线,接口访问速度“嗖”一下就上去了,一切看上去都是那么完美。

事与愿违

上线一个小时后,值班群炸了。

陆续开始有用户反馈自己刚下的订单不见了,其他用户也有反馈自己的订单列表莫名其妙多了一些订单。

我一脸懵逼,没碰到过这种情况,逐渐反馈的用户越来越多,我已经不知所措了。

领导当机立断,赶紧回滚服务。

半个小时后,回滚完毕,用户的情绪逐渐平复下来。

故障复盘

线上故障解决后我的订单详情查询,紧接着就开始排查问题产生的原因。

经过无数次打日志、debug,终于定位到问题了。

确实是线程私有的,并且会在线程销毁后,里面的数据也会被清理掉。

但是问题就出在,无论我们服务端用的是、Jetty、、Dubbo等,都不会来一个请求就创建一个线程,而是创建一个线程池,所有请求共享这这个线程池里的线程。

一个线程处理完一个请求,并不会被销毁。可能导致多个用户请求共用一个线程,最后出现数据越权,看到了别的用户的订单。

解决方案

解决办法就是,在使用完后,再调用方法清除数据。

/**

* @ 本地缓存用户信息

**/

class {

// 使用存储用户信息

final = new ();

/**

* 获取用户信息

*/

User () {

// 如果中没有用户信息,就从请求解析出来放进去

if (.get() == null) {

.set(.());

}

.get();

}

/**

* 删除用户信息

*/

void () {

.();

}

}

使用try/catch包裹业务代码,然后在中清除数据。

/**

* 获取订单列表

*/

List () {

// 1. 从缓存中获取用户信息

User user = .();

// 2. 根据用户信息,调用用户服务获取订单列表

try {

.(user);

} catch ( e) {

throw new (e.());

} {

// 3. 使用完后,删除用户信息

.();

}

null;

}

故障定级

影响用户超过10w,或者错误数据超过10w,或者资损大于100w,故障定级为P1,全年绩效C。

本来想优化程序性能,提高访问速度,给领导一个好印象,好显得自己技术能力强,工作积极主动。

这下好了,不但年终奖没了,工作还可能保不住了。

事故总结

经过这次事故我的订单详情查询,我总结了以下几点教训:

没事儿别瞎逞能。

没有金刚钻,别揽瓷器活。

不求有功,但求无过。

重构优化的水太深,你把握不住。

免责声明:部分文章信息来源于网络以及网友投稿,本站只负责对文章进行整理、排版、编辑,出于传递更多信息之目的,并不意味着赞同其观点或证实其内容的真实性,如本站文章和转稿涉及版权等问题,请作者在及时联系本站,我们会尽快为您处理。

欢乐点

留言咨询

×