2023年双十一,电商天猫开场10分钟成交额破亿的网文品牌有15个。这个数字背后,站毕是业论成千上万台服务器在零点瞬间承接的并发请求——每秒几十万次点击、加购、电商下单。网文电子商务网站能扛住这种流量,站毕靠的业论不是运气,而是电商架构设计。
我去年参与过一个中小型电商项目的网文开发,日活大概五万。站毕上线第三个月做了一次促销,业论流量翻了不到十倍,电商数据库直接挂了。网文订单表锁死,站毕用户点结算页面一直转圈,客服电话被打爆。事后复盘,问题出在两点:一是所有读写都走同一个MySQL实例,二是购物车数据存在关系型数据库里。改造成Redis缓存购物车、MySQL主从分离之后,同样的促销流量再没出过故障。这件事让我意识到,电商网站的技术核心不在于页面多漂亮,而在于数据流动的路径是否合理。
商品展示页看起来简单,实际上牵扯到搜索、排序、分页、库存状态同步。一个用户搜索“运动鞋”,后台要同时查商品库、库存库、价格库,还要根据用户画像做个性化排序。如果每次请求都实打实去查数据库,响应时间轻松超过两秒。解决办法是提前把商品数据同步到Elasticsearch,库存和价格变动时通过消息队列异步更新。用户看到的价格可能比实际价格晚几秒,但这点延迟换来了页面秒开,值得。
购物车是另一个容易踩坑的地方。早期我们用MySQL存购物车,每次加购都要写库,促销时写操作堆积,锁竞争严重。后来换成Redis Hash结构,用户ID做key,商品ID做field,数量做value。加购就是HSET,读取就是HGETALL。内存操作比磁盘快几个数量级,而且天然支持高并发。唯一要注意的是持久化策略,我们配了AOF每秒同步,宕机最多丢一秒数据,对购物车来说可以接受。
订单系统比购物车复杂得多。创建订单要扣库存、算优惠、生成支付单,这些步骤必须保证要么全成功要么全失败。我们用的是本地消息表加定时补偿。下单时先在本地事务里写订单记录和一条“待确认”消息,然后异步通知库存服务扣减。如果扣减失败,定时任务会扫描“待确认”消息重新发起。这套方案不优雅,但比分布式事务框架简单,出错时也容易排查。上线半年,没出现过超卖。
支付环节最怕的是重复支付和掉单。用户点了一次支付没反应,又点一次,结果扣了两笔钱。我们在支付网关层加了幂等控制,同一个订单号多次请求只处理第一次。支付回调也可能丢失,所以每笔支付单都有定时对账任务,每隔五分钟去支付平台查一次状态。这些兜底逻辑写起来枯燥,但少了任何一条,线上都可能出事故。
前端方面,商品列表用虚拟滚动,只渲染可视区域内的卡片。图片全部走CDN,并且根据屏幕宽度返回不同尺寸。用户滑动时预加载下一页数据,体感上几乎无等待。这些优化单看都不起眼,叠在一起,页面加载时间从3.2秒降到了0.8秒。转化率跟着涨了将近两成。
做电商网站,技术选型没有标准答案。日订单几千的时候,单体架构加缓存就够用。日订单几十万,才需要拆微服务、上分库分表。过早追求“高可用架构”,反而会让开发效率变低,故障点变多。我的判断是:先让系统跑起来,遇到瓶颈再针对性解决。电商这行,业务变化太快,技术方案得跟着业务走,而不是反过来。