目录

微服务

分布式与微服务的异同:

  1. 分布式一般以机器为单位,不同机器上部署不同的模块;微服务一般以进程为单位,每个进程是一个服务
  2. 服务的粒度比模块粒度小
  3. 微服务属于分布式,只不过是粒度更小

微服务简介

围绕业务功能构建的,通过业务拆分实现服务组件化,服务关注单一业务,不同服务可组合来实现更复杂的业务,更灵活;服务间采用轻量级的通信机制

优点

  1. 每个模块的代码量相对较小,易于维护
  2. 每个模块具有单一职责,逻辑清晰
  3. 独立进程,隔离部署 方便容器化
  4. 去中心化服务治理
    1. 数据去中心化:每个服务独享自身的数据存储设施(缓存、数据库),有利于服务的独立性
    2. 治理去中心化:去全局热点
    3. 技术去中心化:每个服务可使用自己的技术(语言、中间件等)

ps:热点问题:“热"即访问频率高,“点"即一个地方,热点就是访问频率高的一个地方

缺点

  1. 基础设施的建设复杂
  2. 分布式一致性问题

基础设施自动化

微服务的系统复杂度较高,需要一套自动的测试和部署工具

  1. CI/CD:gitlab + gitlab hooks + k8s
  2. Testing:测试环境、单元测试、API自动化测试
  3. 在线运行时:k8s,及一系列的Prometheus、ELK、control panel

可用性 & 兼容性

记住design for failure思想,所有的代码或设计都可能失败

  1. 隔离
  2. 超时控制
  3. 负载保护
  4. 限流
  5. 降级
  6. 重试
  7. 负载均衡

尽量采用粗粒度的进程间通信,比如rpc请求时,不要多次请求一条数据,而是一次请求一批数据(减轻网络压力)
接口兼容性:发送时保守(最小化传输必要信息),接收时开放(最大限度容忍冗余数据)

微服务设计

API Gateway网关

/images/go/ms0.png

以上图片是第一版,直接将业务垂直拆分,每个服务提供多个面向资源的RESTful API
缺点:前后端强耦合,前端一个业务要关联多个后端API;前端需要多次请求(因需要多个API)
重点:将面向资源的API转换为面向业务的API(底层API的组合),不要让前端来进行API组装,要前轻后重

/images/go/ms1.png

以上图片是第二版,加入了基础的网关,后端和网关对接,网关统一业务接口
优点:轻量交互、差异服务
缺点:单点故障 这种架构称为BFF(backend for frontend):后端组装数据,进行数据编排,为前端提供服务

/images/go/ms2.png

以上图片是第三版,网关拆分,不同组件针对不同的业务
缺点:对跨横切面的功能来说变得复杂,如路由、安全、限流、日志,若每个组件都实现一遍则会很复杂

/images/go/ms3.png

以上图片是第四版,加入了API Gateway,用来处理跨横切面的功能
整个架构可分为以下几层:

  • 负载均衡
  • API GateWay:实现跨横切面的功能
  • BFF:数据组装、编排,实现面向业务的API
  • 原子服务:提供面向资源的API

微服务如何划分

  1. 按业务来组织服务:即拆分后的服务所提供的能力要与业务功能对应。如订单服务和推荐服务,但订单服务和数据服务则不是一种好的拆分
  2. DDD(Domain-Driven Design 领域驱动设计)的有界上下文
    1. /images/go/ms4.png
  3. CQRS:命令查询分离,类似读写分离
    1. /images/go/ms5.png

整个架构分成无状态和有状态两个部分,业务逻辑的部分作为无状态的部分,很容易的横向扩展,在用户分发的时候,可以很容易分发到新的进程进行处理;状态保存在后端有状态的中间件中,如缓存、数据库、对象存储、大数据平台、消息队列等,这些中间件设计之初,就考虑了扩容时状态的迁移、复制、同步等机制,不用业务层关心。
微服务的无状态化是为了将应用服务更好的扩容,和原子性操作无关,要看服务是否要保留之前的交互数据,如果完全不需要保存,或者统一放到了分布式的数据库中,就是无状态的。

微服务安全

外网:用户鉴权
内网:服务之间不能乱调,要进行权限认证,要知道调用我的是什么

/images/go/ms6.png
JWT

gRPC & 服务发现

grpc优势:

  • 支持多语言
  • 基于http2,二进制、支持双向流、单TCP的多路复用、服务端推送等特性
  • 使用protocol buffer定义服务
  • 使用protocol buffer序列化,比单纯的json效率高
  • grpc有标准的健康检测协议

