浅谈web架构之架构设计

心不动则不痛 提交于 2019-11-29 08:01:55

前言

题目有点大,所以不可能说得非常具体,笔者也不能驾驭全部。
前面介绍过网站发展过程中架构的演化过程,本文主要针对网站架构各个方面的建设进行简单介绍。

架构模式

先来说说模式:每一个模式描述了一个在我们周围不断重复发生的问题及该问题解决方案的核心。这样,你就能一次又一次地用该方案而不必做重复工作

先来说说常见的网站架构模式。这里没有涉及具体实现过程,只是简单介绍其思想和原理,方便日后有用到再深入了解。

分层

分层是企业应用系统中最常见的一种架构模式,将系统在横向维度上切分成几个部分,每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统。

分层 功能
应用层 负责具体业务和视图展示,如网站首页以及搜索输入和结果展示
服务层 为应用层提供服务支持,如用户管理服务,购物车服务
数据层 提供数据存储访问服务,如数据库、缓存、文件、搜索引擎等

分层架构还可以细分下去,比如说应用层可以细分为视图层和业务逻辑层。服务层可以细分为数据接口层和逻辑处理层。
分层结构对网站支持高并发向分布式发展至关重要,所以在网站规模很小的时候就应该采用分层的架构,这样将来网站做大时才能有更好地应对

所以说我们在设计一个新项目的架构时,就需要考虑到分层。不能等到日后项目做大了,再重构就耗时耗力了。

分割

上面的分层是将软件在横向方面进行切分,而分割是在纵向方面对软件进行切分。将不同的功能和服务分割开来,包装成高内聚低耦合的模块单元
比如在应用层,将购物、论坛、搜索、广告分割成不同的应用,由独立的团队负责,部署在不同的服务器上;
在同一个应用内部,如果规模庞大业务负责,会继续进行分割,比如说购物业务,可以分割为机票酒店业务、3C业务、小商品业务等更细小的粒度。

分布式

对于大型网站,分层和分割的主要目的是为了切分后的模块便于分布式部署
利用分布式解决网站高并发的问题的同时,会带来其他问题:
分布式意味着服务调用必须通过网络,这可能对性能造成比较严重的影响;

  • 服务器越多,服务器宕机的概率就越大;
  • 数据的一致性问题,分布式事务难以保证;
  • 开发管理维护困难。

所以说要量力而行,不要为了分布式而分布式。
常用的分布式方案有以下几种:

  • 分布式应用和服务:将分层和分割后的应用和服务模块分布式部署,使不同应用复用共同的服务,便于业务功能扩展。
  • 分布式静态资源:网站的静态资源如js、css、图片等独立分布式部署,并采用独立的域名。减轻应用服务器的负载压力,并通过独立域名加快浏览器并发加载速度。
  • 分布式数据和存储:数据量过大,一台机器无法存储。
  • 分布式计算:后台业务需要处理,包括搜索引擎的索引构建、数据仓库的数据分析统计。通过Hadoop及MapReduce分布式计算框架进行批处理计算

集群

使用分布式已经将切分后的模块独立部署,但是对于用户访问集中的模块,还需要将独立部署的服务器集群化,多台服务器部署相同应用构成一个集群,通过负载均衡设备共同对外提供服务。
即使是访问量很小的分布式应用和服务,也会部署两台服务器构成一个小的集群,目的就是提高系统的可用性

缓存

缓存是改善软件性能的第一手段。有以下几种方式:

  • CDN:内容分发网络,部署在距离终端用户最近的网络服务商,在这里缓存网站的一些静态资源,就可以以最快的速度返回给用户。
  • 反向代理:反向代理属于网站前端架构的一部分,部署在网站的前端,当用户请求到达网站的数据中心时,最先访问反向代理服务器,这里缓存网站的静态资源。
  • 本地缓存:在应用服务器本地缓存着热点数据,应用程序可以在本机内存中直接访问数据,而无需访问数据库。
  • 分布式缓存:数据量很大时,除了本地缓存,还需要分布式缓存,将数据缓存在一个专门的分布式缓存集群中,应用程序通过网络通信访问缓存数据

