亿级流量系统架构演进之路

海量用户同时进行高频访问对任何平台都是难题,也是行业乐此不疲的研究方向。但值得庆幸的是,虽然业务场景不同,设计和优化的思想却是万变不离宗。本文将结合业务与高并发系统设计的核心技术点,对系统架构调优方案进行深度剖析。

文章根据Authing身份云高级工程师罗杰林,在又拍云OpenTalk技术沙龙北京站所作主题演讲《亿级流量系统架构演进之路》整理而成,现场视频及PPT可点击阅读原文查看。

相信大家都同意,互联网发展势头的逐渐凶猛改变了我们很多的生活方式。比如网购、银行转账等业务,不再需要我们必须线下办理,这极大方便了我们的生活。这背后当然也对身为互联网从业人员的我们来说,面临的考验也越来越大,在系统架构升级上也会倾注更大的心血。

认识高并发系统

高并发系统拥有高并发、高性能、高可用,分布式、集群化,安全性等特性。

我们首先来看一下高并发、高性能、高可用,也就是我们经常提到的三高系统。当我们流量非常大的情况下,我们一定要保证这三高。这其中高并发是指要支持很多并发用户,高性能是在高并发的前提下保证优秀的性能,高可用则是保证系统在某一节点出现问题时不会整体宕机且继续持续提供服务。由此可见三高的主要特性则是分布式和集群化,而我们主要要解决的问题则是安全性。

上图是一些常见的与我们生活息息相关的高并发场景。左上电商秒杀是最常见的场景了,去年疫情期间口罩紧缺抢口罩就是这个场景,很多人在一个统一的时间去点击同一个页面,这个的并发数是特别高的。右上则是抢票,这个大家也很熟悉了,特别是春节需要回家的在外地工作的朋友们,肯定都是开个抢票软件一直刷给自己抢票的,这种的并发流量特别大。左下则是银行交易系统,我们所有的线上、线下扫码其实都需要通过银行系统,这就让它的日交易量极大。最后是Authing身份证,我们主要是给用户做整套的身份认证和用户管理体系,这个体系让开发者避免了重复构建身份的操作,减少了开发者编写的代码,提高他们的效率。以下图作为例子:

图中展示的是我们的核心组件,表面上看是一个简单的登录框,也就是用户认证界面,但是其背后有一个庞大的由用户体系、管理体系、认证体系等一系列服务组成的后台支撑。尽管用户只是进行了用户名和密码的输入,但是我们要考虑到的不仅仅是用户的安全认证、多种登录方式,还有很多用户同时认证时要如何处理等等多种事项。除此之外,我们还需要考虑到如何让包括私有化用户在内的多种类型的客户实现高可用和快速部署,完成快速集成。

CPA理论

如果有做高并发的朋友,对于CAP理论一定不陌生。它的主要观点是分布式系统无法同时满足三个,只能够满足其中两个。即分布式系统要么满足CA,要么满足CP,但无法同时满足CAP。其中的意思是说如果满足了可用性和分区的容错性,那可能意味着要牺牲一致性,进而达到最终的数据一致性。它是告诉我们要作出取舍。

从单体应用架构说起

上图中示意的单体应用构架是早期常用的模式。早期因为人手紧缺通常会将Web和Server一起开发再一起部署,之后和数据库连在一起就可以正常提供服务。这么做的优点是维护简单,但是迭代比较麻烦。

现在前后端分离后,我们通常把Web和Server分开为两个服务部署,为快速迭代提供了便利。如果我们有一个Server需要修复,我们可以单独对这个服务进行代码修改和部署,然后快速上线服务。但是它的缺点是随着业务的增多,Server包含的内容也越来越多,这会让它耦合很深进而导致服务变慢。这一点我深有体会,多年前我有个朋友架构出了问题,有段时间每到周末他会买一袋瓜子来我家一起琢磨。为什么要买一袋瓜子呢?因为耦合的太深了,服务启动要5分钟,改一个东西又要等5分钟重启,所以我们嗑着瓜子聊天等待。