与http的不同: grpc是关注于服务调用的,而http是关注于传输的;另外grpc是强约束的,消息和服务都是用pb定义好的,而http的参数则比较随意;另外对http的连接可能还要手动维护连接池等,但grpc都自己做好了

grpc 客户端流式,服务端流式,双向流式,在应用中的具体实例:

  1. 客户端流式:请求里 req 包比较大,但 response 包比较小
  2. 服务端流式:请求里 req 包比较小,但 response 包比较大,可以用于定时任务拉取分页信息,缓存中拉取全量数据等。包太大一次返回对服务压力很大,所以在不要求对时间情况下,可以通过流式返回
  3. 双向流式:比如 im 通信,watch 事件

健康检测HealthCheck

/images/go/ms7.png

健康检测是指检测服务是否正常运行,k8s可以检测,grpc也可以检测,相同之处为两者都可以判别服务是否正常,不同之处在于探测时所经过的网络链路不同,k8s是注册中心到服务,grpc是服务调用者到服务,若服务到服务调用者之间的链路故障,但k8s探测后为正常,那么此时服务调用就会超时,但grpc检测是经过此条链路的,若故障则会报告服务不正常,会将此服务节点下线或故障转移,而不会导致服务超时

健康检测还可用于滚动更新:平滑下线与平滑发布
滚动更新:下线旧版本,上线新版本,所以需要平滑下线与上线,一下是结合healthcheck的平滑发布与下线

平滑下线步骤:

  1. 在管理平台(如k8s)上点击下线按钮,会发送SIG_TERM信号给应用,应用在收到退出信号后会先向服务发现中心注销服务,随后服务发现中心便会通知各个consumer此节点不再有效,consumer将关于此节点的链接关闭,当provider中没有连接时则进行下线退出。但通知是需要时间的,所以provider也可以让healthcheck接口置为失败状态,若consumer发现接口不通则也进行相应的下线处理。但若有一些bad case,如consumer一直保持着与provider之间的连接,则此时管理平台(如k8s)会有一个下线超时(10-60s),若超时则强制退出

平滑发布步骤:

  1. 一个服务(provider)上线以后,什么时间向服务发现中心注册这个服务信息呢?做法是provider有一个healthcheck的接口,外部的工具(如k8s)会来调用这个接口,如果这个接口通了,就会向服务发现中心进行注册,这种服务注册方式也成为外挂注册

kill pid 默认发送SIG_TERM信号,kill -9 pid 发送SIG_KILL信号,TERM信号会被应用catch,应用可以选择退出或不退出或在退出前进行一定的处理,而KILL信号应用却catch不住,所以相当于强杀

服务发现

客户端发现
/images/go/ms8.png
客户端查服务的注册表,然后将这些服务通过负载均衡来直接连接
直连较快,但客户端各个语言都要实现一遍服务发现

服务端发现:
/images/go/ms9.png
客户端只需连接到负载均衡器即可,服务发现和负载均衡均由负载均衡器(服务端)来处理

/images/go/ms10.png

服务端发现有个缺点就是比较复杂

service mesh

服务网格是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但对应用程序透明。
简言之:将负载均衡和服务发现等功能与应用服务部署在一起,即在一个pod中

优点:

  1. 屏蔽分布式系统通信的复杂性(负载均衡、服务发现、认证授权、监控追踪、流量控制等等),服务只用关注业务逻辑;
  2. 真正的语言无关,服务可以用任何语言编写,只需和Service Mesh通信即可;
  3. 对应用透明,Service Mesh组件可以单独升级;

缺点:

  1. Service Mesh组件以代理模式计算并转发请求,一定程度上会降低通信系统性能,并增加系统资源开销;
  2. Service Mesh组件接管了网络流量,因此服务的整体稳定性依赖于Service Mesh,同时额外引入的大量Service Mesh服务实例的运维和管理也是一个挑战;

多租户

多租户如测试用户和正常用户,B`是待测试的功能节点,可通过header标记进行路由,测试用户路由到B`,正常用户路由到B
也就是给流量打上不同的标签,如果某些服务有新功能需要测试就拿到此标签的流量进行处理
本质就是路由

/images/go/ms12.png

/images/go/ms11.png

其他

提升架构性能

/images/Distribution/architecture.png

提高稳定性方式

/images/Distribution/stable.png

核心技术

/images/Distribution/core.png

有状态的服务调度

  1. 对于应用层上的分布式事务一致性,只有两阶段提交这样的方式。
  2. 而底层存储可以解决这个问题的方式是通过一些像 Paxos、Raft 或是 NWR 这样的算法和模型来解决。