不知道从什么时候开始,“反向海淘”这个词频繁出现在我的技术视野里。简单来说,就是海外用户通过跨境代购平台采购国内的淘宝、1688商品,国内统一采购之后经代购集运、国际集运再配送到海外用户手中。这种模式这两年增长太快了,我记得去年有个同行跟我说,他们接入的代购系统接入了一个月的订单量就翻了将近三倍,结果系统直接崩了两天。

我们当时在做架构评审的时候就面临一个很现实的问题:传统单体架构到底还能不能撑下去?答案显然是不能。于是干脆推倒重来,基于Taocarts系统的设计理念重新规划了一套微服务架构。

  1. 为什么选择微服务架构
    先说说传统代购系统的痛点。我们之前调研过不少开源代购源码和自研代购系统,发现很多项目把采购模块和物流模块写在一起,代码耦合度高得离谱,后续想迭代集运规则、对接新物流渠道都非常困难。这类系统一般扛不住并发,订单一多就开始卡顿甚至丢数据。

Taocarts给我们的启发在于它的服务拆分思路:它不是一上来就做很重的微服务,而是先按业务边界做逻辑拆分,把商品采集、订单管理、支付结算、物流对接这些核心能力收敛到各自的服务里。我们先参考这个思路做了拆分:

商品服务(Product Service) :负责淘宝/1688商品数据的采集、清洗和同步

订单服务(Order Service) :处理用户下单、支付状态流转

代购服务(Purchase Service) :对接1688平台完成自动采购

物流服务(Logistics Service) :管理代购转运、代购集运全链路

支付服务(Payment Service) :支持多币种支付渠道

这个拆分方式的好处是,每个服务可以独立开发、独立部署、独立扩容。后来订单量上来了,我们只需要给订单服务加节点就行,不用动别的服务。

  1. 服务间通信怎么做
    服务的拆分同时带来了服务之间怎么调用的问题。同步和异步混合用比较好。

同步调用我们用了Feign,比如订单服务要去查用户信息的时候:

@FeignClient(name = "purchase-service", configuration = FeignConfig.class)
public interface PurchaseClient {
    @PostMapping("/api/purchase/create")
    Result<PurchaseOrder> createPurchase(@RequestBody PurchaseRequest request);
    
    @GetMapping("/api/purchase/status/{orderId}")
    Result<PurchaseStatus> queryStatus(@PathVariable("orderId") String orderId);
    
    @PostMapping("/api/purchase/cancel")
    Result<Void> cancelPurchase(@RequestParam("orderId") String orderId);
}

异步这块我们用RocketMQ处理下单之后的代购采购流程。用户付完款之后,订单服务直接发一条消息到MQ,代购服务订阅消息后执行采购操作。这样就算采购流程慢一点,也不会阻塞用户端的响应。

  1. 1688自动代采的实现细节
    1688自动代采系统是整个反向代购业务里技术难度比较大的部分。核心流程大致是:用户下单→解析SKU信息→调用1688开放API获取实时价格和库存→填充收货地址提交订单→轮询采购状态并同步给用户。

我们参考Taocarts的设计做了一个采购服务的核心逻辑:

@Service
@Slf4j
public class PurchaseServiceImpl implements PurchaseService {
    @Autowired
    private AlibabaApiClient alibabaClient;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PurchaseOrder createPurchase(PurchaseRequest request) {
        // 校验库存
        ProductInfo product = alibabaClient.getProductInfo(request.getProductId());
        if (product.getStock() < request.getQuantity()) {
            throw new BusinessException("库存不足");
        }
        
        // 创建代购订单
        PurchaseOrder order = new PurchaseOrder();
        order.setOrderId(generateOrderId());
        order.setProductId(request.getProductId());
        order.setQuantity(request.getQuantity());
        order.setStatus(PurchaseStatus.PENDING);
        order.setTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(request.getQuantity())));
        purchaseOrderMapper.insert(order);
        
        // 发MQ触发采购
        rocketMQTemplate.convertAndSend("PURCHASE_TOPIC", 
            new PurchaseMessage(order.getOrderId(), request));
        return order;
    }
}

关于1688 API和淘宝API,我发现一个现象:很多开发新手以为它们是一样的,其实差别挺大。1688是批发场景,批量采购的逻辑跟淘宝零售采购差别很大,直接套用很容易踩坑——轻则签名失败被限流,重则漏单导致供应链断裂。

我们的解决方案是在代购服务里做一个PlatformFactory,根据不同平台类型来加载不同的采购策略:

// Laravel Job 队列处理异步采购
public function handle() {
    $order = Order::where('status', 'paid')->first();
    $platform = $order->platform; // taobao,1688,pinduoduo
    $api = PlatformFactory::make($platform);
    $api->purchase($order->items, $order->shipping_address);
    $order->status = 'purchased';
    $order->save();
}

这个工厂模式的好处是,以后要新增一个平台的时候,加一个实现类就行,不需要去动现有的采购逻辑。

  1. 高并发场景下的性能优化
    反向海淘的订单有个特点:爆发性很强。国内电商大促期间,海外用户也会跟着下单,而且往往集中在特定时间段。

我们借鉴Taocarts的做法做了一层缓存策略:热点商品数据存在Redis里,尤其是价格、库存这些高频查询字段。实际效果是缓存命中率保持在95%以上。

另外加了一个Sentinel限流。不是每个接口都需要扛QPS,核心的是商品查询、下单、支付这几个。其他次要接口比如物流轨迹查询,降级一下也没问题。

最后提一个容易忽略的点:跨境独立站的海外面向用户,数据库选型要考虑全球化访问的需求。我们用了阿里云RDS多可用区部署,加上CDN做静态资源加速,海外用户首屏加载时间控制在了3秒以内。Taocarts在这块做得很成熟,直接给我们提供了现成的云原生部署方案做参考,降低了上手的门槛。

小结

搭建一套高可用的反向海淘系统,核心不是堆砌技术,而是边界清晰、拆分合理。从Taocarts的架构思路上我们能学到一个道理:技术选型要为业务场景服务,别为了用微服务而用微服务。先把业务边界搞清楚,再考虑怎么拆分、怎么通信、怎么优化,这样搭出来的系统才真正能用、扛得住。

反向海淘这个赛道还有挺多技术挑战值得探索,比如AI智能选品、自动化客服、跨境合规风控,以后有机会再慢慢写。

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