互联网架构(一)总体架构设计

总体架构设计

架构的基本手段就是分与合,先把系统打散,然后再重新组合。
分的过程是把系统拆分为各个子系统/模块/组件。拆的时候首先要解决每个组件的定位问题,然后才能划分彼此的边界,实现合理的拆分。
合就是根据最新终要求,把各个分离的组件有机的整合在一起。
拆分的结构使开发人人员能够做到业务聚焦、技术聚焦、实现开发敏捷,合的结果使系统变得柔软,可以因需而变,实现业务敏捷。

架构的分类

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

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

需要注意的是,系统架构首先都是为人服务的,系统的有序度高,应用逻辑合理、业务概念清晰是第一位。现在大家讨论更多的是技术架构,如高并发设计、分布式事务管理等,只是因为这个不需要业务上下文背景,比较好沟通。具体架构设计时,首先要关注业务架构和应用架构。

大型网站的架构演进

从一个电商网站开始

以电商网站为例,一个交易类型的网站,一定要具备用户(用户注册、用户管理)、商品(商品展示、商品管理)、交易(下单、支付)功能。最开始的架构应该时这样的:在这里插入图片描述
以上是基于Java技术用单机构建的交易网站。这个地方要注意的是各个功能模块之间是通过JVM内部的方法调用进行交互的,而应用和数据库之间是通过jdbc进行访问。

单机负载警告,数据与应用分离

随着网站的开放,访问量不断增大,服务器的负载势必会持续升高,此时将数据库和应用从一台机器分到两台机器。在这里插入图片描述
变化:网站从一台机器变成两台,这个变化对我们影响非常小。单机的情况下,应用采用JDBC的方式和数据库进行连接,现在数据库与应用分离,只需要在配置文件中把数据库的地址从本地改成数据库服务器的ip地址即可。

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

各个资源消耗的原因

  • CPU: 主要是上下文切换,每个CPU同时只能执行一个线程,而CPU的调度有抢占式和轮询等。CPU在切换的过程中需要存储当前线程的执行状态并恢复要执行的线程状态。IO、锁等待等场景都会触发上下文切换,当上下文切换过多的时候会造成内核占用比较多的CPU。
  • 文件IO: 比如频繁的日志写入,磁盘本身处理速度比较慢,都会造成IO性能问题。
  • 网络IO: 包括内存泄露、内存溢出、内存不足。
    实际不管是应用层的调优,还是硬件的升级,无非就是这几个因素的调整。

应用服务器复杂告警,如何让服务器走向集群

应用服务器的压力变大,根据对应用的检测结果,可以针对性能压力大的地方进行优化。可以考虑通过水平扩容及逆行优化,把单机变成集群。在这里插入图片描述
应用服务器从一台变成两台,这两个应用服务器之间没有直接的交互,他们都依赖数据库堆外提供服务,那么这个时候会抛出两个问题:

  1. 最终用户对两个应用服务器访问的选择?(对于这个问题,可以采用DNS解决,也可以通过负载均设备来解决)
  2. Session问题?

水平和垂直扩容

对于大型的分布式架构而言,我们一直追求一种简单、优雅的方式来应对访问量和数据量的增长。这种方式通常指的是不需要改动软件程序,仅通过硬件升级或者增加机器数就可以解决。即分布式架构下的伸缩设计。

垂直伸缩

通过升级或增加单台机器的硬件来支撑访问量以及数据量的增长。优点是技术难度低,运营和改动成本低。缺点是机器性能有瓶颈,成本大。

水平伸缩

通过增加机器来支撑访问量以及数据量增长的方式,成为水平伸缩,水平伸缩理论上没有瓶颈,但是缺点是技术要求比较高。

引入负载均衡设备

在这里插入图片描述
服务的路由,基于负载均衡设备来实现。

负载均衡算法

轮询法

将请求顺序轮流分配到后台服务器,均衡的对待每一台服务器,而不关系服务器实际的连接数和当前系统的负载。
缺点:当集群中服务器硬件配置不同、性能差别大时,无法区别对待。

随机法

通过系统随机函数,根据后台服务器里列表的大小值随机选取一台进行访问。随着调用量的增大,其实际效果接近与平均分配流量到每一台服务器,也就是轮询法的效果。
优点:使用简单,不需要额外的配置和算法。
缺点:随机数的特点是在数据量大到一定程度才能保证均衡,所以如果请求量有限的话,可能会达不到负载均衡的要求。

源地址哈希法

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

加权轮询法

不同的后台服务器的配置可能和当前系统的负载并不相同,因此他们的抗压能力也不一样。给配置高、负载低的机器分配更高的权重,使其处理更过的请求,而配置低、负载高的机器分配较低的权重,降低其系统负载,经请求按照顺粗且根据权重分配给后端。

最小连接数法

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

session问题

在一些场景中,请求需要带有状态特征,引入了session+cookie机制记录每次请求的会话。
当会话开始的时候,给当前会话分配一个唯一的会发标识(sessionid),然后通过cookie把这个标识告诉浏览器,以后每次请求的时候,浏览器都会带上这个会话标识告诉web服务器请求属于哪一个会话。在web服务器上,各个会话有独立的存储,保存在不同的会话中。如过遇到禁用cookie的情况,一般的做法就是把这个会发标识放到URL中。

分布式环境下session的共享
Session复制

