试着探索高并发下的系统架构面貌

前言

以前端入行编码,但是对后端架构也非常感兴趣。一直以来都觉得那些做到在洪水流量面前保持系统提供高可靠,高性能的服务的小哥哥们都很厉害。总想着去学习一番,因此大半年来不断学习后端相关的知识,试图去理解高并发架构的面貌。

当然,本文仅仅是试着探索而已,并没有相关实践的经历,也只能从理论的角度去推演,从现有可参考的资料中去堆砌一个在我看来合理的架构方案。限于作者水平有限,因此难免行文难免有误,亦或是对整个系统的理解上理想化了,欢迎各位指出不足。同时,本文不会详实的阐述提到的每个细节,因为本身自己对细节的把控也不到位,另外也是希望大家能够在本文的基础上自己去详细了解这些技术。

基本架构图

核心技术点

在作者看来,本文偏向于考虑如何做到高并发和高可用,因此一些性能优化的点则可能不作为重点言及,一是因为性能优化点过于繁多,会造成篇幅过长,另外也是因为具体的细节作者也未经实践不敢在这里细究。因此,列出以下这些在作者看来最为重要的核心技术点。

  1. 智能DNS解析调度
  2. 负载均衡
  3. 消息服务
  4. CDN配合对象存储服务
  5. Redis缓存
  6. 分库分表

通过横向叠加机器解决并发突增问题,这是架构设计的一项最基本要求。

技术详解

智能DNS解析调度

在所有用户的都是通过同一域名www.qq.com获取服务的情况下,想要将流量分散到多个负载均衡节点,必须要依赖DNS的解析。

DNS解析最简单的可以通过添加多条A记录将域名映射到多个IP地址来达到分流的目的。看到许多资料,往往只提到这个层面,然后抛出了问题:调度算法简单,往往是动态轮询,而部署的机器之间可能会存在性能差异或者当下健康状况不同,简单的轮询并不能满足实际需求。
因此,经过一番搜索,发现了dnspod这样的第三方DNS解析服务提供设置权重,这样一来就可以针对机器的状况不同进行不同的权重配比。通过配比权重,基本上,就可以完成DNS解析的负载均衡了。

但是作者一直好奇,这些第三方的DNS解析厂商如何工作,因此在查阅资料之后,将原理总结如下:
在DNS解析中,我们购买域名后,可以设置对应域名的权威DNS解析服务器。以访问www.qq.com.为例,DNS解析首先会递归查找对应域名的IP地址。一直查找到根域.,根域让我们去问com.的权威服务器, 之后去问qq.com.的权威服务器,再问www.qq.com.的权威服务器,这时候我们终于找到了www.qq.com.的权威服务器ns-edu1.qq.com.ns-edu2.qq.com.,权威服务器经过一系列算法最后给了我们请求域名的IP地址。

DNS解析图

购买域名后,域名往往被默认的设置为平台默认的DNS解析服务器上,我们也可以对其进行更改,比如设置到dnspod,并自己在dnspod进行配置。对于一些大厂,也可以通过自行架设DNS解析服务器并编写自定义的规则进行处理来达到高度定制化的管控。常见的管控如下:

  • 通过识别用户是电信网还是联通网,将对应的网络内部署的服务器地址返回,以避免用户请求的跨网,跨网会带来一定的网络传输性能的下降
  • 识别用户归属地,分配到最近的服务器以减少网络传输的距离

最后需要注意的是DNS解析的更改的实时性存在很大的限制,因为各地ISP服务商刷新域名DNS的时间不一致,所以导致解析在全球生效一般需要0-72小时。

负载均衡

这里的负载均衡只特指负载均衡的节点。DNS解析后的IP地址即对应负载均衡的IP地址,请求到达负载均衡节点后,将由负载均衡节点对请求进行转发到相应的http应用处理服务器。负载均衡节点可以设置相应转发的策略,例如最简单通过将用户的ip来hash到不同的http应用服务器来分散压力,这样的好处是可以保证每次请求都打到同一台机器上。另外负载均衡节点也会监听应用服务器,并且及时隔离掉异常状态的服务器,在服务器恢复健康后,再次接入。

