后端基础| 青训营笔记

81 阅读7分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 8 天

微服务架构是当前大多数互联网公司的标准架构,开源领域有大量的相关组件可以进行复用。
学校期间接触较少,提前了解相关知识和背景
可学到: ①微服务架构的由来及原理;②服务治理功能是如何工作的
为什么系统架构需要演进?
①互联网的爆炸性发展 ②硬件设施的快速发展 ③需求复杂性的多样化 ④开发人员的急剧增加 ⑤计算机理论及技术的发展
演变历史:单体架构——垂直应用架构——分布式架构——SOA架构——微服务架构
单体架构,all in one process

image.png
优势: 1.性能最高2.冗余小
劣势: 1.debug困难2.模块互相影响3.模块分工、开发流程 垂直应用架构:按照业务线垂直划分

image.png
优势: 1.业务独立开发维护
劣势: 1.不同业务存在冗余 2.每个业务还是单体 分布式架构:抽出业务无关的公共模块

image.png 优势: 1.业务无关的独立服务
劣势: 1.服务模块bug可导致全站瘫痪 2.调用关系复杂 3.不同服务冗余 SOA架构:面向服务

image.png 优势:1.服务注册
劣势:1.整个系统设计是中心化的2.需要从上至下设计3.重构困难 微服务架构:彻底的服务化

image.png 优势: 1.开发效率2.业务独立设计3.自下而上4.故障隔离
劣势: 1.治理、运维难度2.观测挑战3.安全性4.分布式系统 微服务架构概览

image.png

核心要素:服务治理 可观测性 安全性
服务:一组具有相同逻辑的运行实体(运行同一串代码的多个实例)
实例:一个服务中,每个运行实体即为一个实例
实例和进程的关系: 一个实例可以对应一个或多个进程
集群:通常指服务内部的逻辑划分,包含多个实例
常见的实例承载形式:进程、VM、k8s pod.......
有状态/无状态服务:服务 的实例是否存储了可持久化的数据(例如磁盘文件)
HDFS NameNode(单实例)和DataNode应该看出两个服务
服务间通信:
单体服务:不同模块通信只是简单的函数调用
微服务:服务间通信意味着网络传输

image.png

在代码层面,如何制定调用一个目标服务的地址?
①hard code:问题,当你写死之后,他只能访问到一个实例
②DNS:
1.本地DNS存在缓存,导致延时
2.负载均衡问题(提供多个IP,可能会只返回第一个IP)
3.不支持服务实例的探活检查
4.域名无法配置端口(要事先约定要端口)

解决思路:新增一个统一的服务注册中心,用于存储服务名到服务实例的映射。(简单来说就是一个哈希表或者map)

image.png

服务实例上线及下线过程 image.png 假设服务三有问题,直接下线,流量过来会失败,先删记录,然后服务中心就不会去访问服务三,其他两个压力可能会比较大,先把新增的实例增加,然后做一个健康检查,通过之后,就把实例注册到服务中心,恢复流量

流量特征:统一网关入口 内网通信多数采用RPC 网状调用链路

image.png (基于流量的维度)
HTTP文本协议运行效率比较低而RPC是二进制协议,所以效率高

服务发布:即指让一个服务升级运行新的代码的过程。
服务发布的难点:

image.png
蓝绿部署
对于要升级的部分,将他的逻辑分成两个分布的集群,然后先把绿色的集群的流量切过去蓝色那边,然后升级完之后全部导回去绿色,然后再把蓝色的切掉再升级。
优点:简单、稳定
缺点:需要两倍的资源
每天app的流量具有高峰低峰,所以在流量低的情况下就能够进行
灰度发布(金丝雀发布)
新增一个新的代码实例,然后再观察有没有问题,然后没有问题就进行更换,加一个减一个。
挑战:需要精确分割实例,然后回滚比较困难,任何时候都有可能需要回滚。

流量治理:在微服务架构下,我们可以基于地区、集群、实例、请求等维度,对端到端流量的路由路径进行精确控制

image.png

负载均衡:负责分配请求在每个下游实例的分布
①Round Robin(绝对公平的LB策略) ②Random ③Ring Hash 跟请求有一个特定的反应的关系(一致性哈希) ④Least Request

稳定性治理:线上服务总是会出问题的,这与程序的正确性无关
网络攻击流量突增 机房断电 光纤被挖 机器故障 网络故障
机房空调故障
微服务架构中典型的稳定性治理功能

image.png 限流:A的流量太大,然后去调用服务B,Bhold不住,然后有一个rate limit去reject 服务A的请求。
熔断:在服务B的负载过大的时候,服务A调用B的时候,A会有一个熔断器,直接拒绝上一层的流量,服务A可以间断性地尝试连接服务B。
过载保护:服务B压力比较大,B有一个dynamic overload可以直接reject流量
降级:服务B流量过大,B有一个degrade对流量进行级别的划定,然后对优先级高的先执行,低的reject掉

字节在重试方面的实践
本地函数调用可能会有哪些异常:
①参数非法 ②ooM (Out of Memory) ③NPE (Null Pointer Exception) ④边界 case ⑤系统崩溃 ⑥死循环 ⑦程序异常退出
本地函数调用一般没有重试的必要
远程函数调用可能会有哪些异常:
①下游负载高导致超时 ②下游机器宕机 ③本地机器负载高,调度超时 ④下游熔断、限流 ⑤网络抖动 .......
远程函数调用有重试的必要
重试可以避免掉偶发的错误,提高SLA(Service-Level Agreement)

image.png
长尾延时:大部分100ms响应返回,有几个请求会拖到1s。
重试的难点:
幂等性:它描述了一次或多次请求某一个资源对于资源本身应该具有同样的效果,即第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用。
重试风暴

image.png 假设每次都是无脑重复三次,具有指数级的雪崩


超时设置:默认超时是1s,然后第一次超时多少你设置多少合适?第二次?第三次?.....无通用的方法
重试策略:
限制重试比例——设定一个重试比例阈值(例如1%)重试次数占所有请求比例不超过该阈值
防止链路重试——链路层面的防重试风暴的核心是限制每层都发生重试,理想情况下只有最下一层发生重试,可以返回特殊的status表明“请求失败,但别重试”

image.png


Hedged request(对冲请求):
对于可能超时(或延时高)的请求,重新向另一个下游实例发送一个相同的请求,并等待先到达的响应。

image.png

字节内部重试的实践 image.png