小米抢购系统的成长史

大家对下面这个排队的场景应该非常熟悉,这个是小米手机抢购的用户排队交互图,大家看到这些排队的兔子时,说明也有很多用户在同一时间向小米抢购系统提交了购买请求。

小米抢购系统后端服务面临巨大的压力,下图可以反映小米抢购系统面临的瞬间峰值压力。这张图截取2015年米粉节大秒服务后端其中一组LB(负载均衡层)的每分钟请求总数的情况(横轴的时间是UTC时间),如大家可以想象到的一样,峰值流量是普通情况下流量的近10倍。

以上是小米抢购活动时后端服务集群面临的压力,小米抢购系统从2011年底诞生到成长为一个扛过2次米粉节和多次爆品首发的高性能、高可靠的峰值系统,经历了很多次大大小小的架构演进。

1、抢购系统的诞生

2011底,在小米手机首批30万全部发完货之后,接下来便是大家熟知的,每周二中午十二点,小米手机开放购买。在开放购买期间,海量的用户请求瞬间冲击过来,对于一个初创公司,特别是一个刚成立不到半年的电商团队来说,面临的挑战是巨大的。第一次开放购买,在小米商城主站进行,在瞬时压力下,整个主交易系统并没有逃脱挂掉的命运。开放购买活动是结束了,但是一周之后,下一轮的开放购买已经开始开放预约,开放购买会如期而至,为了保证下次开放购买顺利进行,留给小米网工程师团队的时间是有限的,只有短短的7天时间。

经过技术团队讨论,为了避免抢购时的峰值流量压垮整个小米网,决定设计一套独立的抢购系统。预约用户通过在这套独立的抢购系统中抢到购买资格,购买资格会异步的由资格数据同步模块同步到用户的购物车中,从用户抢到手机那一时刻起,在规定的时间内,用户小米商城完成下单和支付。

从此这版独立的抢购系统承接了小米的所有的抢购,经历过大大小小的优化与重构,最后又演化为整个小米网的限流峰值系统。这版最初的抢购系统内部代号:TD。

接下来简单描述下这版抢购系统设计的出发点和技术点

出发点

  1. 并发能力要尽量的高,能承受瞬时的峰值;

  2. 不能超卖(可容忍小量的超卖);

  3. 只有预约用户可以购买,一个用户只能买一台;

  4. 要非常可靠,购买记录不可丢失;

TD技术架构图

小米第一版抢购系统使用的技术栈: LVS + nginx + PHP + node.js + redis;

  • 预约用户信息缓存在远端缓存集群中,一主多从结构,具体在放号的过程中,对预约数据只有查询操作;

  • 放号业务逻辑层使用PHP开发(当时小米网PHP开发者居多),使用远端缓存作为数据中心,存放用户的购买记录,同时,每放一个资格号,记录一条持久化的log(资格日志),保障用户购买记录可靠;

  • 使用node.js开发的资格日志收集及统计模块logagent,收集资格日志,并将资格日志发送到远端的logserver;同时,logagent统计自己所在的机器上购买记录的条数,由于事先均等的分配好每台机器的商品销售数量,当机器上购买成功的日志条数大于等于分配的数量时,则在本地生成一个.Lock的文件;

  • PHP开发的放号业务逻Middle集群中服务可能会辑中首先会检查.Lock的文件是否存在,来标志这台机器上的资格数是否被放完;同时,logserver将用户购买成功的资格同步到购物车及其他相关服务系统中。

总结
1) 可伸缩性强:PHP开发的放号逻辑不持有状态数据,状态数据存在远端数据中心或者由logagent控制生成本地文件锁(.Lock)标识,伸缩性强;
2) 数据的可靠性:抢购成功记录以日志的形式记录,保障数据可靠性;

该系统经过不间断的优化,满足了2012年及2013年上半年的抢购需求,应对的预约量在100万级别。