缓存有两个前提条件,一是数据访问热点不均衡,某些数据会被更频繁的访问,这些数据应该放在缓存中;二是数据在某个数据段内有效,不会很快过期,否则缓存的数据就会因为已经失效而产生脏读,影响结果的正确性。

异步

系统解除耦合的重要手段是异步,业务之间的消息传递不是同步调用,而是将一个业务操作分成多个阶段,每个阶段之间通过共享数据的方式异步执行进行协作。
在单一服务器内部可以通过多线程共享内存队列的方式实现异步,处在业务操作前面的线程将输出写入到队列,后面的线程从队列中读取数据进行处理;
在分布式系统中,多个服务器集群通过分布式消息队列实现异步,分布式消息队列可以看作内存队列的分布式部署。

冗余

要保证在服务器宕机的情况下网站依然可以继续服务,不丢失数据,就需要一定程度的服务器冗余运行,数据冗余备份。
数据库除了定期备份,存档保存,实现冷备份外,还需要进行主从分离,实时同步实现热备份

自动化

发布对网站是头等大事,发布过程自动化可以有效减少故障。自动化测试,自动化安全监测,自动化部署。自动化监控,自动化报警,自动化失效转移,自动化失效恢复。

说完了架构模式,我们分别从性能、可用性、伸缩性、扩展性和安全性来简单聊下如何设计。

高性能架构

对于高性能而言,首先需要知道自己的性能低在哪里,哪里可以用最低的成本进行显著提高性能。

性能测试

性能测试是性能优化的前提和基础,也是性能优化结果的检测和度量标准。

性能测试指标
主要有响应时间、并发数、吞吐量、性能计数器等。

响应时间是系统最重要的性能指标,直观地反映了系统的快慢。
并发数是系统能够同时处理请求的数目,反映了系统的负载特性。对于网站而言,指同时提交请求的用户数目。
吞吐量是单位时间内系统的请求数量,体现系统的整体处理能力。

网站性能优化的目的,除了改善用户体验的响应时间,还要尽量提高系统吞吐量,最大限度利用服务器资源。

前端性能优化

浏览器访问优化
cdn
反向代理

前端优化太多地方都有介绍,不再描述。相比后端架构级别的优化,前端性能提升空间并不是很大。

应用服务器性能优化

分布式缓存
异步操作,将短时间高并发产生的事务消息存储在消息队列中
使用集群,负载均衡

存储性能优化

RAID 廉价磁盘冗余阵列
HDFS Hadoop分布式文件系统

高可用架构

网站的可用性描述网站可有效访问的特性。大型网站的不可用事故直接影响公司形象和利益。

前面说过一个基本的网站架构:

位于应用层的服务器会通过负载均衡设备将 一组服务器组成一个集群共同对外提供服务,当负载均衡设备通过心跳检测等手段监控到某台服务器不可用时,就将其从集群中剔除,并将请求分发到集群中其他可用的服务器上,使整个集群保持可用,从而实现应用高可用。

位于服务层的服务器也是通过集群方式是实现高可用。只是这些服务器被应用层通过分布式服务调用框架访问,分布式服务调用框架会在应用层客户端中实现软件负载均衡,并通过服务注册中心对提供服务的服务器进行心跳检测,发现有服务不可用,立即通知客户端程序修改服务访问列表,剔除不可用的服务器。

位于数据层的服务器为了保证宕机时数据不丢失,数据访问服务不中断,需要在数据写入时进行数据同步复制,实现数据冗余备份。当数据服务器宕机时,应用程序将访问切换到有备份数据的服务器上。

伸缩性架构

网站的伸缩性是指不需要改变网站的软硬件设计,仅仅通过改变部署的服务器数量就可以扩大或者缩小网站的服务处理能力

