小商店从0到1的系统能力构建之路

2021-02-26 18:10:11 浏览数 (1)

作者:endyxu  腾讯WXG后台开发工程师

|导语 小商店系统设计深度解析,本文将围绕快速上线、系统优化、商家入驻、商家成交四个维度的技术思考进行讲解

小程序交易开放方案包含标准低门槛版方案(小商店)以及自定义开发版方案(交易组件)。小商店是用于帮助商家免开发、0成本快速生成卖货小程序的一款低门槛的开店工具。小商店现提供商品信息发布、商品交易、直播等功能。有兴趣的朋友可以通过小程序搜索“小商店助手” 或者 https://shop.weixin.qq.com/了解更多。

小商店自立项以来,除了产品形态上在不断迭代,开发上的核心目标也在跟随着产品战略而有不同的侧重,本文主要围绕以下几个产品战略阶段展开讨论。

01

快速上线

这个时间点的开发上的核心挑战是2个月时间搭建一套电商系统雏形。

这是一个比较考验开发个人积累的阶段,因为除了“怎么快怎么来”以外,选型的时候更需要考虑以下两点:“业界怎么做”,“后面怎么升级”。

这里我们以商品及订单系统为例:

商品体系

商品体系核心主要是解决各类关系型数据,这里数据结构设计各友商们也基本大同小异。1:N的关系型,基本就是SQL表每一行存储关系树上的一条边(id, father_id),有兴趣的同学可以翻看下面文章。

参考:电商项目数据库设计 | 第二篇:商品相关表结构

订单体系

订单的设计,我们可以围绕以下的几个点来展开讨论:

1. 多维度查询问题

(1)用户维度查询

这是我们设计上的第一考虑要点,C端用户体验,这里TDSQL自带了水平分片的能力,分片路由上我们选用了useruin,一是保证C端用户查询快,二是确保数据存储均衡。

(2)订单号维度查询

由于我们选择了useruin作为shardkey,在以订单号查询时,有两个方法来避免扫所有分片,一个是在与前端的协议上,要求所有请求都带上useruin(因为一个订单号只对应一个订单),另一个方法,也是业界常用的“基因法”,既是将useruin的部分路由信息,融合到订单号的几个固定位置上。

(3)商户维度查询

在订单量过亿(目前在百万级)之前,扫描所有分片所用耗时均在50ms以内,属于可接受级别,在当前阶段没必要过度设计。后续数据量暴涨时,我们可以使用双集群相互复制模式,既多一套以商户维度分片的存储集群,将所有商户维度的请求都走该集群,不过该方案会带来两个衍生问题:1,单表数据过大问题,需要做水平切分,后面会讲;2,集群同步延迟带来的不一致问题,我们从业务角度上考虑,是属于可接受级别的,比如商家端发货,商家端可以马上看到订单状态更新,而用户端看到需要少许延时。

(4)搜索、筛选、排序

这类请求的特点是,性能消耗大,因此,业界通用做法是使用ES作为附加索引在解决。

2. 数据切分问题

(1)垂直切分

当存储空间不足时,就需要对存储做垂直切分了,这里可以订单表与ES只保留最核心的索引数据,冗余部分最常用的数据(金额)。

(2)水平切分

目前的设计主要是使用TDSQL自带的水平分片能力,以useruin作shardkey避免单表过大问题。假如后面需要优化商户维度的查询性能,则需对商户维度的存储做定制水平切分处理。

(3)数据冷热

订单的特点是时间越久被访问的频次越低,可以按照时间维度划分冷人数据,冷数据归档到便宜的存储上,既可以让数据库瘦身保持性能,同时也能降低存储成本。

参考:

大规模订单系统解读-架构篇

微信支付核心订单系统的架构是怎样实现的?

02

系统优化

由于接入场景变多,部分场景存在抢购行为(如视频号直播)或者海量导入行为(交易组件),这些场景会给系统带来一定的冲击,因此这个阶段我们核心目标就是系统稳定性建设。

系统解耦

这是常用的降低故障影响面的套路,主要分为以下几点:

(1)主次分离:将核心业务重点隔离出来,将影响到交易,且不可降级的业务为核心业务,DB层/逻辑层均独立部署

(2)读写分离:C端读 B端写的数据可做读写分离(如商品,优惠券),降低写操作对高频读的影响,并可讲读数据简化提升读性能

(3)前后端分离:前端(展示 效果)与后端(数据 业务逻辑)解耦,方便紧急情况下后端做一些降级策略

读优化

之前由于需要快速上线,整个系统基本处于裸奔无任何cache状态,这一阶段我们对整个系统的所有读调用做了梳理,说到加缓存,其实就是以下这几个套路:

电商场景下,我们可以总结出以下几类数据:

(1)商家/商品相关:核心考虑点是保护商家上架时,用户突然间一波峰的抢购冲击,这里需要在上货时主动set cache。

(2)类目/品牌相关:属于少量数据,且变动不频繁,可做全量cache

(3)用户相关:这类数据,需要考虑点是如何做到访问DB的时机与交易时机错开,这个需要因地制宜,例如直播场景下,我们需要在用户进入直播间时预热这些数据

(4)库存相关:在售时属于动态数据,无需cache,但售罄时,需要第一时间cache住售罄状态,并将多余的流量做剪枝。

(5)商品降级数据:触发降级条件时生效,数据是正常请求时随机1%的结果去set cache,后面会详细讲。

关于如何防止缓存同时大量穿透的问题,其实有很多,如做本地 分布式的两级cache,或者stable cache等。

