小米网秒杀系统设计经验
韩祝鹏
2013.12
讲点什么?
抢购系统产生的背景
设计方案产生的过程
没什么高大上的内容
抛出一个特殊的需求实例,供大家探讨
我是来学习的
2012年初,小米手机开放抢购,然后。。。
别人家的流量图
小米家的流量图
简直就是DDoS啊!
我们来解决这个问题!
当时抢购的现状
直接到官网去抢购
准点开始抢
十几台服务器,7、8个开发人员
PHP + Cache + MySQL结构
抢购期间,数据库锁表严重
PHP服务器进程卡死
限制条件
4,5天时间(设计开发测试上线)
3,4个开发人员
20台左右服务器
没有黑科技储备
服务器为什么撑不住?
用户抢购直接走商城
商城PHP + MySQL结构
下单流程操作多
查库存、锁表、减库存、创建订单、查收获地址、支付。。。。
PHP fpm 每台服务器600左右进程
一个环节稍慢一点,就会把PHP所有进程都卡死
带宽也撑不住啊,各种页面、资源
继续优化商城?
优化过了,效果不佳
我们组并没有直接参与商城开发 (决定性的非技术因素)
加两倍服务器也没用啊
加带宽也不行啊,成本太高了
优化程序,时间来不及
此路不通,还是果断放弃这条路吧!
怎样才能撑得住?
市场策略已定,无法更改->
抢购瞬间压力一定巨大 ->
商城无法承担此压力 ->
必须让其它系统承担此瞬时压力!
让商城均匀的承担下单的压力
第一个关键设计决策:
李代桃僵:资格抢购系统
抢购系统设计面临的问题
一定会死人的:资格放多了!
一定会死人的:资格丢失!
可能会死人的:抢购时卡住,无法抢购
暂时死不了人:配置商品,自动流程,优雅的程序结构
性能问题如何解决?
尽量减少PHP的同步操作!
单点问题:商品剩余数量如何控制?
PHP处理请求时,不去管具体的数,只要知道“是否有剩余”即可
判断文件锁是否存在!
用户预约资格、是否抢到的信息如何获取?
存Redis里
每台PHP服务器上放一个Redis从库
PHP读取本地的Redis从库
Redis主库的写操作单点压力如何解决?PHP是否会阻塞?
PHP进程不连接主Redis,也就是不会写Redis!
PHP将抢购结果信息写到Syslog里
后台进程将log异步的传输汇总到一个log_server中
log_server进程写Redis主库
好像有个问题哦
资格放号数量统计存在延迟!
关闭抢购时,数量会多那么几秒的数量
还好,死不了人的问题
有些人抢到资格,但种种原因未下单
放弃数据的实时精确性要求,换来性能
数据准确性
双保险:日志存一份,Redis存一份
开始由我手工发指令上锁结束抢购
后来改成各服务器自动根据数量上锁
后续的问题
每周一次的抢购啊,现在甚至一周两三次
自动化、配置化尤为重要
系统越来越琐碎复杂,监控系统
服务基本的单元测试,规则检测
我们还在摸索
总结
根据现实情况,冷静分析问题
在可能的解空间中寻找最优解
用排除法,将走不通的路径剪枝
核心的技术点可能很简单
合理组合低技术手段,达成目标
不断完善最初的设计
对自己的定位:程序员->工程师->创业团队一员
最后再得瑟一下
谢谢!