分布式服务架构
服务化架构
传统的单体应用的问题:
- 无法满足对海量用户发起的高并发请求进行处理的需求
- 无法突破耦合在一起的模块化组件的性能瓶颈
- 水平扩展的能力有限
为了解决上面的问题,提出了面向服务的架构,即SOA。SOA将单一进程的应用程序拆分为多个模块化组件,每个组件都是一个进程,然后通过定义明确的接口来使各个组件进行通信。SOA定义了良好的对外接口,服务之间松耦合,高内聚,服务内部实现的改变不影响对外提供服务。同时也增加了服务的可重用性,避免了重复开发。
SOA的两种实现方式:
- Web Service。Web Service技术中,提供服务的模块通过UUDI协议将服务注册到Web Service目录中,服务通过WSDL定义的服务发现接口进行访问,并通过SOAP协议进行通信。dubbo也算是Web Service思想的一种实现。
- WSDL(网络服务描述语言,Web Services Description Language)是一门基于XML的语言,用于描述 Web Services 以及如何对它们进行访问。
- SOAP是一种使应用程序有能力通过 HTTP 交换信息的基于 XML 的简易协议。
- ESB。ESB是企业服务总线的简称。ESB服务没有中心化的服务节点,每个服务提供者都是通过总线的模式插入系统,总线根据流程的编排负责将服务的输出进行转换并发送给流程要求的下一个服务。Mule是ESB的一个实现。
微服务架构
SOA的问题:
- web Service依赖中心化的服务发现机制
- ESB的总线本身也是中心化的
微服务特点:
- 微服务架构把每个指责单一的功能放在一个独立的服务中,
- 每个服务有自己独享的数据库、缓存、消息队列资源,服务之间不允许共享数据。
- 微服务没有了中心化的节点。
微服务的组合方式:
- 服务代理模式(例如:dubbo、RMI)
- 服务聚合模式(例如一个服务调用三个服务聚合成一个结果)
- 服务串联模式(A调用B,B调用C)
- 服务分支模式(就是上面三个模式的组合)
- 服务异步消息模式(调用后不等待返回结果)
- 共享数据模式(共享数据库、缓存,减小网络开销、提高性能。不符合微服务的理念,可以用来解决性能问题或遗留系统)
微服务的容错:
微服务的之间的通信通常是restful风格的远程调用,网络通信是不稳定、不可靠的。所以就需要能够及时的发现问题、隔离问题,避免问题导致的资源耗尽等雪崩效应。
- 舱壁隔离模式
- 微服务容器分组
- 线程池隔离
- 熔断机制。当下游的服务因为某种原因突然变得不可用或响应过慢,上游服务为了保证自己整体服务的可用性,不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。常用的熔断器Hystrix
- 限流。主流的限流算法有:
- 计数器滑动窗口算法。通过原子变量计算单位时间内的访问次数,如果超出某个阈值,则拒绝后续的请求,等到下一个单位时间再重新计算。计数器的实现通常定义一个循环数组。计数器算法的缺点是单位时间的粒度比较粗的时候,会出现“突刺现象”,无法有效的达到目的。
- 漏桶算法。漏桶算法能够强行限制数据的传输速率,可以解决“突刺现象”。其实就是一个阻塞队列。
- 令牌桶。通过一个线程以固定速率把令牌放入令牌桶,如果令牌桶装满了,则丢弃令牌。每次请求调用需要从令牌桶中获取到令牌后才能进行请求。令牌桶算法能够在限制数据的平均传输速率的同时还允许某种程度的突发传输。
- 失效转移。
- 快速失败
- 备份服务
微服务的拆分粒度:
拆分越细,耦合度越小,内聚性越高,越适合敏捷发布和上线。但会导致服务数量太多,依赖关系复杂,需要的团队越多。所以从业务需要、团队情况、可重用性、变更频率、接口复杂度来衡量。
分布式一致性问题
分布式系统在哪些地方会遇到一致性问题
- 服务之间同步调用时因网络异常导致的调用失败
- 缓存与数据库不一致
- 各个节点的本地缓存不一致
酸碱平衡理论
ACID
强一致性:原子性、一致性、隔离性、持久性
CAP原理
C:consistency,强一致性。分布式系统中的所有数据备份,在同一时刻具有同样的值。
A:availability,可用性。在任何故障下,服务都会在有限的时间内处理完成并进行响应。
P:partition tolerance,分区容忍性。尽管网络上有部分消息丢失,但系统仍然可以继续工作。
CAP原理是指任何分布式系统智能满足CAP中的两个。
CA:如果要保证一致性和可用性,那么就必须要网络情况良好,服务之间不能因为网络发生数据丢失,那么就必须将所有服务部署在同一个分区,所以系统就不是一个分布式系统了。
CP:如果要满足一致性和分区容忍性,那么数据发生丢失时,为了保证一致性,就必须阻塞请求,等待数据同步一致后再提供服务,因此就不能再有限的时间内处理完成请求。
AP:如果要保证可用性和分区容忍性,那么数据发生丢失时,系统仍然要提供服务,那么不同的网络分区的数据将会不一致。
BASE模型
BASE模型包含三个元素:
- BA:basically available 基本可用。指分布式系统在出现故障的时候,保证核心可用,允许损失部分可用性。
- S:soft state,软状态,状态可一在一段时间内不同步。指允许系统中的数据存在中间状态,并认为该中间状态不会影响系统整体可用性,即允许系统不同节点的数据副本之间进行同步的过程存在时延
- E:eventually Consistent,最终一致,在一定时间窗口内,最终数据达成一致。
分布式一致性协议
DTS分布式事务处理模型中包含四个角色:应用程序、事务管理器、资源管理器、通信资源管理器。通常,我们将事务管理器成为协调者,将资源管理器称为参与者。
两阶段提交协议
两阶段提交协议把分布式事务分为两个阶段。
- 准备阶段。准备阶段协调者向参与者发起指令,询问是否可以执行事务提交操作,如果参与者评估事务可以完成,则会写redo/undo日志,然后锁定资源,执行操作,但不提交。
- 提交阶段。如果每个参与者准备阶段都返回准备成功,那么协调者向参与者发起提交指令,参与者提交资源事务,然后释放锁定的资源;如果任何一个参与者准备阶段返回准备失败,那么协调者就会向参与者发起终止指令,所有参与者取消已经变更的事务,释放锁定的资源。
两阶段提交协议在准备阶段锁定资源,这是一个重量级的操作,能保证强一致性。但是他还有三个缺点:
- 阻塞:任何一个指令都必须收到明确的响应才能继续进行,否则一直处于阻塞状态,占用的资源会被一直锁定,不会被释放。
- 单点故障:如果协调者宕机,参与者没有协调者的指挥,就会一直阻塞下去。如果协调者在发送一个提交指令后宕机,那么新上来的协调者将无法处理这种情况。
- 脑裂:提交阶段协调者发送提交指令,有的参与者没有接收到提交指令,就不会执行事务,那么多个参与者之间就会出现不一致。
三阶段提交协议
三阶段提交协议通过超时机制解决了阻塞的问题。
- 询问阶段:询问阶段协调者询问参与者是否可以完成指令,参与者只需要回答是或不是,不需要做真正的操作,这个阶段超时会导致终止。
- 准备阶段:如果在询问阶段所有参与者都返回可以执行操作,那么协调者向参与者发送预执行请求,这个阶段和两阶段提交协议的准备阶段是一样的,参与者执行操作但不提交。如果在询问阶段,任意参与者返回不能完成指令,那么协调者向参与者发送终止指令。
- 提交阶段:如果所有参与者在准备阶段都返回准备成功,那么协调者向所有参与者发行提交指令,参与者提交事务,释放资源。如果任何参与者返回准备失败,那么协调者将参与者发起终止指令,参与者取消已经变更的事务,释放资源。
三阶段提交协议的优点是在每个阶段都增加了超时。如果询问阶段超时会导致终止,准备阶段和提交阶段超时会继续提交事务。
三阶段提交协议增加了询问阶段,询问阶段可以确保尽可能早地发现无法执行操作而需要终止的行为,但是它并不能发现所有这种行为,只会减少这种情况的发生。
TCC协议
两阶段提交协议和三阶段提交协议在遇到极端情况时,系统会产生阻塞或者不一致的问题,需要手动解决。
另外,这两种方案都包含了多个参与者、多个阶段实现一个事务,实现复杂,性能也是很大的问题。
TCC协议将一个任务拆分成Try、Confirm、Cancel三个步骤。正常的流程会先执行Try。如果执行没有问题,则再执行Confirm;如果执行过程中出了问题,在执行操作的逆操作Cancel。TCC在出现问题时有一定的自我修复能力。TCC在极端情况下出现问题时,系统首先可以通过补偿的方式尝试自动修复,如果系统无法自动修复,这必须由人工参与解决。
保证最终一致性的方法
- 查询+补偿。补偿操作根据发起形式分为三种:1)程序自动回复;2)运行操作;3)紧急发布
- 消息队列异步补偿达到最终一致,保证消息处理器的幂等性。
- 定期校对。
- 缓存一致性:优先使用分布式缓存;数据库和缓存只需要保持弱一致性。
超时处理模式
服务与服务之间的交互模式有:同步调用、接口异步调用、消息队列异步处理。
同步和异步的选择:
- 能用同步解决的问题不要引入异步。因为你异步引入复杂度。
- 在遇到性能问题时,从业务的角度,尽量使用异步来替换同步操作。
- 同步调用可以使用查询+补偿的方式保证最终一致性
- 异步调用应该尽最大努力将用户的请求操作处理成功
补偿有两种不同方式:调用方补偿和被调用方补偿。
系统容量评估和性能保障
系统非功能质量需求
非功能质量指标包括:高性能、可用性、可伸缩性、可扩展性、安全性、可监控性、可测试性、鲁棒性、可维护性、可重用性、易用性
应用服务器的非功能质量需求有:负载均衡策略、线程池模型、每天请求量、请求响应时间、在线用户数、请求大小、网络IO、磁盘IO、内存占用率、CPU占用率、进程上下文切换次数、缓存失效和预热策略
数据库的非功能质量需求有:分库分表策略、读写分离、归档策略、数据容量、数据增量、读峰值、写峰值、索引、慢查询
缓存的非功能质量需求:缓存失效和预热策略、淘汰策略、缓存大小、缓存数量、过期时间、缓存穿透、缓存雪崩、是否避免资源竞争
消息队列的非功能质量需求:数据增量、读峰值、写峰值、每条消息大小、消息删除策略、消费者线程池模型、哈希分片策略
技术评审内容
- 描述业务现状和遇到的问题,以及要实现的新需求
- 方案描述。方案的概述简要概括方案的亮点,包括双写,迁移主从分离,分库分表,扩容,归档。
- 详细描述方案的架构包括中间件架构、逻辑架构和数据架构,方案的优点,以及性能评估。方案的中间件架构包括数据库的选择,缓存以及消息队列。嗯。逻辑架构包括模块的划分,数据的流向,模块的通信。数据架构包括数据结构,数据库的拆分策略,缓存策略。方案的详细说明还包括异常处理,灰度发布,上线方案以及回滚方案。方案的性能评估包括测试基准,单机并发量,单机容量还有单机吞吐量。
- 方案的对比给出选择的理由
- 技术评审还包括风险评估和工作量评估
容量评估
性能评估
常用的系统层性能指标
- 硬盘IO
- 网络IO
- 数据库
- IDC
- 网站UV、PV
性能压测方案
- 确定压测目标。
- 设计压测方案。
- 准备压测环境。
- 执行压测。
压缩方案中首先要分析业务场景,然后确定测试类型。测试类型包括基准测试,容量测试,负载测试,稳定性测试和异常测试。
容量测试是指检查系统能处理的最大业务量,在测试过程中采用梯度加压的方式,不断增加并发用户数。监控响应时间、系统资源的变化情况。
负载测试用于测试单个接口,在不产生任何错误的情况下,能够提供的最佳系统性能。从而得出单个接口在响应时间,满足用户需求时的最大吞吐量和并发数。
压测的目的是找到系统在满足一定的响应时间需求,并保证系统资源利用率合理的情况下,系统能够提供的最优吞吐量、最佳的响应时间和所承受的最佳并发数。
压测的加压方式有三种。瞬间加压,逐渐加压,梯度加压
压测的终止方式有两种,逐渐退出和立即退出。
准备压测环境时,尽量在多个客户端机器上对同一机器进行测试,避免因为客户端机器导致的压测结果不准确。
压测工具:ab、jmeter
线上事故处理
海恩法则:每一起严重事故的背后,必然有29次轻微事故和300起未遂先兆及1000起事故隐患。
海恩法则强调2点:
- 事故的发生是量的积累的结果
- 再好的技术、再完美的规章,在实际操作层面也无法取代人自身的素质和责任心。
线上应急的原则
- 第一时间恢复系统、快速止损而不是彻底解决问题
- 应急指挥要围绕目标,快速启动应急过程和快速决策止损方案。
- 当前应急责任人如果短时间内不能解决问题,则必须进行升级处理
- 应急过程中在不影响用户体验的前提下,要保留部分现场和数据
线上应急步骤
- 发现问题
- 定位问题
- 解决问题
- 消除影响
- 复盘(回顾问题、避免措施)
发现定位问题方法论
- 最后是否有变更/上线/升级,如果有则会滚
- 是否遇到过同类问题,如果有,使用历史经验
- 是否有相关领域专家,如果有找专家
- 复现、找到原因、解决、验证、上线