服务器实现session复制或者共享:在WEB服务器之间增加会话数据同步,通过同步保证了不同web服务器之间Session数据的一致。一般应用容器都支持Session Replication方式。
存在问题

  1. 同步Session数据造成网络宽带的开销。只要Session数据有变化,就需要将数据同步到所有的其他机器,机器越多,通过带来的数据开销就越大。
  2. 每台web服务器都要保存多有的session数据,如果整个集群的Session数据很多的话,每台机器用于保存Session数据的内容占用会很严重。
    这个方案是靠应用容器完成Session的复制从而解决Session的问题,应用本身不关心这个事情,这个方案不适用集群机器多的场景。
Session集中存放

利用成熟的技术做Session复制,比如12306使用的gemfire, 比如常见的内存数据库redis。
Session数据不保存到本机而是存放在一个集中存储的地方,修改Session也是发生在集中存储的地方。web服务器使用session从集中存储的地方读取。这样保证了不同web服务器读取到的session数据都是一样的。存储Session的具体方式可以是数据库。
存在问题

  1. 读写Session数据引入网路操作,存在延时和不稳定。
  2. 如果集中存储Session的机器或者集群有问题,会影响到应用。
Session维护在客户端

利用cookie存储,但是客户端存在风险,数据不安全,而且存放的数量比较小,将Session维护在客户端还要对Session进行加密。

数据库压力变大,读写分离

随着业务的继续增长,数据量和访问量持续增加,对于读多写少的情况,可以考虑读写分离的方式来优化数据压力。在这里插入图片描述
这个结构的变化会带来两个问题:

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

搜索引擎其实是一个读库

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

加速数据读取的利器-缓存及分布式存储

在大型网站中,基本上就是在解决存储和计算的问题,所以存储是一个重要的支撑系统。

分布式文件系统与NoSQL

对于一些图片,大文本,采用分布式文件系统来实现文件存储:淘宝的TFS、google的GFS,还有开源的HDFS。

NoSQL可以存储一些非关系型数据。

数据缓存

大型网站内部都会使用一些数据缓存,主要用于分担数据库的读的压力,魂村系统一般是用来保存和查询键值对的。应用系统中一般会把热点数据放入缓存,二缓存的填充也应该由应用系统完成。如果数据不存在,则从数据库读取数据后放入缓存。

页面缓存

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

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

我们使用的最多的还是关系型数据库,但是在一些场景中关系型数据库不合适,引入分布式存储系统,如:redis、mongoDB、cassandra、HBase等。
根据不同的场景和数据结构类型,选择合适的分布式存储系统可以极大提高性能。分布式系统通过一个集群提供一个高容量、高并发、数据冗余的支持。

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

通过读写分离以及在某些场景下使用分布式缓存替换关系型数据库的方式,能够降低主库的压力,解决数据存储的问题。但是随着业务的不断发展,我们的主库也遇到平静。

专库专用,数据垂直拆分

在这里插入图片描述
不同业务的数据从原来的一个数据库拆分到了多个数据库中,那么就需要考虑到如何处理原来单机跨业务的事务。

  1. 使用分布式事务。
  2. 去掉事务或者不追求强事务的支持。

对数据进行垂直拆分后,解决了把所有业务数据放在一个数据库中的压力问题,并且根据不同的业务特点进行更多的优化。

垂直拆分后,遇到瓶颈,数据水平拆分

数据的水平拆分就是把同一个表的数据拆分到两个数据库中,产生数据水平拆分的原因是某个业务的数据表的数据量或者更显量达到了单个数据库的瓶颈,这个时候就可以把表拆分到两个或多个数据库中。

数据库水平拆分与数据垂直拆分的区别是,垂直拆分就把不同的表拆分到不同的数据库,水平拆分是把同一个表拆分到不同的数据库中。

数据水平拆分与读写分离的区别是:读写分离解决是读压力大的问题。

水平拆分带来的影响:

  1. sql路由问题,余姚根据一个条件判断当前请求发送到哪一个数据库中。
  2. 主键的处理,不能采用自增ID,需要全局id。
  3. 由于用一个业务的数据被拆分到不同的数据库中,因此需要涉及一些查询需要跨连个数据库获取,如果数据量大并且需要分页,比较难处理。

应用面临的挑战

随着业务的发展,用用的功能会越来越多,应用也会越来越大,我们需要考虑如何不让应用变大,这就需要把应用拆分,从一个应用变为多个。

服务化:把应用分为三层,最上面的web系统,用于完成不同的业务功能;中间的是一些服务中心,不同的服务中心提供不同的业务服务;最下面的是业务的数据库。

与之前相比有几个重要的变化:

  1. 业务功能的访问不仅仅是单机内部的方法调用,还引入了远程的服务调用。
  2. 共享代码不再是散落在不同的应用中,这个实现被放在各个服务中心。
  3. 数据库的交互放到服务中心,让web应用更加注重与浏览器的交互工作,而不必过多关注业务逻辑的事情。

什么是分布式架构

分布式架构的定义

分布式系统是指位于网络计算机上的组件仅通过传递消息来通信和协调目标系统。其中有两个重要因素:

  1. 组件是分布在网络上的。
  2. 组件之间仅仅通过消息实现通信并协调行动。

分布式架构的意义

  1. 升级单机提升性能的性价比越来越低。
  2. 单机处理存在瓶颈。
  3. 针对稳定性和可用性的要求。

猜你喜欢

转载自blog.csdn.net/baidu_41934937/article/details/108918250