一般来说,网站的伸缩性设计可以分成两类,一类是根据功能进行物理分离实现伸缩,一类是单一功能通过集群实现伸缩。前者是不同的服务器部署不同的服务,提供不同的功能;后者是集群内的多台服务器部署相同的服务,提供相同的功能。

应用服务器伸缩性设计

应用服务器的伸缩性主要需要通过负载均衡。
这里主要谈谈负载均衡的实现方式:

HTTP重定向负载均衡

HTTP重定向服务器是一台普通的应用服务器,其唯一的功能就是根据用户的HTTP请求计算一台真实的Web服务器地址,并将该Web服务器地址写入HTTP重定向响应返回给用户浏览器。
该方法优点是比较简单,缺点是浏览器需要两次请求服务器才能完成一次访问,性能较差。

DNS域名解析负载均衡

每次域名解析请求都会根据负载均衡算法计算一个不同的IP返回,这样多个服务器就构成了一个集群,并实现负载均衡。

该方法优点是将负载均衡的工作转交给DNS,省掉了网站管理维护负载均衡服务器的麻烦。缺点是控制器在域名服务商那里,网站无法对其做更多改善和更强大的管理。

事实上,大型网站部分使用DNS域名解析,利用域名解析作为第一级负载均衡手段,也就是说域名解析得到的一组服务器并不是实际提供Web服务的物理服务器,而是同样提供负载均衡服务的内部服务器,这组内部负载均衡服务器再进行负载均衡,将请求分发到真实的Web服务器上

反向代理负载均衡

反向代理服务器处于Web服务器前面,所以大多数反向代理服务器在缓存资源的同时也提供负载均衡的功能,管理一组Web 服务器,将请求根据负载均衡算法转发到不同Web服务器上。优点是部署简单,缺点是反向代理服务器是所有请求和响应的中转站,其性能可能会成为瓶颈

IP负载均衡

在网络层通过修改请求目标地址进行负载均衡。

负载均衡服务器在操作系统内核进程获取网络数据包,根据负载均衡算法计算得到真实Web服务器IP,将数据目的IPD修改,不需要通过用户进程处理。处理完成后,响应数据包回到负载均衡服务器,负载均衡服务器再将数据包源地址修改为自身IP发送给用户浏览器。

该方法在内核进程完成数据分发,较反向代理负载均衡有更好的处理性能。但是由于所有请求响应都需要经过负载均衡服务器,集群的最大响应数据吞吐量不得不受制于负载均衡服务器网卡带宽。

数据链路层负载均衡

在通信协议的数据链路层修改mac地址进行负载均衡。

负载均衡数据分发过程中不修改IP地址,只修改目的mac地址,通过配置真是物理服务器集群所有机器虚拟IP和负载均衡服务器IP地址一致,从而达到不修改数据包的源地址和目的地址就可以进行数据分发的目的,由于实际处理请求的真实物理服务器IP和数据请求目的IP一致,不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽成为瓶颈。这种方式又称为直接路由方式(DR)。

负载均衡算法

负载均衡服务器的实现可以分成两个部分:
1.根据负载均衡算法和Web服务器列表计算得到集群中一台Web服务器的地址。
2.将请求数据发送到该地址对应的Web服务器上。

具体的负载均衡算法通常有以下几种:

  • 轮询:所有请求依次分发到每台应用服务器上,适合于所有服务器硬件都相同的场景。
  • 加权轮询:根据应用服务器性能,在轮询的基础上,按照配置的权重分发。
  • 最少连接:记录每个应用服务器正在处理的连接数,将新到的请求分发到最少连接的服务器上,这是最符合负载均衡定义的算法。

分布式缓存集群的伸缩性设计

分布式缓存集群的伸缩性不能使用简单的负载均衡手段来实现。
分布式缓存服务器集群中不同的服务器中缓存的数据各不相同,缓存访问请求不可以在缓存服务器集群中的任意一台处理,必须先找到缓存有需要数据的服务器,然后才能访问。这个特点会严重制约分布式缓存集群的伸缩性设计,因为新上线的缓存服务器没有缓存任何数据,而已下线的缓存服务器还缓存着网站的许多热点数据。

