mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-10-17 07:23:44 +08:00
mod
This commit is contained in:
103
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/48 | 优秀的测试工程师为什么要懂大型网站的架构设计?.md
Normal file
103
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/48 | 优秀的测试工程师为什么要懂大型网站的架构设计?.md
Normal file
@@ -0,0 +1,103 @@
|
||||
<audio id="audio" title="48 | 优秀的测试工程师为什么要懂大型网站的架构设计?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/7f/81/7f0515c5e496f2fcaf6b6cf391402281.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:优秀的测试工程师为什么要懂大型网站的架构设计?
|
||||
|
||||
上周我准备了两期答疑文章,希望可以帮助你解决在阅读前11篇文章时的一些疑问。今天,我们一起回到正题上来,讨论一下互联网的架构设计这个话题。
|
||||
|
||||
在这个话题里,我会和你分享测试工程师为什么要具备架构知识、怎么学架构知识,以及学到什么程度就可以了。同时,我会针对网站架构设计中最关键的四个主题:高性能架构设计、高可用架构设计、伸缩性架构设计,以及可扩展性架构设计,和你分享一些案例,让你切实体会到懂得架构知识在测试范围确定和用例设计等方面的重要性。
|
||||
|
||||
## 为什么要懂得网站的架构设计?
|
||||
|
||||
其实,如果你是工作在传统软件企业的工程师的话,网站的架构设计知识对你来说可能没那么重要。因为,你的测试对象是传统软件,此时你需要对你的被测软件的架构有比较深入的理解。
|
||||
|
||||
而现在如你所知,互联网企业已经占据软件产品的大半壁江山。如果你想跳出传统软件产品测试这个舒适区的话,那互联网企业将是一个最可能的去向。
|
||||
|
||||
而在互联网企业进行软件测试的话,很多时候需要针对互联网的架构来设计有针对性的测试,另外对于互联网的压力测试以及结果分析也需要对架构知识有比较清楚的认识。这时,不懂得网站架构设计知识,在开展测试时,就真的会有处处被掣肘的感觉了。更别提,这还会直接影响到你的能力提升和职业发展了。
|
||||
|
||||
在测试过程中,你可能会经常遇到诸如负载均衡器、缓存集群、数据库读写分离、消息队列、CDN、反向代理服务器和分布式数据库等概念,在测试执行中也经常会和这些系统打交道。但是,很多时候,你只是知道网站在架构设计上有这些组件,并不清楚这些组件真正的作用,在对应的测试设计时也很难做到“有的放矢”。
|
||||
|
||||
还有些时候,特别是性能测试,如果你不清楚详细的架构设计以及其中的技术细节,你可能根本无去解读和分析性能测试的报告。
|
||||
|
||||
我来举两个实际的例子吧。
|
||||
|
||||
### 基于消息队列的分布式系统测试设计的例子
|
||||
|
||||
在分布式系统的架构中,为了减少各个应用系统之间的直接耦合,往往会引入消息队列来实现解耦。
|
||||
|
||||
也就是说原本的功能实现是由系统A调用系统B来完成业务功能的,而引入了消息队列后,系统A不会再直接去调用系统B,而是将调用B所需要的数据放到了消息队列中,此时我们将系统A称为消息的生产者,然后系统B通过监听该消息队列,主动从消息队列中依次抓取数据进行系统B的处理,系统B在这种情况下称为消息的消费者。
|
||||
|
||||
通过这种方式,就完成了系统A和系统B之间的调用解耦。
|
||||
|
||||
那么,我们再来看测试的设计。测试用例的设计可以站在黑盒测试的视角,完全不需要知道消息队列的存在,而直接从业务功能的层面去设计用例。
|
||||
|
||||
但如果只这么做的话,你会发现虽然你的测试全部通过了,但是产品一旦到了线上,还可能会出现很多问题。
|
||||
|
||||
比如说,消息的生产者产生消息的速度远远大于消息消费者处理消息的速度时,很可能会造成消息队列满的情况,此时系统的行为是怎么样的?
|
||||
|
||||
显然仅仅通过黑盒测试很难完成系统性的、全面的测试。要做到系统性全面的测试设计,你就必须知道消息队列的基本原理,然后在此基础上去设计针对具体架构的测试用例和场景。
|
||||
|
||||
另外,既然我们的系统设计希望是解耦的,那么我们的测试设计也希望是解耦的。也就是说,对于一些更详细的测试,我们希望系统A和系统B可以被单独的进行测试。
|
||||
|
||||
那么,这个时候,如果是对系统A进行测试的话,你的测试验证就需要在消息队列中进行。同样的道理,如果你是对系统B进行测试的话,你就需要在消息队列中构造测试输入数据了。
|
||||
|
||||
由此可见,如果你不知道消息队列的存在以及其基本原理的话,你的测试将寸步难行。
|
||||
|
||||
### 缓存的例子
|
||||
|
||||
很多时候,在我们搭建完性能测试的基准环境,开始执行性能基准测试的时候,往往会发现系统刚开始运行时业务处理的响应时间都会相对比较长,只有当性能测试执行了一段时间后,系统的各项指标以及事务的响应时间才逐渐趋于正常。
|
||||
|
||||
为此,在做性能基准测试的时候,有经验的工程师通常都会先用性能场景对系统进行一下“预热”,然后再真正开始测试。你有想过这其中的原因吗?
|
||||
|
||||
另外,在做前端性能测试的时候,我们对于一个页面的打开时间通常会去统计两个指标,一个是首次打开时间,另一个是多次打开的时间。而且,通常来讲首次打开时间会远大于后面再次打开的时间。你有想过这其中的原因吗?
|
||||
|
||||
其实,造成上述两种情况的背后原因都是采用了缓存技术。
|
||||
|
||||
造成第一个情况的原因,是服务器端会对“热点”数据进行缓存,而不是每次访问都直接从数据库中获取数据。那么,系统刚开始运行时,由于没有任何之前的访问记录,所有数据都需要访问数据库,所以前期的事务响应时间都会比较长。但是,随着缓存的建立,后续的访问就会比较快了。这个前期对系统的“预热”过程其实是在“预热”缓存。
|
||||
|
||||
对于第二种情况也是同样的道理。浏览器端也会缓存从服务器端拿到各种静态资源,在第一次访问时这些资源都需要从服务器端获取,而后面再访问时,这些静态资源已经在浏览器的缓存中了,所以访问速度会大大加快。
|
||||
|
||||
由此可见,如果不知道缓存的存在、不理解缓存的基本原理,你就不可能从根本上理解性能测试的方法设计以及测试结果数据。
|
||||
|
||||
其实,对于缓存还有很多需要考虑的测试点,但是需要解释这些测试点就需要深入理解缓存的原理以及缓存的架构设计,因为在互联网环境下,缓存本身也是分层的,浏览器端有本地缓存、网络端有CDN缓存、数据中心前端有反向代理的缓存、应用服务器端有本地缓存,对于大规模互联网应用更有大规模的专用缓存服务器集群。所以,要有针对性的设计缓存相关的测试场景,就需要理解这些缓存的架构。
|
||||
|
||||
那么,接下来我就和你聊聊作为测试工程师应该怎么学习架构知识。
|
||||
|
||||
## 测试工程师怎么学架构知识?
|
||||
|
||||
其实,对于测试工程师来说,学习软件架构和系统架构知识的确是个不小的挑战。因为很多架构知识都是基于开发框架和系统设计的,对开发工程师来说,已经是个不小的挑战,对测试工程师来说更是一个难以驾驭的领域。
|
||||
|
||||
不过好在,同样是对架构知识的学习和掌握,不同角色的工程技术人员都有不同的视角,需要了解和掌握的全局知识和细节程度也各不相同。以消息队列知识为例:
|
||||
|
||||
- 如果你是系统架构师,那么你就不仅要掌握各个不同消息队列实现的技术细节,还清楚不同方案的优势和劣势,最关键的是能够根据业务的应用场景和特点来选择最合适的消息队列方案。
|
||||
- 如果你是软件开发人员,那么你就需要掌握消息队列的使用方法、消息push和pull的模式,以及在应用中如何以异步方式来对消息进行妥善处理,并且还要考虑到异常场景的处理。
|
||||
- 而作为软件测试人员,你需要知道消息队列的基本原理以及在被测系统中的部署情况,同时应该知道如何访问消息队列或者队列中消息的情况。在需要模拟消息进行解耦测试的场合,你还需要知道如何添加测试消息以满足测试的目的。
|
||||
|
||||
可见,对于测试人员来讲,学习架构知识应该有自己独特的视角,基本只要做到清楚原理、了解在被测系统中的部署架构,从测试的角度能够调用必要的接口就可以了。
|
||||
|
||||
那么,我们到底应该怎么来学习架构知识呢?根据我的个人经验,我认为应该遵循“由广度到深度”和“自上而下”两个基本原则。
|
||||
|
||||
**“由广度到深度”中的“广度”是指在平时工作以外的时间中,应该多注重全领域架构知识的积累,此时那些系统性地介绍架构知识的书籍或者专栏就可以给你最大程度的帮助了。**
|
||||
|
||||
因为这类资料往往已经对纷繁复杂的架构知识做了系统性地梳理。这里,我个人非常推荐极客时间李运华老师的“从0开始学架构”专栏,以及李智慧老师所著的图书《大型网站技术架构:核心原理与案例分析》。它们都能帮你从广度上积累架构知识。
|
||||
|
||||
**“由广度到深度”的“深度”是指,对于架构中某一领域的特定知识在项目中要实际使用的时候,必须要刨根问底,通过实际的测试来加深对架构知识细节的理解。**
|
||||
|
||||
**“自上而下”是指,在实际测试项目中,当需要设计涉及架构的测试用例和场景的时候,千万不要直接基于“点”来设计测试,而是应该:首先通过全局阅读理解上层架构设计;然后,在理解了架构设计的初衷和希望达成目的的基础上,再向下设计测试场景和用例。**
|
||||
|
||||
这个过程,一方面可以帮你设计出有针对性的测试用例,另一方面可以帮助你理解架构在实际项目中是如何落地的。
|
||||
|
||||
随着你经历的项目越来越多,你的架构知识就会逐渐充实丰满起来。这就好比你在走一个旋转楼梯,一直感觉自己在原地打转,但是不知不觉走了一段时间后你回头往下看的时候,就会发现已经站在了比原来更高的点上。
|
||||
|
||||
最后,我再特别提一下,对于架构知识的学习没有任何捷径可走,你必须一步一个脚印,才能达到下一个高峰。
|
||||
|
||||
## 总结
|
||||
|
||||
今天我通过消息队列和缓存两个实例给你讲解了测试工程师学习架构知识的重要性,并且从我个人的经验出发,提出了“由广度到深度”和“自上而下”的架构学习思路,最后指出了学习架构没有捷径,你必须一步一个脚印夯实自己的知识结构。
|
||||
|
||||
## 思考题
|
||||
|
||||
对于架构知识的学习,我只是给出了我的一些方法和意见,你对此还有什么其他的想法或者学习方法吗?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
123
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/49 | 深入浅出网站高性能架构设计.md
Normal file
123
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/49 | 深入浅出网站高性能架构设计.md
Normal file
@@ -0,0 +1,123 @@
|
||||
<audio id="audio" title="49 | 深入浅出网站高性能架构设计" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/12/65/120458a1f86167fce5f1194d5efef865.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:深入浅出网站高性能架构设计。
|
||||
|
||||
在上一篇文章中,我从全局的角度和你分享了测试人员学习架构知识的重要性、应该学到什么程度,以及怎么学的问题,希望你可以借此明白网站架构的why、what、how。
|
||||
|
||||
接下来,我将站在测试人员的视角,通过这个专栏的最后四篇文章,和你分享网站的高性能架构、高可用架构、伸缩性架构以及扩展性架构。希望借此机会,可以让你对网站的架构设计做到心中有数,在设计测试用例时可以做到有的放矢。
|
||||
|
||||
今天我们就先从网站高性能架构的设计开始吧。
|
||||
|
||||
性能是网站的重要指标,如果一个网站的访问速度很慢,就会直接导致大量用户的流失。所以说,性能是设计网站架构时要考虑的关键因素。也因此,网站的性能问题成了网站架构升级、优化的导火索。
|
||||
|
||||
目前,为了优化网站性能,业界出现了很多相关的架构改进方案和技术手段。而包括了这些升级、优化网站性能的方案、技术手段在内的高性能架构设计,是个很大的话题,单单依靠几篇文章是很难讲清楚的。所以,我从中精选了一些对测试工程师比较关键的概念和技术,和你展开今天的分享。
|
||||
|
||||
如果你想了解更细节的技术实现的话,可以参考我在上一篇文章中推荐的学习资料,也可以直接在留言区给我留言。
|
||||
|
||||
从全局来看,网站的高性能架构设计包括两大部分内容:一是前端性能,二是后端服务器相关的性能优化和架构设计。
|
||||
|
||||
## 前端的高性能架构
|
||||
|
||||
关于什么是前端性能,以及如何设计针对前端性能的测试,你可以直接参考第31篇文章[《工欲善其事必先利其器:前端性能测试工具原理与行业常用工具简介》](https://time.geekbang.org/column/article/17935)中的相关内容。
|
||||
|
||||
相对来说,**前端高性能架构比较直观易懂,其本质就是通过各种技术手段去优化用户实际感受到的前端页面展现时间。**
|
||||
|
||||
目前,业内的标准实践是来自于雅虎前端性能团队提出的35条原则,我已经在第29篇文章[《聊聊性能测试的基本方法与应用领域》](https://time.geekbang.org/column/article/14832)中,为你解读了其中几个比较典型的规则,你可以再回顾下。同时,你还可以访问[雅虎网站](https://developer.yahoo.com/performance/rules.html?guccounter=1)查看经典的35条规则,以及对各规则的详细解读。
|
||||
|
||||
前端的高性能架构相对于后端来讲比较容易实现,因为前端性能优化的方法是相对标准的。而且,目前的前端性能测试工具,比如我在前面文章中曾经介绍过的WebPageTest和YSlow之类的工具等,都能系统性地分析前端的性能问题,并给出对应的解决方案建议。
|
||||
|
||||
可以说,我们只要在项目开发过程中,把前端性能优化纳入了测试范围,那么一般来讲都能获得比较理想的性能优化结果。
|
||||
|
||||
## 后端服务器的高性能架构
|
||||
|
||||
后端服务器的高性能架构,业内采用的最主要的技术手段是缓存。同时,集群也可以从计算能力的角度,提升后端的处理性能。
|
||||
|
||||
### 缓存
|
||||
|
||||
可以说,在计算机的世界中,凡是想要提高性能的场合都会使用到缓存的思想。缓存是指将数据存储在访问速度相对较快的存储介质中,所以从缓存中读取数据的速度更快。
|
||||
|
||||
另外,如果缓存中的数据是经过复杂计算得到的,那么再次使用被缓存的数据时,就无需再重复计算即可直接使用。从这个意义上讲,缓存还具有降低后端运算负载的作用。
|
||||
|
||||
可见,缓存在软件系统和网站架构中几乎无处不在。当然了,在系统和软件的不同级别对应有不同层级的缓存:
|
||||
|
||||
- 浏览器级别的缓存,会用来存储之前在网络上下载过的静态资源;
|
||||
- CDN本质也是缓存,属于部署在网络服务供应商机房中的缓存;
|
||||
- 反向代理服务器本质上同样也是缓存,属于用户数据中心最前端的缓存;
|
||||
- 数据库中的“热点”数据,在应用服务器集群中有一级缓存,在缓存服务集群中有二级缓存;
|
||||
- 甚至是用于URL和服务器IP地址转换DNS服务器,为了减少重复查询的次数也采用了缓存。
|
||||
|
||||
启用了缓存后,当应用程序需要读取数据时,会先试图从缓存中读取:
|
||||
|
||||
- 如果读取成功,我们称为缓存命中,此时就可以在很大程度上降低访问数据库的时间开销。
|
||||
- 如果没有读取到数据或者缓存中的数据已经过期失效,那么应用程序就会访问数据库去获取相应的数据。获取到数据后,在把数据返回给应用程序的同时,还会把该数据写入到缓存中,以备下次使用。
|
||||
|
||||
**缓存主要用来存储那些相对变化较少,并且遵从“二八原则”的数据。这里的“二八原则”指的是80%的数据访问会集中在20%的数据上**。
|
||||
|
||||
也就是说,如果我们将这20%的数据缓存起来,那么这些数据就会具有非常高的读写比。读写比越高,说明缓存中的数据被使用的次数也就越多,从而节省的数据库访问也就越多,缓存的优势也就越明显。
|
||||
|
||||
需要特别注意的是,**缓存技术并不适用于那些需要频繁修改的数据**。对于这种需要频繁修改的数据来说,经常会出现刚刚写入缓存的数据还没来得及被读取就已经失效了的场景。所以,在这种情况下,缓存不仅不会带来性能提升,反而会增加系统开销。
|
||||
|
||||
从理论上来讲,缓存的作用是辅助提升数据的读取性能,缓存数据丢失或者缓存不可用不应该影响整个系统的可用性,因为即使没有了缓存,数据依旧可以从数据库中获得。但是,现在的数据库已经习惯了有缓存的日子,假如哪天缓存系统奔溃了,就会在短时间内有大量的请求来访问数据库,数据库就很可能会因为无法承受这样的并发压力而宕机。
|
||||
|
||||
为了解决这个问题,有些网站会使用缓存热备等技术手段来提供缓存的高可用性,即:当某台缓存服务器宕机的时候,会将缓存访问切换到热备的缓存服务器上。
|
||||
|
||||
另外,如果你采用了分布式缓存服务器集群的话,那么缓存的数据将被分布到集群中的多台服务器上,当其中一台服务器宕机的时候,也只会丢失一部分缓存数据,此时通过访问数据库来重建这些缓存数据的开销并不算太大。
|
||||
|
||||
目前,分布式缓存架构的主流技术方案有两种:
|
||||
|
||||
- **一种是,在企业级应用中广泛采用的JBoss Cache**。JBoss Cache需要在缓存集群中的每台机器上同步所有缓存的副本,当集群规模比较大的时候,同步代价会很高。而且,多份副本也会造成存储资源的浪费。但其最大的优点是速度非常快,所以JBoss Cache更适用于企业级规模不是很大的缓存集群。这种企业级的集群一般在几台到十几台服务器的规模。
|
||||
<li>**另一种是,在互联网应用的主流Memcached**。Memcached属于互不通信的分布式架构,集群中各个节点缓存的数据都不一样,缓存使用者基于Hash一致性算法来定位具体的内容到底缓存在集群中的哪个节点。<br />
|
||||
因此,Memcached具有缓存容量大,存储效率高,可以很方便地支持集群的扩展,但是速度相对较慢的特点。这些特点决定了Memcached非常适用于现如今的互联网产品架构,几乎成为了网站分布式缓存架构的代名词。</li>
|
||||
|
||||
互联网产品架构的应用服务器集群规模一般都很大,即使小规模的应用集群也有上百台机器,规模大的话可以达到上万台,这种架构下的缓存集群规模要求也非常大。
|
||||
|
||||
通过上面这些些缓存的基础知识,再结合着你在平时项目中积累的相关经验,相信你已经理解了缓存的原理。那么,接下来我们再从测试人员的视角来看看,在执行测试时需要考虑到哪些与缓存相关的测试场景:
|
||||
|
||||
- 对于前端的测试场景,需要分别考虑缓存命中和缓存不命中情况下的页面加载时间。
|
||||
- 基于缓存过期测试策略的设计,需要考虑到必须要重新获取数据的测试场景。
|
||||
- 需要针对可能存在的缓存“脏数据”,进行有针对性的测试。缓存“脏数据”,是指数据库中的数据已经更新,但是缓存中的数据还没来得及更新的场景。
|
||||
- 需要针对可能的缓存穿透进行必要的测试。缓存穿透,是指访问的数据并不存在,所以这部分数据永远不会有被缓存的机会,因此此类请求会一直重复访问数据库。
|
||||
- 系统冷启动后,在缓存预热阶段的数据库访问压力是否会超过数据库实际可以承载的压力。
|
||||
- 对于分布式缓存集群来说,由于各集群使用的缓存算法不同,那么如果要在缓存集群中增加更多节点进行扩容的话,扩容对原本已经缓存数据的影响也会不同。所以,我们需要针对缓存集群扩容的场景,进行必要的测试和性能评估。
|
||||
|
||||
### 集群
|
||||
|
||||
集群也是提升网站性能和并发处理能力的典型架构设计方法。
|
||||
|
||||
当一台服务器不足以满足日益增长的用户流量时,我们就可以考虑使用多台服务器来组成一个集群:外部请求将统一和负载均衡器打交道;负载均衡器根据不同的负载调度算法,将访问请求传递给集群中的某台服务器处理。
|
||||
|
||||
需要注意的是,在这种模式下,集群中的任何一台服务器宕机都不会给整个系统带来明显的影响。此时,每台服务器的地位也都不怎么高,我们可以直接替换掉出现了问题的某台服务器。同样地,当需要支持更大的系统负载时,我们就可以在集群中添加更多的服务器。
|
||||
|
||||
这时,集群中的每台服务器都可以被随时替换或者淘汰掉,就像“牲口”似的可以任人宰割。所以,这种模式,就有点类似于“牲口”模式。
|
||||
|
||||
与“牲口”模式对应的是“宠物”模式,比如一些企业级的应用,它们往往不通过集群来扩展系统的能力和提高系统的性能,而是采用更为强劲的服务器。
|
||||
|
||||
这种性能非常强大的单台服务器,价格往往十分昂贵,所以通常都会被特别关照,比如给其配备最好的机房和UPS等等。另外,大家都不敢对这样的服务器有任何大的动作,生怕把它们搞坏了。此时,这些价格昂贵的服务器更像是“宠物”。
|
||||
|
||||
综上所述,现今的互联网应用采用的都是“牲口”模式。在这种模式下,我们在开展测试时,相应地需要额外关注以下这些测试点:
|
||||
|
||||
- 集群容量扩展。也就是说,集群中加入新的节点后,是否会对原有的session产生影响。
|
||||
- 对于无状态应用,是否可以实现灵活的实效转移。
|
||||
- 对于基于session的有状态应用,需要根据不同的session机制验证会话是否可以正常保持,即保证同一session始终都有同一个确定的节点在处理。
|
||||
- 当集群中的一个或者多个节点宕机时,对在线用户的影响是否符合设计预期。
|
||||
- 对于无状态应用来说,系统吞吐量是否能够随着集群中节点的数量呈线性增长。
|
||||
- 负载均衡算法的实际效果,是否符合预期。
|
||||
- 高并发场景下,集群能够承载的最大容量。
|
||||
|
||||
## 总结
|
||||
|
||||
今天,我以测试人员的视角,和你分享了网站高性能架构设计中,需要重点关注的点。
|
||||
|
||||
首先,网站的性能,在很大程度上和用户的体量有直接关系。因此,开发人员在设计网站架构时,必须要重点考虑与性能相关的架构设计。相应地,测试人员在测试网站性能时,也要考虑到这其中的架构设计。
|
||||
|
||||
其次,网站高性能架构设计,主要包括前端性能优化和后端服务器的性能调优。所以,我从这两个方面,和你展开了今天的分享。测试人员在理解了两大部分知识的基础上,在设计具体的测试时,要考虑到这些网站高性能架构设计的方案、技术手段,以此制定出需要额外增加的测试点,以及对应的测试方法。
|
||||
|
||||
最后,关于网站性能测试的理论与方法,你可以参考我在第28~34篇文章(也就是性能测试系列文章)中的相关内容。
|
||||
|
||||
## 思考题
|
||||
|
||||
在你接触过的项目中,都遇到过哪些系统层面的高性能架构设计方案?从测试的角度来看,你又会设计怎样的测试场景和用例?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
129
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/50 | 深入浅出网站高可用架构设计.md
Normal file
129
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/50 | 深入浅出网站高可用架构设计.md
Normal file
@@ -0,0 +1,129 @@
|
||||
<audio id="audio" title="50 | 深入浅出网站高可用架构设计" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/0d/8a/0dd162cbb3f2da766c6df824bf2c388a.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:深入浅出网站高可用架构设计。
|
||||
|
||||
在今天这篇文章中,我将沿着网站架构的话题,和你继续聊聊高可用的架构设计。
|
||||
|
||||
顾名思义,网站高可用指的就是,在绝大多的时间里,网站一直处于可以对外提供服务的正常状态。业界通常使用有多少个“9”来衡量网站的可用性指标,具体的计算公式也很简单,就是一段时间内(比如一年)网站可用的时间占总时间的百分比。
|
||||
|
||||
我用下面这个表格,列出了四种最常见的可用性等级指标,以及允许的系统不可用时长。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/25/30/2510233c57cf223b83b25d9d14d60d30.jpg" alt="">
|
||||
|
||||
一般,我们以“年”为单位来统计网站的可用性等级。“9”的个数越多,一年中允许的不可用时间就越短,当达到5个“9”的时候,系统全年不可用时间只有区区5分钟,可想而知这个指标非常难达到。
|
||||
|
||||
所以一般来讲,业界的网站能做到4个“9”,也就是说在一年内只有53分钟的时间网站是处于不可用状态,就已经是算是非常优秀了。
|
||||
|
||||
另外,可用性指标还有个特点,越往后越难提高,需要付出的经济成本和技术成本都会呈现类似指数级的增长。因此,在实际的网站架构设计过程中,到底需要做到几个“9”还需要结合具体的业务要求,以及风险评估来最终确定。
|
||||
|
||||
那么,接下来我就首先和你分析一下造成网站不可用的主要原因,然后再基于这些原因谈谈我们可以通过哪些对策和方法,将这些造成网站不可用的因素的影响降到最低。
|
||||
|
||||
其实,造成网站不可用的主要原因有以下三大类:
|
||||
|
||||
<li>
|
||||
服务器硬件故障;
|
||||
</li>
|
||||
<li>
|
||||
发布新应用的过程;
|
||||
</li>
|
||||
<li>
|
||||
应用程序本身的问题。
|
||||
</li>
|
||||
|
||||
## 服务器硬件故障
|
||||
|
||||
网站物理架构中,随机的硬件服务器的故障,比如某台服务器由于硬件故障宕机,可以说不是偶然,而是必然会发生的。尤其是目前互联网企业普遍采用的“牲口”模式集群方案。
|
||||
|
||||
而且随着网站规模不断扩大,网站后台的服务器数量也越来越多,所以由硬件故障引起问题的概率也是不断飙升。
|
||||
|
||||
所以,网站的高可用架构设计,需要保障的是即使出现了硬件故障,也要保证系统的高可用。
|
||||
|
||||
## 发布新应用的过程
|
||||
|
||||
网站的新版本发布过程中,往往会出现需要重新部署新的应用程序版本,然后再重启服务的情况。如果这个更新过程中不采用特殊技术手段的话,也会造成短暂的服务不可用。而且这种形式的不可用,相比服务器硬件故障的不可用更为常见。
|
||||
|
||||
原因很简单,互联网网站的功能更新迭代非常快,基本都是以“天”为单位来发布上线的,也就是说几乎每天都有需要中断服务来完成服务升级的可能。
|
||||
|
||||
显然,从业务角度来看,这种为了应用升级造成的服务不可用,完全不可能被接受。这就好比eBay或者淘宝告诉你说,我们每天某个时间段需要内部升级维护无法对外提供服务一样,让人无法接受。
|
||||
|
||||
从网站可用性指标的角度来看,这种频繁出现的停机升级过程将大大增加网站的不可用时间。因此,我们的高可用架构设计必须能够提供切实可行的方案,将这种停机升级的影响降到最小。
|
||||
|
||||
## 应用程序本身的问题
|
||||
|
||||
造成网站不可用的最后一个原因是,应用程序本身的问题。
|
||||
|
||||
比如,发布的应用程序版本身存在潜在的内存泄露,那么经过较长时间的运行积累后,最终会造成服务器的内存被占满,之后必须要靠重启服务来恢复。那么,这个时候就会引入短暂的服务不可用时间。
|
||||
|
||||
再比如,应用程序在测试环境没有经过充分的测试验证,或者说由于测试环境的配置和实际生产环境之间存在差异,有可能造成应用程序在生产环境部署完后无法使用的情况,从而造成服务不可用。
|
||||
|
||||
由此可见,应用程序在上线发布前进行充分、全面的测试,是多么的重要。无论是立竿见影就能发现的功能缺陷,还是需要长期运行才能暴露的软件问题,都可以通过软件测试去发现,然后反馈给开发人员去解决,从而避免造成系统的不可用。同时,我们也需要尽可能减少测试环境和生产环境的差异,尽可能采用完全相同的环境以及第三方依赖。
|
||||
|
||||
## 网站高可用架构设计
|
||||
|
||||
为了系统性地解决造成系统不可用的上述三类问题,提高网站的可用性,我们在网站高可用架构设计上,探索出了对应的三类方法。
|
||||
|
||||
- 第一类方法是,从硬件层面加入必要的冗余;
|
||||
- 第二类方法是,灰度发布;
|
||||
- 第三类方法是,加强应用上线前的测试,或者开启预发布验证。
|
||||
|
||||
**对于第一类硬件故障造成的网站不可用,最直接的解决方案就是从硬件层面加入必要的冗余,同时充分发挥集群的“牲口”优势。**
|
||||
|
||||
比如,对于应用服务器来说,即使没有伸缩性的要求,我们也会至少采用两台同样的服务器,并且引入一台额外的负载均衡器,所有的外部请求会先到负载均衡器,然后由负载均衡器根据不同的分配算法选择其中的某一台服务器来提供服务。
|
||||
|
||||
>
|
||||
备注:伸缩性是指通过增加或减少服务器的数量,就可以扩大或者减小网站整体处理能力。我会在下一篇文章中和你详细分享。
|
||||
|
||||
|
||||
这样,当其中一台服务器硬件出现问题甚至宕机的时候,另一服务器可以继续对外提供服务。这时,在外部看来系统整体依然是可用的,这就给恢复那台故障服务器提供了时间。而两台服务器同时出现硬件故障的概率是很低的。
|
||||
|
||||
因此,从测试人员的角度来看,知道了应用服务器集群的工作原理,就可以在设计测试的时候,针对集群中的某一个或者某几个节点的故障情况设计测试用例。
|
||||
|
||||
再比如,对于数据存储的服务器来说,往往通过数据冗余备份和失效转移机制来实现高可用。为了防止存储数据的服务器发生硬件故障而造成数据丢失,我们往往会引入多个数据存储服务器,并且会在数据有更新操作的时候自动同步多个数据存储服务器上的数据。
|
||||
|
||||
也就是说,数据的存储存在多个副本,那么当某台数据存储服务器故障的时候,我们就可以快速切换到没有故障的服务器,以此保证数据存储的高可用。
|
||||
|
||||
那么,从测试人员的角度来看,我们依旧可以针对这种情况设计出针对部分数据服务器发生故障时的测试用例,以完成系统应对故障的反应情况的测试。
|
||||
|
||||
**对于第二类由于发布新应用造成的系统不可用,我们采用的主要技术手段是灰度发布。**
|
||||
|
||||
使用灰度发布的前提是,应用服务器必须采用集群架构。假定现在有一个包含100个节点的集群需要升级安装新的应用版本,那么这个时候的更新过程应该是:
|
||||
|
||||
- 首先,从负载均衡器的服务器列表中删除其中的一个节点;
|
||||
- 然后,将新版本的应用部署到这台删除的节点中并重启该服务;
|
||||
- 重启完成后,将包含新版本应用的节点重新挂载到负载均衡服务器中,让其真正接受外部流量,并严密观察新版本应用的行为;
|
||||
- 如果没有问题,那么将会重复以上步骤将下一个节点升级成新版本应用。如果有问题,就会回滚这个节点的上一个版本。
|
||||
- 如此反复,直至集群中这100个节点全部更新为新版本应用。
|
||||
|
||||
在这个升级的过程中,服务对外来看一直处于正常状态,宏观上并没有出现系统不可用的情况。就好比是为正在飞行中的飞机更换引擎,而飞机始终处于“正常飞行”的状态一样。
|
||||
|
||||
**对于第三类应用程序本身的问题造成的系统不可用,我们一方面要加强应用程序上线部署前的测试以保证应用本身的质量,另一方面需要启用所谓的预发布验证。**
|
||||
|
||||
我们一定遇到过这样的尴尬情况:应用在测试环境中经过了完整、全面的测试,并且所有发现的缺陷也已经被修复并验证通过了,可是一旦发布到了生产环境,还是立马暴露出了很多问题。
|
||||
|
||||
这其中的主要原因是,测试环境和生产环境存在差异。比如,网络环境的限制可能不一样;再比如,依赖的第三方服务也可能不一样,测试环境连接的是第三方服务的沙箱环境,而生产环境连接的是真实环境。
|
||||
|
||||
为了避免这类由于环境差异造成的问题,我们往往会预发布服务器。预发布服务器和真实的服务所处的环境没有任何差别,连接的第三方服务也没有任何差别,唯一不同的是预发布服务器不会通过负载均衡服务器对外暴露,只有知道其IP地址的内部人员才可以对其进行访问。
|
||||
|
||||
此时,我们就可以借助自动化测试来对应用做快速的验证测试。如果测试通过,新的应用版本就会进入到之前介绍的灰度发布阶段。这种做法,可以尽最大可能保证上线应用的可用性。
|
||||
|
||||
## 总结
|
||||
|
||||
今天我和你分享了衡量网站高可用性的指标,对于一些大型网站来说,达到4个“9”(即99.99%,一年中的不可用时间不超过53分钟)已经算是优秀了。
|
||||
|
||||
然后,我将影响网站高可用的因素归为了三类,并相应地给出了解决这三类问题的方案:
|
||||
|
||||
<li>
|
||||
由服务器硬件故障引起的网站不可用,对应的解决方案是从硬件层面加入必要的冗余;
|
||||
</li>
|
||||
<li>
|
||||
由发布新应用的过程引入的网站不可用,对应的解决方案是采用灰度发布的技术手段;
|
||||
</li>
|
||||
<li>
|
||||
由应用本身质量引入的网站不可用,对应的解决方案是,一方面加强测试提高应用本身的质量,另一方面是引入预发布服务器消除测试环境和生产环境的差异。
|
||||
</li>
|
||||
|
||||
## 思考题
|
||||
|
||||
关于高可用架构设计,我在文章中和你分享了应用服务器和数据存储服务器的高可用架构。但是,我并没有介绍缓存服务器的高可用架构。那么,你认为缓存服务器是否也需要高可用架构的支持呢?如果需要的话,缓存集群的高可用架构应当如何设计?如果不需要,也请你分享一下你的理由。
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
143
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/51 | 深入浅出网站伸缩性架构设计.md
Normal file
143
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/51 | 深入浅出网站伸缩性架构设计.md
Normal file
@@ -0,0 +1,143 @@
|
||||
<audio id="audio" title="51 | 深入浅出网站伸缩性架构设计" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/2e/64/2e37d8f12384b5094239be38a3bf1364.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟,今天我分享的主题是:深入浅出网站伸缩性架构设计。
|
||||
|
||||
目前,很多测试工程师,甚至是开发工程师都一直分不清楚可伸缩性和可扩展性这两个概念,主要原因是从字面上看这两个概念的确有相似之处。但实际情况呢,可伸缩性和可扩展性这两两个概念的含义相差十万八千里,根本不具有任何可比性。
|
||||
|
||||
所以,我将通过两篇文章来和你分享,网站的伸缩性和可扩展性架构设计到底是什么,以及在设计测试用例时需要注意哪些点。
|
||||
|
||||
## 可伸缩性和可扩展性的概念区别
|
||||
|
||||
**可伸缩性翻译自Scalability**,指的是通过简单地增加硬件配置而使服务处理能力呈线性增长的能力。最简单直观的例子,就是通过在应用服务器集群中增加更多的节点,来提高整个集群的处理能力。
|
||||
|
||||
而**可扩展性翻译自Extensibility**,指的是网站的架构设计能够快速适应需求的变化,当需要增加新的功能实现时,对原有架构不需要做修改或者做很少的修改就能够快速满足新的业务需求。
|
||||
|
||||
接下来,我就先和你分享下网站的可伸缩性架构。而关于网站的可扩展性架构设计,我会在下一篇文章中和你详细分享。
|
||||
|
||||
## 分层的可伸缩性架构
|
||||
|
||||
网站的可伸缩性架构设计主要包含两个层面的含义:
|
||||
|
||||
- 一个是指,根据功能进行物理分离来实现伸缩;
|
||||
- 另一个是指,物理分离后的单一功能通过增加或者减少硬件来实现伸缩。
|
||||
|
||||
在根据功能本身进行物理分离来实现伸缩的过程中,还有两种不同的实现方式:
|
||||
|
||||
- 一种是功能的“横切”,比如一个电商网站的购物功能从上至下就可以分为界面UI层、业务逻辑处理层、公共服务层和数据库层,如果我们将这些层区分开来,每个层就可以独立实现可伸缩;
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/10/fd/10baabfe5ca950199108c230bce1b5fd.png" alt="">
|
||||
|
||||
- 另一种是功能的“纵切”,比如一个电商网站可以根据经营的业务范围(比如书店、生鲜、家电和日化用品等)进行功能模块的划分,划分后的每个业务模块都可以独立地根据业务流量和压力来实现最适合自己规模的伸缩性设计。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/40/c3/40bbc4426be6a8fc2b3c7ae38cd3c7c3.png" alt="">
|
||||
|
||||
同样地,对于单一功能可以通过增加或者减少硬件来实现的可伸缩性,也有两种不同的实现方式:
|
||||
|
||||
<li>一种是纵向的可伸缩性,指的是通过增加单一服务器上的硬件资源来提高处理能力。比如,在现有服务器上增加CPU、内存,或者在现有的RAID/SAN存储中增加硬盘等。<br>
|
||||
传统软件企业使用的“宠物”模式,就是通过这个思路来实现有限的可伸缩性,我们往往把这种方式的伸缩性称为单节点的可伸缩性。显然,在如今海量互联网流量的情况下,想仅仅依赖于某一台服务器来处理各种请求显然是不可能的。</li>
|
||||
<li>另一种是横向的可伸缩性,指的是通过使用服务器集群来实现单一功能的可扩展性。当一台机器不足以处理大量用户并发请求的时候,我们就采用多台机器组成集群来共同负担并发压力。<br>
|
||||
这种方式是基于集群的可伸缩性实现的,也是目前最主流的网站可伸缩性方法,也就是我之前提到过的“牲口”模式。很多时候当我们谈及网站的可伸缩性设计时,如果没有特定的上下文或者特指的场景,往往指的都是基于集群的可伸缩性。</li>
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/28/ba/289556cf89912d61408967bba1baafba.png" alt="">
|
||||
|
||||
基于集群的可伸缩性设计,是和网站本身的分层架构设计相对应的:
|
||||
|
||||
- 在应用服务器层面有应用服务器集群的可伸缩性架构设计;
|
||||
- 在缓存服务器层面有缓存服务器的可伸缩性架构设计;
|
||||
- 在数据库层面有数据库服务器的可伸缩性架构设计。
|
||||
|
||||
虽然都是可伸缩性设计,但是由于应用服务器、缓存服务器和数据库服务器本身的架构在设计上就有所区别,加之它们的使用场景不同,使得它们的可伸缩性架构设计就有着巨大的差异。
|
||||
|
||||
接下来,我就先简单解释一下这三个层面的可伸缩性设计指的是什么,以及从测试人员的角度来看我们需要关注哪些点。
|
||||
|
||||
## 应用服务器的可伸缩性设计
|
||||
|
||||
应用服务器的可伸缩性设计是最直观,也是最容易理解的。当一台应用服务器不足以支撑业务流量的时候,我们就可以用多台服务器来分担业务流量。
|
||||
|
||||
但是,为了保证这批服务器对外暴露的是一个统一的节点,我们就需要一个负载均衡器作为统一的窗口来对外提供服务,同时负载均衡器会把实际的业务请求转发给集群中的机器去具体执行。
|
||||
|
||||
这里需要特别注意的是,负载均衡器并不是按照你在字面上理解的“均衡”那样,把业务负载平均分配到集群中的各个节点,而是通过负载均衡算法(比如轮询算法、基于加权的轮询算法、最小链接算法等)将用户流量分配到集群机器。从这个意义上说,**将负载均衡器称为任务分配器才更合适。**
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/03/ba/035f500a8526b34c66e3f1fd7e42c0ba.png" alt="">
|
||||
|
||||
为了实现线性可伸缩性,我们希望应用本身是无状态的。此时,任何请求都可以在集群中任意节点上来执行,也就是说集群的处理能力将随着节点数量的增多呈现线性增长的态势。
|
||||
|
||||
但是,如果应用本身是有状态的,那么就会要求基于一次会话(session)的多次请求都被分配到集群中某一台固定的服务器上去执行。
|
||||
|
||||
理解了上述应用服务器集群的可伸缩性架构原理后,我们再从测试人员的角度来想想,应该考虑哪些相关的测试场景。为此,我总结了以下几点供你参考:
|
||||
|
||||
- 需要通过压力测试来得出单一节点的负载承受能力;
|
||||
- 验证系统整体的负载承受能力,是否能够随着集群中的节点数量呈现线性增长;
|
||||
- 集群中节点的数量是否有上限;
|
||||
- 新加入的节点是否可以提供和原来节点无差异的服务;
|
||||
- 对于有状态的应用,是否能够实现一次会话(session)的多次请求都被分配到集群中某一台固定的服务器上;
|
||||
- 验证负载均衡算法的准确性。
|
||||
|
||||
## 缓存集群的可伸缩性设计
|
||||
|
||||
缓存集群的可伸缩性设计,相比应用服务器集群要复杂得多。
|
||||
|
||||
**传统的缓存服务器集群是无法通过简单地加入新的节点来实现扩容的**,其中的根本原因,就要从缓存的核心原理开始讲起了。
|
||||
|
||||
假定,一个缓存集群中有3台机器,那么我们在将需要缓存的内容存入缓存集群的过程,包括了这三步:
|
||||
|
||||
- 首先,将需要缓存的内容的Key值做Hash运算;
|
||||
- 然后,将得到的Hash值对3取余数;
|
||||
- 最后,将缓存内容写入余数所代表的那台服务器。
|
||||
|
||||
而此时,如果我们在缓存集群中加入了一台新的机器,也就是说缓存集群中机器的数量变成了4。这时Key的Hash值就应该对4取余,你会发现这么一来,原本已经缓存的绝大多数内容就都失效了,必须重构整个缓存集群。而这,显然不能被接受。
|
||||
|
||||
为了解决上述这个问题,使得缓存集群也可以做到按需、高效地伸缩,那就必须采用更为先进的Hash一致性算法。这个算法可以很巧妙地解决缓存集群的扩容问题,保证了新增机器节点的时候大部分的缓存不会失效。
|
||||
|
||||
如果你想了解Hash一致性算法更详细的细节,请自行百度。
|
||||
|
||||
同样地,知道了缓存集群扩容的实现细节后,我们再从测试人员的角度出发,看看需要额外关注哪些点。这里,我总结了以下几点供你参考:
|
||||
|
||||
- 针对缓存集群中新增节点的测试,验证其对原有缓存的影响是否足够小;
|
||||
- 验证系统冷启动完成后,缓存中还没有任何数据的时候,如果此时网站负载较大,数据库是否可以承受这样的压力;
|
||||
- 需要验证各种情况下,缓存数据和数据库数据的一致性;
|
||||
- 验证是否已经对潜在的缓存穿透攻击进行了处理,因为如果有人刻意利用这个漏洞来发起海量请求的话,就有可能会拖垮数据库。
|
||||
|
||||
## 数据库的可伸缩性设计
|
||||
|
||||
从实际应用的角度来看,数据库的可伸缩性设计主要有四种方式:
|
||||
|
||||
**第一种方式是目前最常用的业务分库**,也就是从业务上将一个庞大的数据库拆分成多个不同的数据库。比如,对于电商网站来说,它们可以考虑将用户相关的表放在一个数据库中,而商品相关的表放在另一个数据库中。
|
||||
|
||||
这种方式本身也符合模块设计分而治之的思想,但最大的问题是跨数据库数据的join操作只能通过代码在内存中完成,实现代价和成本都比较高。这种方式目前在一些中大型电商有不同程度的应用。
|
||||
|
||||
**第二种方式是读写分离的数据库设计**,其中主库用于所有的写操作,从库用于所有的读操作,然后主从库会自动进行数据同步操作。这样一来,主库就可以根据写操作来优化性能,而从库就可以根据读操作来优化性能。
|
||||
|
||||
但是,这个架构最大的问题在于可能出现数据不一致的情况。比如,写入的数据没能及时同步到从库,就可能会出现数据不一致。另外,这种读写分离的设计对数据库可伸缩性的贡献来讲,比较有限,很难从根本上解决问题。
|
||||
|
||||
这种方式主要应用在中小型规模的网站中,同时读写分离的设计也通常会和业务分库的设计一起采用,来提高业务分库后的数据库性能。
|
||||
|
||||
为了进一步提高数据库的可伸缩性,于是就出现了**第三种数据库的可伸缩性设计:分布式数据库**。分布式数据库同样存在数据不一致的问题,并且,这个方法通常只在单个数据表异常庞大的时候才会被采用,否则我还是更推荐业务分库的方法。这种数据库设计可以说是比较主流的应对大规模高并发应用的数据库方案。
|
||||
|
||||
**第四种方式则是完全颠覆了传统关系型数据数据库的NoSQL设计**。NoSQL放弃了事务一致性,并且天生就是为了可伸缩性而设计的,所以在可伸缩性方面具有天然优势。因此,在互联网领域被广泛使用。
|
||||
|
||||
从测试的角度出发,无论是数据库架构哪种设计,我们一般都会从以下几个方面来考虑测试用例的设计:
|
||||
|
||||
- 正确读取到刚写入数据的延迟时间;
|
||||
- 在数据库架构发生改变,或者同样的架构数据库参数发生了改变时,数据库基准性能是否会发生明显的变化;
|
||||
- 压力测试过程中,数据库服务器的各项监控指标是否符合预期;
|
||||
- 数据库在线扩容过程中对业务的影响程度;
|
||||
- 数据库集群中,某个节点由于硬件故障对业务的影响程度。
|
||||
|
||||
## 总结
|
||||
|
||||
首先,我和你分享了可伸缩性翻译自Scalability,而可扩展性翻译自Extensibility,从英文单词的含义上我们就可以看出这两个概念间的差异了。
|
||||
|
||||
在我看来,网站的可伸缩性架构设计主要包含两个层面的含义,一个是指根据功能进行物理分离来实现伸缩,另一个是指物理分离后的单一功能通过增加或者减少硬件来实现伸缩。
|
||||
|
||||
从整体架构的角度来看,应用服务器、缓存集群和数据库服务器各自都有适合自己的可伸缩性设计策略:应用服务器主要通过集群来实现可伸缩性,缓存集群主要通过Hash一致性算法来实现,数据库可以通过业务分库、读写分离、分布式数据库以及NoSQL来实现可伸缩性。
|
||||
|
||||
而相应的理解了网站的可伸缩性架构设计后,我们在开展测试时,就可以非常自信地设计出有针对性的测试用例了。
|
||||
|
||||
## 思考题
|
||||
|
||||
你所接触的被测系统,是否采用了可伸缩性的架构设计方案?在具体开展测试的时候,你又是如何设计测试用例的呢?
|
||||
|
||||
感谢你的收听,欢迎你给我留言一起讨论。
|
||||
|
||||
|
111
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/52 | 深入浅出网站可扩展性架构设计.md
Normal file
111
极客时间专栏/软件测试52讲/测试人员的互联网架构核心知识篇/52 | 深入浅出网站可扩展性架构设计.md
Normal file
@@ -0,0 +1,111 @@
|
||||
<audio id="audio" title="52 | 深入浅出网站可扩展性架构设计" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ac/94/ac8d28fa18e9203684a158b1b1668d94.mp3"></audio>
|
||||
|
||||
你好,我是茹炳晟。今天我和你分享的主题是:深入浅出网站可扩展性架构设计。
|
||||
|
||||
在上一篇文章中,我从可伸缩性和可扩展性对应的英文术语的角度,和你分享了这两个概念的差异,并且和你详细介绍了网站的可伸缩性架构设计主要包括的内容,以及从测试人员的视角需要关注哪些点进行针对性的测试。
|
||||
|
||||
所以,在今天这篇文章,也是这个专栏最后一篇正文中,我会再和你详细讨论网站的可扩展性(Extensibility)架构设计。这里,我先带你一起回顾一下可扩展性的定义:
|
||||
|
||||
>
|
||||
可扩展性,指的是网站的架构设计能够快速适应需求的变化,当需要增加新的功能实现时,对原有架构不需要做修改或者做很少的修改就能够快速实现新的业务需求。
|
||||
|
||||
|
||||
从这个定义中,我们很容易就可以得出衡量网站可扩展性设计优秀与否的主要标准,就是增加新功能的时候对原有系统的影响是否足够小。
|
||||
|
||||
当今的商业环境决定了网站新功能开发与上线的时间周期必须非常短,如果每次添加新功能,都需要对原有系统进行大量修改,从而还会牵连出更多测试工作的话,那么你的竞争力就会被大打折扣,用一个不太恰当的比喻就是直接“输在了起跑线上”。
|
||||
|
||||
其实,你我都清楚添加新功能时必须要对系统进行大幅度修改的原因是,系统架构设计上的耦合性。那么,有什么“好的”架构设计方案可以使得我们添加新功能的时候,只需对原有系统做少量修改,甚至完全不需要修改吗?
|
||||
|
||||
咋一听起来,这就像“又要马儿跑,又要马儿不吃草”。但,其实不是的。我们往往可以通过架构上的设计优化来达到事半功倍的效果。
|
||||
|
||||
为了帮助你理解可扩展性,我先和你分享一个案例。
|
||||
|
||||
## 网站可扩展性架构设计的案例
|
||||
|
||||
假设你现在为了实时监控服务器的健康状态,需要为网站添加一个实时收集服务器端监控指标的功能,此时最直接的方案就是用代码去实现对每一个监控指标的收集,然后将所有的这些代码集成在一起形成一个可执行程序运行在服务器端后台。
|
||||
|
||||
这样的设计固然简单直接,而且也能实现所有的功能需求(收集各种监控指标),但是当你需要收集一个新的监控指标时,就不得不更新整个可执行程序了。如果你需要经常添加新的监控指标的话,那么这样的设计就不能满足可扩展性的要求了。
|
||||
|
||||
**我们希望的是,当增加新的监控指标的时候,原有的系统不需要做任何修改,甚至可以做到实时添加全新的监控指标**。为了达到这个目的,现有的其他方案都不能满足或者不容易满足这个要求,所以我们就必须要在架构设计上做些文章了。
|
||||
|
||||
我们可以把对每一个监控指标的代码实现,直接打包成一个个的可执行监控子程序,比如收集CPU使用率的程序A、收集内存使用率的程序B等,然后运行在服务器后台的监控主程序通过调用这些子程序,比如程序A和B,来实现所有的监控需求。
|
||||
|
||||
这时,再增加新的监控指标时,原有系统就不需要做任何改动,只需要独立实现新的监控子程序,然后以配置文件的形式“告诉”主程序新添加的监控子程序的路径即可。这也就实现了系统的可扩展性。
|
||||
|
||||
接下来,我们再一起回到网站的可扩展性设计上来。其实,**提升网站可扩展性性的核心,就是降低系统各个模块和组件之间的耦合**。耦合程度越低,各个模块和组件的复用可能性就越大,系统的可扩展性也会越好。
|
||||
|
||||
从现在来看,实现网站可扩展性架构的主要技术手段包括事件驱动架构和微服务架构。
|
||||
|
||||
微服务架构从根本上改变了网站的架构形式,带来可扩展性便利的同时,还带来了很多其他优秀的特性。在微服务架构下,一个大型复杂软件系统不再由一个单体组成,而是由一系列的微服务组成。其中每个微服务可被独立开发和部署,各个微服务之间是松耦合的。每个微服务仅专注于完成一件任务,并要很好地完成该任务。
|
||||
|
||||
在微服务架构下,当网站需要增加新功能时,我们除了可以添加新的业务逻辑外,还可以利用原本已经存在的微服务来构建新的功能。由于服务和服务之间是相互隔离的,并且单个服务还可以被其他多个服务复用,所以系统的可扩展性会比较好。
|
||||
|
||||
而关于微服务架构下,测试人员应该关注的测试点,建议你参考专栏的第24篇文章[《紧跟时代步伐:微服务模式下API测试要怎么做?》](https://time.geekbang.org/column/article/13581)中的相关内容。如果还有哪些不清楚的,你可以再自行查找更多的相关资料,或者给我留言一起讨论。
|
||||
|
||||
所以,在今天这篇文章中,我会和你重点分享事件驱动架构是如何提升网站的可扩展性的。
|
||||
|
||||
而事件驱动架构的落地靠的是消息队列,所以我会同时和你分享消息队列的内容。最后,我会再和你分享引入了消息队列后,从测试人员的角度来看会有哪些需要额外关注的点。
|
||||
|
||||
## 事件驱动架构与消息队列
|
||||
|
||||
事件驱动架构设计的出发点源于这样一个事实:如果系统的各个模块之间的协作不是通过直接的调用关系来实现的,那么系统的可扩展性就一定会更好。问题是,系统的各个模块间的协作如何才能不基于调用关系呢?
|
||||
|
||||
答案就是事件消息。系统各个模块之间只是通过消息队列来传输事件消息,而各模块之间并没有直接的调用关系、保持松散的耦合关系。
|
||||
|
||||
**事件驱动架构最典型的一个应用就是操作系统中常见的生产者和消费者模式,将其应用到网站设计中就是分布式消息队列。**
|
||||
|
||||
分布式消息队列同样采用了生产者和消费者模式:
|
||||
|
||||
- 消息的发送者负责将消息发布到消息队列中,也就是“生产者”;
|
||||
- 另外,系统中会有一个或者多个消息接收者订阅消息,订阅目的是为了获取消息并进行处理,这里的消息订阅者其实就是“消费者”。消息接收者发现消息队列中有新的消息后,就会立马对其进行处理。
|
||||
|
||||
可以看到,在这种模式下,消息的发送者和接收者之间并没有任何直接的联系,是松耦合的。它们的协作是通过消息队列这个“中间人”进行的。消息的发送者将消息发送至消息队列后,就结束了对消息的处理,而消息的接收者只是从消息队列中获取消息进行后续的处理,并不需要知道这些消息从哪里来,因此可以很方便地实现高可扩展性。
|
||||
|
||||
所以,采用这种模式的话,当网站需要增加新功能的时候,只要增加对应的新模块,再由对此模块感兴趣的“消费者”进行订阅,就可以实现对原有系统功能的扩展了,而对原本的系统模块本身并没有影响。
|
||||
|
||||
此时,消息队列的架构如图1所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/13/93/13baedfd3f262c91ea8875b4d0080793.png" alt="">
|
||||
|
||||
引入了消息队列后,我们不仅可以提高系统的可扩展性,还可以再一定程度上改善网站架构的高性能、高可用性和可伸缩性。
|
||||
|
||||
- 从性能方面来看,消息发送者不需要等接收者实际处理完成后才返回,也就是从原本的同步处理变成了异步处理,所以用户会感知到网站性能的提升。
|
||||
- 从高可用方面来看,假如消息的接收者模块发生了短时间的故障,此时并不会影响消息发送者向消息队列中发送消息,等到消息接收者模块恢复后可以继续后续的处理,只要这段时间内消息队列本身没有被塞满而出现消息丢失的情况。从整体角度看,系统并不会感知到消息接收者模块曾经发生过短暂故障,也就相当于保证了系统的高可用。
|
||||
- 从可伸缩性方面来看,消息队列的核心其实就是一个无状态的存储。所以,当系统需要能够保留更多的消息时,我们通过简单地增加存储空间就可以实现。尤其是,大规模的电商网站来更会将消息队列扩展成为分布式消息队列集群,来实现消息队列的可伸缩性。
|
||||
|
||||
## 引入消息队列后,测试人员需要额外关注的点
|
||||
|
||||
现在,你应该已经掌握了消息队列的基本原理,以及在网站架构中的用法。接下来,我们再一起看看消息队列对测试的影响,以及我们在测试时需要特别关注哪些点。
|
||||
|
||||
这里,我把测试人员需要额外关注的点,归纳为了以下几点:
|
||||
|
||||
<li>
|
||||
从构建测试数据的角度来看,为了以解耦的方式测试系统的各个模块,我们就需要在消息队列中构造测试数据。这也是为什么很多互联网的自动化测试框架中都会集成有消息队列写入工具的主要原因。
|
||||
</li>
|
||||
<li>
|
||||
从测试验证的角度来看,我们不仅需要验证模块的行为,还要验证模块在消息队列中的输出是否符合预期。为此,互联网的自动化测试框架中也都会集成消息队列的读取工具。
|
||||
</li>
|
||||
<li>
|
||||
从测试设计的角度来看,我们需要考虑消息队列满、消息队列扩容等情况下系统功能是否符合设计预期。
|
||||
</li>
|
||||
<li>
|
||||
除此之外,我们还需要考虑,某台消息队列服务器宕机的情况下,丢失消息的可恢复性以及新的消息不会继续发往宕机的服务器等等。
|
||||
</li>
|
||||
|
||||
## 总结
|
||||
|
||||
在今天这篇文章中,我和你分享了网站架构知识中的最后一个内容:可扩展性。
|
||||
|
||||
可扩展性指的是网站的架构设计能够快速适应需求的变化,当需要增加新功能时,我们只要对原有架构进行少量修改,甚至不用修改就能快速实现新的业务需求。
|
||||
|
||||
从技术实现上来看,消息队列是实现可扩展性的重要技术手段之一。其基本核心原理是各模块之间不存在直接的调用关系,而是使用消息队列,通过生产者和消费者模式来实现模块间的协作,从而保持模块与模块间的松耦合关系。
|
||||
|
||||
引入消息队列后,测试数据的创建和测试结果的验证工作,都需要通过读写消息队列来完成。同时,我们还要考虑到消息队列满、消息队列扩容,以及消息队列服务器宕机情况下的系统功能验证。这几个点,就是测试人员需要额外关注的点了。
|
||||
|
||||
## 思考题
|
||||
|
||||
你在实际工作中接触过哪些种类的消息队列?在测试过程中,是否遇到过和消息队列有关的缺陷呢?
|
||||
|
||||
感谢你的收听,欢迎你给我留言一起讨论。
|
||||
|
||||
|
Reference in New Issue
Block a user