高并发架构的优化方案

应用情景:12306抢票,春运期间,一票难求!票的数量是有限的,但也罩不住中国出门打工的人多啊,如果放任所有请求去读库,哪个数据库能扛得住?

优化草案

将请求尽量拦截在上游

如果将所有的请求都落到数据层,数据读写时锁冲突严重,并发响应就会很慢,用户体验就会很差。所以可以让系统中的每一层都做些事情,不要只做一个过渡者,尽量拦截下一些无效的请求,给数据库减压。

利用缓存

12306抢票是一个典型的读多写少的应用场景,比如一个班次的票有2000张,有200w人抢票,刷票时就是读,抢到票就要写,读写比是1000:1, 是非常适合用缓存的,其实大多数企业应用都是读多写少,都可以用缓存。

系统架构

下面是一个常见的站点架构图,高并发的优化就从这张图说起。

frame.png

  • 浏览器: 与用户交互,会执行js
  • 站点层: 会访问服务层,返给浏览器界面
  • 服务层: 复杂的业务
  • 数据层: 封装访问数据的复杂,访问数据库

各层优化

客户端优化(浏览器、App)

  • 可以做防重复提交,按钮点击后置灰
  • 可以用js限制x秒内只能提交一次请求

这样可以挡住普通用户,但是挡不住一些黄牛的for循环,好的是99%的都是普通用户,最起码能拦截下80%的无效请求。

站点层优化

客户端防重复提交也只能拦住普通用户,在黄牛盛行的今天,我们是很有必要连黄牛的请求也一并拦截!那么怎么样来拦截黄牛的for循环呢?其实也是类似客户端的防重复提交,对于每次请求,我们都能拿到用户ID,结合业务我们可以对请求进行计数,判断x秒内只能透过一次请求,这个计数可以放在session中,这样就能裆下黄牛99%的for循环请求。

但是有些黄牛手里有N(=10w)个肉鸡,N个账户,同时请求。站点层的拦截就挡不住了!

服务层优化

不管怎么样,搞死不让请求落到数据库,那么我怎么拦截肉鸡的高并发请求呢?利用队列!
比如,有2000张票,有20w用户想要下单购买,请求已经到了服务层,这时候可以把请求加入队列,如果队列长度大于2000(或者大于余票)就把其他请求拦截下来。

数据层

客户端拦截了80%,站点层拦截了99%,服务层又有队列控制,数据库基本无压。

业务优化

一切脱离业务的架构都是耍流氓!比如,抢票时间可以调整一下,分时分次抢票,8点卖一批次,9点卖一批次,…。将流量均摊。其次,粒度的优化,我们有时候只关心有票和无票,二不关心具体还剩多少票,所以只需要做一个粗粒度的缓存即可。

预备

如果并发量实在太大,可以对站点层的机器进行扩充,通过增加机器来分担压力。

总结

高并发架构优化的基本思路:

  • 尽量将请求拦截在上游
  • 读多写少多用缓存
  • 结合业务来优化