分布式缓存集群伸缩性设计的最主要目标就是让新加入缓存服务器后应使整个缓存服务器集群中已经缓存的数据尽可能还被访问到。

以memcached分布式缓存集群为例:

路由算法负责根据应用程序输入的缓存数据KEY计算得到应该将数据写入到Memcached的哪台服务器或者应该从哪台服务器读取数据。
所以说在分布式缓存集群的伸缩性设计中,路由算法很重要

简单的路由算法可以使用余数Hash:用服务器数目除以缓存数据KEY的Hash值,余数为服务器列表下标编号。
目前比较流行的算法是一致性Hash算法。

数据存储服务器集群的伸缩性设计

数据存储服务器集群的伸缩性对数据的持久性和可用性提出了更高的要求。

关系型数据库集群的伸缩性设计

市场上主要的关系数据都支持数据复制功能,使用这个功能可以对数据库进行简单伸缩。

主从复制:数据写操作都在主服务器上,由主服务器将数据同步到集群中其他从服务器,数据读操作及数据分析等离线操作在从服务器上进行。
分库:不同业务的数据表部署在不同的数据库集群上,这种方式的制约条件是跨库的表不能进行Join操作。
分片:对一些单表数据仍然很大的表,将一张表拆开分别存储在多个数据库中。

数据库中存储着数据,要想保住集群扩容后数据一致负载均衡,必须要做数据迁移,将集群中原来机器中的数据迁移到新添加的机器中。

NoSQL数据库的伸缩性设计

HBase为可伸缩海量数据存储而设计,实现面向在线业务的实时数据访问延迟。HBase的伸缩性主要依赖其可分裂的HRegion及可伸缩的分布式文件系统HDFS实现。

HBase整体架构如下:

当一个HRegion中写入的数据太多,HRegion会分裂成两个HRegion,并将HRegion在整个集群中进行迁移,是的HregionServer的负载均衡。

可扩展性架构

网站的扩展性架构设计,就是在对现有系统影响最小的情况下,系统功能可持续扩展及提升的能力。
这里有必要区分一下扩展性和伸缩性
扩展性
指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。表现在系统基础设施稳定不需要经常变更,应用之间较少依赖和耦合,对需求变更可以敏捷响应。也就是说当系统增加新功能时,不需要对现有系统的结构和代码进行修改。
伸缩性
指系统能够通过增加(减少)自身资源规模的方式增强(减少)自己计算处理事务的能力。也就是说利用集群的方式增加服务器数量,提高系统的整体事务吞吐呢能力。

设计网站可扩展架构的核心思想是模块化,并在此基础上,降低模块间的耦合性,提高模块的复用性。
前面提到过,通过分层和分割的方式进行架构伸缩,分层和分割也是模块化设计的重要手段,利用分层和分割的方式将软件分割为若干个低耦合的独立的子组件模块,这些组件模块以消息传递及依赖调用的方式聚合成一个完整的系统。

在大型网站中,这些模块通过分布式部署的方式,独立的模块部署在独立的服务器集群上,从物理上分离模块之间的耦合关系,进一步降低耦合性提高复用性。
模块分布式部署以后具体集合方式主要有分布式消息队列分布式服务

利用分布式消息队列降低系统耦合性

事件驱动架构
通过在低耦合模块之间传递事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作。在大型网站架构中,实现手段为分布式消息队列:

消息队列使用发布订阅模式。
分布式消息队列原理如下:

消息队列服务器根据消息订阅列表查找订阅该消息的消息消费者应用程序,将消息队列中的消息按照先进先出的原则将消息通过远程通信接口发送给消息消费者程序。

利用分布式服务打造可复用的业务平台

前面说的分布式消息队列通过消息对象分解系统耦合性,不同子系统处理同一个信息;而分布式服务则通过接口分解系统耦合性,不同子系统通过相同的接口描述进行服务调用。

随着网站规模越来越大,一个应用中聚合了大量的应用和服务主机:

