01-分布式架构演进

分布式架构演进

架构的本质

一个软件系统随着功能越来越多,调用量急剧增长,整个系统逐渐碎片化,越来越无序,最终无法维护和扩展,所以系统在一段时间的野蛮生长后,也需要及时干预,避免越来越无序。架构的本质就是对系统进行有序化重构,使系统不断进化。

那架构是如何实现无序到有序的呢本的手段就是分和合,先把系统打散,然后重新组合。分的过程是把系统拆分的过程是把系统拆分为各个子系统、模块、组件,拆的时候首先要解决每个组件的定位问题,然后才能划分彼此的边间,实现合理拆分。合就是根据最终要求,把各个分离的组件有机整合在一起,先对来说,第一步的拆分更难。

拆分的结果使开发人员能够做到业务聚焦、技能聚焦,实现开发敏捷,合的结果是系统变的柔性,可以因需而变,实现业务敏捷。

架构的分类

架构一般可分为业务架构、应用架构、技术架构:

  1. 业务架构从概念层面帮助开发人员更好的理解系统,比如业务流程、业务模块、输入输出、业务域。
  2. 应用架构从逻辑层面帮助开发落地系统,如数据交互关系、应用形式、交互方式、,使得整个系统逻辑上更容易理解,步入大家熟知的SOA就属于应用架构的范畴。
  3. 技术架构主要解决技术平台选型、如操作系统、中间件、设备、多机房、水平扩展、高可用等问题。

需要注意的是,系统或者架构首先都是为人服务的,系统的有序度高,应用逻辑合理,业务概念清晰是第一位。现在大家讨论更多的是技术架构,如高并发设计,分布式事务处理等,只是因为这个不需要业务上下文本经,比较好相互沟通。具体架构设计时,首先要关注业务架构和应用架构,这个架构新手要特别注意。也是面试时候的痛点。

大型网站的架构演进

从一个电商网站开始

为了更好的理解,我们用电商网站来举例,作为一个交易类型的网站,一定会具备用户(用户注册、用户管理)、商品(商品展示、商品管理)、交易(下单、支付)这些功能。

假如我们只需要支持这几个基本功能,那么我们最开始的架构应该可能是这样的:

image-20191030133402386

变化:网站从一台机器变成了两台机器,这个变化对我们来说影响非常小。单机的情况下,我们应用采用JDBC的方式来和数据库进行连接,现在数据库与应用分开了,我们只需要在配置文件中把数据库的地址从本机改成数据库服务器的IP地址就行了。对于开发、测试、部署都没有影响

调整以后我们能够缓解当前的系统压力,不过随着时间的推移,访问量继续增大的话,我们的系统还是需要做改造。

为什么这么分呢计算机本身的角度来考虑的话,一个情况的访问到处理最终到返回,性能瓶颈只会是:CUP、文件IO、网络IO、内存、等因素。而一台计算机中这些维度是有性能瓶颈的,如果某个资源消耗过多,通常会造成系统的响应速度较慢,所以增加一台机器,使得数据库的IO和CPU资源独占一台机器从而增加性能。

这个地方插入一点题外话,就是简单说一下各个资源消耗的原因:

CPU/IO/内存:

  1. 主要是上下文的切换,因为每个CPU核心在同一时刻只能执行一个线程,而CPU的调度有几种方式,比如抢占式和轮询等,以抢占式为例子,每个线程会分配一定的执行时间,当达到执行时间、线程中有IO阻塞或者有高优先级的线程要执行时。CPU会切换执行其他线程。而在切换的过程中,需要存储当前线程的执行状态并回复要执行的线程状态,这个过程就是上下文切换。比如IO、锁等待等场景下也会触发上下文切换,当上下文切换过多时会造成内核占用比较多的CPU,因为得不到足够的执行时间而效率低下。
  2. 文件IO,比如频繁的日志写入,磁盘本身的处理速度较慢、都会造成IO性能问题。
  3. 网络IO,带宽不够
  4. 内存, 包括内存溢出、内存泄漏、内存不足。

实际上不管是应用层的调用也好,还是硬件的升级也好。其实无非就是这几个因素的调整。

应用服务器负载告警,如何让应用服务器走向集群

假如说这个时候应用服务器的压力变大了,根据对应用的检测结果,可以针对性的对性能压力大的地方进行优化。我们这里考虑通过碎屏扩容来进行优化,把单击变为集群:

image-20191030140437664

引入复杂均衡器后,会带来session相关的问题。

负载均衡算法

轮询(Round Robin)算法

将请求按顺序轮流分配到后台服务器上,均衡的对待每一个服务器,而不关心服务器实际的连接数和当前的系统负载。

缺点:当集群中服务器硬件配置不同、性能差别大时,无法区别对待。

随机法

通过系统随机函数,根据后台服务器列表的大小值来随机选取其中一台进行访问。随着调用量的增大,其实际效果越来越接近于平均分配流量到后台的每一台服务器,也就是轮询法的效果。

优点:简单实用,不需要额外的配置和算法。

缺点:随机数的特点是在数据量大到一定量时才能保证均衡,所以如果请求量有限的话,可能达不到均衡负载的要求。

源地址哈希法

根据服务消费者请求客户端的IP地址,通过哈希函数计算得到一个哈希值,将这个哈希值和服务器列表的大小进行取模运算,得到的结果便是要访问的服务器地址的序号。采用源地址哈希法进行负载均衡,相同的IP客户端,如果服务器列表不必拿,将映射到同一个后台服务器进行访问。

加权轮询(Weight Round Robin)法