通过负载均衡节点接入多台应用服务器,当遇到促销等场景时,动态增加应用服务器即可满足需求。

此外,我们还需要确保负载均衡节点的高可用性。通过VRRP(Virtual Router Redundancy Protocol, 虚拟路由冗余协议)保证负载均衡节点的高可用性。原理如下:
负载均衡节点往往由2台机器通过VIP(virtual IP,负载均衡向客户端提供服务的 IP 地址)技术向用户提供服务,两台机器同时只有一台机器保持在active的状态,两台机器之间通过Keepalived技术互相监听对方的状态,如果active的机器宕机,则另一台机器自动切换到active的状态,通过冗余来保证负载均衡节点的高可用性。

消息服务

项目简单的时候,我们往往会把所有的代码耦合在一起,同步执行。诸如购买一件商品,执行下单,减库存,支付等等操作同步运行完成之后再将请求返回,造成单个请求驻留时间过长,堆积大量的请求,造成应用服务器的不可用。
通过消息服务,我们可以将这些服务解耦,并且通过将同步逻辑异步化,减少请求的驻留,从而减轻并发压力。用户操作产生消息,再通过建立另外的消费者进行消费。
我们还可以根据情况,设置消费者的策略,比如,通过拉取消息而非推送消息,来保证无论前端并发多大的流量,都可以在消息服务这里熨平,消费者根据自己的能力拉取,不至于超负荷造成服务不可用。

CDN配合对象存储服务

CDN这个技术基本上写代码的人都知道,说优化的时候大家都能提到,可是过往也一直没有真正的设置过CDN的使用,这次专门去腾讯云上查看了下配置,并了解了下策略。

首先,用户准备一个域名用来作为CDN的分发域名,这里比如说qian-img.tenpay.com。设置qian-img.tenpay.com的别名CNAME为CDN厂商给我们提供的域名比如说tenpay.com.CDN.dnsv1.com,之后还需要设置源站(ip/域名)即你静态文件实际存放的机器地址。这样对qian-img.tenpay.com的请求都会打到对应的CDN域名上,CDN域名也会解析到最近的CDN节点上,并且递归查找资源,类似于DNS解析。当没有找到资源的时候,才会去用户设置的源站IP上去获取资源。这样对自己的静态资源源站的性能要求会大大减少,系统性能也会大大提高。

而源站的资源管理上也推荐使用对象存储服务,相比与使用自己搭建服务器的文件系统。对象存储服务,也可以存储任意形式的非结构化的数据,并且高可用、高稳定、强安全。

Redis缓存

Redis是基于内存的键值对数据库,IO性能远远高于基于文件系统的数据库。对一个接口的请求的多个请求过程中,往往数据并没有产生变化,如果每次都去数据库中去查询,则会造成数据库压力过大,同时接口性能下降,通过将数据缓存在Redis这样的内存键值对数据库中可以大大提高系统的性能。

分库分表

常用的数据库诸如MySQL都是基于文件系统,而文件系统是基于磁盘,整个系统中,磁盘的IO可以说是最慢的一个地方。因此数据库往往是系统的性能瓶颈,分库分表,是最常用的策略。

单个数据库存在并发连接数上线单位是百,因此面对海量的请求,是无能为力的。因此需要通过分库来将压力分担到不同的数据库机器上,以承载高并发的请求。分库的策略可以简单的根据用户UID的尾号进行水平拆分,同时分库后,单个数据库的记录数也减少了,读写性能也得到提高。

写在最后

大半年前,在公司听后端童鞋讲解后端架构的时候,很多东西都是一脸懵逼,大半年里不断认知学习,认识上终于有不少进步。学无止境,需要去学习的还有很多~
行将毕业,7月入职,希望在未来工作中能够在Web这一块有更加深入的认识。

分享 留言