系统架构演变历史
单体架构,垂直架构,分布式架构,SOA 架构,微服务架构,...
-
单体架构:把所有的逻辑放在一个项目里面。劣势是 debug 困难,模块相互影响,模块分工,开发流程很难
-
垂直应用架构:按照业务线垂直划分,这下业务可以独立开发维护了,但是不同业务存在冗余,而且每个业务还是单体
-
分布式架构:垂直应用 + 抽出与业务无关的公共模块(服务层)。劣势是服务模块 bug 可导致全站瘫痪,调用关系复杂,不同服务之间可能冗余
-
SOA:面向服务。垂直应用 + 服务注册中心和服务发现 + 服务层。劣势是整个系统设计是中心化的,必须先明确有几层,层中有哪些组件,从上至下设计,重构困难
- 微服务架构:彻底的服务化。网关 + 各类服务 + MQ(消息队列),在周边有服务配置和治理,链路追踪和监控这两个大平台。自下而上业务独立的设计。最大的优势是开发效率高,故障隔离,容易重构。劣势是分布式系统通用的问题,治理,运维的难度,观测的难度
基本概念和核心要素
基本概念
服务:一组具有相同逻辑(代码一样)的运行实体
实例:一个服务中,每个运行实体即为一个实例。一个实例对应一个或多个进程,反之不会存在。常见的实例承载形式,进程,VM,k8s pod
集群:服务内部实例之间的划分,包含多个实例
有状态/无状态服务:服务的实例是否存储了可持久化的数据,例如磁盘文件
服务间通信:对于单体服务,不同模块通信只是简单的函数调用,对于微服务,服务间通信意味着网络传输(不同的实例通常是不同的机器)
通信协议:HTTP gRPC Thrift
核心要素
- 服务治理:服务注册和发现,负载均衡,扩缩容,流量治理,稳定性治理
- 可观测性:不能每个服务登上去看。所以要设置一些观测点。日志采集,分析,监控大点,大盘,异常报警,链路追踪(类似于调用栈,看服务的调用链,这个链条甚至是跨机器的)
- 安全性:服务之间的调用必须有认证授权的过程。身份验证,认证授权,访问令牌,审计,传输加密,黑产攻击
服务注册与发现
背景
找某个服务和端口,一般直接自己定义,硬编码一个目标服务的地址。但是在微服务中这个方法不行,因为
- 服务地址会变(可以用 DNS 解决,但是本地 DNS 存在缓存时不时得刷新)
- 一个服务里有多个实例,如果固定指定地址,如何做到多个实例负载均衡(这下不能用 DNS 解决了)
- 不支持服务实例的探活检查,这个实例是正常运行,还是挂掉了
- 域名无法配置端口
- 无损的实例上线和下线
类似于 DNS 引入一个中间层,负责服务注册和发现,新增一个统一的服务注册中心,用于存储服务名到服务实例的映射,不仅注册 ip 还可以注册 端口,还能在这个注册中心中做负载均衡和探活
无损实例上线和下线
下线:在下线之前先删掉注册信息,这样外面的服务和客户就不会调用这个实例了,过个几秒钟这个实例就没有流量了,可以下线
上线:先把实例加好,做健康检查,试一试能不能真的处理请求,再把这个实例注册上去
流量特征和流量控制
流量特征:负载均衡,统一网关入口,打入不同服务中
一般来说,内网通信多数采用 RPC,在统一网关入口之后就是 RPC 了
网状调用链路
CDN,内容分发网络 = 更智能的镜像+缓存+流量导流
Offline training job:一些机器学习工作,其结果也以调用微服务的形式呈现
在微服务架构下,可以基于地区,集群,实例,请求等维度,对端到端的路由流量进行精细化过程
- 地区:比如让 60% 的流量打到北京,40% 的流量达到上海
- 集群:10% 测试集群,90% 线上稳定集群
- 实例:新机器多流量,老机器少流量
- 请求:内部用户发起测试请求(有个测试标识),让这部分流量进测试实例
服务发布
一个服务升级运行新代码的过程
其难点在于:服务不可用是不行的(服务实例大家一起下线升级),服务抖动(某个实例短暂不可用),服务回滚(升级完之后大家都有 bug 了,会造成服务不可用,需要回滚)
解决方法:
- 蓝绿部署:把实例分成两个逻辑集群,先关闭绿色集群,升级绿色,然后再把流量全切到绿色集群,关掉蓝色,升级蓝色。这方法简单稳定但需要两倍资源(一半的资源可以处理全部需求,不过这方法可以用在流量低谷的时候,比如说凌晨四五点)
- 金丝雀发布(灰度发布,滚动发布):上线一只新的金丝雀,如果观察正常,那么实例就一个个陆续切换到新版本。但精细地切流量是个难点,因为要不断改注册表均衡,回滚也是难点,不能像蓝绿一样批量操作
负载均衡
负责分配请求在每个下游实例上的分布,Load Balance 组件
常见的 LB 策略:Round Robin, Random, Ring Hash(一致性哈希),Least Request
稳定性治理
背景:线上服务一定是会出问题,与程序的正确性无关,别人可能会挖光纤之类。所以搞一些组件降低损失
- 限流,被调用者 rate limit 组件
- 熔断,负载过大或被调用者有问题不反应,就熔断,拒绝更上游的流量,间断性试试被调用者能不能连上
- 过载保护,被调用者 dynamic overload 组件,检测系统性能如果 CPU 占用太大,就拒绝一部分流量
- 降级,degrade,保证上游重要服务,拒绝上游次要服务
这节课离在校学生好像有点远,也接触不到这种环境,但却是企业实践中非常重要的部分。大项目试着用微服务写一写吧