问题点
1) 单机处理能力有限:由于单机处理能力有限,如果要应对千万级别的预约量时,假设不暴漏伸缩性问题的话,需要的资源数量是否能承担的起?
2) logserver 处理能力: logserver的管理能力有限,随着抢购人数的增多,并发量的增加,当前逻辑下,每秒放的资格数量会增加,logserver是否能够及时的处理这些资格记录?

基于上述问题,接下来我们来看小米第二版 抢购系统,也可以理解为第一版的加强版。

2、限流服务助力抢购系统扛过百万并发

2013年7月份,小米发布了红米手机,并与QQ空间合作首发,1分钟内预约达到30万,半个小时预约量达到100万,72小时预约量突破500万,小米手机的预约量从此进入了千万级别,面对如此惊人的预约量,像之前分析的那样,如何在短时间内应对这个突发的量级变化呢?(红米手机发布前,技术团队并不清楚将要面临的挑战)。

经过技术团队讨论之后,决定在抢购系统之前加一层限流服务,将流量限制在TD能够处理的能力范围之内,由此便演进出一个新的服务——限流服务,内部代号: TC。

第二版抢购系统的整体架构介绍如下:

最初的TC使用nginx+Lua开发,主要负责用户预约验证和每秒向后端放行流量控制。

  • TC在活动开始前,load预约用户数据到nginx共享内存中

  • 使用Lua开发每秒放量计数逻辑,nginx的异步IO机制加上Lua的多协程处理能力,使限流层能够达到一个很高的并发量。

  • Nginx是多进程运行,我们需要将预先限流层的每秒放行总量均摊到整个Nginx集群的进程数量上,而非按照机器数量均摊。

TC与TD之间以token的形式交互,用户从TC上取得放行资格,然后拿着这个资格去TD放量集群中请求放量,TD放行通过,才代表最终的抢购成功。

有了上述的系统结构,只要放行控制得当,再高的流量压力也不用怕了,我们也成功撑过了红米首发。

从此这个小米开放购买预约量进入了千万级别,红米2首发预约量更是在两千万级别。

尽管系统并发能力有了大大的提升,但是整个系统还有一些不足

1) 管理功能简陋:活动过程中需要人工干预活动的结束,在TD服务将商品卖完后,手动执行命令设置TC内存中指定商品的销售状态为售罄,这个误操作风险非常高,并且延迟很高,在商品售罄后不能及时的通知用户售罄状态。

2) 灵活性较弱:技术团队对于lua使用还不够灵活,TC也只能处理一些简单的业务逻辑;

3) 反应能力不足:前后端处理能力差距较大,一旦限流失误,后端很快就会崩溃,管理体系的不完善,不能瞬时响应。往往在流量高峰下,再多1秒的请求量,就有可能使整个系统发生雪崩。反应能力的不足造成,系统的可靠性下降。

在TC限流服务优化的过程中,我们调研了其他高并发的语言,如: C/C++、 scala、erlang、node.js、golang等。

从学习成本、开发效率、运维便捷性等多方面评估,我们选择使用golang开发了一版TC服务。在2013年11月,我们上线了golang版的TC服务,同时也针对这款golang版的TC限流服务和TD放号服务开发了统一的监控管理平台,由监控管理平台统一协调整个活动以及参与活动的商品的配置与状态,在整个系统流程上保证了很好的连贯性以及运营的灵活性。监控管理平台同时还负责监控各个服务的运行状态,及时报警。