这一块重点想讨论的是,“如何排查出系统里面有哪些地方没加缓存”,发现未知的隐患,不然某一天一波突发流量进来了,他就是一颗定时炸弹。有人说压测/测试可以吗?可以,但前提是测试case要覆盖全逻辑链路,在一套庞大的系统面前几乎不可能。

这里我们提出了一个的监控方法:

怎么理解呢?我们假设理想情况下,DB里面所有数据有加了完美缓存,那么理论上DB的GET次数为GETuv(多少个key就访问多少次,同一个key第二次访问会被cache挡住) SETpv(数据更新时,我们会删除缓存,所以需要额外访问一次DB),而实际的DB GET次数为GETpv次。因此我们可以根据该公式,对每一个DB的表做监控,如:

当曲线值远大于1(1为理想情况),且抖动明显时,可通过告警发现系统处理无缓存无优化状态。

写优化

说到写,在整个电商场景里面,最难的应该就是秒杀了,这也是经典的面试题。

秒杀场景的瓶颈在于热点库存的吞吐量,这里由于我们之前使用的是TDSQL的事务来做,基本上限是在100QPS左右。这道面试题标准的解法就是使用Redis集群代理模式来解决,这里我们主要围绕CAP理论展开讨论下实际使用中的一些注意点(面试干货)。

(1)租借式:同一条库存在某个时间节点只有一个DB可用(避免信息同步不及时带来的一致性问题),以DB为准,缓存只做代理租借,借出与归还都要写凭证,成交流水凭证也要同步给DB。

(2)平滑租借:从tdsql借出,到入账redis的过程,如何规避这个短暂不可交易状态?可以从业务上来考虑,在上架前完成租借,或者使用类似两阶段提交的模式,一次只租借部分的库存,保证任何时刻至少有一方有库存。

(3)redis可靠性:lua脚本保证操作的原子性;部署方案使用集群,双机热备,保证5个9的可用性;未知极端选择少卖,这里有一个技巧,所有扣库存的操作,都是先扣库存再写凭证,所有还库存的操作,都是先写凭证再还库存,确保库存当前值<=库存实际值。

(4)最终一致性:以写凭证成功为准,并在系统低峰基于凭证修复库存数。

(5)扩展性:动态扩容分桶模式,一个桶代理不够了,可以使用两个桶代理,这里我们可以对每个库存桶做一个令牌桶告警,当令牌桶水位超过50%时,自动将该库存桶的库存一分为二。由于库存分散在多个桶,可能会有碎片问题,但结合业务实际思考,能触发到扩容(至少2w/s以上的单key并发请求),其实货物马上就售罄了,所以碎片问题不会暴露。

柔性可用

如何做用户无感知的降级?在电商场景下,有一个核心思想很重要:调用峰值=min(库存数,同时购买人数),因为在商品售罄后,我们可以直接从一个复杂case变成简单case。

在突发大流量进来时,我们没必要去硬抗,确保有少部分用户(超过库存数)能正常交易就行,其他用户看到的其实都是静态页面。

这里我们在商详页的读请求做了简单的频率限制,超过3w/s(普遍抢购场景库存数都不超过1k)的请求自动加载降级页面。由于降级页面属于静态页面,因此我们可以直接做在CGI层的local cache,通过正常请求随机1%的流量去更新cache,这样即使有百万级以上的抢购流量进来时,我们只需简单扩容CGI层的机器即可,轻量的水平拓展。

03

商家入驻

当系统趋于稳定后,我们的部分精力会去思考如何辅助产品做好这个项目。

电商场景下,商家入驻影响因素:拉力与门槛。而我们是否可以从技术的角度去辅助产品降低门槛呢?

(1)OCR自动填表:优化用户多余的无必要操作

(2)自动识物:拍照即可为商家自动填充所需商品信息,“自动识图”的底层是“扫一扫—识物”的基础能力。基于识物的召回结果,首先对多个相关商品标题进行信息整合,通过Pointer-Generator-Network得到包含品牌、商品名和基础属性的精简标题;其次,采用基于AL-BERT的多标题的文本分类,提取精确的商品三级类目;此外,对召回的商品图集,通过DBSCAN的同款聚类、PHash的相似图去重、CNN的图像质量分排序,为商家挑选高质精美的商品主图。

(3)爬虫代替API模式:电商场景中,部分商家是基于API导入商品的,这个过程本质就是字段的copy。而其实该商品有对应的小程序页面,我们正在规划一种接入模式,商家只需告诉我们path,我们可以自己爬取。

04

商家成交

继上面的命题,商家入驻了之后,我们如何用技术的手段辅助商家促成交易呢?

(1)智能海报:转化率最高的传播方式,这里我们正在做一套类似阿里“鹿班”的系统,结合设计的模版与u2net像素级抠图算法智能生成花样百出的海报

(2)智能文案:多用于微商场景群聊传播,转化率高,但创作门槛也高,这里我们通过对抗网络生成离线生成营销文案库,在线场景通过倒排检索相关营销文案,辅助商家0成本创作

(3)智能视频:用户短视频消费时间越来越长,微商已经把广告投放到短视频生态中,这里我们结合设计的模板(PAG)与智能选图,智能魔性配乐,降低商品视频的制作成本,辅助促成交易

05

小结

本文主要围绕工程算法在不同的时期,不同产品方向目标下,所面临的问题,以及如何做好对应的技术决策的思考小结,很多细节本文没有展开。项目能够在短时间能上线,并取得不错的业务结果,背后有很多人的付出,感谢整个项目团队的共同努力。

近期热文

基于云原生基础设施的后台架构设计思考

云时代,我们需要怎样的数据库?

大数据AI时代的产品修炼之路:A/B测试

让我知道你在看

0 人点赞