第三十二周的周报我拖到周四深夜才动笔。不是没东西写恰恰相反这周经历了订单模块重构收尾、报表导出功能发布、还有一次线上接口超时的排查随便挑一件都够写两千字。但真正坐下来打开文档的时候我反而反复删了好几版——原因是周报这东西写浅了像流水账写深了没人看这个度很难拿捏。后来我想明白了周报真正的作用不是汇报而是把本周的决策、踩坑、数据变化这些依据沉淀下来。这篇就把第三十二周的工作做个完整复盘既算给你看更算给未来的自己看。1. 第三十二周工作全景先说结论再讲细节1.1 本周核心目标与完成情况第三十二周恰好处在我们产品线一个迭代周期的中段。上周迭代评审会定下了三个核心目标订单模块重构的收尾、报表导出功能的正式上线、以及支付回调成功率从99.92%提升到99.95%以上。到周五下班前盘点三个目标里两个完成、一个延迟。订单模块重构按期合入主干报表导出功能完成灰度发布支付回调成功率的优化目标最终卡在99.94%差了0.01个百分点。这个结果不算漂亮但过程里冒出来的问题和对应的处理方式比结果本身更有价值。先放一张本周的周报速览表方便你快速抓重点目标项状态关键进展遗留问题订单模块重构已完成核心链路重构完毕单元测试覆盖率提升至87%部分旧接口需继续兼容两个版本报表导出功能已完成异步导出链路上线灰度放量到30%超大日期范围导出需限流保护支付回调优化进行中定位到Redis连接池瓶颈并完成修复还剩0.03%的失败样本待分析1.2 为什么这周值得单独拿出来复盘可能有人会觉得第三十二周这个数字没什么特别含义撑死是Q3中间某一周。但恰恰因为处在季度中段很多问题容易在这个时间点被掩盖上半年定的年度目标已经淡化了Q3的阶段性压力还没完全传导下来团队容易进入一种匀速前进的节奏。这种节奏之下技术债、流程漏洞、沟通损耗会悄悄积累等到Q4再集中爆发。这周就挺典型。两个项目能按计划交付靠的不是大家加班而是前几周把设计做透了但支付回调的偶发超时问题恰恰是因为新功能上线的同时共用了底层的Redis连接池暴露出了容量规划上的盲区。所以我写这篇复盘想把按计划交付背后的设计取舍和偶发故障背后的排查思路都拆开讲清楚下周也好给团队做一次内部分享。2. 核心项目实录异步报表导出功能的完整落地过程2.1 需求分析与方案选型为什么不做同步导出报表导出这个需求表面上看非常简单用户在前端选择时间范围和订单状态点击导出后端把符合条件的订单列表生成Excel文件返回下载。第一版设计稿里产品同学画的流程就是同步的前端发请求、后端查库生成Excel、直接返回文件流。我看了之后没有直接签字而是先拉着研发一起做了个简单的容量评估。我们的订单表主表一年大概有4000万行数据单日订单峰值在15万左右。如果用户选的是最近三个月全部状态一次导出可能要扫600万行数据即使只取需要导出的30个字段JVM里临时对象也会有几百MB复杂查询的耗时按经验推算至少是20秒往上。这在同步方案下会带来三个直接问题第一API网关层配置的超时时间是30秒但数据量波动大超过超时时间会导致客户端重试重试又会触发重复查询形成恶性循环第二同步请求会占用Tomcat的请求线程期间连接一直挂着线程池被导出一占普通查询接口的响应就会跟着变慢第三用户等不了20秒如果中途关掉页面请求虽然取消了但服务端的查询和文件生成并不会自动中断白白消耗资源。所以最后定的是异步导出方案前端提交导出请求后后端只创建一个导出任务并立即返回任务ID前端每隔3秒轮询任务状态任务完成后拿到文件下载地址。用户在这期间可以继续做其他操作体验上更像提交了一个后台任务。方案转换的代价是前端多写一套轮询逻辑后端多建一张任务表和一个线程池但把这三个问题全部规避掉了。2.2 线程池参数计算与异步任务实现异步方案里最先要落地的是线程池。直接用Executors.newFixedThreadPool(10)当然可以但我在这上面吃过亏。无界队列意味着高峰期的所有导出任务都会堆积在内存里任务一多轻则任务延迟重则直接OOM。这次我手动创建了一个ThreadPoolExecutor参数是这样的ThreadPoolExecutor exportExecutor new ThreadPoolExecutor( 4, 8, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue(200), new ThreadFactoryBuilder().setNameFormat(export-task-%d).build(), new ThreadPoolExecutor.CallerRunsPolicy() );参数是我按线上情况算的。核心线程数设为4是因为我们导出的机器是4核8G的容器核心线程数不超过CPU核数避免无谓的线程上下文切换。最大线程数放宽到8理由是导出任务不是纯计算型任务里面有IO等待查数据库、写Excel、传OSS适当增加线程可以提升吞吐。队列容量选了200这个数字不算拍脑袋。我们按导出的平均耗时估算过一个任务大约需要8到12秒4个核心线程每秒最多能处理约0.4个任务一分钟也就24个。200的队列意味着理论上可以缓冲8分钟的任务量对绝大多数场景足够。如果有超过这个量的突发需求说明需要从产品层面限流而不是盲目扩充队列。拒绝策略这里有个讲究。我用了CallerRunsPolicy意思是队列满了以后新提交的任务不再进入线程池而是由提交任务的线程自己执行。我们给导出任务建的提交线程是接口请求线程这样做的效果是系统负荷过高时接口响应自然变慢用户感知到提交没反应就会减少请求量相当于一个天然的反压机制。比起丢弃任务或者直接抛异常这个策略在导出这个场景更安全至少任务不会丢。任务表的DDL也值得记一笔字段不多但都踩过坑CREATE TABLE export_task ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_id VARCHAR(32) NOT NULL COMMENT 业务任务ID, user_id BIGINT NOT NULL COMMENT 提交用户, task_type TINYINT NOT NULL COMMENT 0订单导出 1对账单导出, params_json TEXT NOT NULL COMMENT 导出参数快照, status TINYINT NOT NULL DEFAULT 0 COMMENT 0等待 1处理中 2成功 3失败, file_url VARCHAR(512) DEFAULT NULL COMMENT 文件下载地址, error_msg VARCHAR(512) DEFAULT NULL COMMENT 失败原因, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_user_id (user_id), KEY idx_status (status), KEY idx_created_at (created_at) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;params_json这个字段一开始想用多列存储后来改成JSON快照好处是以后增加导出条件不需要改表结构。task_id用UUID生成通过接口返回给前端查询任务状态时用它做唯一标识。2.3 生成本地文件到OSS上传一个容易被忽视的细节导出任务处理过程中最容易出的问题不是查询也不是生成Excel而是文件放哪。最开始有同事提议直接把生成的文件写到服务器本地磁盘然后下载接口再从磁盘读取返回。这个方案在开发环境跑完全没问题一上线就会翻车——我们的部署平台是无状态的容器随时可能被重新调度本地磁盘文件说没就没而且多副本部署时文件只在其中一台机器上下载请求如果被路由到另一台机器就会404。所以文件必须放在对象存储上。我的实现流程是先在线程池里把数据查询出来用EasyExcel写到本地临时目录文件完全写好后上传到OSS上传成功后再把file_url更新到任务表并置状态为成功。流程里有两个小细节值得说。第一临时的本地文件命名一定要带taskId前缀否则不同用户同时导出时容易互相覆盖。第二OSS的bucket要设生命周期规则我们规定导出文件保留7天自动清理否则用户反复导出存储成本会无节制上涨。上传的关键代码里我会强调传给OSS的contentType// 使用阿里云OSS SDK核心配置省略 String key export/ taskId / fileName; ossClient.putObject(bucketName, key, tempFile);这里有个隐蔽的坑如果不显式设置Content-TypeOSS默认按application/octet-stream处理用户在浏览器点下载链接时会直接下载而不是预览某些场景下还会出现中文文件名乱码。建议生成文件时把Content-Type设置为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet下载的Excel文件就不会出幺蛾子。3. 线上问题排查支付回调偶现超时的根因与修复3.1 问题表象一条看起来像偶发的告警周三下午两点多告警群突然弹出通知支付回调接口的P99延迟从正常值的120ms涨到接近980ms持续了约15分钟后自行恢复。当时值班同事的第一反应是慢SQL直接去慢查询日志里翻了半天一条超过500ms的查询都没有。这种偶发、短暂、会自愈的故障最让人头疼。你还没来得及抓现场它自己就好了等你放松警惕它又不定什么时候冒出来。那两天我让值班同事保留了一个原则任何接口异常哪怕已经恢复也要保留当时的线程栈和日志上下文为后续定位做素材。事后证明这个原则救了大忙。3.2 排查过程从GC到Redis连接池我当时按这个顺序排查先看监控面板确认所有应用实例的表现是不是一致的——如果只有一台机器异常多半是单机问题如果所有机器同时异常基本可以排除GC毛刺和本地资源问题。监控显示两台实例的耗时同步上涨所以方向锁定在共享依赖上。接着看GC日志。CMS或G1的remark/mixed GC阶段偶尔出现几百毫秒的停顿很正常但不会导致P99飙到接近一秒。日志显示最近没有明显的大停顿这条线先排除。然后看外部依赖的耗时。支付回调链路里依赖三样东西数据库、Redis、下游支付网关。数据库没有慢SQL支付网关的监控表现平稳唯一异常的是Redis那段时间Redis命令平均耗时从1ms涨到了35ms但Redis服务器的CPU和内存指标都很健康说明问题不在Redis本身而在客户端——也就是应用与Redis的连接层面。最后在Arthas里查了JedisPool的状态active连接数长时间顶在200附近大量线程在acquire方法上等待。到这里原因已经很清晰了连接池被打满了。为什么会被打满这就要说到本周两个项目之间的互相影响。支付回调里有一个幂等校验逻辑每次回调都会查一次Redis而新上线的报表导出功能在异步任务里也要读Redis做数据权限校验。两套逻辑默认共用了同一个JedisPool实例配置里的maxTotal200本来按旧流量是够用的但导出功能上线后新增的并发请求直接把连接池剩余容量吃光了。3.3 修复思路与连接池参数调整修复分两步走。第一步是快速止血把连接池的maxTotal从200调到500maxIdle从100调到200同时把minEvictableIdleTime调短一点加速空闲连接回收。这个调整在周三当天生效支付回调的P99立刻回落到130ms以内。但调整参数只是治标。更关键的是第二步把报表导出的Redis访问拆到独立的连接池实例从物理上隔离业务之间的资源竞争。我让同事在公共的Redis配置类里增加一个exportRedisPool的Bean所有导出相关代码通过独立的连接池访问Redis支付回调链路继续用原来的池子。这样即使导出任务把它的池子占满也不会影响支付回调。这一步做完我又让团队在监控面板上加了连接池活跃度和等待线程数的指标并且配置了独立告警阈值当池子使用率超过80%且持续5分钟时告警会提前触发不用等接口慢到异常才被动响应。关于参数计算我补一下思路。连接池maxTotal不是越大越好太大了也不一定是好事因为每一条连接在Redis服务端都要占用内存和文件描述符。合理估算方式是maxTotal 高峰期QPS × 单请求平均耗时 / 1000 × (1 20%冗余)。我们支付回调高峰期QPS按400算平均耗时50ms算下来需要约24个连接原来200其实是够的。问题在于没把新增的导出流量算进共用池里导出的并发和支付回调叠加后峰值瞬间超过200。所以容量规划必须按所有共享方峰值之和来计算而不是只看单个链路的均值。4. 团队协作与周报写法复盘4.1 需求变更处理一次善意加需求引发的连锁反应周二下午产品同学过来沟通说希望在报表导出功能里加一个包含退款订单的过滤选项。这个需求听起来很小就一个复选框的事。但真正评估下来涉及查询SQL的改动、前端筛选项的调整、导出模板的列变动还要补一批退款订单的测试数据整体至少要多出两到三天的工作量。当时团队里有两个声音一个觉得顺手做掉反正导出都上线了加个条件不算难另一个认为应该排到下一个迭代。我最后拍板这周不加但把设计文档和测试用例提前准备好下迭代开工直接复用。理由很简单本周已经有两个核心目标在收尾临时插入看起来再小的需求都会打断所有人的上下文切换还容易让支付回调优化这个本来就紧张的目标进一步延期。产品同学当时有点不情愿事后复盘时他也承认如果当时顺手做了很可能导致导出功能灰度期间的回归问题没人管。这里我总结的经验是需求变更管理里最危险的其实不是变更本身而是看起来很小的变更。越小的变更越容易被低估、被顺手做掉然后在不经意的地方引发连锁反应。4.2 复盘感悟周报写的是决策记录不是流水账第三十二周的周报我修改了三版才最终定稿。第一版是标准的流水账式写法周一改代码周二联调周三排查线上问题周四写文档。写完自己读了一遍感觉像工作日志完全没有信息增量领导看完只会知道你干了活但不知道你解决了什么问题。于是重写改成结果决策下一步的结构。每个项目下面不再写做了什么而是写遇到了什么选择、为什么这么选、结果如何、下一步要怎么做。比如报表导出这件事核心不是我实现了异步导出而是我为什么否决了同步方案、线程池参数怎么定的、文件为什么必须上OSS。这些才是以后可以拿出来复用、值得让团队其他人看到的内容。我后来还养成一个习惯每周周报里固定有一节叫本周最重要的一个决策。如果这一周想不起来有什么值得一提的决策说明这一周的产出质量需要打问号。这个习惯倒逼我在日常工作中更留意自己做的选择和取舍而不是只顾着把任务清单一项项划掉。4.3 第三十三周的目标规划基于这周的复盘我对下一周的工作有四个安排。第一继续推进支付回调成功率优化当前99.94%距离目标还差0.01个百分点方向是补偿机制和失败重试策略的细化重点分析剩余失败样本里的超时原因和重复回调场景。第二报表导出功能灰度范围从30%扩大到60%同时盯着连接池监控防止流量上涨后出现新的瓶颈。第三把本周排查Redis连接池的经验整理成一份《异步任务依赖隔离规范》下周团队内部分享避免其他业务线踩同样的坑。第四需求侧开启退款订单导出方案的设计评审目标是在第三十四周进入开发。我特别想强调第三点。很多团队总在同一个地方跌倒两次就是因为把问题定位在参数配小了这个表面上没有把共享依赖需要做隔离这个原则沉淀出来。一份规范文档看起来不产生代码但它能节省未来不知道多少个小时的排查时间。最后再分享一个我自己写周报的收尾习惯我会在每周五下班前把周报里提到的所有数据点都核实一遍包括监控截图、参数改动、上线记录。这不是为了应付谁而是因为周报里写的每个数字都可能是未来某个问题的排查线索。像这周99.94%这个数字如果当时随手写成基本达标下周做分析时就不会有紧迫感去翻那0.03%的失败样本了。周报也别写太长控制在三屏以内因为没人愿意看超过三屏的周报。重点永远是这周解决了什么、决策依据是什么、下一步要推到哪。
企业数字化 ERP 产品动态
相关推荐
ESXi将USB硬盘映射为本地磁盘并创建VMFS的完整实操指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 7:33:38
开源LLM代码审查工作流:CLI+Git原生集成实践 1. 项目概述:这不是一个“工具”,而是一套可落地的开源代码审查工作流open-code-review 这个名字乍看像某个具体软件,但实际它代表的是一类正在快速成型的新型开发实践——用开源、透明、可审计的方式,把大语言模型(LL… · 2026/9/25 7:33:38
用Trellis驯服AI编码代理:规范文件如何让代码不再失控 1. AI编码代理的失控时刻:为什么没人敢放手让它写代码如果你这段时间用过Cursor、Windsurf这类AI编程工具,八成已经体会过那种"又爽又怕"的感觉。爽的是,一个前端页面、一个后台接口、一段脚本,敲几行提示词就出来了&am… · 2026/9/25 7:33:38
SVM检测恶意URL:37维手工特征与线性核工程实践 简介:本资源是一套基于机器学习的恶意URL检测实战项目,面向计算机、人工智能、大数据等专业的本科生及初阶开发者,适用于课程设计、毕业设计与安全算法入门实践。项目完整实现从URL特征提取、模型训练(含SVM等经典算法)… · 2026/9/25 7:53:39
Atlas 300V 24G推理加速卡上高效部署YOLOv5全流程指南 先来说个真实经历。入职第二年接手了一个园区安防项目,甲方丢过来一批盒子,点名要跑YOLOv5做实时检测,厂家给的资料就一行字:Atlas 300V 24G推理卡。当时团队里没人碰过昇腾,第一反应是这卡到底能不能用来训练… · 2026/9/25 7:53:39
SQL注入绕过登录原理与防御:从拼接逻辑到实战靶场 第一次在 PortSwigger Academy 上做 SQL 注入绕过登录(Login Bypass)这个实验的时候,我其实有点不以为然。万能密码这东西听起来像十几年前的考古内容,总觉得在参数化查询、ORM 普及的今天,早就没什么实战价值了。但真… · 2026/9/25 7:53:39
Atlas 300V 24G NPU上部署YOLO:从环境配置到性能优化 最近有人问我“Atlas”是什么,说实话第一反应是数据库中间件那头大象,结果他后面跟了一句“部署YOLO”,又补了个“300V 24G”,我立马就明白他说的其实是昇腾Atlas系列的AI加速卡。这名字在AI领域有点被说烂了,因为它既… · 2026/9/25 7:53:33
昇腾Atlas 300V 24G加速卡部署YOLO全流程实战 1. 先搞清楚Atlas 300V 24G的定位:是加速卡,但不是你以为的那种加速卡1.1 一张卡解决什么问题看到热搜里连续出现“atlas部署yolo”和“atlas 300v 24g 是运算加速卡吗”这两条,我就知道又有一批做边缘AI或服务器推理的同学被这张卡吸引过来了… · 2026/9/25 7:53:27
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37