云原生架构进阶实战-读书笔记
云原生概念
云原生(Cloud Native)概念是由Pivotal的Matt Stine在2013年首次提出的。这个概念得到了社区的不断完善,内容越来越丰富,目前已经**包括了DevOps(Development和Operations的组合)、持续交付(Continuous Delivery,CD)、微服务(MicroServices)、敏捷基础设施(Agile Infrastructure)和十二要素(The Twelve-Factor App)**等几大主题。
2015年云原生计算基金会(CNCF)成立,对云原生定义进行了修改,认为云原生需要包含应用容器化、面向微服务架构以及支持容器编排调度等方面的内容。
2015年云原生计算基金会(CNCF)成立,对云原生定义进行了修改,认为云原生需要包含应用容器化、面向微服务架构以及支持容器编排调度等方面的内容。
云原生主要包括两部分内容:云原生基础架构和云原生应用。
为什么需要云原生
云的核心理念是弹性。
从技术发展的角度看:
开源让云计算变得越来越标准化,容器已经成为企业应用分发和交付的标准,可以将应用与底层运行环境解耦;
Kubernetes成为资源调度和编排的标准,屏蔽了底层架构的差异性,帮助应用平滑运行在不同的基础设施上;
在此基础上建立上层应用抽象(如微服务和服务网格),逐步形成应用架构现代化演进的标准,
开发者只需要关注自身的业务逻辑,无须关注底层实现。
云原生正在通过方法论、工具集和理念重塑整个软件技术栈和生命周期,帮助企业和开发者在云上构建和运行可弹性扩展、容错性好、易于管理、便于观察的系统。
云原生的设计原则
1、去中心化原则
SOA一般有一个中心化的企业服务总线(Enterprise Service Bus,ESB)负责所有服务的注册发现以及调用路由;
微服务架构虽然也有一个服务注册中心,但服务注册中心只负责应用启动或者状态变更时做服务推送,真正在运行过程中微服务之间的相互调用都是点对点直接调用,即运行时是去中心化的。
2、松耦合原则
1、实现的松耦合
服务消费端不需要依赖服务契约的某个特定实现,消费端未来还可以自由切换到该契约的其他服务提供方。
2、时间的松耦合
典型的是异步消息队列系统,由于有中介者(broker),因此生产者和消费者不必在同一时间都保持可用性以及相同的吞吐量,而且生产者也不需要马上等到回复。
3、位置的松耦合
典型的是服务注册中心,消费端完全不需要直接知道提供服务端的具体位置,而都通过注册中心查找服务来访问。
4、版本的松耦合
消费端不需要依赖服务契约的某个特定版本来工作,这就要求服务的契约在升级时要尽可能地提供向下兼容性。
3、面向失败设计原则
在发生异常时能够快速失败,然后快速恢复,以保证业务永远在线,不能让业务半死不活地僵持着。
面向失败设计(design for failure),意味着所有的外部调用都有容错处理。
系统架构设计时需要考虑到应用系统的每一个层面,包括硬件和软件是可能出现故障的,并据此在应用系统架构设计上消除单一故障点,从而实现高可用性(High Availability,HA)的系统架构。
4、无状态化原则
云原生的应用服务设计尽可能是无状态的,使得业务天生具有扩展性,在业务流量高峰和低峰时期,依赖云的特性自动弹性扩容、缩容,满足业务需求。
无状态指的是服务在处理请求时,不依赖除请求本身以外的其他内容,也不会有除响应请求之外的额外操作。
将“有状态”的业务处理过程改造成“无状态”的过程,思路比较简单,主要有以下两种手段。
(1)状态分离:服务端所有的状态信息统一保存在外部独立的分布式存储中(如缓存、消息队列、数据库)。(2)请求附带全部状态信息:将状态信息前置,丰富请求的入参,将需要处理的数据尽可能都通过上游的客户端放到入参中传过来。
基于状态的Web服务
在基于状态的Web服务中,Client与Server交互的信息(如:用户登录状态)会保存在Server的Session中。再这样的前提下,Client中的用户请求只能被保存有此用户相关状态信息的服务器所接受和理解,这也就意味着在基于状态的Web系统中的Server无法对用户请求进行负载均衡等自由的调度(一个Client请求只能由一个指定的Server处理)。同时这也会导致另外一个容错性的问题,如果指定的Server在Client的用户发出请求的过程中宕机,那么此用户最近的所有交互操作将无法被转移至别的Server上,即此请求将无效化。
基于无状态的Web服务
在无状态的Web服务中,每一个Web请求都必须是独立的,请求之间是完全分离的。Server没有保存Client的状态信息,所以Client发送的请求必须包含有能够让服务器理解请求的全部信息,包括自己的状态信息。使得一个Client的Web请求能够被任何可用的Server应答,从而将Web系统扩展到大量的Client中。
有状态和无状态是相对于计算机系统中的应用程序而言的:
- 有状态:指应用程序会保存一些数据,这些数据反映了应用程序的运行状态。也就是说,在不同的请求之间,应用程序的运行状态可能会改变。这些数据通常存储在内存或数据库中,并且可以被多个用户或客户端共享访问。
- 无状态:指应用程序没有保存任何数据,每次请求都是独立的,不依赖于之前的请求。也就是说,应用程序对于每一个请求都是重新生成结果,不会基于之前的结果进行优化或者缓存。在这种情况下,数据可以通过请求的参数来传递。
举个例子,计算器程序可以是一个无状态的应用程序。每一次计算都仅依赖于输入的数据(例如加数、减数),不会基于之前的计算结果进行优化。
而网上购物应用程序则通常是一个有状态的应用程序。因为它需要记录用户的购物车、订单等信息,这些信息随着用户的登录和操作而变化。如果该应用程序是一个无状态的应用程序,那么每次购买商品时,都需要重新输入订单和配送信息,用户体验将非常不好。
Java Web 应用程序大多数情况下都是有状态的,它们需要处理会话(session)和状态(state)等概念。但是,如果一个Web应用程序使用了RESTful架构风格,那么它就是一个无状态的应用程序,不保存会话信息或其他相关数据。
5、不变性原则
希望所有的服务(包括环境)无差异化配置,实现标准化可迁移,而不希望在部署任何服务的过程中还需要手动操作。
实现不变性原则的前提是,基础设施中的每个服务、组件都可以自动安装、部署,不需要人工干预。所有的资源都可以随时拉起、随时释放,同时以API的方式提供弹性、按需的计算、存储能力。
为了提升可用性,应该尽量减少故障修复时间,要知道替换的速度远远快于修复的速度。
6、自动化驱动原则
自动化驱动分为持续集成、持续部署、持续交付等阶段,用来确保需求的提出、设计开发测试,再到代码快速、安全地部署到生产环境中。
持续集成是指每当开发人员提交了一次改动,就立刻进行构建、自动化测试,确保业务应用和服务均能符合预期,从而可以确定新代码和原有代码能否正确地集成在一起。
持续部署是指使用完全的自动化过程把每个变更自动提交到测试环境中,触发自动化测试用例,测试验证通过后将应用安全地部署到生产环境中,打通开发、测试、生产等各个环节。
持续交付是软件发布的能力,在持续集成完成后,能够提供到预发布之类的环境上,满足生产环境的条件。
云原生基础架构
云原生基础架构是隐藏在抽象背后的由软件管理并由API进行控制的基础架构,它的目标是运行应用系统。
云原生基础架构不仅仅是在公有云上运行基础架构,也不是在容器中运行应用程序,所以公有云和容器化不是云原生基础架构的代名词。
但是云原生基础架构可以借助容器化技术和公有云技术去实现。
公有云仅仅是IaaS层的实现,一般的公有云还是要借助人力去申请、分配。
而云原生基础架构则是用程序代码自动去申请。
容器仅仅是应用程序的一种打包方式,这并不意味着这些应用程序具备自治功能。
即使应用程序是通过持续集成和持续交付等DevOps流水线自动构建和部署的,也并不一定就是云原生基础架构。
Kubernetes也不能简单地称为云原生基础架构。
Kubernetes的容器编排技术为云原生基础架构提供了必要的平台支撑功能。
是否是云原生基础架构的关键在于是否使用自动化处理的方式。
例如在Kubernetes中手工分配物理卷,就不能称为云原生基础架构,因为物理卷不是自动分配的。
而如果使用动态卷,依靠卷声明来分配容量,进而分配使用该卷的容器,则满足了云原生基础架构的要求。
云原生应用对基础架构的基本要求有:
● 运行时间和隔离。● 资源分配和调度。● 环境隔离。
● 服务发现。● 状态管理。● 监测和日志记录。
● 度量聚合。● 调试和追踪。
云原生应用程序和基础架构协作以发现其相关依赖服务。
Prometheus实现了一种服务发现方式,主动感知系统监控目标的变化,自动添加、删除和更新服务。以下是一个Kubernetes上的服务允许Prometheus自动发现的代码,其中的prometheus.io/scrape:"true"就是为了让Prometheus感知到该服务。该服务暴露了HTTP协议访问,端口为8080,端点为/metrics。
通常,云原生应用程序构建为在Docker容器中运行的一组微服务,在Kubernetes中编排,并使用DevOps和Git Ops工作流进行部署和管理。
云原生架构是一种包含技术实现与管理(组织流程)的软件开发方法论。技术实现部分主要包括敏捷基础设施、云公共基础服务和微服务;组织流程部分主要包括持续交付和DevOps。
云原生应用架构包含3个特征:容器化、微服务和DevOps。
云原生应用
云原生应用程序的关键在于提供弹性、敏捷性、可操作性和可观察性。
弹性的概念隐含了允许应用程序失败而不是试图阻止程序失败的意思。
敏捷性允许应用快速部署和快速迭代,这就需要引入DevOps文化。
可操作性是指从应用程序内部控制应用程序的生命周期,而不是依赖外部进程和监视器。
可观察性是指应用程序需要提供信息以反映应用程序的状态。
目前实现云原生应用程序所需特性的常用方法有:
● 微服务。
● 健康状况报告。
● 自动测量数据。
● 弹性。
● 声明模式而不是响应模式。
微服务
传统应用程序是以单个实体为目标进行管理和部署的,称为单体应用程序。
单体应用程序的好处是显而易见的,但是它无法解决面向大量互联网用户提供服务的并发量问题,且使得开发过程变得臃肿,开发进程变得缓慢,维护也越来越困难。解决这些问题最好的方法之一就是分解单体应用为众多小的服务模块。
这些服务模块相互独立,使得开发人员可以独立维护这些小系统,而且开发和维护过程也变得敏捷。
分解成微服务后,各服务的编写语言也可以自行确定,只需要遵守总体的API优先和通信要求即可。
微服务更像是UNIX哲学的实践和改造。UNIX哲学是“程序应该只关注一个目标,并尽可能把它做好。让程序能够互相协同工作。”
微服务也是如此,服务更专注于其用途,也就是只应做一件事,并把这件事做好。
但是微服务不能等同于云原生架构,微服务只是云原生文化的一种实现。
健康状况报告
为了能够由软件控制一切,应用程序必须提供可供管理软件监测的度量指标。而一个应用程序的度量指标只有创建应用程序的作者最清楚,因此在应用程序中内置度量指标是最好的设计方式。
这要求各应用程序提供必要的端点,供管理软件访问以判断应用程序状态。例如Kubernetes、ETCD都通过HTTP提供了大量的度量指标。
此外,应用程序应该提供更加丰富且必要的状态报告。
在云原生架构下,一切皆是代码,一切皆可由软件控制。
为了可以控制,各应用程序必须提供度量接口让管理软件获知应用程序运行状态以做出必要的反应,例如应用程序崩溃时,管理程序可做出停掉当前应用程序实例然后启动新实例的操作。应用程序的健康状况只是能够自动执行应用程序声明周期的一部分,管理程序还需要知道应用程序是否正在工作。
自动测量数据
自动测量数据是做出决定所必需的信息,这些数据与健康状况报告的数据是有重叠的,但是它们的用途不一样。
健康报告是告知管理程序所辖应用程序的生命周期状态,
而自动测量数据是告知应用程序的业务度量指标。
度量的指标一般称为服务级别指标(Service Level Indicator,SLI)或关键绩效指标(Key Performance Indicator,KPI)。这些指标是特定于应用程序的数据,让管理程序监测应用程序的性能在服务级别目标(Service Level Objectives,SLO)内。自动测量数据可以解决以下问题:
● 应用程序每分钟收到的请求数。● 是否有任何错误。
● 应用程序延迟多久。● 业务处理需要多长时间。
监测数据经常被抓取或推送到时间序列数据库(如Prometheus或InfluxDB),然后再由度量指标模型进行处理分析,以便后续提醒或者大屏展示。
在一个动态可自我修复的环境中,管理程序几乎不关心单个应用程序的生命周期,而更多关心应用程序的SLO,因为若是一个程序崩溃,管理程序可以动态重启应用程序实例以恢复正常运行状态。
举一个例子,在Kubernetes中运行以下命令可以看到coredns重启过两次和3次,但是管理程序不关心这个行为,只关心它是否在正常运转,因为管理程序的SLO就是要正常运转。
SLO:Service Level Objective,服务质量目标,它通常指的是维护系统的最高级别的目标,是为期望的系统的可用性设定的目标,以一段时间内的百分比表示。
弹性处理故障
云原生应用程序应当正视故障而不是竭力避免故障。唯一不应该有故障的系统是那些维持生命的系统。任何系统都应该有一个合理的SLO,如果无视SLO而去避免故障发生,则花费的成本将非常巨大。为此,必须假设应用程序可能发生故障,并采取必要的措施应对故障,这是云原生应用的一种模式。
无论发生什么样的故障,云原生应用都必须适应,并采取合理的调整措施应对。
此外,云原生应用还需要设计一种方法应对过载,处理过载的一种常见方法是适度降级。
云原生应用要求具备服务优雅降级的能力。最现实的处理方式是服务降级,返回部分回应或使用本地缓存中的旧信息进行回应。
声明式通信
由于云原生应用程序在云环境中运行,因此它们与基础架构和支持应用程序的交互方式与传统应用程序不同。在云本机应用程序中,与任何内容进行通信的方式都是通过网络。
很多时候,网络通信是通过RESTful HTTP调用完成的,但也可以通过其他接口实现,例如远程过程调用(RPC)。
在传统应用程序中,通信的介质可能是文件或者消息队列,但是这些方式都是尝试构建避免失败的方式,它们在云原生架构下存在一些问题。例如应用程序把结果写入到文件,写完后应用程序崩溃了。此时会出现了一种情况:应用程序崩溃之前,计算结果已经写入文件中。按照云原生理念,此时应用程序将重启,再次执行计算过程,计算结果再次写到文件中。因此,开发人员应该停止使用反应式通信,开始使用声明式通信,从而提高应用程序的健壮性,并且减少应用程序的依赖。
命令式编程(Imperative):详细的命令机器怎么(How)去处理一件事情以达到你想要的结果(What);
声明式编程(Declarative):只告诉你想要的结果(What),机器自己摸索过程(How)。
比如:
// 命令式编程做法
let res = false;
for(i = 0; i < dataArr.length; i++) {
if (i === 3) {
res = true;
}
}
console.log(res);
// 声明式编程做法
let res = dataArr.filter(i => i === 3);
console.log(res);
还可以用一个例子说明:
问:我就在万达旁边,怎么去你家?
命令式回复:沿着中山路直走,前方第二个红绿灯右转,然后直走100米左右,你就能看到门牌号666,那就是我家。
声明式回复:我家地址是中山路666号。
十二要素应用
(1)一份基准代码(Codebase),多份部署(Deploy)
(2)显式声明依赖关系(Dependency)
(3)在环境中存储配置
这允许应用程序非常方便地在不同的部署间修改,而不需要改动一行代码。
(4)把后端服务(backing services)当作附加资源
(5)严格分离构建、发布和运行
(6)以一个或多个无状态进程运行应用
(7)通过端口绑定(Port binding)来提供服务
(8)通过进程模型进行扩展
(9)快速启动和优雅终止可最大化健壮性
(10)尽可能地保持开发、预发布和线上环境相同
(11)把日志当作事件流
(12)后台管理任务当作一次性进程运行
要实现高质量的微服务环境,可以不用严格遵循这些要素。但是,通过牢记这些要素,用户可以在持续交付环境中构建和维护可移植应用程序或服务。这是非常重要的。
实现云原生模式
云原生基础架构由应用程序来维护,而云原生应用则由基础架构来维护,两者密不可分。这就要求基础架构和应用程序设计必须是简单的。如果一个应用程序比较复杂,则应该采用微服务模式,将复杂功能拆分为细微的服务,然后通过集成这些细微服务来组装成一个应用系统。但由微服务构成的如此复杂的系统,势必无法通过人工管理,应该采用自动化管理,这也是云原生应用的一个基本特征。
在云原生架构下,应用的生命周期也是由软件来进行控制的,普通用户无须关心应用的生命周期。应用程序的集成、测试和部署应该是自动化、自助式的,按照DevOps文化来进行。
应用的生命周期是应用在宿主的环境中从创建,运行,到消亡的一种过程描述,对用户来说一个直观的感受是一个应用启动了,应用退出了,应用后台了
微服务
一个微服务基本是一个能独立发布的应用服务,因此可以作为独立组件升级、灰度或复用等;对整个大型应用的影响也较小,每个服务可以由专门的组织来单独完成,依赖方只要定好输入和输出接口即可完成开发,甚至整个团队的组织架构也会更精简,因此沟通成本低、效率高。
微服务将大型复杂软件应用拆分成多个简单应用,每个简单应用描述一个小业务,系统中的各个简单应用可以被独立部署,各个应用之间是松耦合的,每个应用仅关注完成一件任务并很好地完成该任务。相比传统的单体架构,微服务架构具有降低系统复杂度、独立部署、独立扩展、跨语言编程等特点。
微服务架构并不是技术创新,而是开发过程发展到一定阶段对技术架构的要求,是在实践中不断摸索而来的。微服务的核心思想是化繁为简的应用拆分。
微服务架构确实有很多吸引人的地方,然而它的引入也是有成本的,它并不是银弹,使用它会引入更多技术挑战,比如性能延迟、数据一致性、集成测试、故障诊断等。企业需要根据业务的不同阶段进行合理的引入。
目前,在微服务技术架构实践中主要有侵入式架构和非侵入式架构两种实现形式。
侵入式微服务架构:Spring Cloud
以阿里巴巴HSF、开源Dubbo和Spring Cloud 为代表的传统侵入式架构占据着微服务市场的主流地位。
侵入式架构将流程组件与业务系统部署在一个应用中,实现业务系统内的工作流自动化。
由于侵入式架构本身服务与通信组件互相依赖,当服务应用数量越来越多时,侵入式架构在服务间调用、服务发现、服务容错、服务部署、数据调用等服务治理层面将面临新的挑战。
服务网格推动微服务架构进入新时代。服务网格是一种非侵入式架构,负责应用之间的网络调用、限流、熔断和监控,可以保证应用的调用请求在复杂的微服务应用拓扑中可靠地穿梭。
非侵入式微服务架构:服务网格
服务网格是用于处理服务到服务通信的专用基础设施层。它负责通过包含现代云原生应用程序的复杂服务拓扑来可靠地传递请求。实际上,服务网格通常实现为多个轻量级网络代理(通常被称为 SideCar 模式),这些代理与应用程序代码一起部署,但不需要知道应用程序。
服务网格作为独立层的概念与云原生应用程序的兴起有关。在云原生架构中,借助于Kubernetes这样的编排器,单个应用程序可能包含数百个服务,每个服务可能有数千个实例,并且每个实例可能处于不断变化的状态。这就使得这些服务实例间的通信不仅非常复杂,而且确保端到端的性能和可靠性至关重要。
目前,服务网格已成为云原生堆栈的关键组件。
2017年5月 IBM和Google共同发布开源Istio。
Kubernetes主要是通过API或者声明式配置管理容器化工作负载和服务的一整套系统。
服务网格并没有给软件开发和部署带来新功能,它解决的是其他工具已经解决过的问题,只不过这次是针对云原生架构下的Kubernetes环境的实现。服务网格的主要特点有:
● 应用程序间通信的中间层。
● 轻量级网络代理。
● 应用程序无感知。
● 解耦应用程序的重试/超时、监控、追踪和服务发现。
目前两款流行的服务网格开源软件Istio和Linkerd都已经在Kubernetes中集成,但是Istio的接受度和采用量更多一些。
服务网格通过服务发现、路由、负载均衡、健康检查和可观察性来帮助管理流量。
2018年年初,Google、IBM 和Lyft 联合开发的项目Istio 的发布,标志着服务网格带领微服务架构进入新的时代。
云原生的未来
(1)混合云环境中使用云原生基础设施架构。
(2)在边缘计算中引入云原生技术,简化管理。
(3)服务网格继续发展,并以Istio领先。
(4)发展基于Kubernetes的融合函数即服务的技术fPaaS(又称FaaS)。
(5)基于成本考虑,云原生技术更多部署在裸机或者针对容器化定制的微虚拟机上。
(6)越来越多的第三方软件提供商采用容器化技术轻量级部署。
(7)对有状态应用的支持越来越丰满。
(8)跨Kubernetes的成熟项目将会越来越多。
敏捷基础架构
**传统的基础架构是由运维人员根据软件系统的需求进行人工管理。但是在云原生架构下,云原生应用的负载是动态分配的,完全没有人工参与。**其实际需求也不可能事先知道,例如淘宝双11活动期间,有多少用户访问购物是无法预先准确知道的。
在这种情况下,企业必须实现敏捷基础架构。
敏捷基础架构的目的是通过代码来自动化动态完成服务器部署、更新,以及存储和网络资源的动态分配,这样运维人员可以像开发软件系统一样快速迭代,从而迅速满足各项工作负载的即时需求。
云原生架构下的开发,要求可以自动化测试、构建、部署。
在一个完善的DevOps环境下,必须对常用的Yum、Maven、Nuget、NPM和Docker实施本地库镜像。
部署本地Repository(本地仓库)的方法有很多种,如可以选用Sonatype Nexus Repository Manager。
不仅基础架构是敏捷的,云原生应用的开发部署过程也是敏捷的过程。DevOps是开发(Development)和运维(Operations)的组合词,它是一种重视软件开发人员和IT运维技术人员之间沟通合作的文化、流程以及平台和工具。通过自动化软件交付和架构变更流程,使得构建、测试、发布软件能够更加快速、频繁和可靠。
在云原生架构下,由于Dev和Ops的工作职责非常清晰,所以两个团队变得相互独立又相互配合。应用开发团队完全负责产品的开发,而运维团队服务云原生基础架构的敏捷性,两者因为基础架构的标准化更加容易实现多种环境下的统一。
换句话说,云原生架构的DevOps变成了应用开发者和基础架构运维者之间的沟通。者和基础架构运维者之间的沟通,他们各自维护自己服务的生命周期,通过专业性提高效率,并且通过统一技术语言(如Kubernetes、容器化、微服务架构等)来进行沟通。
云原生下的监控可以使用 Prometheus 等。Prometheus是一个开源的监视和警报工具。
服务网格应用
基于Netflix OSS项目的Spring Cloud、阿里集团开源的Apache Dubbo都是优秀的微服务框架。
当前的微服务架构的实现往往是以代码库的方式构建在应用程序内部,这些代码库中包括了服务发现、熔断、限流等功能。代码库方式不但会引入潜在的版本冲突问题,而且一旦代码库变更,即使应用逻辑并没有任何变化,整个应用也要随之全部构建变更。
此外,企业组织和复杂系统中的微服务经常会使用不同的编程语言和框架实现,针对异构环境的服务治理代码库实现往往存在差异,缺少共性问题的统一解决方案。
为了解决上述问题,社区开始推动服务网格(Service Mesh)技术。
服务网格这个术语通常用于描述构成这些应用程序的微服务网络以及应用之间的交互。
Istio、Linkerd等都是服务网格技术的代表作。
服务网格的目标就是提供实现无关的服务通信基础协议栈。
企业上云
一场以IT技术为主体的科技革命浪潮正席卷而来,云计算、大数据、人工智能、物联网、区块链等新技术正加速应用落地。在这些新技术中,作为基础设施,云计算是这场科技革命的承载平台,全面支撑着各类新技术和新应用。
企业应用上云,按其使用云产品的深入程度分为云托管模式(IaaS 上云)和云原生模式(PaaS上云)两种类型。
IaaS 上云:云托管模式
IaaS解决了物理机资源的资源管理和资源供给问题,通过对计算、存储和网络的统一和抽象化实现基础资源的统一化供给。IaaS没有跨越开发和运维之间的鸿沟,开发人员仍然需要关注运行在操作系统上的各种基础中间件。
PaaS上云:云原生模式
PaaS的目标是为应用提供运行所需的各种基础软件,提供实际业务的开发运行环境,从而让业务系统的开发更加简便、高效。
企业上云是指企业通过互联网将企业的基础设施、管理及业务部署到云端上,即可利用网络便捷地获取云计算服务商提供的计算、存储、软件、数据等服务,从而提高资源配置效率、降低信息化建设成本、促进共享经济发展、加快新旧转换。
服务器:
服务器是专门提供服务的计算机,可以存储、处理和传输数据,并通过网络连接与其他设备进行通信。 服务器通常是物理设备,可以在本地托管或通过托管提供商进行外部管理。 服务器负责管理网络资源、提供对文件和应用程序的访问以及执行数据存储和备份功能。
云平台:
云平台是基于云计算模型的技术架构,通过网络提供各种计算资源和服务。 云平台可以包括各类服务器、存储设备、网络设备和软件,通过虚拟化技术和自动化管理实现资源的高效利用。 云平台灵活可扩展,用户可以按需获取所需资源,并根据业务需求动态调整资源。 云平台还提供许多高级功能,例如备份和恢复、安全和监控等,帮助用户更好地管理和保护其数据和应用程序。
服务器和云平台的区别:
首先,**云平台是基于云计算模型构建的,服务器是云平台的一部分。 **云平台可以包括多个服务器和其他设备以提供灵活且可扩展的资源。 服务器是云平台的基础设施,负责存储和处理数据,以及提供应用和服务。 云平台还可以通过虚拟化技术将多台服务器组合起来,实现资源共享和统一管理。
其次,云平台提供更先进、更全面的功能,帮助用户更好地管理和利用资源。 云平台通常提供备份和恢复功能,以保证数据的安全性和可用性。 它还提供监控功能,通过警报和报告对服务器和其他设备进行实时监控。 云平台还具有先进的安全功能,可以对数据进行加密和访问控制,以保护用户隐私和机密信息。 此外,云平台还提供自动化管理和自助服务能力,使用户能够更轻松地管理和配置资源。
云平台通常由第三方服务提供商管理和维护。 用户可以通过订阅服务的方式使用云平台,并根据实际使用情况付费。 这使得用户无需购买和管理自己的服务器和设备,从而降低了成本和风险。 此外,云平台通常具有较高的可靠性和稳定性,服务提供商通常会提供监控和维护服务,以保证平台的正常运行和故障恢复。
对于基础设施上云,我们一般称之为“云托管模式”,企业只是把原本部署在IDC机房服务器上的应用改为部署在云上虚拟机(或容器)中,应用的架构基本没有发生任何改变,上云的改造成本低、风险低。
采用云原生架构,使用适合云部署的技术,如虚拟化、容器化、微服务化,同时基础设施要建立相应的计算、网络、存储等资源池,采用计算虚拟化、软件定义存储(Software Defined Storage,SDS)、软件定义网络(Software Defined Network,SDN)、容器Docker等技术,提供IaaS、PaaS、SaaS、CaaS等云服务。
使用PaaS云,既不用创建虚拟机,也不用配置环境了,用户需要做的就是把应用部署到云平台上,即可使用。要想使用数据库,既不必使用数据库服务器、安装操作系统、安装数据库,也无须完成复杂的配置,所要做的只是在云平台上选择创建一个数据库服务,然后绑定到应用上就可以使用了,这就是PaaS云带来的变化。
Iaas、PaaS、SaaS
我们把企业信息服务比做盖房子,laaS是根据建造的需要,向大家提供各种各样的砖头。
接下来我们发现,一块砖一块砖的盖房子,效率太低了,这时候我们发明了预制件,在工厂里面,把墙面,楼板,立柱等等都预制好,到了现场直接组装,就可以完成建造,而这个提供预制件的服务就是PaaS,PaaS是资源提供方和最终使用方直接的过渡。
SaaS做得更干脆,直接为我们提供一个完整的房子。
SaaS 云服务提供商这时有 3 种选择:
-
租用别人的 IaaS 云服务,自己再搭建和管理 平台软件层和应用软件层。
-
租用别人的 PaaS 云服务,自己再部署和管理 应用软件层。
-
自己搭建和管理基础设施层、平台软件层和应用软件层。
企业应用架构演进
企业应用架构又经历了客户端/服务器(Client/Server,C/S)、浏览器/服务器(Browser/Server,B/S)、面向服务的架构(Service-Oriented Architecture,SOA)、前后端分离、微服务架构、Serverless等阶段。
单体架构
单体应用(monolith,也叫巨石应用)并不是单机应用,生产环境的单体应用通常是在一个集群环境下的多个节点部署的。单体应用架构是指业务功能的实现全部在一个进程(process)内完成。用户请求的接收、相关业务逻辑的调用、从数据库中获取数据等处理全部在一个进程内完成。一个应用的归档包(例如war格式或jar格式)包含了应用所有功能的应用程序,放入Tomcat等Web容器里运行,我们通常称之为单体应用。架构单体应用的方法论,我们称之为单体应用架构,这是一种比较传统的架构风格。
分布式架构
为解决单体应用面临的各种问题,技术人员以垂直拆分、水平拆分等不同手段,把一个大型单体应用系统拆分为若干独立的小应用系统。
每个小应用系统由一个团队负责开发维护,团队可自主选择该应用的系统架构及技术栈,应用的发布部署也更加自由灵活,应用之间通过分布式服务的方式进行交互,以企业JavaBean(Enterprise JavaBean,EJB)、WebService、消息队列(Message Queue,MQ)为代表的分布式架构逐渐成为大型复杂应用系统的技术选择。
在技术变革中,架构进一步被细分:
(1)第一个细分:前后端进行了分离。
(2)第二个细分:后端进行了服务化的拆分。
分布式架构是由一组通过网络进行通信、为了完成共同的任务而协同工作的计算机节点组成的系统架构。
SOA
随着分布式架构应用系统的水平+垂直拆分,应用系统以及服务的规模急剧上升,服务之间的相互调用关系盘根错节,系统烟囱林立、数据孤岛和应用协同又成为了企业信息化的问题。系统集成成为一个比较重要的问题,服务总线应运而生,它也算是SOA的雏形阶段。
SOA是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。
SOA站在系统的角度解决了企业系统间的通信问题,把原先散乱、无规划的系统间的网状结构梳理成规整、可治理的系统间星形结构,这一步往往需要引入一些产品,比如企业服务总线(Enterprise Service Bus,ESB)以及技术规范、服务管理规范。这一步解决的核心问题是“有序”,使构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。
通过服务的抽取和服务总线来实现应用系统的互通互联,消除数据孤岛。
服务总线不是SOA,而仅仅是通过服务抽取与暴露来解决互通互联的问题。SOA还有更重要的工作——对企业应用进行整体布局。
SOA能够统筹全局,实现企业应用系统的全局协同
SOA的整体架构分为3层:
最底层是单体应用,可记录系统,满足局部的业务能力;
中间层是SOA层,实现各个单体应用之间的协同,满足企业内部核心的业务流程;
最上层是门户层,实现协同业务或新业务的暴露。
SOA是一种粗粒度、松耦合的服务架构,服务之间通过简单、精确定义的接口进行通信,不涉及底层编程接口和通信模型。
站在功能的角度,SOA把业务逻辑抽象成“可复用、可组装”的服务,通过服务的编排实现业务的快速再生,其目的是把原先固有的业务功能转变为通用的业务服务,实现业务逻辑的快速复用,这一步解决的核心问题是“复用”。
SOA按照业务功能单元进行拆分,分为交互服务、信息服务等。每一个服务都是单体服务,单体服务之间通过企业服务总线进行交互。
SOA仅进行了垂直方向的拆分,对每个服务并没有按照水平方向进一步拆分,因此SOA的拆分也不彻底。
以IBM为代表的大型国际企业对SOA的发展起到了重要的推动作用,其提出的“业务服务化,服务流程化,流程标准化”的三化理念更是提供了企业实施SOA改造的方法论指导。
微服务架构:Spring Cloud
单体应用架构的设计都是针对应用本身的设计,而不是针对企业的设计。
SOA是真正意义上的面向企业全局的设计,但是SOA并没有发挥出SOA设计者预期的效果,而沦为一种应用集成的工具。
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协同、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP协议的REST API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。
微服务与SOA看似都是分布式服务化架构,但在服务设计理念以及系统运行架构方面,二者有着本质的区别:
1、服务粒度
SOA的出现其实是为了解决历史问题,即企业在信息化的过程中会有各种各样互相隔离的系统,需要有一种机制将它们整合起来,所以才会有ESB的出现。
SOA提供了粗粒度的服务能力,即大块业务逻辑的封装。
而微服务则更加轻量化,提供单独任务或小块业务逻辑的服务封装;
按照微服务的初衷,服务要按照业务的功能进行拆分,直到每个服务的功能和职责单一,甚至不可再拆分为止。
这样每个服务都能独立部署,方便扩容和缩容,能够有效地提高利用率。拆分得越细,服务的耦合度越小,内聚性越好,越适合敏捷发布和上线。
2、去中心化
SOA下服务的注册发现以及路由调用一般会通过ESB。
ESB 看似完美地兼容了现有的互相隔离的异构系统,可以利用现有的系统构建一个全新的松耦合的异构的分布式系统。但在实际使用中,它还是会有很多的缺点:
首先,ESB本身就很复杂,这大大增加了系统的复杂度和维护量。
其次,由于ESB想要做到所有服务都通过一个通路通信,其本身就是一个中心化的思路,因此ESB很容易成为系统运行的瓶颈。
微服务虽然也有一个“服务注册中心”,但一般只用于应用系统启动时注册或拉取服务地址,真正调用时并不会通过服务注册中心,而是直接从本地客户端的服务地址缓存中读取目标地址信息,点对点地发起服务调用,因此运行效率比经过中心节点路由转发要高很多,是一个“去中心化”的运行架构,消除了单点瓶颈,可扩展性也会更强。
服务网格架构:Istio
微服务架构也存在一些明显的弊端:
第一,对于采用RPC协议的微服务架构,不同微服务之间的调用存在协议绑定的问题;
第二,开发人员除了关注业务逻辑的实现,还需要在微服务模块中处理一系列问题,比如服务注册、服务发现、服务通信、负载均衡、服务熔断、请求超时重试等,这是非常糟糕的。
能否让业务开发人员仅关注业务开发,而不再关心服务间通信以及请求管理功能呢?服务网格(service mesh)架构解决了这个问题,它是微服务概念的延伸,目的是让业务开发人员真正从琐碎的技术中解脱,更加聚焦于业务本身。
在服务网格模式中,每个服务都配备了一个代理“sidecar”(边车),用于服务之间的通信。
在服务网格模式中,每个服务都配备了一个代理“sidecar”(边车),用于服务之间的通信。
这些代理通常与应用程序代码一起部署,并且不会被应用程序所感知。将这些代理组织起来形成了一个轻量级网络代理矩阵,也就是服务网格。
这些代理不再是孤立的组件,它们本身是一个有价值的网络。服务网格呈现出一个完整的支撑态势,将所有的服务“架”在网格之上。
服务网格是用于处理微服务和微服务通信的“专用基础设施层”,通常被实现为与应用程序代码一起部署的轻量级网络代理矩阵
它通过这些代理来管理复杂的服务拓扑,可靠地传递服务之间的请求。从某种程度上说,这些代理接管了应用程序的网络通信层,并且不会被应用程序所感知。
服务网格是云原生技术栈中一个非常关键的组件。
服务网格架构通过sidecar将服务治理与业务解耦并下沉到基础设施层,使应用更加轻量化,让业务开发更聚焦于业务本身,以体系化、规范化的方式解决微服务架构下的各种服务治理挑战,提升了可观察性、可诊断性、治理能力和快速迭代能力。
Serverless 架构
Serverless(无服务器)是一种构建和管理基于微服务架构的完整流程,允许用户在服务部署级别而不是服务器部署级别来管理应用部署,甚至可以管理某个具体功能或端口的部署,这能让开发者快速迭代,更快速地开发软件。
Serverless是一种架构理念,其核心思想是将提供服务资源的基础设施抽象成各种服务,以API的方式提供给用户按需调用,真正做到按需伸缩、按使用收费。
Serverless架构是传统云计算平台的延伸,是PaaS向更细粒度的BaaS和FaaS的发展,真正实现了当初云计算的目标。目前业界较为公认的Serverless架构主要包括两个方面,即提供计算资源的函数服务平台FaaS以及提供托管云服务的后端服务BaaS。
(1)函数即服务(FaaS)是一项基于事件驱动的函数托管计算服务。通过函数服务,开发者只需要编写业务函数代码并设置运行的条件,无须配置和管理服务器等基础设施。函数代码运行在无状态的容器中,由事件触发且短暂易失,并完全由第三方管理,基础设施对应用开发者完全透明。函数以弹性、高可靠的方式运行,并且按实际执行资源计费,不执行则不产生费用。
(2)后端即服务(BaaS)覆盖了应用可能依赖的所有第三方服务,如云数据库、身份验证、对象存储、消息队列等服务,开发人员通过 API 和由BaaS 服务商提供的SDK,能够集成所需的所有后端功能,而无须构建后端应用,更不必管理虚拟机或容器等基础设施,就能确保应用的正常运行。
Serverless规模在扩展性方面由于充分利用云计算的特点,因此其扩展是平滑的,同时由于Serverless是基于微服务的,而一些微功能、微服务的云计算是按需付费的,因此有助于降低整体运营费用。
Serverless架构是在传统容器技术和服务网格上发展起来的,侧重于让使用者只关注自己的业务逻辑。
从最早的物理服务器开始,我们在不断地抽象或者虚拟化服务器,以便提供更加轻量、更灵活控制、更低成本的基础设施。服务器越来越轻量化的演进过程如同人类的进化过程一般。
服务器技术发展是为上层应用系统提供更加敏捷的基础设施服务,轻量化意味着更强的弹性、更短的启动时间。弹性是云的核心能力,而在云原生Serverless架构下,这种弹性将表现得更加极致,无须提前评估业务并预置资源,所有的资源随需秒级拉起,用完即释放,真正做到按需付费。
物理机的性能在过去的几十年里始终保持以摩尔定律的速度在增长,这就导致单个应用根本无法充分利用整个物理机的资源,所以需要有一种技术解决资源利用率的问题。
简单地想,如果一个应用不能占满整个物理机的资源,就多部署几个,但在同一个物理机下混合部署多个应用,又会出现各种冲突以及资源争抢的问题。
因此开发人员想出各种各样的虚拟化技术来共享机器资源,提升资源利用率,同时又能确保应用之间有一定的隔离性以解决冲突与资源争抢的问题。
Serverless让用户零门槛地使用容器作为应用的部署载体,Serverless 不是没有服务器,而是应用不用关心服务器和系统,而只需关注代码,平台提供者将处理其余部分工作,剩下的运维等工作都不需要操心。这样消除了对传统的海量持续在线服务器组件的需求,降低了开发和运维的复杂性,降低了运营成本,并缩短了业务系统的交付周期,使用户能够专注在价值密度更高的业务逻辑的开发上。Serverless是真正的按需使用,请求到来时才开始运行,而且是按运行时间和所占用的资源来计费的,由于业务及流量的不确定性,对初创期的互联网企业而言,能大幅减少企业的IT成本。
Serverless是一种架构思想,秒级启动、极致弹性、按需计费、无限容量、不用关心部署位置、支撑全托管免运维的后端服务。基于容器及Kubernetes等行业标准,通过创新地应用极致弹性技术,托管传统应用,让用户不再关心容量评估,从容应对突发流量,大幅提升运维效率;加速中间件和开发框架轻量化,使用户在FaaS及轻应用框架上更自由、更便捷地探索和创新。
云原生技术
Docker、Kubernetes、Prometheus、微服务
云原生的核心技术之一就是容器,容器为云原生应用程序增加了更多优势。使用容器,我们可以将微服务及其所需的所有配置、依赖关系和环境变量移动到全新的服务器节点上,而无须重新配置环境,这样实现了强大的可移植性。
Docker 就是流行的容器技术。
容器技术也是一种资源隔离的虚拟化技术。
容器=cgroups(资源控制)+namespaces(访问隔离)+rootfs(文件系统)+engine(容器生命周期管理)
虚拟化技术可针对具体应用系统创建特定目的的虚拟环境。
容器是在Linux上本机运行,并与其他容器共享主机的内核,无须模拟操作系统指令,它是运行在宿主机上的一个独立的进程。
虚拟机运行的是一个完整的访客操作系统,每个虚拟机中都有一个独立的操作系统内核,通过软件模拟宿主机的操作系统指令,虚拟出多个OS,然后在OS的基础上构建相对独立的程序运行环境,因此隔离效果要比容器好一些。
由于容器的标准性、可移植性、可扩展性等优点,越来越多的企业生产系统开始使用容器作为应用部署的载体。随着分布式微服务系统架构的流行,企业生产系统应用节点个数呈爆发式增长,少则几百,多则几千上万。面对如此众多的应用节点(容器),其编排与日常运维管理成为重要的课题。
容器编排市场出现了Swarm集群和Kubernetes集群两大阵营。
Kubernetes底层基于Docker、rkt等容器技术,提供强大的应用管理和资源调度能力。
K8s(Kubernetes,源于希腊语,意为航海大师,缩写为K8s)是一个全新的、基于容器技术的分布式架构解决方案,并且是一个一站式的、完备的分布式系统开发和支撑平台。
Prometheus(意为普罗米修斯)是一套开源的系统监控告警框架。Prometheus是一个开源的服务监控系统和时序数据库,由Go语言编写而成。
作为新一代的云原生监控系统,Prometheus相比传统监控系统(如Nagios或Zabbix)具有如下优点:
(1)强大的多维度数据模型。
(2)灵活而强大的查询语句(PromQL)
(3)高效且灵活的存储方案:高性能本地时序数据库。
(4)易于管理:Prometheus Server是一个单独的二进制文件,可直接在本地启动工作,不依赖分布式存储;并且提供了容器化部署镜像,可以方便地在容器中拉起监控服务。
(5)支持多种发现机制:支持通过静态文件配置和动态发现机制来发现被监控的目标对象,自动完成数据采集。
(6)良好的可视化:有多种可视化图形界面,基于Prometheus提供的API,用户还可以实现自己的监控可视化UI。
(7)易于伸缩:通过使用功能分区(sharing)+联邦集群(federation)可以对Prometheus进行扩展,形成一个逻辑集群;Prometheus提供多种语言的客户端SDK,这些SDK可以快速使应用程序纳入Prometheus的监控中。
(8)采用HTTP:使用pull方式拉取数据,简单易用。
微服务框架
High-Spped Service Framework(HSF):HSF是阿里巴巴内部应用最为广泛的RPC协议的微服务框架。
HSF微服务框架是一个“去中心化”的服务框架。
Dubbo:Dubbo是阿里巴巴于2012年开源的分布式服务框架(目前已是Apache顶级项目),是一款高性能、轻量级的开源Java RPC框架。
Dubbo最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦(或者最大限度地松耦合)。
Spring Cloud:Spring Cloud建立在Spring Boot的基础之上,Spring Cloud为最常见的分布式系统模式提供了简单易用的编程模型,帮助开发人员构建弹性、可靠和协调的应用程序。
Spring Cloud是一系列框架的有序集合,它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,比如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控、链路追踪等。Spring Cloud 并没有重复造轮子,而是将市面上开发得比较好的模块集成进去,进行封装,从而减少了各模块的开发成本。
gRPC:gRPC是谷歌于2015年开源的技术框架,一个基于HTTP/2通信协议和Protobuf序列化的RPC实现。
从实现和特性来看,gRPC更多地考虑移动场景情况下客户端和服务器端的通信。
gRPC默认使用Protobuf进行序列化和反序列化。Protobuf是谷歌成熟的、开源的,用于结构化数据序列化的机制,是已经被证明的一种非常高效的序列化方式。同时,gRPC也可以使用其他数据格式,比如json。
服务网格(service mesh):
2016年由Buoyant公司首先提出了服务网格(service mesh)的理念。
service mesh推动微服务架构进入新时代。服务网格是一种非侵入式架构,用于处理服务到服务通信的专用基础设施层。它负责通过复杂的服务拓扑来可靠地传递请求。
实际上,服务网格通常被实现为与应用程序代码一起部署的轻量级网络代理矩阵,并且它不会被应用程序所感知。
service mesh帮助应用程序在海量服务、复杂的架构和网络中建立稳定的通信机制。
Linkerd、Envoy、Istio、SOFAMesh 等开源项目都是服务网格的框架。
SOFAMesh是蚂蚁金服于2018年开源的service mesh产品,SOFAMesh在产品路线上跟随社区主流,选择了目前service mesh中最有影响力和前景的Istio。
SOFAMesh的目标是打造一个更加务实的Istio落地版本,在继承 Istio 强大功能和丰富特性的基础上,为满足大规模部署下的性能要求以及应对落地实践中的实际情况而作必要的改进。
IaaS:设施即服务
云原生基础设施层IaaS包含计算资源、存储资源和网络资源、分布式系统基础服务、基础云服务,是整个云计算环境的基础。
计算资源、存储资源和网络资源属于物理硬件设备。
分布式操作系统、基础云服务主要用于对硬件设备进行整合管理,突破传统单机单用的架构,采用虚拟化、分布式存储、SDN等技术手段,构建动态可扩展的计算资源池、存储资源池、网络资源池,实现资源的共建共享,同时构建资源编排、自动化部署等自动化云服务,支持上层应用及各平台的稳定运行。
DaaS:数据即服务
DaaS 数据服务主要包含大数据平台、数据资源池和数据集成平台。
云原生架构把数据库当成一种资源服务,与应用系统进行解耦。
PaaS:平台即服务
企业级分布式应用服务是一个围绕应用和微服务的PaaS平台,为企业提供高可用和分布式的应用支撑平台。它不仅提供资源管理和服务管理系统,而且提供分布式服务框架、服务治理、统一配置管理、分布式链路追踪、高可用及数据化运营等。利用分布式应用服务,可以轻松构建微服务架构,建设大规模分布式系统,以发布和管理应用,协助应用进行 IT 系统转型,以满足不断增长的业务需求。
分布式应用服务平台是一个结合应用托管和微服务管理的PaaS平台,提供应用开发、部署、监控、运维等全栈式解决方案。
高可用
应用高可用(High Availability,HA)是一个综合性问题,IT系统的目标是为了确保业务的连续可用,所有可能引起业务无法按用户预期提供正常服务的问题,都属于高可用要解决的问题范畴。
系统的可用性有几个度量指标,其中最核心的是系统的平均无故障时间(Mean Time To Failure,MTTF)。MTTF标识了一个应用系统平均能够正常运行多长时间才发生一次故障。系统的可用性越高,平均无故障时间越长。一个系统的可维护性用平均维修时间(Mean Time To Repair,MTTR)来度量,即系统发生故障后维修和重新恢复正常运行平均花费的时间。系统的可维护性越强,平均维修时间越短。一般来说,应用系统的可用性定义为MTTF/(MTTF+ MTTR)×100%。
高可用设计
1、应用设计
1、消除单点
单点服务是一种比较简单的服务模型,所有服务功能在一个服务程序上实现,所有请求服务的客户端,都连接到这一台服务上,和服务直接通信。
分布式是云原生架构设计的根本,一个应用系统要实现真正的分布式,所有的层次都必须做到分布式,即从流量接入到服务调用、数据存储、缓存、消息队列、对象存储等,都必须是分布式,没有任何一个环节存在单点的问题,这样的系统才具备良好的弹性能力。
分布式还意味着去中心化。
2、无状态化
总体原则的一个推论就是,服务不应为有状态的。阻碍单体架构变为分布式架构的关键点就在于状态的处理。如果状态全部保存在本地,无论是本地的内存,还是本地的硬盘,都会给架构的横向扩展带来瓶颈。
无状态化并不意味着应用系统完全没有状态,而是通过状态外置来实现可伸缩部分服务的无状态化。
将状态保存在有状态的中间件中,如缓存、数据库、对象存储、大数据平台、消息队列等,这就是我们常说的状态外置。
3、幂等设计
幂等一般针对后台服务而言,“服务幂等性”是指针对某一服务的多次调用,只要请求的参数是一样的,那么服务返回结果一定是一致的,且后台系统不会因为多次调用而产生任何副作用。
比如:
支付宝扣款服务。
用户购买商品后支付(参数中会带订单流水号),调用支付宝扣款成功,但是返回结果时网络异常(此时钱实际上已经扣了)。前端应用请求超时会重试再次调用支付宝扣款服务,支付宝扣款服务内部会判断当前订单流水号是否已扣款。如果已扣款,则直接返回给前端应用“已扣款成功”;如果未扣款,则正常扣款后再返回给前端应用“已扣款成功”。
因此,即使前端应用针对同一个订单流水号多次重复调用支付宝扣款服务,支付宝返回的结果也应该是“已扣款成功”,而不能返回类似于“重复扣款”这样的异常,这就是服务的幂等设计。
再比如删除服务等,也需要遵循幂等设计。
5、弹性伸缩
弹性伸缩包括弹性扩展和弹性收缩,在业务高峰期,当系统负载较大时,通过横向扩展新的应用节点或者拉起新的容器来分摊原有压力节点上的负载,让系统平稳渡过前端应用高并发流量的冲击。而在业务低峰期,通过释放部分应用节点以提高资源的有效利用率。
自动弹性伸缩的规则一般包括CPU、负载基本服务器性能指标,也可以包括响应时间、线程数等应用相关的指标。自动弹性收缩时,系统会保证最低的服务节点数(一般不少于两个节点)。
还有人工弹性伸缩。
5、容错设计
容错性是指软件检测应用程序所运行的软件或硬件中发生错误并从错误中恢复的能力,通常可以从系统的可靠性、可用性、可测性等方面来衡量。
6、同步转异步
在实现方面,通常把同步的请求通过消息队列转成异步化订阅处理,以减少系统之间的耦合,避免核心应用被非核心应用拖垮。
7、缓存设计
缓存的主要作用是降低应用和数据库的负载,提高系统性能和客户端访问速度。在架构和业务设计上,可以考虑将访问量较大、不经常修改的(如字典表和系统参数),或对数据库性能影响较大的查询的结果进行缓存,以提高系统整体性能。
8、动静分离
动静分离是指静态页面与动态页面分开在不同的系统上访问的架构设计方法,静态资源(如html、js、css、img等)与后端服务分离部署。静态资源放在CDN、Nginx等设施上,访问路径短,访问速度快(几毫秒);动态页面访问路径长,访问速度相对较慢(数据库的访问、网络传输、业务逻辑计算),需要几十毫秒甚至几百毫秒,对架构扩展性的要求更高。
9、流控降级
流控降级相当于给后端应用系统上了一道保险,让系统具有一定的抗压能力,被广泛用于秒杀、消息削峰填谷、集群流量控制、实时熔断等场景中,从多个维度保障客户的业务稳定性。
流控,即流量控制(flow control),把随机到来的流量调整成合适的形状,即流量塑形,避免应用被瞬时的流量高峰冲垮。
熔断降级会在调用链路中某个资源出现不稳定状态(例如调用超时或异常比例升高)时对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。
10、应用健康检查
应用健康检查是为了确保当前节点的应用能够正常对外提供服务,一旦应用健康检查失败,管控节点(如负载均衡、服务注册中心、K8s管控等)必须及时把该故障节点摘除,防止请求再打到故障节点而导致业务失败。
11、优雅上下线
优雅上下线是实现业务7×24小时不间断运行的重要保障。为了实现应用版本变更的发布过程对在线业务的无感知,应用发布时我一般采用分批发布的策略。
假设某个应用集群中有10个节点,我们分5个批次,每一批只发布其中2个节点,确保一批一批地发布,线上的业务基本是不受影响的。
12、快速失败设计
面向失败设计原则是所有的外部调用都有容错处理,希望失败的结果是可预期的、经过设计的。系统发生异常时能够快速失败,然后快速恢复,以保证业务永远在线,不能让业务半死不活地僵持着。
2、数据设计
1、数据分布式
数据库的高可用一般分为主备数据库和分布式数据库。
通过分布式数据库中间件实现分库分表、平滑扩容、读写分离等技术,以此达到底层物理库的横向扩展,解决应用规模越来越大时数据库的吞吐量和容量的瓶颈。
分布式数据库通过添加物理资源的方式,让数据库的性能得以准线性的增长。
2、异构数据
应根据不同场景综合考虑技术储备和实现成本,选择最合适的数据库技术。
异构数据源之间的数据集成及同步,是设计高可用应用系统所必不可少的要素。应根据数据同步的场景,如离线同步/在线同步、全量同步/增量同步、实时同步/定时同步等,选择合适的同步技术及方案。
3、数据容灾
数据容灾是为了在灾难(地震、强台风、火灾、水灾等)以及人为重大误操作等情况下导致主数据中心机房被毁坏时,确保关键数据在一定时间内可恢复,让业务的损失降到可接受的程度。
根据数据灾备及数据多活的不同模式,数据的部署形态分为以下5种:
(1)A-S模式:即主备模式(Active-Standby)。只有主中心提供正常的数据服务,备中心仅作数据冷备,当灾难发生时,主中心才会切换到备中心。
(2)A-Q模式:即读写分离模式(Active-Query)。对于数据实时性要求不高的读场景,分发到备中心的数据提供只读服务,以此来分担主中心数据库的压力。
(3)A-A’ 模式:即非对称运行模式。主备中心提供业务读写服务,但是两者承接的业务是不同的,为避免数据交叉覆盖冲突,主备两边的业务数据必须能够完全分隔。备中心只承接部分非核心业务,主备之间数据双向同步。
(4)A-A 模式:即对称运行模式。主备中心提供完全相同的业务读写服务,通过前端的流量入口来标识区分具体某一次请求该路由到哪一个数据中心,不同用户之间数据不存在交叉覆盖的问题,主备之间数据双向同步。
(5)C-U模式:即单元化部署模式(Centre-Unit)。一般是多个中心的超大规模应用,如阿里巴巴内部的电商应用系统就采用单元化部署,分为中心节点和单元节点,根据用户的注册地点流量分发路由到就近的单元节点,单元节点内完成绝大部分的业务闭环,少数中心化服务(如库存相关服务)必须请求中心节点。
相应的多中心机房部署由简单到复杂依次为:单中心,同城双中心,两地三中心,三地五中心,五地七中心,以及多地多中心。
3、兼容性设计
1、数据变更约束
随着业务的变更,数据库表设计也需要变更,我们可能需要增加一些字段内容,以往的某些数据表字段如果不用了,可以删除吗?任何设计都是基于当前已知的业务场景和商业模式进行设计的,我们很难预测未来的变化。正因为如此,我们更希望在架构设计方面留有一定的弹性,在未来业务发生变化时,系统能够从容地应对这些变化,而不至于推倒重来。
在数据变更方面,我们同样希望通过良好的数据库设计尽量做到向下兼容,可以参考一下原则:
(1)1+N主从表设计:把相对稳定的基础数据放在主表中,把与特定业务相关的、容易变化的数据放在单独的从表(子表)中。
(2)冗余字段设计:在数据库表中预留一定个数的冗余字段,以备将来业务扩展使用,但这种模式导致设计不清晰,后期运维成本高。
(3)列转行设计:通过单独一张字段扩展表(setting表)来保存业务扩展信息,扩展表核心有3列,分别是主表主键、扩展字段名、扩展字段内容。主表的每一个扩展字段用扩展表的一行记录保存(即主表的列转成扩展表的行)。通过列转行的扩展表设计,理论上主表的列可以任意伸缩。
(4)字典表设计:数据表中的某一列,在不同的业务场景下,可能有不同的取值含义和取值范围,这时可以通过单独的字典表来定义业务规则。
2、数据库兼容
同一个应用代码可能需要适配不同的数据库。通过MyBatis官方提供的databaseIdProvider方案实现一套MyBatis文件,可以在多种关系型数据库中以兼容的方式运行。其主要思路是,在各数据库SQL具有差异化的写法,需要在MyBatis的mapper文件中,添加databaseId标签。
3、接口变更约束
在分布式应用架构下,服务之间的相互调用错综复杂,默认情况下,某个服务器端应用迭代升级时,应确保调用方接口的向下兼容,即调用方无须感知服务器端的应用升级。如果确实业务变动比较大,原有的接口无法满足要求,建议通过新增加一个接口的方式予以解决(或者如果服务支持多版本,也可以通过不同的服务版本号区分)。新老接口并行一段时间,给调用方一定的时间平滑升级过渡,待最终业务全部迁移到新接口,老接口再下线。
4、容量设计
1、容量预估
所谓容量预估,就是系统在被压垮之前所能承受的最大业务负载,这是技术人员了解系统性能的重要指标。容量预估一般通过全链路压测、线性分析、相似类比、经验判断等多种手段,综合评估当前应用系统所能承载的业务容量。业务容量是指针对特定业务场景,系统所能处理的峰值每秒事务数(Transactions Per Second,TPS)、吞吐量、响应时间(Reaction Time,RT)等性能指标。
2、容量规划
(1)什么时候应该增加服务节点?什么时候应该减少服务节点(比如服务器端接收到的流量达到什么量级)?比如“双11”、大促、秒杀。
(2)为了“双11”、促销、秒杀、渠道拓展引流等业务需求,需要扩展到什么数量级的服务,才能既保证系统的可用性、稳定性,又能节约成本?
容量规划是在容量预估的基础上,根据业务的发展规划,指出为了适应业务发展的需要,未来系统所能承受的业务容量规模,以及为了达到这样的容量规模,系统需要经过什么样的投入和改造。
高可用方案
1、全链路压测方案
提高一个系统的可用性的最有效方式就是通过测试进行验证。
最佳的验证方法就是让事件提前发生,即让真实的流量来访问生产环境,实现全方位的真实业务场景模拟,确保各个环节的性能、容量和稳定性均做到万无一失。这就是全链路压测产生的背景,也是将性能测试进行全方位的升级,使其具备“预见能力”。
全链路压测是指全业务覆盖、全链路覆盖的系统压测方式。全链路压测解决方案通过技术手段模拟海量用户的真实业务场景,让所有性能问题无所遁形。
全链路压测方案实施过程包括压测场景梳理(性能目标、时序图、状态图、系统架构、数据架构、技术架构)、全链路压测执行步骤、技术要点、环境改造(影子表、序列隔离、挡板拦截、mock、日志过滤、压测标识传递)、打底数据导入、压测数据(参数化)准备、工具支持等。
2、流控降级方案
应用流控降级广泛用于秒杀、大促活动、集群流量控制、实时熔断等场景中,确保系统在可预期的范围内正常运行,从多个维度保障业务的稳定性和可靠性。
3、故障演练方案
故障演练的目的在于演练常态化、故障标类化、演练智能化。用常态化的演练驱动稳定性提升,而不是大促前进行补习;丰富故障场景,定义好最小故障场景和处理手段;基于架构和业务分析的智能化演练,根据应用架构智能推荐故障演练场景,沉淀行业故障演练解决方案。
4、故障隔离方案
故障隔离是指当系统中某些模块或者组件出现异常故障时,把这些故障通过某种方式隔离起来,让其不和其他的系统产生联系,即使这个被隔离的应用或者系统出现了问题,也不会波及其他的应用。
故障隔离的基本原理是当故障发生时能够及时切断故障源,按其隔离范围由高到低依次为:数据中心隔离、部署隔离、网络隔离、服务隔离、数据隔离。
5、弹性伸缩方案
弹性伸缩的目标是为了实现服务容量线性扩展,即服务容量随服务提供者部署实例的个数线性扩展。弹性伸缩的前提是敏捷基础设施和资源池共享,敏捷基础设施确保应用需要伸缩时能够快速创建出所需的虚拟计算资源,资源池共享确保一个应用释放的资源能被其他应用所使用。
(1)弹性扩容
(2)弹性缩容
(3)弹性自愈:弹性伸缩提供健康检查功能(定时请求指定的服务地址,验证是否得到预期的返回),自动监控伸缩组内的虚拟机实例的健康状态,避免伸缩组内健康虚拟机实例低于预设的最小值。当检测到某台虚拟机实例处于不健康状态时,弹性伸缩自动释放不健康节点并创建新的服务节点,自动挂载新建的服务节点到负载均衡实例中。
6、应用应急预案
应用应急预案是当系统出现可预期和不可预期的各种异常时,为防止系统的异常对业务造成不可控的损失而预先设计的一种保障手段,是系统运维保障的最后一道防线。应急预案是全方位综合性的故障解决方案,既有技术方面的应急预案,也有管理流程方面的应急预案。
每一项应急预案包括明确的效果描述、触发条件、执行步骤、涉及的系统、影响范围、验证方式等,以及该预案的相关人,包括决策人、执行人等。
可以通过工具化提效,加速故障恢复,完善监控告警,精准快速地定位故障。
数据一致性解决方案
1、强一致性解决方案
在强一致性的分布式环境下,一次交易请求对多个数据源的数据执行完整性以及一致性的操作,满足事务的特性,要么全部成功,要么全部失败,保证原子性以及可见性。强一致性通过锁定资源的方式确保分布式并发下数据不会产生脏读脏写的情况,但以牺牲性能为代价。
一般来说,强一致性的分布式事务会比单机的本地事务性能下降一个数量级左右,因此在实际应用场景中使用时,需要谨慎评估业务上是否一定要求强一致性事务,可否在业务上做一些取舍和折中,或者改为性能更强一点的最终一致性方案。
XA协议是全局事务管理器与资源管理器的接口。
之所以需要XA,是因为在分布式系统中从理论上讲两台机器是无法达到一致性状态的,因此引入一个单点进行协调。由全局事务管理器管理和协调的事务可以跨越多个资源和进程,负责各个本地资源的提交和回滚。全局事务管理器一般使用XA二阶段提交(Two-Phase Commit,2PC)协议与数据库进行交互。
目前主流分阶段提交协议实际上也很难做到百分百的数据一致性,最终还是要采用“异步校验+人工干预”的手段来保障。
2、弱一致性解决方案
数据一致性在严格意义上只有两种分法,强一致性与弱一致性。强一致性也叫作线性一致性,除此之外,其他所有的一致性都是弱一致性的特殊情况。
所谓强一致性,即复制是同步的;弱一致性,即复制是异步的。
最终一致性是弱一致性的一种特例,保证用户最终能够读取到某操作对系统特定数据的更新。
弱一致性主要针对数据读取而言,为了提升系统的数据吞吐量,允许一定程度上的数据“脏读”。某个进程更新了副本的数据,但是系统不能保证后续进程能够读取到最新的值。典型场景是读写分离,例如对于一主一备异步复制的关系型数据库,如果读的是备库(或者只读库),就可能无法读取主库已经更新过的数据,所以是弱一致性。
3、最终一致性解决方案
由于强一致性的技术实现成本很高,运行性能低,很难满足真实业务场景下高并发的要求,因此在实际生产环境中,通常采用最终一致性的解决方案。
最终一致性不追求任意时刻系统都能满足数据完整且一致的要求,系统本身具有一定的“自愈”能力,通过一段业务上可接受的时间之后,系统能够达到数据完整且一致的目标。
最终一致性有很多解决方案,如通过消息队列实现分布式订阅处理、数据复制、数据订阅、事务消息、尝试-确认-取消(Try-Confirm- Cancel,TCC)事务补偿等不同的方案。
1、消息队列方案
方案的核心要点是建立两个消息topic,一个用来处理正常的业务提交,另一个用来处理异常冲正消息。
请求服务往业务提交topic发送正常的业务执行消息,不同的业务模块各自订阅消费该topic并执行正常的业务逻辑。
如果所有的业务执行都正常,数据自然也是完整一致的;
如果业务执行过程中有任何异常,则向业务冲正topic发送异常冲正消息,通知其他的业务执行模块进行冲正回滚,以此来实现数据的最终一致性。
该方案无法解决脏读、脏写等问题,使用时需要在业务上做一定的取舍。
2、事务消息方案
该方案的核心要点是消息队列产品必须支持半事务消息(如RocketMQ)。半事务消息提供类似于X/Open XA二阶段提交的分布式事务功能,这样能够确保请求服务执行本地事务和发送消息在一个全局事务中,只有本地事务成功执行后,消息才会被投递。该方案不会产生脏读、脏写等问题,且实现起来比较简单,但要求消息队列产品必须支持半事务消息,且消息一旦投递,默认设计业务执行必须成功(通过重试机制)。如果因为某些异常导致业务执行最终失败,系统无法自愈,则只能通过告警的方式等待人工干预。
3、数据订阅方案
该方案的核心要点是数据订阅产品[如阿里巴巴的数据传输服务(Data Transmission Service,DTS)、Data Replication Center(DRC)]能够接收数据库的更新日志(如MySQL的binlog、Oracle的归档日志)并转化为消息流供消费端进行订阅处理。业务执行模块消费数据变更消息并执行变更同步处理逻辑,以达到数据的最终一致性。由于数据订阅是异步的,会存在一定的消息延迟,且延迟时间依赖数据的变更量及数据订阅处理的性能。
4、TCC 事务补偿
TCC是服务化的二阶段编程模型,其尝试(try)、确认(confirm)、取消(cancel)这3个阶段均由业务编码实现。
此外还有 Saga 事务模式、Seata 全局事务中间件等模式来实现最终一致性方案。
容灾多活解决方案
容灾系统是指在相隔较远的异地,建立两套或多套功能相同的系统,系统之间可以相互进行健康状态监视和功能切换,当一处系统因意外(如火灾、洪水、地震、人为蓄意破坏等)停止工作时,整个应用系统可以切换到另一处,使该系统可以继续正常工作。容灾系统需要具备较为完善的数据保护与灾难恢复功能,保证生产中心不能正常工作时数据的完整性及业务的连续性,并在最短时间内由灾备中心接替,恢复业务系统的正常运行,将损失降到最小。
有数据容灾方案、同城双活方案、两地三中心方案、异地双活方案、单元化方案等。
数据容灾是指建立一个异地的数据系统,该系统是本地关键应用数据的一个实时复制(或离线复制,具体视业务可接受的数据丢失程度而定)。在本地数据及整个应用系统出现灾难时,系统至少在异地保存有一份可用的关键业务的数据。
同城双活方案是指同一城市内的两个机房同时部署业务,底层共用同一套存储,存储主备部署在不同机房。一般是服务双活数据主备的架构,真正做到数据双活的较少,因为数据双活的实施难度太大,双中心的数据一致性很难100%保证。
两地三中心是指“同城双中心”+“异地灾备”的一种商用容灾备份解决方案,是综合评估业务高可用和数据安全的一种折中方案,投入产出比较高,因此很多金融机构及大型企业的核心应用系统均采用这种方案建设。
两地三中心方案在同城双活的基础上,加了异地灾备中心来支持数据灾备服务,以确保同城双中心发生重大自然灾害(地震、海啸、火灾等)时重要业务数据不丢失(或仅少量丢失)。
异地双活(或者多活)是真正实现业务高可用的必要条件,任何一个城市出现重大灾难时,异地的机房仍可以确保核心业务的连续不中断。
不同于同城双活方案,异地双活的两个机房之间的距离要远很多,网络延迟已经超出业务允许的范围,数据主备架构单中心运行模式在性能上已经不可行。
为了避免两地机房之间的针对同一份数据的双向复制引起的冲突,异地双活(或多活)架构要求不同机房的数据基于特定的垂直拆分规则(如根据用户ID取模),能够完全拆分,不存在交叉重叠的数据。
单元化方案是对异地双活方案的进一步延伸,当异地机房个数超过两个时,多个机房之间的两两数据复制就会变得非常困难,且随着机房个数的增加这种复杂度会急剧上升。
单元化架构由若干单元节点和一个中心节点构成。
单元化方案中会存在一个中心节点,中心节点存放无法按单元进行拆分的中心应用及全局数据,如电商系统中卖家相关的数据以及库存相关的数据,要求所有单元看到的这些全局数据都是同一份。为了实现中心节点可以接管任何一个单元的业务,中心节点还会保存全量的单元数据,即所有单元都会把该单元的数据复制到中心节点。这样,当某一个单元出现故障时,其流量将由中心单元接管,中心单元访问中心节点的单元全量数据。