类似上面提到的依赖复杂、臃肿繁杂是单体应用会遇到的一个问题,除此之外单体应用还有以下问题:

单点瓶颈

稳定差

扩展性差

业务模型缺失

新业务扩展差

业务流程基础能力缺乏

前后端耦合严重

API杂乱难维护

既然痛点如此明显,那么如何去优化就很重要。不过在谈这个问题之前需要思考一个新问题——CPU越多性能就会越好吗?

大多数情况是这样的,因为CPU可以提高运算速度。但这不是绝对的,假如我们的程序里有很多锁的概念,那就无法体现出多线程的多核性。那可能CPU的多少就不会有显著效果。一般遇到这种情况,许多公司会考虑把服务拆开。这就涉及到成本问题,也就是说增加CPU并不是最优解,我们还是需要考虑如何去优化锁。不过思考具体优化前我们可以先了解下池化技术。

上图是池化技术的抽象概念,一般获取连接以及线程用完后都会放入资源池资源池。同时我们还需要有以下四个概念:连接池、线程池、常量池、内存池。

一般用连接池较多,因为系统之间的调用、请求外部服务时都会通过请求连接来进行。曾经我们使用的是短连接,但是由于HTTP的每次连接都需要重复建立和关闭连接的过程,非常耗时,所以现在开始使用连接池。它每次请求完后创建的连接都是重复可用的,非常有助于节省开销。同时我们的任务最后都是需要拆出来的,而那些拆出来的异步任务则都放置在线程池内进行。常量池和内存池的概念是想通的,我们会申请一块大的内存复用。

了解池化技术后,我们回到具体优化。

应用架构优化

WebServer优化

首先来看一下WebServer的优化,它主要通过代码优化、热点缓存、算法优化等等步骤实现。

第一步是代码优化,将不合理的代码进行优化。比如查询接口通常都会查询很多内容,使得运算缓慢,这就需要优先进行优化。

第二步是热点缓存,将全部的热点数据进行缓存从而尽可能减少数据库的操作。比如Authing身份认证在拿到token后不可能每次进行数据库运算,这样QPS会非常慢,我们可以通过将热点数据全部缓存来提高QPS。

第三步是算法优化,因为我们的业务通常都非常复杂,所以这个概念非常广泛。比如查询一个列表,是需要一次性列出全部列表还是在内存中计算完毕后将结果返回给前端呢?这就需要针对不同的业务场景进行优化,从而提高性能。

单独部署

完成单体应用优化后,如果这些服务都部署在同一台服务器上,那可能会出现CPU和内存被占用的情况。这时候我们可以把Web、以及加载完缓存的应用程序拎出来分别部署到一个单独服务器上。同时将静态资源全部存储在CDN上,通过就近访问加快页面加载速度。通过这些方式,让我们的Auting达到了50毫秒内响应的需求。单独部署的方式也非常适合系统之间的需求,无论你是什么业务场景,如果需要提升响应速度,那大家可以考虑这个方式。

垂直拆分

之后我们需要对业务进行拆分。业务拆分有以下三种方式:

按照业务场景拆分,比如将用户、订单、账务进拆分。

按照业务是同步还是异步进拆分,这样做的好处是可以很好控制异步流量,不让它影响我们的核心服务运行。

按照模型拆分,因为业务拆分主要是为了解决系统之间耦合严重依懒性问题,为了后期尽量减少系统间的以来,所以前期的模型一定要尽可能的建设好。

在完成系统拆分后,我们需要评判优化后的系统能承载多少业务量,优化了多少。那么我就需要对它进行一次压测。压测会涉及到大家都有所了解的木桶理论,我们将系统比作一个木桶,那么木桶能够承载多少水量取决于最低的那块木板。所以压测时我们不需要


转载请注明:http://www.guyukameng.com/jspt/jspt/16537.html