这是我参与「第三届青训营 -后端场」笔记创作活动的的第 9 篇笔记
微服务架构介绍
系统架构演变历史
1. 单体架构
思想:所有的业务逻辑放在一个项目里面
优势:性能最高、冗余小
劣势:debug困难,模块之间相互影响,模块分工、开发流程复杂
2. 垂直应用架构
思想:按照业务线垂直划分,根据不同的业务线划分多个模块,每条业务线都是单体架构
优势:业务独立开发维护
劣势:不同业务存在冗余,每个业务还是单体,每个业务就存在单体架构的问题
3. 分布式架构
思想:抽出业务无关的公共模块,对公共逻辑进行复用
优势:业务无关的独立服务
劣势:服务模块bug可导致全站瘫痪,调用关系复杂,不同服务冗余
4. SOA架构
思想:面向服务
优势:服务注册
劣势:整个系统设计是中心化的,需要从上至下设计,重构困难
5. 微服务架构
思想:彻底的服务化
优势:开发效率,业务独立设计,自下而上,故障隔离
劣势:治理、运维难度高,观测挑战,安全性,分布式系统
微服务架构核心要素
- 服务治理:服务注册、服务发现、负载均衡、扩缩容、流量治理、稳定性治理
- 可观测性:日志采集、日志分析、监控打点、监控大盘、异常报警、链路追踪
- 安全:身份验证、认证授权、访问令牌、审计、传输加密、黑产攻击
微服务架构原理及特征
基本概念
- 服务(service):一组具有相同逻辑的运行实体
- 实例(instance):一个服务中每个运行实体即为一个实例
- 实例与进程的关系:实例与进程中没有必然对应关系,一个实例可以对应一个或多个进程
- 集群(cluster):通常指服务内部的逻辑划分,包含多个实例
- 常见的实例承载形式:进程、VM、k8s pod等
- 有状态/无状态服务:根据服务的实例是否存储了可持久化的数据(例如磁盘文件);存储性质的服务是有状态的,代理性质的服务是无状态的
服务间通信
对于单体服务,不同模块间的通信只是简单的函数调用,对于微服务,服务间通信意味着网络传输
服务的注册与发现
服务的注册中心:用于存储服务名到服务实例的映射,通过注册中心访问服务,同时可以完成负载均衡、服务监测的功能
服务下线:从注册中心将实例映射删除->将实例下线
服务上线:将实例上线->健康检查->增加实例映射->服务刷新发现新的实例
流量特征
- 统一网关入口
- 内网通信多路采用RPC
- 网状调用链路
核心服务治理
服务发布
服务发布即让一个服务升级运行新的代码的过程
服务发布的难点
- 服务不可用:kill旧服务,新服务发布过程会导致服务不可用
- 服务抖动:短暂的替换过程,服务不可用
- 服务回滚:如果新的服务有bug,需要回滚到旧服务,等新服务修复后重新升级
1. 蓝绿部署
将服务复制成两个相同的集群(蓝色集群),服务升级时,断掉一个蓝色集群,然后对他进行升级为绿色集群,此时的流量全部由另一个蓝色集群处理;然后对绿色集群上线,蓝色集群断掉,此时所有流量由绿色集群处理,对蓝色集群升级为绿色后上线
优点:简单、稳定
缺点:需要两倍资源
2. 灰度发布
先上线一个新的版本的实例,然后检测服务是否有bug,如果没有发现bug再一步步的去升级新的实例,新代码是逐渐占据主要逻辑的,趁早发现bug节省发布资源
流量治理
在微服务架构下,可以基于地区、集群、实例、请求等未读,对端到端的流量的路由路径精确控制
负载均衡
负载均衡负责分配请求在每个下游实例上的分布
常见的LB策略
- Round Robin
- Random
- Ring Hash
- Least Request
稳定性治理
线上服务总是会出问题,这与程序的正确性无关,如:
- 网络工具
- 流量突增
- 机房断电
- 光纤被挖
- 机器故障
- 网络故障
- 机房空调故障
微服务架构中的稳定性治理功能
- 限流:限制服务访问的频率
- 熔断:当下游服务出现问题,熔断器会熔断对下游服务的请求,然后检测下游服务的正常,如果下游服务恢复了再冷却
- 过载保护:在下游服务负载过大,减少服务的负载
- 降级:下游服务压力过大,对等级高的服务处理,等级低的去掉
字节跳动服务治理实践——请求重试
重试的意义
远程函数调用可能出现网络抖动、下游负载高导致超时、下游机器宕机、本地机器负载高导致调度超时、下游熔断限流;此时调用的请求是可能是有效的,所有有重试的必要
- 重试可以避免掉偶发的错误,提高SLA(Service-Level Agreement)
- 降低错误率:假设单次请求的错误率为0.01,那么连续两次错误概率为0.0001
- 降低长尾延时:对于偶尔耗时较长的请求,充实请求有机会提前返回
- 容忍暂时性错误:某些时候系统会有暂时性异常(例如网络抖动),重试可以尽量规避
- 避开下游故障实例:一个服务中可能会有少量实例故障(例如机器故障),重试其他实例可以成功
重试的难点
- 幂等性
- 重试风暴
- 超时设置
重试策略
- 限制重试比例:设定一个重试比例值,如(1%),重试次数占请求比例不超过该阈值
- 防止链路重试:链路层面防止重试风暴的核心是限制每层都发生重试,理想情况下只有最下一层发生重试,可以返沪i特殊的status表明请求失败但不要重试
- Hedged requests:对于可能超时(或延时高)的请求,重新向另一个下游实例发送与一个相同的请求,并等待先到达的响应