WEB应用架构发展历程(简)

196 阅读12分钟

一、单体应用架构

Web应用的所有功能模块都部署和运行在一台服务器上,浏览器通过Http(或其他协议)向服务器发送请求,服务器对请求进行响应和处理并返回结果信息。服务器可以进一步将前后进行分离,前端主要负责页面交互逻辑,后端主要负责业务逻辑,二者通过API接口进行通信。

单机应用架构示意图

以上架构存在隐患,因为仅使用一台服务器提供服务,如果唯一的服务器挂掉以后整个应用就会崩溃,并且一台服务器的性能终归有限,无法满足应用高性能的要求。所以后来又引入了分布式架构。

二、分布式架构

将Web应用提供的服务分别同时部署在多台服务器上,这样即使一台服务器挂掉,浏览器(后面用客户端进行抽象)仍可以通过别的正常运行的服务器来正常获取请求的结果。其中涉及到一个问题,客户端如何决定将请求发送到哪台服务器上呢?负载均衡(loading balance)可以提供解决方案。

distributedSys.jpg

1. 轮询负载均衡算法

简单地按次序进行服务器的分配,做个假设:有三台服务器,第一个客户端将请求发送到第一台服务器上,第二个客户端对应第二台,第三个第三台,第四个第一台......周而复始。

2. 加权轮询负载均衡算法

但是服务器的性能是不同的,有的网络带宽,存储容量大,处理能力就比较高。为了更科学地分配客户端的请求,该算法根据标准为每个服务器分配了一个权重,性能越高的服务器分配到的权重也更高。请求则更容易被分配到权重高的服务器上,所谓能者多劳。

3. 最小连接数数算法

不同于加权轮询算法,最小连接数算法对服务器的利用上注重的是尽可能地提高服务器的利用率。它动态地将请求转发到当前连接数最少的服务器上,更灵活地将任务分流,提高任务执行的效率。

4. 源地址哈希算法

这个算法根据客户端的IP地址进行哈希计算获得哈希值,再根据这个值对服务器列表的数量取模,获得的最终数值就对应服务器的序号。当发来的客户端IP地址不变并且服务器列表不变时,同一IP的客户端总会将请求发送到同一台服务器上。

三、微服务架构

当应用容量过大,提供的功能过多时,如果某一个功能有问题,就容易牵一发动全身导致整个应用都需要更新维护。我们可以把整个应用的功能拆分成一个个微服务,每个微服务承担单一的功能,并且独立地部署,这样某一个服务出现问题或需要修改时并不影响其他服务的正常运行。

1.RPC

微服务之间也不能永远各自为政,需要彼此通信。远端过程调用RPC(remote process call)是一种可以实现一个程序的函数调用另一个程序的函数的计算机通信协议,它不需要程序员显示编程这个过程,所以无论调用的这个函数是在本地还是其他服务器上,使用的是何种网络协议,本质上程序员编写的调用代码是相似的。

1.1 thrift框架

由Facebook开源的一个RPC框架,可以进行可扩展且跨语言的服务的开发。我们可以根据Thrift的规范简单定义访问接口,通过Thrift编译器编译生成各种语言的代码,实现了在大规模分布式集群中各独立模块之间的高效协同。它包含完整的服务端和客户端堆栈,可以快速实现RPC,支持同步和异步通信。

1.2 protobuf

由谷歌开源的一种序列化与结构化数据的机制,通信的信息为二进制数据格式,性能好,速度快,但它只涉及序列化和反序列化技术,不涉及RPC功能(例如XML或JSON的解析器)。

2.Metrics接口

微服务架构所需的组件繁多,为了排除隐患,需要定时监控各个组件的状态指标并能及时发现问题,发出警告。但是每个组件所关注的指标是不同的,例如Redis缓存一般监控占用的内存值,网络流量;数据库监控连接数,磁盘空间;业务服务监控并发数、响应延迟,错误率等。为了把每个组件的监控指标统一起来,一般的做法是每个组件和服务都返回数据格式一致的Metrics接口来报告自己的状态,然后部署一个指标采集器组件定时地从这接口中获取并保持组件状态以及提供查询,还需要UI界面对这些状态数值进行可视化并发出警告。

一般网上都有开源的组件提供不同组件的接口,微服务则根据各个服务的实际业务逻辑实现自定义自己的指标接口。可以使用Prometheus作为指标采集器,Grafana配置监控界面和邮件预警。

3.定位问题-链路跟踪

一个用户的请求往往需要涉及多个内部服务的调用,为了能在请求出现问题时发现故障点并迅速进行排查,需要链路跟踪这个方法去记录每个请求中发生了多少服务调用以及调用的关系。

开源组件Zipkin实现了链路跟踪的原理和流程,这样每次在客户端请求时增添一个Http请求拦截器,将请求的具体链路信息注入到Headers中,同时异步地发送调用日志到Zipkin的Logger收集器中就可以定位到具体是哪个请求出现了问题。

4.分析问题-Logger分析

定位到问题还不算完,需要具体的错误信息来做到发现问题解决问题。这需要用到Logger分析组件来分析具体Logger,查找错误原因。

著名的日志分析组件ELK可以做到:Elastisearch——提供Logger的存储并搜索功能;Logstash——日志采集器,它能够接受日志的输入并对日志采取一些预处理并发送到Elastisearch中;Kibana——UI组件,通过Elastisearch的接口查找数据并展示给用户。