这种巨无霸应用系统带来很多问题,比如说编译、部署困难,代码分支管理困难,数据库连接资源耗尽,新增业务困难等问题。

解决方案就是拆分,将模块独立部署,降低系统耦合性。分为横向拆分和纵向拆分。

纵向拆分:将一个应用拆分为多个小应用,如果新增业务较为独立,那么就直接将其设计部署为一个独立的Web应用系统。
横向拆分:将复用的业务拆分出来,独立部署成分布式服务,新增业务只需要调用这些分布式服务,不需要依赖具体的模块代码,即可快速搭建一个应用系统,而模块内部业务逻辑变化时,只要接口一致就不会影响业务程序的其他模块。

纵向拆分相对简单,通过梳理业务,将较少相关的业务剥离,使其成为独立的Web应用,而对于横向拆分,不但需要识别可复用的业务,设计服务接口,规范服务依赖关系,还需要一个完善的分布式管理服务框架。应该具有以下特性:

  • 负载均衡
  • 失效转移
  • 高效率的远程通信
  • 整合异构系统
  • 对应用最少侵入
  • 版本控制
  • 实时监控

大型网站需要更简单高效的分布式服务框架构建其SOA(Service Oriented Architecture面向服务的体系架构)
Facebook利用Thrift管理其分布式服务。国内一般是阿里巴巴的Dubbo。

我们以Dubbo为例,分析其架构:

服务消费程序通过服务接口使用服务,而服务接口通过代理加载具体服务,具体服务可以是本地的代码模块,也可以是远程的服务,因此对应用较少的侵入:应用程序只需要调用服务接口,服务框架根据配置自动调用本地或远程实现
服务框架客户端模块通过服务注册中心加载服务器提供者列表,查找需要的服务接口,并根据配置的负载均衡策略将服务调用请求发送到某台服务提供者服务器。如果服务调用失败,客户端模块会自动从服务器列表选择一个可提供同样服务的另一台服务器重新请求服务,实现服务的自动失效转移,保证服务高可用。

安全性架构

各种各样的攻击手段就不再介绍了。这里说写通用的配置吧。

防火墙

ModSecurity是一个开源的Web应用防火墙,探测攻击并保护Web营业员程序,既可以嵌入到Web应用服务器中,也可以作为独立的应用程序启动。

ModSecurity采用处理逻辑攻击规则集合分离的架构模式,处理逻辑负责请求和响应的拦截过滤,规则加载执行等功能。而攻击规则集合则负责描述对具体攻击的规则定义、模式识别、防御策略等功能。处理逻辑比较稳定,规则集合需要不断针对漏洞进行升级,这是一种可扩展的架构设计,如图:

信息加密

信息加密技术可分为三类:单向散列加密、对称加密和非对称加密。

单向散列加密

指通过对不同输入长度的信息进行散列计算,得到固定长度的输出,这个散列计算过程是单向的,即不能对固定长度的输出进行计算从而获得输入信息。常用的算法有MD5、SHA等。

salt相当于加密的密钥,可增加破解的难度。网站密码一般都是用这种算法来存储。这样即使被拖库,也不会泄露。

对称加密

指加密和解密使用的密钥是同一个密钥(可以互相推算),如图:

对称加密通常用在信息需要安全交换或存储的场合,如cookie加密、通信加密等。
对称加密的优点是算法简单,加密效率高,系统开销小,适合大量数据加密。缺点是加密解密使用同一个密钥,远程通信的情况下如何安全的交互密钥是个难题,如果密钥丢失,那么所有的加密信息也就没有秘密可言了。
常用的对称加密手段有DES、RC算法。

非对称加密

加密和解密使用的不是同一密钥,其中一个对外界公开,被称作公钥,另一个只有使用者知道,被称作私钥。用公钥加密的信息必须用私钥才能解开,反之用私钥加密的信息只能用公钥才能解开。且不可能通过公钥算得私钥。