小米抢购限流峰值系统架构历年演进历程相关推荐

  1. 小米抢购限流峰值系统「大秒」架构解密2

    上文介绍了[年度案例]小米抢购限流峰值系统架构历年演进历程 ,本文主要介绍最新版「大秒」系统架构. 整合的抢购限流峰值系统--「大秒」 2014年初,公司决定举办一场"米粉节"活动 ...

  2. 【年度案例】小米抢购限流峰值系统「大秒」架构解密

    编者按:高可用架构推出2015年度案例系列文章,分享在架构领域具有典型意义的年度案例,本文根据小米工程师马利超的分享记录.转载请注明高可用架构公众号ArchNotes. 马利超 小米科技的系统研发与大 ...

  3. 小米抢购限流峰值系统「大秒」架构解密 - 推酷

    小米抢购限流峰值系统「大秒」架构解密 - 推酷 小米抢购限流峰值系统「大秒」架构解密 - 推酷 posted on 2016-05-09 12:17 lexus 阅读(...) 评论(...) 编辑 ...

  4. 小米抢购限流峰值系统「大秒」架构解密

    https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=402182304&idx=1&sn=1bd68d72e6676ff ...

  5. 《程序员》2014年11月刊:电商峰值系统架构设计

    双11来临之际,<程序员>以"电商峰值系统架构设计"为主题,力邀京东.当当.小米.1号店.海尔商城.唯品会.蘑菇街.麦包包等电商企业,及商派.基调网络等服务公司,分享电 ...

  6. 《点融支付系统架构的演进》阅读有感

    <点融支付系统架构的演进>阅读有感 在点融,支付最开始是作为一个模块存在于点融的大系统之中,它缺乏统一实现.扩展性较差,我们有大概有三到四个支付渠道,每个支付渠道都有自己的端到端的实现.相 ...

  7. 【供应链架构day9】美团配送系统架构的演进之路:从MVP到规模化

    本文是美团永俊老师的分享. 写在前面 美团配送自成立以来,业务经历了多次跨越式的发展.业务的飞速增长,对系统的整体架构和基础设施提出了越来越高的要求,同时也不断驱动着技术团队深刻理解业务.准确定位领域 ...

  8. 点融支付系统架构的演进

    点融支付系统架构的演进 支付产品模块是按照支付场景来为业务方提供支付服务.这个模块一般位于支付网关之后,支付渠道之前. 它根据支付能力将不同的支付渠道封装成统一的接口,通过支付网关来对外提供服务.所以 ...

  9. 云时代架构之点融支付系统架构的演进

    点融支付系统架构的演进 支付产品模块是按照支付场景来为业务方提供支付服务.这个模块一般位于支付网关之后,支付渠道之前. 它根据支付能力将不同的支付渠道封装成统一的接口,通过支付网关来对外提供服务.所以 ...

最新文章

  1. 借助Glances Monitor,密切关注你的系统
  2. 用 JavaScript 编写测试脚本
  3. Task.Factory.StartNew 和 Task.Factory.FromAsync 有什么区别?
  4. java 图像处理两例:图像缩放与圆角图片的制作
  5. ActiveMq工作笔记002---Centos7.3安装ActiveMq
  6. cacti mysql-bin_Cacti环境搭建(LNMP环境)
  7. Java获取当前时间(二)
  8. 历史文章之机器学习和深度学习
  9. [转载]赵匡胤做事有底线
  10. 详述ArrayList类contains方法
  11. 远程计算机维修,电脑坏了不用愁,向日葵电脑远程维修省时又省力
  12. 头条 上传图片大小_遇到不会注册今日头条号,这么办?
  13. PHP的消息队列详解
  14. “白嫖”时代进入最后倒计时,网盘行业到底是怎么由盛及衰的?
  15. unity il2cpp 热更实现
  16. linux游戏主机,Steam OS界面介绍
  17. 使用Python及SMTP协议发送邮件(以163邮箱为例)
  18. Mediawiki安装经验分享
  19. 如何使用谷歌浏览器Chrome把整个网页保存成图片
  20. 看清有关 SDN 的七大认识偏差

热门文章

  1. scanf函数和printf函数
  2. poj1815最小割
  3. 极其好用好学的规则引擎 - A2D规则引擎
  4. java 线程中断(转)
  5. 【Transact-SQL】SQL Server自动把left join自动转化为inner join、以及关联时的数据重复问题...
  6. SQL SERVER 2008的SQLCMD模式
  7. WINCE6.0+S3C6410的触摸屏驱动
  8. JavaScript一步一步:JavaScript 对象和HTML DOM 对象
  9. python画图代码turtle-Python使用Turtle图形函数画图 颜色填充!
  10. python爬虫requests-Python爬虫---requests库快速上手