【架构】评分较高的三本微服务书籍的阅读笔记

1. 前言

最近看了三本有关微服务的书:

  • 《凤凰架构》
  • 《微服务设计模式》
  • 《微服务实战(第二版)》

同时回顾了一本通用知识的书:

  • 《数据密集型应用系统设计》

从宏观上看,微服务都是重构出来的,所有作者都不建议一上来就把项目搭建成微服务。这种基于重构来搭建微服务的指导思想是:要明确知道微服务解决单体的缺点时,同时也引入了风险和挑战,当微服务的风险和挑战大于单体架构时请谨慎。当微服务的收益大于单体架构时,需要遵循一些设计原则甚至是必备的组件。除了比较抽象的原则外,作者都给出了具体的例子,其中国外的《微服务设计模式》给出了个很完整的重构方案,其中“服务的拆分策略”尤为经典,并且受到《凤凰架构》的认同。但是使用的技术都是国外且是最新的,对工程师有较高的要求;《凤凰架构》则是结合国内流行的技术,以架构师的视角对分布式技术娓娓道来,其中很多流程图很接地气;《微服务实战(第二版)》顾名思义,是一本实战书,开箱即用的代码(基于Docker)十分直观的介绍了微服务中流行技术的应用层代码实现,包括之前从未听过但是功能很强的Resilience4j

2. 合并目录

三本书讲的东西是有交集的,现在做一个目录合并,旨在突出:

  1. 重复即重要的知识点
  2. 对同一事物不同角度论述的知识点
  3. 可以交叉验证的知识点

2.1 目录全景

具体目录的顺序分别对应如下

  • 凤凰架构
  • 微服务设计模式
  • 微服务实战
合并后的目录 具体目录
服务架构介绍
服务架构的演进
逃离单体地狱
欢迎迈入云世界,Spring / 使用 Spring Cloud 探索微服务世界
服务拆分
向微服务迈进
服务的拆分策略 / 微服务架构中的业务逻辑设计 / 微服务架构的重构策略
使用 Spring Boot 构建微服务
服务间通信
远程访问服务
微服务架构中的进程间通信
-
事务
事务处理
使用 Saga 管理事务
-
事件驱动
-
使用事件溯源开发业务逻辑
使用 Spring Cloud Stream 的事件驱动架构
安全
架构安全性 / 可靠通信
开发面向生产环境的微服务应用
保护微服务
共识算法
分布式共识
-
-
服务发现
从类库到服务-服务发现
-
关于服务发现
网关
从类库到服务-网关路由
外部API模式
使用 Spring Cloud Gateway 进行服务路由
外部化配置
服务网格
开发面向生产环境的微服务应用
使用 Spring Cloud Config 服务端控制配置
高可用
从类库到服务-客户端负载均衡 / 流量治理
开发面向生产环境的微服务应用
当糟糕的事情发生时:使用 Spring Cloud 和 Resilience4j 弹性模式
查询优化
透明多级分流系统
在微服务中实现查询
-
服务监控
可观测性
开发面向生产环境的微服务应用
使用 Spring Cloud Sleuth 和 Zipkin 进行分布式追踪 / 监控微服务
测试
-
微服务中的测试策略
-
容器与运维
虚拟化容器 / 资源与调度
部署微服务应用
欢迎来到 Docker
部署
服务网格 / 部署 Kubernetes 集群
部署微服务应用
部署微服务

2.2.《数据密集型应用系统设计》进行补充

合并后的目录 具体目录
服务架构介绍
服务架构的演进
逃离单体地狱
欢迎迈入云世界,Spring / 使用 Spring Cloud 探索微服务世界
分布式系统的挑战
事务
事务处理
使用 Saga 管理事务
-
事务
共识算法
分布式共识
-
-
一致性与共识
查询优化
透明多级分流系统
在微服务中实现查询
-
数据模型与查询语句

3. 提炼骨架

3.1. 什么场景下需要使用微服务

单体架构发展到一定程度后,无法支持对市场机会作出快速反应时,需要重构成微服务。快速反应指:

  • 尽量缩短开发周期
  • 系统失效或者维护时间越长,损失越大,甚至大到无法承受。

3.2 微服务解决了什么问题

《微服务设计模式》提到了两种拓展模式

  1. N个相同实例的扩展
    EG: 同一个应用,创建同样的N个实例,请求进来后可以根据N个实例负载均衡。
  2. N个相同实例,但是每个实例只处理一部分用户。
    EG: 同一个应用,创建同样的N个实例,请求先经过路由器,判断是来自于哪个用户,路由到处理该用户的实例上。

以上两种拓展模式很好的提升了应用的吞吐量和可用性,然而这两种方法都没有解决日益增长的开发问题和应用复杂性,而基于功能性分解,把应用拆分成服务,以服务为粒度拓展即可解决这个问题。

