关于技术探索与实践的一些经验

FullStackHero
2025-12-18 03:52
阅读 1633

上周五晚上十一点半,我瘫在工位上,盯着屏幕里 Spring Boot 应用启动日志里那行 Started Application in 8.234 seconds 发呆。窗外国贸的霓虹灯还亮着,通勤一小时回家也得凌晨了,干脆再调会儿代码吧——反正明天是周末,产品经理应该不会半夜在钉钉@我改需求(天真如我)。

我是北京一家小厂的后端开发,独立负责一条业务线。说“独立负责”,其实就是一个人扛起从需求评审、接口设计、数据库建模、联调测试到线上运维的全链路。团队不到十个人,老板信奉“小而美”,所以没有专职测试、没有 SRE,连 CI/CD 都是我用 Jenkins 搭的(别问,问就是被逼的)。最近除了搞业务,还在偷偷啃 AI 相关的东西——毕竟听说大模型要取代程序员了,得先学会怎么 prompt 才能保住饭碗(笑)。

今天想和大家聊聊我在技术探索与实战中踩过的坑、攒下的经验。不讲高大上的理论,全是血泪换来的实战经验,尤其围绕我们主力框架 Spring Boot 展开。如果你也在小厂单打独斗,或许能共鸣一二。


起因:一个“简单”的需求,差点让我原地爆炸

事情发生在去年双11前两周。产品经理突然找我:“咱们加个实时库存预警吧,商品快卖光的时候自动发企业微信通知运营。”
听起来挺简单?但现实是:

  • 我们的库存服务是单体架构,基于 Spring Boot 2.6
  • 没有消息队列(老板说“没必要,省点钱”)
  • 数据库用的是 MySQL,高并发下频繁读写已有点吃力

我当时内心 OS:这不就是典型的“又要马儿跑,又要马儿不吃草”?但 deadline 就在眼前,只能硬着头皮上。

第一版方案:定时任务轮询 + 睡觉式优化

最朴素的想法:写个 @Scheduled 定时任务,每 30 秒扫一遍库存表,发现低于阈值就发通知。

@Scheduled(fixedDelay = 30_000)
public void checkLowStock() {
    List<Product> lowStockProducts = productRepository.findByStockLessThan(10);
    for (Product p : lowStockProducts) {
        wechatService.sendAlert("【库存告急】" + p.getName() + "仅剩" + p.getStock() + "件!");
    }
}

结果上线第二天,DBA 找上门:“你这定时任务把主库 CPU 干到 90% 了!能不能别这么暴力?”
我:……(默默打开监控面板,看到 QPS 瞬间飙升)

教训一:别在生产环境裸奔轮询,尤其当数据量上去后,数据库不是你的玩具。


第二版:引入缓存 + 异步非阻塞

痛定思痛,我决定用 Redis 缓存库存状态,并采用事件驱动的方式触发检查。

具体做法:

  1. 每次下单成功后,通过 ApplicationEventPublisher 发布 StockReducedEvent
  2. 监听该事件,在异步线程中检查库存是否低于阈值
  3. 若低于阈值且未通知过,则发送预警并标记“已通知”
// 下单服务中
@Transactional
public void placeOrder(Order order) {
    // ...扣减库存逻辑
    stockService.reduce(order.getProductId(), order.getQuantity());
    
    // 发布事件
    applicationEventPublisher.publishEvent(
        new StockReducedEvent(order.getProductId())
    );
}

// 事件监听器
@Component
public class StockAlertListener {

    @Async // 开启异步
    @EventListener
    public void handleStockReduced(StockReducedEvent event) {
        Long productId = event.getProductId();
        Integer currentStock = stockService.getCurrentStock(productId);
        
        if (currentStock < 10 && !redisTemplate.hasKey("alert_sent:" + productId)) {
            wechatService.sendAlert("【库存告警】商品ID=" + productId + "库存不足!");
            redisTemplate.opsForValue().set("alert_sent:" + productId, "1", Duration.ofHours(24));
        }
    }
}

同时在 application.yml 中开启异步支持:

spring:
  task:
    execution:
      pool:
        core-size: 4
        max-size: 8

效果:数据库压力骤降,预警延迟控制在毫秒级,且避免重复通知。

但问题又来了:某天测试同学反馈,“为什么我本地调试时事件没触发?”
一查才发现:@Async 默认使用的是 SimpleAsyncTaskExecutor,每个任务新建线程,但在测试环境下事务回滚导致事件丢失。

教训二:异步 + 事务 = 高危组合。务必确保事件发布在事务提交之后,或使用可靠的消息中间件(可惜我们没有)。


技术选型的权衡:小厂的“将就”哲学

其实我知道,最佳实践是引入 Kafka/RabbitMQ 做解耦。但现实很骨感:

方案 优点 缺点 是否可行(小厂视角)
定时轮询 实现简单 DB 压力大、实时性差 ❌ 已被 DBA 列入黑名单
Spring Event + Async 无外部依赖、响应快 事务边界模糊、可靠性低 ✅ 勉强可用
引入消息队列 可靠、解耦、削峰 运维成本高、需额外服务器 ❌ 老板不同意

最后我们选择了“够用就好”的中间路线。虽然不够完美,但在资源受限下,快速交付 + 可维护性比“架构洁癖”更重要。


最近的新尝试:用 AI 辅助写 CRUD?

说到技术探索,最近我在研究怎么把 AI 融入日常开发。比如让 Copilot 帮我生成 Spring Boot 的 Repository 方法:

“帮我写一个根据商品分类和价格区间查询商品的方法”

它真能吐出:

List<Product> findByCategoryAndPriceBetween(String category, BigDecimal minPrice, BigDecimal maxPrice);

但有一次它建议我用 @Query("SELECT * FROM products WHERE ...") 写原生 SQL,结果忘了加 nativeQuery = true,直接报错:

org.hibernate.QueryException: Named parameter not bound : category

我:……AI 啊,你还是太年轻。

不过说实话,AI 确实提升了我的编码效率,尤其是在写样板代码、单元测试、文档注释时。但它替代不了我对业务的理解和对系统边界的判断——比如什么时候该加缓存,什么时候该熔断,这些还得靠人。


总结:在夹缝中成长

回顾这段经历,我最大的体会是:

  • 实战经验 ≠ 理论正确,而是在资源、时间、人力限制下找到最优解
  • Spring Boot 很强大,但别滥用它的便利性(比如乱用 @Async@Transactional
  • 小厂开发者必须“全栈思维”:既要懂代码,也要看监控、读日志、和 DBA 聊索引
  • 技术探索不能停,哪怕每天只学 30 分钟,积少成多

现在,我的库存预警服务已经稳定运行半年多,没再出过 P0 事故。上周运维甚至夸我:“你这服务,CPU 曲线平得像我的发际线。”

深夜写代码的日子还在继续,通勤依旧一小时,但每次看到自己写的系统稳稳扛住流量高峰,那种成就感,真的值了。

共勉, fellow coder。

评论 0

最热最新
暂无评论
FullStackHeroLv.1
0
影响力
0
文章
0
粉丝