在做一站式日淘全品类平台开发时,我接手过一个早期项目——所有业务逻辑塞在一个服务里,雅虎代拍、煤炉秒切、乐天中古商品抓取全挤在一起 。当时每次改代码都提心吊胆:改一个雅虎出价接口的逻辑,一不小心就把煤炉自动代拍的下单流程搞崩了。更头疼的是,日亚的商品详情页解析和日本雅虎的竞拍数据同步用的是同一套HTTP客户端配置,雅虎那边触发了反爬,日亚的采集也跟着挂 。
这就是典型的单体架构之痛。后来决定用微服务重构,技术选型定了Spring Cloud + React + Ant Design 。拆分思路是按业务域来:竞拍服务(日本雅虎出价、截标监控)、代购订单服务(煤炉代购、乐天代购下单)、仓储服务、爬虫采集服务、用户资产服务。
服务拆分后第一个问题是服务间怎么通信。竞拍成功之后要通知订单服务生成采购单、通知资产服务冻结保证金,同步调用的话一个服务挂了整个链路都堵死。
我们的方案是 异步消息 + 最终一致性 。竞拍服务拍中商品后只发一个“竞拍成功”事件到消息队列,订单服务和资产服务各自消费 。核心代码如下:
// 竞拍成功事件发布
@Service
public class AuctionEventPublisher {
@Autowired
private RabbitTemplate rabbitTemplate;
public void publishBidSuccess(String auctionId, String userId, BigDecimal price) {
BidSuccessEvent event = new BidSuccessEvent();
event.setAuctionId(auctionId);
event.setUserId(userId);
event.setPrice(price);
event.setTimestamp(System.currentTimeMillis());
// 发送到竞拍业务专用交换机
rabbitTemplate.convertAndSend("exchange.auction", "bid.success", event);
}
}
这个方案在bidfans系统里已经跑了很久,核心思想是按业务划分独立交换机,每个交换机绑定专属队列,业务间消息完全物理隔离 。雅虎竞拍的消息风暴不会堵死煤炉下单的队列 。
雅虎拍卖有一个特殊性:截标前最后几秒的数据延迟会直接导致用户出价失败 。如果爬虫服务还在用同样的频率轮询所有商品,临近截标的商品很容易因为数据更新不及时而漏出价。
网关层引入了 Redis ZSet优先级队列 ,雅虎竞拍剩余5分钟截标的商品标记为最高优先级,分配独立异步协程池优先处理 。煤炉商品上新监控、乐天中古商品价格同步这些非紧急任务放到普通队列慢慢跑。
// 优先级队列调度
public class PriorityTaskScheduler {
private RedisTemplate<String, Object> redisTemplate;
public void submitTask(Task task) {
// 计算优先级分数:截标时间越近分数越高
double score = task.getDeadline() - System.currentTimeMillis();
// 分数越小越优先(距离截标越近)
redisTemplate.opsForZSet().add("task:priority", task, -score);
}
}
教训一 :别一上来就拆太细。我们最初把“商品详情”拆成独立服务,结果每次展示一个商品页面要调四五个服务,网络开销大得离谱。后来把高频读操作做了数据冗余,才把响应时间压下来。
教训二 :分布式事务能不用就不用。早期用Seata做竞拍保证金扣减的分布式事务,性能损耗严重,后来改成TCC补偿模式,失败了走人工对账,反而更稳。
这套微服务架构后来成了不少挖煤姬平替、乐一番平替平台的技术参考——毕竟日淘代购这个赛道,系统稳定比什么都重要。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70049657/viewspace-3174992/ ,如需转载,请注明出处,否则将追究法律责任。