同的后台服务器可能机器的配置和当前系统的负载并不相同,因此他们的抗压能力也不一样。跟配置高、负载低的机器分配更高的权重,使其能处理更多的请求,而配置低、负载高的机器,则给其分配较低的权重,减低其系统负载,加权轮询很好的处理了这一问题,并肩请求按照顺序且根据权重分配给后端。

最小连接数法

前面几种方式都是通过对请求次数的合理分配最大可能提高服务器的利用率,但是实际上,请求次数的均衡并不能代表负载的均衡。所以,引入了最小连接数法。它正是根据后端服务器当前的连接情况,动态的选取其中当前挤压连接数最少的一台服务器来处理当前请求,尽可能的提高后台服务器的利用率,将负载合理的分流到每一台服务器。

session问题

我们打开一个网页,基本上需要浏览器和web服务器进行多次交互,我们都知道http协议本身是无状态的,这也是http协议设计的初衷,客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没必要记录彼此过去的行为,每一次请求之间是独立的,好比一个顾客和一个自动售货机之间的关系一样。

而实际上,我们很多场景都需要带有状态的特性,因此我们引入了session+cookie机制来记住每次请求的会话。

在会话开始时,给当前会话分配一个唯一的会话标识(sessionId),然后通过cookie把这个标识告诉浏览器,以后在每次请求的时候,浏览器都会带上这个会话标识来告诉web服务器请求属于哪个会话。在web服务器上,各个会话有独立的存储,保存不同的会话的信息。

如果遇到禁用cookie的情况,一般的做法就是把这个会话标识放到url的参数中。

image-20191030144300538

我们在Web服务器之间增加了会话数据同步,通过同步就保证了不同Web服务器之间session数据的一致。一般应用容器都支持session replication.

存在问题
  1. 同步session数据造成了网络带宽的开销。只要session数据有变化,就需要将数据同步到所有其他机器上,机器越多,同步带来的网络带宽开销就越大。
  2. 每台web服务器都要保存所有session数据,如果这个集群的session数据很多(很多人同时访问网站)的话,每台机器用于保存session数据的内存就会占用很严重。

这个方案是靠应用容器来完成session的复制从而解决session的问题的,应用本身并不关心这个事情。这个方案不适合集群机器数多的场景。

session集中存储

session数据不保存到服务器本机而存放到一个集中存储的地方,修改session也是发生在集中存储的地方。Web服务器使用session从集中存储的地方读取。这样保证了不同Web服务器读取到的session数据都是一样的。存储session的具体方式可以是数据库、缓存等。

存在问题
  1. 读写session数据引入了网络操作,这相对于本机的数据读取来说,问题就在于存在时延和不稳定性,不过我们的通讯基本都是发生在内网,问题不大。
  2. 如果几种存储session的机器或者集群有问题,就会影响到应用。

相比于Session Replication,当web服务器数量比较大、session数比较多的时候,这个几种存储方案的优势是非常明显的。

将session维护在客户端

很容易想到就是利用cookie,但是客户端存在风险,数据不安全,而且可以存放的数据量比较小,所以将session维护在客户端还要对session中的信息加密。

image-20191030150610594

这个结构的变化会带来两个问题:

  1. 数据如何同步:我们希望通过读库来分担主库上的读压力,那么首先需要解决的是怎么复制到读库的问题。数据库系统一般都提供了数据复制的功能,我们可以直接使用数据库系统自身的机制。不同的数据库系统有不同的支持,比如MySql支持Master+slave的结构提供数据复制机制。
  2. 应用对数据源如何路由:对于应用来说,增加一个读库对结构变化产生了一定的影响,也就是我们的应用需要根据不同情况来选择不同的数据源。

搜索引擎其实是一个读库

搜索引擎其实可以理解成一个读库,我们的商品存储在数据库中,而网站需要提供用户实时检索的功能,尤其是在商品搜索这块。对于这样的读请求,如果全部走读库,其实性能也会存在瓶颈。而使用搜索引擎,不仅仅能大大提高检索速度。还能减轻读数据库的压力而搜索引擎最重要的工作,就是需要根据被搜索数据构建索引,而随着被搜索的数据的变化,索引页需要相应变化。

image-20191030153009157
页面缓存

除了数据缓存外,我们还可以对页面做缓存,数据缓存可以加速应用在相应请求时的数据读取速度,但是最终展示给用户的还是页面,有些动态产生的页面或者访问量特别高的页面,我们会对页面或者内容做一些缓存。

弥补关系型数据库的不足,引入分布式存储

我们应用最多的主要还是关系型数据库,但是在有些场景中,关系型数据库不是很合适。所以我们会引入分布式存储系统,比如redis、mongoDB、cassandra、HBase等。

根据不同的场景和数据结构类型,选择合适的分布式存储系统可以极大提高性能。分布式系统通过集群提供一个高容量、高并发访问、数据冗余的支持。

image-20191030160453623

读写分离后,数据又遇到瓶颈

通过读写分离以及在某些场景用分布式存储系统替换关系型数据库的方式,能够降低主库的压力,解决数据存储方面的问题,不过随着业务发展,我们的主库也会遇到瓶颈。推演到现在,我们的网站各个模块:交易、商品、用户数据都还是存储在一个数据库。尽管增加了缓存、读写分离的方式,但是数据库的压力仍然在持续增加,因此我们可以对数据垂直拆分和水平拆分来解决数据库压力问题。

专库专用,数据垂直拆分

垂直拆分的意思是把数据库中不同业务数据拆分到不同的数据库中,那么根据我们推演的例子,把用户、交易、商品的数据分开。

来源:VwenbinV

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2019年9月26日
下一篇 2019年9月26日

相关推荐