3.2. 微服务引入了什么问题

  1. 决策者需要考虑什么情况需要使用微服务
  2. 服务的拆分和定义是一项挑战
  3. 分布式系统本身的复杂度
    3.1. 维护服务之间的数据一致性 —— 分布式事务
    3.2. 引入显著的运维复杂性
  4. 当部署多个服务是,需要更谨慎得协调开发团队

3.3. 微服务需要的技术栈

这一部分注意是在 《微服务实战(第二版)》中整理

  1. 服务发现
    Eureka Consul Nacos

  2. 服务间通信
    2.1. 负载均衡
    选用Eureka作为注册中心后,可以将集群注册到Eureka,集群用起来后就伴随着负载均衡技术的引入,Netflix Ribbon 是一个稳定的负载均衡解决方案,但是Spring Cloud Loadbalancer活跃度比较高,所以选用这个实现。那么就需要在配置文件中禁用掉Netflix的实现:

    spring:
    	loadbalancer:
    		ribbon:
    			enabled: false
    

    2.2. 集成了负载均衡的客户端
    将服务注册到注册中心后,每个服务都能拿到注册信息,可以使用注册信息访问对方。基于Eureka 的服务间通信可以使用三种客户端进行通信:

    Spring Discovery Client
    启用了 Discovery Client 的Rest 客户端
    Netflix Feign 客户端

    选用 Netflix Feign,主要是使用方式比较简洁。

  3. 外部化配置
    Spring Cloud Config

  4. 网关
    Spring Cloud Gateway

  5. 安全
    Spring Security Keycloak jwt

  6. 事件驱动
    Spring Cloud Stream

  7. 分布式链路追踪
    Spring Cloud Sleuth Zipkin

  8. 高可用组件
    8.1. 负载均衡组件
    已经提到过的开箱即用的Spring Cloud Loadbalancer

    8.2. 断路器模式 (熔断器)
    Resilience4j 使用 @CircuitBreaker(name = "licenseService")

    8.3. 后背模式 (服务降级)
    Resilience4j 使用 @CircuitBreaker(name = "licenseService", fallbackMethod = "buildFallbackLicenseList"), 其中buildFallbackLicenseList放入降级逻辑。

    8.4. 舱壁模式

    # 信号量隔离
    resilience4j.bulkhead:
    	instance:
    		bulkheadLicenseService:
    			maxConcurrentCalls: 20
    			# 省略其他参数
    			
    # 线程池隔离
    resilience4j.thread-pool-bulkhead:
    	instance:		
    		bulkheadLicenseService:
    			maxThreadPoolSize: 1	
    			# 省略其他参数
    

    Resilience4j 使用 @Bulkhead(name = "licenseService", fallbackMethod = "buildFallbackLicenseList"), 其中buildFallbackLicenseList放入降级逻辑。值得注意的是:舱壁模式也支持服务降级

    8.5 重试模式
    Resilience4j 使用 @Retry(name = "licenseService", fallbackMethod = "buildFallbackLicenseList")
    值得注意的是:重试模式也支持服务降级

    8.6 限流模式
    Resilience4j 使用 @RateLimiter(name = "licenseService", fallbackMethod = "buildFallbackLicenseList")
    值得注意的是:限流模式也支持服务降级

    8.7 兼容ThreadLocal
    使用Resilience4j 注解的方法,父线程的ThreadLocal可以被子线程继承。

4. 容易搞混的高可用组件的解释

组件(模式)名 作用
客户端负载均衡 对一个集群中的多个实例进行轮询或者随机调用。
断路器模式 调用方的能力,当远程服务被调用时,调用方会监控这个调用的质量,如果时间太长或者失败次数过多,则进行快速失败。防止一个低效的远程调用拖垮整个应用。熔断器有自适应能力,意思是当远程调用的服务质量恢复时,熔断器则关闭。具体算法暂不提。
后备模式 可以跟其他模式组合用。后被模式也就常说的服务降级,“快速失败”是否还有优化空间呢?最简单的就是失败后返回200的响应,提示客户请求正在排队,请不要频繁请求。稍微复杂一定的降级:淘宝千人千面的商品推荐页,如果推荐系统出错,那么降级成千人一面的首页。
舱壁模式 将每个远程调用的线程资源隔离开,可以是每个调用都预设一个线程池(线程池隔离),可以是每个调用都进行信号量管理(信号量隔离)。这样做的好处是防止一个响应缓慢的远程调用侵占整个应用的资源。
重试模式 微服务是运行服务失败的,同时也该允许调用方重试,可以幂等性调用的接口用重试可以提升整体业务成功率。
限流模式 舱壁模式是控制某个调用的并发度,限流模式关注的是时间区间的总调用数。