一、前言
随着用户量级的快速增长,vivo 官网商城 v1.0 的单体架构逐步暴露出弊病:模块愈发臃肿、开发效率低下、性能呈现瓶颈、系统维护艰难。
从 2017 年开始启动的 v2.0 架构降级,基于业务模块进行垂直的零碎物理拆分,拆分进去业务线各司其职,提供服务化的能力,独特撑持主站业务。
商品模块是整个链路的外围,模块的增多重大影响零碎的性能,服务化革新势在必行。
本文将介绍 vivo 商城商品零碎建设的过程中遇到的问题和解决方案,分享架构设计教训。
二、商品零碎演进
将商品模块从商城拆分进去,独立为商品零碎,逐步向底层倒退,为商城,搜寻,会员、营销等提供根底标准化服务。
商品零碎架构图如下:
后期商品零碎比拟芜杂,蕴含业务模块比拟多,如商品流动业务、秒杀业务,库存治理,随着业务的一直倒退,商品零碎承载更多的业务不利于零碎扩大和保护。
故思考逐步将商品业务逐步下沉并作为最底层、最根底的业务零碎,并为泛滥调用方提供高性能的服务,上面介绍商品零碎的降级历史。
2.1 商品流动、赠品剥离
随着商品流动的一直增多,玩法多样,同时与流动相干的额定属性也相应减少,这些都并不是与商品信息强关联,更偏差于用户营销,不应该与外围商品业务耦合在一起,故将其合并入商城促销零碎。
赠品不仅仅是手机、配件,有可能会是积分、会员等,这些放在商品零碎都不适合,也不属于商品模块的内容,故同步将其合并入商城促销零碎。
2.2 秒杀独立
家喻户晓,秒杀流动的特点是:
- 限时:工夫范畴很短,超过设置的工夫就完结了
- 限量:商品数量很少,远低于理论库存
- 访问量大:价格低,能够吸引十分多的用户
基于以上个性,做好一个秒杀流动不是欲速不达,因为零碎资源共享,当突发的大流量冲击会造成商品零碎其余业务拒绝服务,会对外围的交易链路造成阻塞的危险,故将其独立为独自的秒杀零碎,独自对外提供服务。
2.3 代销零碎成立
咱们商城的次要销售品类还是手机以及手机配件等,商品的品类比拟少,为了解决非手机商品品类不丰盛的问题,经营思考与出名电商进行单干,冀望引入更多的商品品类。
为了不便后续扩大,以及对原有零碎的不侵入性,咱们通过思考专门独立出一个子系统,用于承接代销业务,最初冀望做成一个齐备平台,后续通过提供凋谢 API 的形式让其余电商被动接入咱们业务。
2.4 库存剥离
库存治理的痛点:
- 因为咱们的库存都是到商品维度,仅仅一个字段标识数量,每次编辑商品都须要为商品调整库存,无奈动静实现库存治理;
- 同时营销零碎也有本人流动库存管理机制,入口扩散,关联性较弱;
- 可售库存和流动库存治理的根据都是理论库存,造成容易配置谬误。
基于以上痛点,同时为了更不便经营治理库存,也为将来应用理论库存进行销售打下基础,咱们成立库存核心,并提供以下次要性能:
- 与 ecms 理论库存进行实时同步;
- 能够依据理论库存的仓库散布状况,计算商品的预计发货仓库和发货工夫,从而计算商品预计送达工夫;
- 实现低库存预警,能够依据可用库存、均匀月销等进行计算,动静揭示经营订货。
三、挑战
作为最底层的零碎,最次要的挑战就是具备稳定性,高性能,数据一致性的能力。
3.1 稳定性
- 防止单机瓶颈:依据压测抉择适合的节点数量,不节约,同时也能保障沟通,能够应答突发流量。
- 业务限流降级:对外围接口进行限流,优先保证系统可用,当流量对系统压力过大时将非核心业务进行降级,优先保障外围业务。
- 设置正当的超时工夫:对 Redis、数据库的拜访设置正当超时工夫,不宜过长,防止流量较大时导致利用线程被占满。
- 监控 & 告警:日志规范化,同时接入公司的日志监控和告警平台,做到被动发现问题并及时。
- 熔断:内部接口接入熔断,避免因为内部接口异样导致本零碎受到影响。
3.2 高性能
多级缓存
为了晋升查问速度,升高数据库的压力,咱们采纳多级缓存的形式,接口接入热点缓存组件,动静探测热点数据,如果是热点则间接从本地获取,如果不是热点则间接从 redis 获取。
读写拆散
数据库采纳读写拆散架构,主库进行更新操作,从库负责查问操作。
接口限流
接入限流组件,间接操作数据库的接口会进行限流,避免因为突发流量、或者不标准调用导致数据库压力减少,影响其余接口。
不过晚期也踩过一些坑:
1、商品列表查问造成 redis key 过多,导致 redis 内存不够的危险
因为是列表查问,进行缓存的时候是对入参进行 hash,获取惟一的 key,因为入参商品较多,某些场景下入参是随时变动的,依据排列组合,会造成根本每次申请都会回源,再缓存,可能造成数据库拒绝服务或者 redis 内存溢出。
计划一 :循环入参列表,每次从 redis 获取数据,而后返回;
这个计划解决了 key 过多导致内存溢出的问题,然而很显著,它减少了很多的网络交互,如果有几十个 key,可想而知,对性能会有不小的影响,那有什么其余方法能缩小网络交互呢,上面咱们看计划二。
计划二 :咱们通过对原有的 Redis 组件进行加强,因为 Redis 集群模式不反对 mget,故咱们采纳 pipeline 的形式实现,先依据 key 计算出其所在的 slot,而后聚合一次性提交,这样每个商品数据只需缓存一次即可,同时采纳 mget 也大大晋升了查问速度。
这就即解决了 key 值过多的问题,也解决了计划一中屡次网络交互的问题,通过压测比照,计划二比计划一性能晋升 50% 以上,key 越多,成果越显著。
2、热点数据,导致 redis 单机瓶颈
商城常常有新品发布会,发布会完结后会间接跳转到新品商详页,此时新品商详页就会呈现流量特地大且突发、数据繁多,这就导致 Redis 节点负载不均衡,有些 10% 不到,有些达到 90% 多,而一些惯例的扩容是没有成果的。
针对热点问题咱们有以下解决方案:
- key 的散列,将 key 扩散到不同的节点
- 采纳本地缓存的形式
开始咱们采纳的是基于开源的 Caffeine 实现本地缓存组件,本地主动计算申请量,当达到肯定的阀值就缓存数据,依据不同的业务场景缓存不同的工夫,个别不超过 15 秒,次要解决热点数据的问题。
起初替换成咱们本人研发的热点缓存组件,反对热点动静探测,热点上报,集群播送等性能。
3.3 数据一致性
1、对于 Redis 的数据一致性比拟好解决,采纳“Cache Aside Pattern”:
对于读申请采纳先读缓存,命中间接返回,未命中读数据库再缓存。对于写申请采纳先操作数据库,再删除缓存。
2、因为库存剥离进来,保护入口还是在商品零碎,这就导致存在跨库操作,平时的单库事务无奈解决。
开始咱们采纳异样捕捉,本地事务回滚的形式,操作麻烦点,但也能解决这个问题。
起初咱们通过开源的 seata 实现分布式事务组件,通过改写代码引入公司的根底组件,目前曾经接入应用。
四、总结
本篇次要介绍商城商品零碎如何进行拆分、并缓缓下沉为最根底的零碎,使其职责更加繁多,可能提供高性能的商品服务,并分享在此过程中遇到的技术问题和解决方案,后续会有库存零碎的演进历史、分布式事务相干内容,敬请期待。
作者:vivo 官网商城开发团队 -Ju Changjiang