5.权限控制、服务治理-网关

将整个应用拆分为多个微服务后,会出现大量的服务调用和接口,容易在开发过程中忘记每个服务的作用或者干脆调用了错误的服务,所以需要在调用者和被调用的服务间添加一层网关在服务被调用时进行权限校验,网关也可以作为一个提供服务接口文档的平台。

有的应用服务量不大时,可以所有微服务都共同使用一个网关,微服务外部通过网关调用微服务,内部则直接调用;服务调用比较复杂时,可以按照业务的领域将微服务分为几个区域,在区域内部直接调用,在外部则通过网关调用;最复杂的情况是无论是微服务内部的调用还是来自外部的调用都需要通过网关。

6.服务注册与发现-动态扩容

虽然前面的组件都在力求降低服务产生故障的概率,但是还需要考虑一旦故障发生如何将故障带来的影响降低到最小。

最简单粗暴的方法就是冗余,将一个服务部署多个实例,这样可以分担压力、提高服务的效率也可以在一个实例挂了以后其他实例还能接着响应。

新增实例的步骤可以概括为两步:部署新实例和将新实例注册到LB(负载均衡)或DNS上。一般的解决方案是服务注册与发现。首先需要部署一个服务发现服务,它是一个提供每个已经注册的服务的具体地址信息的服务,DNS也是一种服务发现服务。每当各个应用服务启动时,都会自动将自己注册到服务发现服务上,并且实时地从服务发现服务中同步各个应用服务的地址信息到本地。服务发现服务也会定期检查服务应用的健康状态,去掉不健康的实例地址。这样新增实例时只需要部署新实例,实例下线时直接关停服务即可。服务发现服务会自动地更新服务实例地址列表的。

因为应用服务已经将服务地址列表存储在本地了,所以客户端可以搭配负载均衡共同使用服务发现。比如客户端可以根据服务地址在发送请求时自己决定负载策略,还可以让服务在注册时添加一些元数据,客户端根据这些元数据进行流量控制、实现A/B测试、蓝绿发布等功能。

服务发现有多种组件可以选择:Zookeeper 、Eureka、Consul、Etcd等

7.熔断

如果一个请求的链路很长,在发生错误而停止响应时,调用方一般要等待较长的时间触发超时错误或等待错误返回,链路就会一直占用资源直到下游回应。熔断机制可以在多次访问一个服务失败时标记该任务已经停止工作直接返回错误,在上游服务偶尔发送的健康检查中检查出服务已经在恢复后再建立连接。

7.1 服务降级

当一个服务停止工作时,如果这个服务不是核心业务,则上游服务应该降级来保证核心业务能正常运行。

7.2 限流

一个服务停止工作以后,上游服务或者用户一般会重复发送请求,这样会导致服务重启时又因为过大的网络流量再次挂掉。因此服务需要限流进行自我保护,比如在请求过多时丢掉多余的请求或者只拒绝来自产生大量请求的服务的请求。

8.测试

微服务架构下,测试从层次的细分从上至下分为了三个层次:1、端到端的测试:覆盖整个系统,一般在用户界面机型上测试 2、服务测试:针对服务接口进行测试 3、单元测试:针对代码单元进行测试。他们的测试难度从难到易,效率从低到高。

9. 动态配置-配置中心

区别于传统的静态配置,一般是把系统的各类配置参数都集中地写死在配置文件里,实现动态配置的配置中心的思路是将项目的各类配置放到一个地方进行管理,并提供一套统一的接口。当各个服务需要配置的时候,就来配置中心进行拉取。当配置中心有更新时也会通知各个服务来同步最新的配置信息,使之动态更新。

这样有效地解决了各个独立模块各自的配置文件过于分散,每次配置更新时都需要重启服务的问题。

四、 微服务架构-抽离公共代码

1. 微服务框架

微服务框架可以把上述的各个组件和应用服务的对接代码和另外的一些公共代码抽离到框架之中,并使所有的应用服务都使用这一套框架开发。

使用微服务框架可以自定义很多功能,比如将程序调用堆栈信息注入到链路跟踪,实现代码级别的链路跟踪。或者输出线程池、连接池的状态信息,实时监控服务底层状态。

但微服务框架的更新成本很高,每次框架升级都需要所有的应用服务配合升级。一般会使用兼容方案等待所有应用服务升级。如果应用服务非常多时,需要等待的更新时间就很长,并且一些稳定使用几乎不需要升级的应用服务的负责人也许会拒绝更新。

2. Service Mesh

另一种抽象这些公共代码的方法是将他们抽象到一个反向代理组件,每个服务都额外部署这个组件,所有出站入站的流量都通过这个代理进行处理和转发。这个组件被称为Sidecar。

Sidecar不会产生额外的网路成本,Sidecar会和微服务节点部署在同一台主机上并且共用相同的虚拟网卡。

Sidecar只负责网络通信。还需要有个组件来统一管理所有Sidecar的配置。在Service Mesh中,负责网络通信的部分叫数据平面(data plane),负责配置管理的部分叫控制平面(control plane)。数据平面和控制平面构成了Service Mesh的基本架构。

Sidecar不需要侵入代码,升级和维护更加方便。虽然它不占据网络资源,但仍然有对内存的拷贝的额外成本,并且一些集中式的流量管理也会影响性能。

www.cnblogs.com/skabyy/p/11… 作者:古露卡比 以上内容为自用的学习梳理,大量引用上文,特此注明