架构与思维:互联网高并发架构

一、什么是高并发

  在互联网行业中,我们时常会面临着流量巨大且复杂的分布式场景。这要求我们在设计系统时,既要保证系统具有承载高并发的能力,同时能够保证系统的高可用性。所以具备高并发架构是要通过稳健的系统设计能力,来保证系统能处理复杂业务场景的同时,也能保证性能稳定性、可用性的架构体系。

高并发相关常用的一些指标有响应时间,吞吐量,并发用户数,每秒请求数QPS、每秒事务数TPS等,如下:

响应时间:系统对请求作出响应的时间,对于单用户的系统,相应时间可以很好地度量系统的性能,例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间。

吞吐量:系统在单位时间内处理请求的数量,对于并发系统,通常需要用吞吐量作为性能指标。

并发用户数:同时承载正常使用系统功能的用户数量。例如一个即时通讯系统,同时在线量一定程度上代表了系统的并发用户数。与吞吐量相比,并发用户数是一个更直观但也更笼统的性能指标。实际上,并发用户数是一个非常不准确的指标,因为用户不同的使用模式会导致不同用户在单位时间发出不同数量的请求。

TPS:吞吐量的常用量化指标,应用于特定场景的吞吐量。

QPS:每秒响应请求数。在互联网领域,这个指标和吞吐量区分没有这么明显。

二、如何提升系统的性能指标

  在互联网分布式架构设计,提高系统并发能力的方式,方法论上主要有两种:垂直扩展(Scale Up)与水平扩展(Scale Out)。

  1. 垂直扩展(Scale Up)

      (1)提升单机硬件性能,通过将内存、CPU、硬盘等升级到更高的配置来扩大系统的能力;

      (2)提升单机架构性能,例如:使用Cache来减少IO次数,使用异步来增加单服务吞吐量,使用无锁数据结构来减少响应时间;

      在互联网业务发展非常迅猛的早期,如果预算不是问题,建议使用“增强单机硬件性能”的方式提升系统并发能力,因为这个阶段,公司的战略往往是发展业务抢时间,而“增强单机硬件性能”往往是最快的方法。但不管是提升单机硬件性能,还是提升单机架构性能,都有一个致命的不足:单机性能总是有极限的。所以互联网分布式架构设计高并发终极解决方案还是水平扩展。

  2. 水平扩展(Scale Out)

      只要增加服务器数量,就能线性扩充系统性能。所以我们通过水平扩展,在架构的各个层面做水平扩容,增加实例数量,比如Services Cluster、Redis Cluster、MySQL Cluster,并在长期的业务实践中不断优化。相对于Scale Up,优势如下:

      (1)集群可以持续扩张,bat大厂核心服务的成千上万的服务集群就是很好的业内范例。

      (2)提高了可用性,水平扩容最终会把计算能力和数据能力分摊在不同的实例、不同的服务、不同机房,某个分区出问题也不会导致整个系统崩塌。

如何在架构各层进行可水平扩展的设计以及各层常见的水平扩展实践,是本文重点讨论内容。

三、常见的系统分层架构

➢Client:典型调用方是浏览器browser或者手机应用APP。

Reverse Proxy:系统入口,提供反向代理、负载均衡等能力的支持。

Web Services:Web服务层,实现核心应用逻辑,直接面向用户视觉,返回HTML页面、文档、Json信息等。

Computing Services:提供计算能力,所有繁琐的业务计算、数据存取、缓存存取。

Cache:缓存层,缓存加速访问存储。

Data:数据层,数据库固化数据存储。

要保证整个系统的高性能,不仅是对缓存层或数据层进行扩容,是整个系统各层次的水平扩展,下面我们来一一拆解。

四、分层水平扩展架构实践

1. Reverse Proxy的Scale Out

 

  通常我们使用Nginx来实现负载均衡,但单台Nginx仍有宕机的风险。所以我们就使用DNS轮询在Nginx上层做反向代理,DNS Service对于一个域名上配置了多个解析IP。每次DNS解析请求来访问DNS Service,会轮询的返回IP。而我们增加Nginx实例的时候,同时也在DNS Service上增配解析IP,这样就达到理论上的无限扩容了。如上图中,当我们有多个Nginx实例的时候,我们还可以配置keepalive做探活,以保证可用性。

2. Web Services的Scale Out

  Web Services本身就是出色的负载均衡利器,可以使用Nginx作Web Services的反向代理,以实现Web Services请求的负载均衡功能。当我们有多个服务实例时,只要在Nginx上conf文件上进行配置,就能实现强大而稳定的负载。Nginx可以调度足够多的Web Services实例,实现互联网系统高并发运行。