非对称加密通常用在信息安全传输,数字签名等场合。
常见的非对称加密算法有RSA算法,HTTPS中浏览器使用的数字证书实质上也是。

实际应用中,常常会混合使用非对称加密和对称加密,先使用非对称加密技术对密钥进行安全传输,然后使用对称加密技术进行信息加解密与交换。

密钥安全管理

前面介绍的加密技术都基于密钥的安全基础上。如果密钥泄露,就失去了安全性。实际开发中,经常有工程师把密钥直接写在源代码中,或者是配置文件中,线上和开发环境配置不同的密钥。这样的话,不够安全。
通过两种方案改善:
1.密钥和算法放在一个独立的服务器上,甚至做成一个专用的硬件设备,对外提供加密和解密服务,用用程序通过调用这个服务,实现数据的加解密。这种方法由专人维护,密钥不容易泄露,但是成本较高。
2.将加解密算法放在应用系统中,密钥则放在独立服务器中,为了提高密钥的安全性,实际存储时,密钥被切分成数片,加密后分别保存在不同存储介质中,兼顾密钥安全性的同时又改善了性能。

信息过滤和反垃圾

常见手段:
1.文本匹配
解决敏感词过滤的问题。通常网站维护一份敏感词列表,如果用户发表的信息含有列表中的敏感词,则转义。
快速匹配到敏感词可以通过正则,效率低。也可以使用Trie算法。简单点的可以通过构造多级Hash表进行文本匹配。还可以先进行降噪预处理,放在”敏词”这样的词汇绕过防御。

2.分类算法
对于广告贴、垃圾邮件等内容的识别比较有效的自动化方法是采用分类算法。

比较简单实用的分类算法有贝叶斯分类算法、TAN算法、ARCS算法,一种利用概率统计方法进行分类的算法。分类算法除了用于反垃圾,还可以用于信息自动分类。门户网站可以用该算法对采集来的新闻稿件进行自动分类,分发到不同的频道。

3.黑名单
将发起人放入黑名单。可以通过Hash表实现,但是如果黑名单列表过大,Hash十分占用内存,可以用布隆过滤器代替Hash表。如果需要精确的判断,就不适合布隆过滤器了。

风险控制

交易安全是电子商务网站的底线。电子商务具有多种形式,B2B,B2C,C2C每种交易的场景都不相同,风险也各有特点,大致可以分为以下几种:

  • 账户风险:包括账户被黑客盗用,恶意注册账号等几种情况
  • 买家风险:买家恶意下单占用库存进行不正当竞争;黄牛利用促销抢购低价商品;
  • 卖家风险:不良卖家恶意欺诈
  • 交易风险:交易过程漏洞

大型电商网站都配备有专门的风控团队进行风险控制,风控的手段也包括自动和人工两种。机器自动识别为高风险的交易和信息会发送给风控审核人员进行人工审核,机器自动风控的技术和方法也不断通过人工发现的新风控类型进行逐步完善。

机器自动风控的技术手段主要有规则引擎和统计模型
规则引擎:当交易的某些指标满足一定条件时,就会被认为具有高风险的欺诈可能性。比如用户来自欺诈高发地区;交易金额超过某个数值;和上次登录的地址距离差距很大;用户登录地与收货地不符;用户第一次交易等等。
这种高风险交易规则的判断如果通过编程方式使用if—else来实现,代码量会非常大,由于运营过程中不断发现新的交易风险类型,需要不断调整规则,代码也需要不断修改。
网站一般使用规则引擎技术处理此类问题,规则引擎是一种将业务规则和规则处理逻辑相分离的技术,业务规则文件由运营人员通过管理界面编辑,当需要修改规则时,无需更改代码发布程序,即可实时使用新规则。

统计模型
规则引擎虽然技术简单,但是随着业务规则的增加,会出现规则冲突、难以维护等问题。目前大型网站更倾向于使用统计模型进行风控。通过机器学习算法进行智能统计。

小结

就先说到这里吧,待日后实践到一定程度后再回来添砖加瓦。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!