背景
在微服务盛行的当下,一个系统多由很多个细分的微服务组成,每个微服务负责一个功能模块,每个模块由各个不同的小组成员负责开发和维护。因此一个成熟的微服务项目往往由多达几十个微服务组成。
在日常的开发过程中,微服务之间的调用依赖错综复杂,因此微服务的治理迫在眉睫。
不知道在日常开发中,有没有遇到过以下几种场景:
- 同时有多个功能分支并行开发,而测试/开发环境只有一套。多个并行开发任务时,可能设计到同一个模块,在同事A开发完功能1时,需要合并到dev分支,同事B开发完功能2时,也需要合并到dev分支,两人则存在代码分支合并的冲突。
- 针对测试同学,好好的正在测试功能A,突然新功能2的代码,也部署到测试环境了,莫名奇妙的测试到其他需求且未上线的功能。
- 在上线应用前,往往需要进行一下realease 分支回归测试,保证上线的最终代码是完整的。但是测试环境只有一套,如果部署了功能1的代码,则功能2的测试工作无法进行。
其实说白了,就是共用一套测试环境,而导致环境冲突问题。
那么,针对此问题,我们应该如何解决呢?目前有两种比较广泛的方案
解决方案
物理环境隔离
通过增加机器搭建流量隔离环境,部署服务的灰度版本。这种方式适用于测试、预发开发环境,但成本较高,灵活性不足
逻辑环境隔离
构建逻辑上的环境隔离,部署服务的灰度版本,流量在调用链路上流转时,由流经的网关、各个中间件以及各个微服务来识别灰度流量,并动态转发至对应服务的灰度版本。这种方式节省成本,灵活性高
理想状态
挑战
- 实例打标
- 流量染色
- 服务路由
- 数据库,redis,消息中间件流量路由
- DevOps
- 全链路追踪,监控
针对以上问题,每一个点都是值得探讨和研究的,涉及到的技术细节跟需要权衡对比。
实现方案
实例打标
- 使用服务发现注册时添加元数据: 在服务注册到服务发现中心时,可以通过添加元数据来区分不同的服务实例。例如,在Spring Cloud框架中,可以使用Nacos作为服务发现和配置管理组件,在服务注册时指定自定义的版本号作为元数据
- 利用容器化技术进行打标: 在容器化的应用中,可以在Docker容器或者Kubernetes的Pod中添加标签。例如,在Kubernetes中,可以在Deployment的Pod模板中为节点添加标签,通过这些标签可以进行服务的版本控制和服务发现
- 服务网格(Service Mesh)中的实例打标: 使用服务网格技术如Istio,可以在微服务间实现更细粒度的流量控制和路由规则。服务网格可以识别服务实例的标签,并根据这些标签来实现流量的灰度发布、A/B测试等
- API网关层的流量染色: 在微服务架构中,API网关层可以对请求进行染色,根据请求的特征(如用户ID、地理位置等)将请求路由到特定的服务实例。这可以在API网关的配置中实现,通过编写相应的过滤器来判断请求是否属于灰度用户,并据此进行路由
- 结合配置中心进行动态打标: 使用Spring Cloud Config等配置中心组件,可以在运行时动态地为服务实例添加标签或修改标签值,实现动态的流量控制和路由策略
流量染色
- 基于用户标识的染色: 根据用户的唯一标识(如用户ID、会话ID等)对流量进行染色。例如,可以设定只有ID尾号为奇数的用户访问新版本服务,而尾号为偶数的用户访问旧版本服务。
- 基于地理位置的染色: 根据用户的地理位置信息,将来自特定地区的用户流量路由到新版本服务。这可以通过用户的IP地址来实现。
- 基于请求特征的染色: 检查请求中的特定参数或头部信息,根据这些特征来决定流量的路由。例如,可以在请求中添加一个特定的查询参数或HTTP头部,用以标识请求应该路由到哪个服务版本。
- 服务发现组件的配合使用: 在服务注册时,为服务实例添加版本标签或其他元数据,服务发现组件根据这些信息进行服务实例的选择。
- 使用服务网格(Service Mesh) : 使用Istio等服务网格技术,可以在微服务间实现细粒度的流量控制,包括流量染色。服务网格可以独立于应用程序实现流量管理。
服务路由
- 服务发现与负载均衡: 使用服务发现组件(如Eureka、Consul、Zookeeper,nacos等)来注册和发现服务实例,并通过内置的负载均衡策略(如轮询、随机、最少连接等)来分配请求。
- API网关路由: 在微服务架构的边缘部署API网关,所有外部请求首先到达网关,然后由网关根据路由规则将请求转发到适当的服务实例
- 服务网格路由: 使用服务网格(如Istio)来控制服务间的通信。服务网格可以在服务间实现智能路由、流量分割和流量镜像等高级路由功能。
数据库
time.geekbang.org/column/arti…
这里最优、最安全的方案当然首推影子库
redis
time.geekbang.org/column/arti…
因为redis默认有16个库,这里我们采用与mysql影子缓存类似的方案,影子库。(前提选择未使用的库)
消息中间件
- 多实例
- 消息header增加标识
- 影子topic
这里我们采用影子topic
DevOps和全链路追踪和监控,我们放到后面再讲。
下面我们将针对两种场景,传统的Spring cloud体系和Kubernetes+Istio,讲解不同的实现细节。