导航栏

×
申请书 > 工作总结 > 导航

〔高质量〕Java工作总结

去年年中接手订单履约系统时,我翻了一遍核心代码,心里直骂娘——状态机里直接写字符串“PAID”“SHIPPED”,拼写错了两个地方;一个订单取消的逻辑里try-catch吞了异常,返回个null,导致调用方空指针。能跑就行,是这套代码的最高纲领。

今年我主要干了一件事:把它从“能跑”变成“能修”。

错误码这事,差点没推下去

年初我说要加统一错误码,组里一个老同事直接怼:“加这玩意儿有啥用?出问题不照样看日志?”我没反驳,等到三月份出了个线上事故——用户下单一直失败,日志里只有“调用失败”四个字,调哪个接口、什么参数、什么原因,全没有。我拉着他一起排查了四十分钟,最后发现是库存服务的限流阈值配错了。他当时没说话,第二天主动来找我:“你那错误码方案,咱们下午对一对。”

落地过程没那么顺利。老代码里有两百多个异常抛出点,每个都得改成抛业务异常并带上错误码。我写了个脚本扫描所有throw new RuntimeException,按调用链路分类,排了个优先级:核心下单链路先改,边缘功能后改。每周五下午发个进度表,谁负责的模块还剩几个没改,群里@一下。有人拖了两周,我就拉他一起处理一个真实客诉——那次客诉刚好就是因为他的模块没加错误码,定位花了半小时。之后进度就快了。

到六月份,核心链路全部覆盖。现在监控系统按错误码聚合,比如“ORD-3002(优惠券已过期)”五分钟出现五十次,那不用猜,肯定是运营配的活动券过期时间有问题,直接找他们改配置。平均定位时间从原来的二十分钟压缩到三分钟以内。

一个故障让我重写了幂等逻辑

七月那次重复核销优惠券的事,前面说过了。但有个细节没提:我当时首先想到的不是加唯一索引,而是改Redis锁——把锁时间从5秒改成30秒。上线后观察了两天,又出事了。有个订单处理时调用了第三方风控接口,对方响应慢了,锁还是过期了,消息又被重复消费。这次更隐蔽,因为锁过期但业务还没执行完,第二条消息进来发现锁已释放,再次执行,把库存多扣了一次。

我这才意识到,分布式锁在跨网络调用的场景下根本不可靠。最后选的数据库唯一索引方案,但上线后第一个小时就报死锁。排查发现,高并发下多个线程同时插入核销记录,唯一索引的间隙锁导致互相等待。解决方案是改事务隔离级别为读已提交,并且在插入前先做一次select for update(带条件,只锁单行)。改完后压测,一千并发没有死锁。

这个教训让我重新审视了团队里所有“用Redis锁实现幂等”的代码。一口气改了五个类似场景,包括库存预扣、积分发放、消息发送。改完后的那个月,重复操作导致的工单从每月十五六起降到了零。

跟运营吵架吵出来的问题处理流程

以前运营报bug,经常一句话:“用户付不了钱了,赶紧看。”我回一句“订单号呢?”,对方半天发过来。今年我索性做了个标准化模板:截图、订单号、操作时间、手机型号(有些问题是前端兼容性导致)。发到群里,不符合格式的工单,开发有权先不处理,等补齐信息。

有次运营觉得这太官僚,直接找领导投诉。领导问我,我把近三个月的bug处理耗时数据拉出来——有订单号的,平均解决时间四十分钟;没订单号的,平均两小时十五分钟,而且有三分之一因为信息不足最终关闭,用户问题没解决。领导看了数据,回去把模板要求写进了运营考核里。

说个具体案例。有个用户反馈用微信支付时,跳转回来一直显示“支付中”。运营按模板给了订单号和截图,我十分钟内从日志里查到:微信回调已经到了,但代码里更新订单状态时,判断条件多了一个status.equals(“WAIT_PAY”),而实际状态是“PAYING”,导致更新被跳过。改了一行代码,上线后问题消失。这个bug其实存在了半年,之前因为信息不全,开发一直说“没复现”就给关了。

预防性维护不是口号,是每天扫慢查询

我写了个shell脚本,每天凌晨跑一遍慢查询日志(超过200毫秒的),按执行次数排序,发到群里。有一次扫出来一条新SQL:查询已关闭订单时,用了order by create_time desc limit 1000,但create_time字段没索引,每次执行要扫三百万行。找对应开发问,他说“测试环境数据少,没发现慢”。我让他看生产慢查询记录,他没话说了,当天就加上了索引。

后来我把脚本升级了,加了个功能:如果同一类SQL连续三天出现在慢查询列表里,自动给负责人发钉钉消息,第三天还没处理就@群主。这招管用,现在团队里没人敢写没有索引的查询了。

还有一堆没解决的问题

订单表按用户ID哈希分了十六个库,但查询逻辑里还残留着跨库联查——比如根据外部渠道订单号反查内部订单,得遍历十六个库。今年双十一前夕压测,这个查询一多,数据库连接池直接爆了。临时方案是加了个Redis缓存,把外部订单号和内部订单号的映射存进去,扛住了。但长期看,得做个映射表或者改分片键。

单元测试覆盖率只有四成。老代码里一堆静态方法,想mock都难。我试过用PowerMock,但维护成本太高,跑一次单测要两分钟。现在每次加新功能,我强制要求至少覆盖正常路径和两个异常分支,老代码只能慢慢重构。

一点实在的体会

别指望一次性搞定所有问题。我今年最大的收获是:把最疼的那几个bug彻底修好,比写一百个设计文档管用。用户不关心你架构多优雅,他只关心自己下单时别报错。每次修复完一个重复出现的故障,我会把根因、解决步骤、如何避免写成一条备忘,发到团队群里。到年底攒了三十多条,整理成《常见故障处理手册》,新人入职第一周先看这个,看完再上手改代码。

    我们精彩推荐工作总结专题,静候访问专题:工作总结

文章来源://m.swy7.com/a/5325224.html

更多
L

猜你喜欢

更多
N

最新更新

更多
H

推荐访问