13-微服务框架原理与治理实践
[TOC]
13.1 微服务架构介绍
13.1.1 系统架构演变历史
需要演进的原因
历史
①单体架构
把所有逻辑放在一个软件下面
优点:效率高,性能高,冗余小
缺点:debug困难;模块相互影响;模块分工复杂、开发流程
②垂直应用架构
按照业务线垂直划分,每个业务线又是一个单体架构。
优势:业务独立开发维护
缺点:不同业务存在冗余;每个业务还是单体
③分布式架构
抽出业务无关的公共模块
优势:业务无关的独立服务;公共服务的去冗余
缺点:服务模块bug可导致全站瘫痪;调用关系复杂;不同服务冗余
④SOA架构
面向服务
优势:服务注册
缺点:整个系统设计是中心化的;需要从上到下设计;重构困难
⑤微服务架构
彻底的服务化
优势:开发效率高;业务独立设计;自下而上;故障隔离
缺点:治理、运维难;观测挑战;安全性;分布式系统
13.1.2 微服务架构概览
①网关
②服务配置和治理
③链路追踪和监控
13.1.3 微服务架构核心要素
- 服务治理
- 可观测性
- 安全:身份验证、服务之间调用的认证授权...
13.2 微服务架构原理及特征
13.2.1 基本概念
- 服务
- 一组具有相同逻辑的运行实体 = 一个服务就是运行同一段代码的多个实例
- 相同逻辑:一个服务的代码是一样的,必须运行相同的代码
- 运行实体:实例
- 实例:一个服务中,每个运行实体就是一个实例
- 实例与进程的关系:没有必然对应关系,可以一实例对一/多进程,反之不常见
- 集群cluster:通常指服务内部的逻辑划分,包含多个实例
- 常见的实例承载形式:进程,VM,k8s pod
- 有状态/无状态服务:服务的实例是否存储了可持久化的数据(如磁盘文件)。如存储式的服务-有状态,代理式的服务-无状态
- 服务包含集群,集群包含实例
- 服务间通信
- 对于单体服务:不同模块通信只是简单的函数调用
- 对于微服务:服务间通信意味着网络传输
- 服务之间通信通常包含一些协议如HTTP,gRPC...
13.2.2 服务注册与发现
// service A wants to call service B
client := grpc.NewClient("10.23.45.67:8080")
问题:①ip地址是变化的,不能写死 ②一个服务有多个实例,这样只指定一个实例是不行的
解决:用域名DNS
新问题:
①本地DNS是存在缓存的,会导致延时;
②负载均衡问题:返回具体哪一个ip,大多数时间会选择第一个
③不支持服务实例的探活检查;
④域名无法配置端口
解决:服务注册中心,用于存储服务名到服务实例的映射
服务实例上线及下线过程:
服务B的第三个实例有问题,需要下线——问题是服务A有流量过来
下线:
①在服务注册中心,把第三个实例的记录删掉
②删掉几秒后,服务A不会再调用第三个实例,那么就没有流量
③删除B的第三个实例,是安全的——下线
上线:
①先在B中把实例加好,并进行health check
②实例注册到服务中心里
③服务A发现第三个实例,流量又可以恢复了
13.2.3 流量特征
两种流量 HTTP和RPC,一般而言,终端进来的流量是HTTP,后来进到里面后变成RPC
统一网关入口
内网通信多数采用RPC
网状调用链路
13.3 核心服务治理功能
13.3.1 服务发布
服务发布:让一个服务升级运行新的代码的过程。
相关笔记:服务发布全流程
①服务发布的难点
- 服务不可用。服务A使用服务B,B要更新不可用了,A瘫痪
- 服务抖动。流量短暂不可用
- 服务回滚。旧代码没问题,升级的新代码有问题,那么不管问题大小都先倒回旧代码,使损失最小。
②蓝绿部署
把服务B分成绿色和蓝色的集群。
先断掉绿色集群,然后升级;升级完毕后,将蓝色集群服务流量导入到绿色集群,然后断掉蓝色集群进行升级。由此达成无错的升级
优点:简单,稳定
缺点:但需要两倍的资源,要求一半的实例要求处理所有的流量
③灰度发布(金丝雀发布)
达到提前探险的效果。
节省发布资源但有代价:
整个发布以实例为维度去切流量——难度大
回滚的难度大
13.3.2 流量治理
微服务架构下,我们可以基于地区、集群、实例和请求,对端到端流量的路由路径进行精确控制。
①地区
beijing,shanghai
②集群
serviceA,稳定集群
③实例
serviceB,老机器处理性能不如新机器
④请求
serviceC,普通流量走正常集群;内部请求去特征测试实例
13.2.3 负载均衡
负载均衡,load balance负责分配请求在每个下游实例上的分布。
常见策略:Round Robin...
13.2.4 稳定性治理
线上服务总会出问题,这与程序的正确性无关。
外界因素:网络攻击,流量激增,机房断电,光线被挖,机器故障,网络故障,机房空调故障....
客观因素无法避免,那么在系统层面努力维护。
稳定性治理功能:
- 限流
- 熔断
- 过载保护
- 降级
13.4 字节跳动服务治理实践
13.4.1 重试的意义
本地函数调用:会有各种异常,不能保证调用一定成功。这里没有重试的必要
远程函数调用:网络抖动等异常。这里有重试的必要,重试可以避免掉偶发的错误
降低错误率
降低长尾延时:对于偶尔耗时较长的请求,重试请求有机会提前返回
容忍暂时性错误
避开下游故障实例:重试其他实例
13.4.2 重试的难点
重试是默认不用的。所以不要无脑重试
- 幂等性
- 重试风暴:微服务的调用链路是很深的
- 超时设置
13.4.3 重试策略
①限制重试比例
设定一个重试比例阈值(如1%),重试次数占所有请求比例不超过该阈值。
大部分成功的情况下才有必要重试;若大部分失败那么重试都失败,没有意义。
②防止链路重试
核心是限制每层都发生重试,理想情况下只有最下一层发生重试。
可以返回特殊的status表名“请求失败,但别重试”。
③hedged requests,对冲请求
对于可能超时的请求,重新向另一个下游实例发送一个相同的请求,并等待先到达的响应。
13.4.4 重试效果验证
验证经过上述重试策略后,在链路上发生的重试放大效应。