这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
本文总结微服务架构课程中所做的笔记,行文逻辑是课堂上讲解的逻辑,并对其中弄不懂的概念进行了穿插注释。
微服务架构介绍
系统架构演变历史
原因:互联网爆炸性发展、硬件设施快速发展……
单体架构
将所有的业务场景的表示层、业务逻辑层和数据访问层放在一个工程中,最终经过编译、打包,部署在一台服务器上。
优点:性能最高、冗余小
缺点:debug困难、模块相互影响
垂直应用架构
按照业务线把项目垂直划分成多个子项目
优点:业务独立开发维护
缺点:不同业务存在冗余、每个业务还是单体
分布式架构
抽出业务无关的公共模块,根据业务性质的不同做好分层
优点:业务无关的独立服务
缺点:服务模块bug可导致全站瘫痪、调用关系复杂、不同服务冗余
SOA(Service Oriented Architecture)架构
在分布式架构的基础上进一步优化,面向服务,引入服务和服务注册的概念
优点:服务注册,解耦
缺点:整个系统设计是中心化的、需要自上至下设计、重构困难
微服务架构
是SOA架构的一种拓展,这种架构模式下它拆分粒度更小,服务更独立,把应用拆分一个个微小的服务。
优点:开发效率高、业务独立进展、自下而上、故障隔离
缺点:治理、运维难度,观测挑战,安全性,分布式系统
….
微服务架构核心要素:服务治理、可观测性、安全
微服务架构原理及特征
基本概念
服务:一组具有相同逻辑(运行相同代码)的运行实体
实例:一个服务中每个运行实体即为一个实例
实例与进程:没有必然的对应关系,一个实例通常对应一个或多个进程
服务间通信:对于单体服务,不同模块通信只是简单的函数调用。对于微服务,服务间通信意味着网络传输。
服务注册与发现
如何在代码层面调用目标服务的地址?
-
指定ip:port?- 因为服务实例的IP和端口本身是动态变化的
- 一个服务有多个实例,对应多个IP
-
指定域名DNS?- 本地DNS存在缓存,导致延时
- 负载均衡问题
- 不支持服务实例的探活检查
- 域名无法配置端口
-
服务注册与发现:
- 新增一个统一的服务注册中心,用于存储服务名到服务实例的映射。如下图所示:
服务上线及下线
下线:先把在服务注册中心注销相应的映射,然后再下线机器
上线:先上线机器,再将IP及端口写道服务注册中心
流量特征(流量视角微服务长什么样子):
统一网管入口
内网通信多采用RPC
网状调用线路
核心服务治理功能
服务发布
让一个服务升级运行新代码的过程
难点:服务不可用、服务抖动、服务回滚
实践
蓝绿部署:
- 将服务分成蓝绿两个部分,分别先后发布
- 简单、稳定
- 但需要两倍资源(因此在流量低峰时进行蓝绿部署)
灰度发布(金丝雀发布):金丝雀发布通过在生产环境中小规模地部署新版本,以便在生产环境中评估新版本的影响,并通过监控和诊断工具来验证新版本是否正常工作。如果新版本发现了问题,可以立即回滚。
- 先发布少部分实例,接着逐步增加发布比例
- 不需要增加资源
- 回滚难度大,基础设施要求高
流量治理
在微服务架构中,可以从各个维度(地区、集群、实例、请求)对端到端的流量在链路上进行精确控制,如下图所示
负载均衡
负责分配请求在每个下游实例上的分布
- 常见的LB策略
- Round Robin(轮询调度):是一种以轮询的方式依次将一个域名解析到多个IP地址的调度不同服务器的计算方法。
- Random:随即调度
- Ring Hash:一致性哈希算法
- ……
稳定性治理
定义:线上服务总是会出现问题,这与程序的正确性无关
原因
- 网络攻击
- 流量突增
- 机房断电
- 光纤被挖
- 机器故障
- 网络故障
- 机房空调故障
- …
方法
限流:下级服务无法处理上级服务传递的全部数据,便会reject一些
熔断:在下级服务濒临崩溃的时候,立即中断服务,从而保障系统稳定避免崩溃
过载保护:是指负载超过系统的承载能力时,系统会自动采取保护措施,确保自身不被压垮。
降级:当服务过载,重要服务能正常工作,不重要的服务被reject
字节跳动服务治理实践
重试的意义:
-
重试可以避免掉偶发的错误,提高SLA(sevice-level agreement)不过需要注意,本地函数调用没有重试的必要,远程函数调用有重试的必要(因为有可能因为网络问题导致函数调用失败)。
-
降低错误率
-
降低长尾延时
- 对于偶尔耗时较长的请求,重试请求有机会提前返回
-
容忍暂时性错误
-
避开下游故障实例
重试的难点
幂等性:多次请求导致的数据不一致
重试风暴:服务分成很多级,随着调用深度的增加,重试次数指数级上涨
超时设置:超时时间的选择依赖于具体的情况,不能一概而论
重试风暴的解决措施
限制重试比例:设定一个重试比例阈值(例如1%),重试次数占所有比例不超过该阈值。因为重试只有在大部分请求成功,少量失败时才有必要,如果大部分请求失败,重试只会增加问题的严重性
防止链路重试:限制每层都发生重试,理想情况下只有最下一层发生重试,如果最下一层重试失败,可以返回特殊的状态变量status,表明请求失败,但不要重试
hedged request:对于可能超时的请求,重新向另一个下游实例发送一个相同的请求,并等先到达相应的效果:
思考题
- 结合 CAP 等原理,思考微服务架构有哪些缺陷?
- 维护数据一致性比较困难
- 随着微服务数量增多,系统的复杂度和成本相应增加
- 分布式链路难以跟踪,测试困难
- 微服务是否拆分得越“微”越好?为什么?
- 并不是,期间微服务的分解要考虑到业务需求,代码耦合度和维护难度等因素。
- Service Mesh 这一架构是为了解决微服务架构的什么问题?
- 解决系统架构微服务化后的服务间通信和治理问题