速剖架构
一、先耍流氓
1 百万 QPS 大概是什么样子
服务器和数据库是一个系统里面最主要的部分,所以决定从这两个开始说起。
1、服务器集群
1.1 容量与服务器集群规模估算
当根据容量进行架构设计的时候,一般会做一个粗略的估算
估算主要指标是 QPS(query per second)、TPS(transaction per second)、PV(page view)
QPS 可理解为每秒读数量,TPS 则对应每秒写,PV 是指某段时间内的浏览数。
PV 可以根据活跃用户量和具体业务去推算
有了总量 PV,除去总时间长度,就能得出 QPS。根据 1/10 或者 2/10 可以大概估算出 TPS
假设一个网站一天 PV 为 1000w,用户集中访问的时间为一天早晚 10 个小时,则:
QPS = 1000w / (10*60*60) = 278
峰值 QPS = QPS * 2.5 = 700
假设一台 2 核 4g 服务器能支撑的 QPS 为 1000,则得出对应的关系。
1、每 1000QPS 需要一台服务器
2、每 1000w PV 需要 0.7 台服务器,实际上需要向上取整,即 1 台
如果忽略架构的其他部分,100w QPS 用 1w 台服务器组成的集群就可以撑住了。
2、数据库
虽然是耍流氓,但是如果只谈服务器而不谈数据库,就有点过于流氓了。
结论:直接撑住 100w QPS,对任何非分布式数据库来说,都是不可能完成的任务。
以 MySQL 为例,单机撑住 QPS4w 已经很好了,如果 MySQL 的部署架构为 1 主 3 从,一共 4 台机器提供读,则是 16w 的 QPS。
假设我们用 7 个 MySQL,都是 1 主 3 从部署架构,一共 28 台机器,每台 4w,就能撑住 100wQPS 了。
但是数据库是属于架构中有状态的部分,不像服务器理可以随意扩展。以这个案例来说,7 台 MySQL 以垂直或水平分库分表的形式来存储数据,那么由服务器过来的请求需要先知道去到哪一台 MySQL 获取数据。如果需要全局查询,会遇到跨数据库访问的情况。等等,这些都是需要去考虑的问题。
实际操作:数据库选型、确定数据库部署方式(主备、主从、一主多从,分区)
3、总结
经过上面两部分流氓式分析,我们大概对高并发的架构规模有了一些粗略的认识。
下一部分会对其中涉及的细节进行分析,在这个粗略的骨架中慢慢得填入细节。
二、再当暖男
嘘寒问暖,细节满满
1、“负载均衡”
1.1 真的 负载均衡
请求由用户发起,经过 DNS 域名解析,进入 4 层(包括 2、3 层)负载均衡,进入 7 层负载均衡,最终分配到业务服务器。DNS 解析后可能涉及到 cname 解析,7 层负载均衡后也可能会进入网关处理,不同的设置会有不同的细节,但主要路径是一样的。
4 层负载均衡一般是指工作在 OSI 模型 2、3、4 层的负载均衡软硬件
2 层的硬件(比如 F5)处理能力是每秒百万到千万级别,4 层采用 LVS 能达到 50w 级别
那么 100w 请求进来,需要两台 4 层负载均衡机器
7 层负载均衡采用 Nginx,每秒的处理能力在 5w 左右,100w QPS 需要 20 台安装了 Nginx 的服务器
但是此时 Nginx 还能做许多额外的事情,如根据路由规则分配请求到不同服务器,还能根据规则进行流量治理(限流、熔断等)。
不管如何,最终 100w 的请求就被均分到每台 Nginx 服务器了。
如果你是用云服务商的 SLB(server loading balance)服务,那么恭喜你,啥都不用管,流量已经被承接住并分配到配置对应的服务器了。
1.2 假的 负载均衡
一般所说的负载均衡是指 4 层、7 层负载均衡,除此之外,还有一些措施,也是为了让请求能均衡分布到各个服务器。比如根据请求的 ip 地址去分配到不同的服务器集群,这一步在 DNS 解析的时候,设置指向不同地区的服务器集群,这样就能在 4 层、7 层负载均衡之前起到流量分配的作用。
请求进入不同地区后,在 7 层负载均衡 nginx 时,可以根据业务类型,比如登录服务、支付服务、账单查询服务等,分配到不同的服务器集群。也能根据其他字段比如 UserId 去分配具体处理的服务器集群。
业务服务器根据业务类型、userid 等方式接受到流量后,当需要访问数据库等时候,也只需要访问特定的数据库集群,比如账单业务只需要访问账单数据库,这类属于数据库的垂直拆分。而当用 userid 为 key 去访问特定数据库时,这类属于数据库表的水平拆分。
我把以上这些称为假负载均衡,因为不在平时所讲的负载均衡范围内,但却起到非常大的负载均衡作用。
这样,就在第一部分的虚空骨架中填入了一部分实在的东西。
2、分级缓存
缓存的作用是减少业务服务器和数据库的压力
2.1 客户端、浏览器缓存
APP 客户端可以使用多种方式进行数据存储,如果序列化存储、SQLlite 等,可以根据业务需要缓存图片和数据。数据可以设置过期时间,比如 5 秒,这样在高峰的时候,就可以减少请求数量。
浏览器也可以做到类似的效果,当更多是静态文件的缓存。根据 header 的设置以确定是读取缓存还是重新请求。
2.2 CDN 缓存
CDN 缓存就是指用 CDN 服务商提供的地址进行文件的读取,在进入服务器之前返回用户请求的内容,并且能根据地理位置优化访问速度
2.3 web 服务器缓存
web 服务器比如 nginx 或者以 nginx 为基础开发的组件,可以设置静态和动态资源的缓存。但是需要注意的是,所设置的缓存是缓存在磁盘还是内存,两者所需的 IO 时间是区别很大的。
此外,nginx 还能通过安装插件配合分布式缓存组件 redis、memcache 进行动态缓存,这样的好处是我们对缓存的更新、失效等更加容易控制。
这样,请求在到达业务服务器前就结束了。
2.4 业务服务器缓存
业务服务器本身也可以缓存数据,比如需要生成趋势递增的订单 ID,可以先从 redis 申请一段订单 ID 缓存在业务服务器,比如一次性申请 400-499,然后缓存在本地,那么后面 99 次都不需要去申请了。 比如秒杀的时候缓存部分库存到本地,有库存的时候可以访问数据库并减库存,当本地没库存了,就不需要再去请求数据库了,因为秒杀的时候时间和库存都比较有限,而请求也会均分到各服务器。 其实这样也是属于流量治理的一部分了,大大减少了数据库的压力。
2.4 分布式缓存
redis 是目前分布式缓存的事实标准。redis 因为属于内存型数据库所以单机 QPS 很高,大概在 10w,如果采用 1 主 2 从读写分离的话,QPS 就 30w 了。当然 redis 也有集群部署的方案,性能就进一步提升了。
当缓存层层下来之后,真正进入业务服务器的流量就更少了。
缓存还有一些值得思考的问题,比如缓存的经典问题:穿透、击穿、雪崩等。
3、流量治理
3.1 容错
当请求发生错误的时候,为了避免用户重复请求或者错误请求导致系统被拖垮,需要进行熔断或者降级处理。
3.2 限流
客户端、浏览器限流:是用答题、验证码等方式平缓用户的请求量。甚至可以进行一个概率不发请求直接返回失败来减少峰值请求数。
服务端限流:当某个 api 的每秒请求数超出设计范围,则进行限流。
限流还有很多规则,可以在网关进行处理也可以在云服务商提供的面板上操作。
3.3 消息队列
消息队列也被我归类到流量治理的一部分,因为本质上就是对流量的一种控制手段。当大量请求访问某服务时,先放入消息队列,再通过一个较慢的速度从队列里面获取请求,并处理。
需要注意的时候,同步的请求会被转成异步请求,实时会变延时。
例 1: 当用户下单并付款后,清空购物车对应的物品。 清空购物车物品这个操作对用户来说并不需要实时,所以可以先放入消息队列,然后再排队处理。
例 2: 直接将用户请求放入消息队列,前端进入一个排队提示,并到一定时间再请求结果。
流量治理包含的内容非常多,反正就是用适合具体业务的方式去安排流量。
三 安稳过日子
1 容灾
1.1 服务器冗余
多搞几台服务器支撑
1.2 数据库热备、冷备
热备:类似从库,但是实时性要求会低一点。平时不提供服务,主从数据库出问题时,人工切换热备数据库
冷备:定时备份,没有随时提供服务的能力
1.3 异地多活
真正的容灾
常用:同城双中心、跨城多中心、
2 快速部署与可伸缩
2.1 容器
2.2 k8s
额,明白的都明白
3 可观测
1.1 日志
日志记录与分析。
分析日志的意义很多,比如做业务数据挖掘、分析热点数据并建立热点数据库等
一般用 kafka+elk。如果数据量很大,比如一周 100g 以上的数据,需要引入大数据组件。
1.2 链路追踪和监控
链路追踪:Zipkin, Pinpoint, Skywalking
监控:zabbix,或者云运营商的监控面板
还有类似 prometheus+Grafana 的方案
四 总结
先有骨架(大概的服务器规模、数据库规模),再填充内容(负载均衡、缓存、流量 的设计),再增加稳定运行的能力(容灾等)。这大概就是基础架构能做的事情。剩下的需要根据业务去做业务架构的建设。
版权声明: 本文为 InfoQ 作者【Dinfan】的原创文章。
原文链接:【http://xie.infoq.cn/article/4e032d45754792259ab891b27】。文章转载请联系作者。
评论