3. Computing Services的Scale Out

  计算服务这一层的横向扩展,可以使用Name Server模式进行处理。比如我们建立一个高可用的服务注册和发现中心。

  Alive的计算服务实例都注册到服务中心,Web服务层则订阅服务中心,获取可用的计算服务并执行调用。当明显发现计算服务无法支撑逐渐上升的流量的时候,可以部署新的计算服务实例,并自动注册到服务中心,实现平滑的动态的计算服务扩容。另外,目前服务间调用一般是去中心化的,会把订阅到的注册服务实例信息保存在本地(比如 Web 服务把计算服务地址列表保存在本地),哪怕服务中心挂了,短时间内也不影响请求的正常运转。

4. 数据层的Scale Out

  这个算老生常谈了,在网上很多人都讨论过缓存层和数据库层水平扩容的方式。在如今的互联网高速发展中,海量的数据已覆盖我们生活的每个角落。当数据过于庞大的情况下,数据层(缓存,数据库)涉及数据的水平扩展,将原本存储在一台服务器上的数据(缓存,数据库)水平拆分到不同服务器上去,以达到扩充系统性能的目的。

以数据库为例,互联网数据层常见的水平拆分方式一般有以下三种拆分方式:

4.1 按照RANGE拆分

 

  RANGE分区是根据分区键值的范围把数据行存储到表的不同分区中,并且多个分区的范围要连续,但是不能重叠,上图为例:对岗位编号共分为3个分区,岗位编号为1 ~ 25w 的对应在分区P0中,25w+1 ~ 50w 编号在分区P1中,依次类推即可,类别编号大于 50w的数据统一存放在分区P3中即可。

➢优势:判断简单,service只需判断一下id范围就能路由到对应的存储服务;数据均衡性较好;扩展简单,当超过50w的数据比较多的时候,可以随时再加一个 id(50w,75w) 的分区。

➢不足:请求的负载可能不均衡,一般来说,新注册的用户会比老用户更活跃,大RANGE的服务请求压力会更大。

4.2  按照HASH拆分

  HASH分区根据MOD(分区键,分区数)的值把数据行存储到表的不同分区中,使数据可以平均的分布在各个分区中,上图为例:对createtime进行HASH运算,以年为单位共分为3个分区。建表语句上添加一个“PARTITION BY HASH (expr)”子句,其中“expr”是一个返回整数的表达式,它可以是字段类型为MySQL 整型的一列名字,也可以是返回非负数的表达式。

➢优势:判断简单,只要对相应字段进行HASH计算一下就可以了。而且大部分情况下,数据、请求分布都可以比较均匀。比如使用日期、性别等来HASH,得到的结果一般是比较均衡的。

➢劣势:不容易扩展,扩增一个数据实例,或者HASH属性对应改变的时候,可能需要进行数据迁移。

4.3  按照LIST拆分

  LIST分区按分区键取值的列表进行分区,并且同范围分区一样,各分区的列表不能重复,如上图,对位置编号共分为2个分区,编号为46,77,89的对应在分区P0中,106,125,177类别在分区P1中。不同于RANGE的是,LIST分区的数据必须匹配列表中的位置编号才能进行分区,所以这种方式只是适合比较区间值确定并少量的情况。

  不管是哪种模式,我们通过水平扩展,将数据分摊到不同的实例甚至服务器上,以此提升了数据库单实例的性能和稳定性。

五、总结

  高性能、高可用是互联网分布式系统的架构设计中必须考虑的因素之一,通过设计保证系统能同时并行处理很多请求、能够提高稳定持久服务的时间、能够大幅降低事务处理时间。而提高系统高并发能力的方式主要有两种:垂直扩展(Scale Up)与水平扩展(Scale Out)。前者垂直扩展可以提升单机处理能力或者提升单机架构性能来提升并发性,但单机性能总归是有限的,所以互联网分布式架构设计高并发终极解决方案还是后者:水平扩展。

  在我们上面的讨论中,我们通过对各层逐层的水平扩容来实践互联网系统保持高性能高可用性的可能性,而各层次水平扩展的时间又有所不同:

  ➢Reverse Proxy 通过“DNS轮询”的方式实现IP解析的增配,以保证快速的扩容。

  ➢Nginx 通过配置conf实现对上游Web Services的扩容和负载均衡。

  ➢Computing Services通过服务注册中心实现新增服务实例的自动发现,保证水平扩容的高效和稳定

  ➢数据库可以按照数据范围,或者数据哈希的方式来进行水平扩展。

posted @   优顶特技术  阅读(606)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示