微服务引擎 MSE 是火山引擎提供的一款面向微服务全生命周期的一站式微服务解决方案。产品提供开源增强的 Nacos 注册发现、配置管理的能力,兼容原生 Spring Cloud 、gRPC及 Service Mesh 架构丰富微服务治理能力,助力用户快速构建稳定、安全、高效云原生微服务体系。
来源 | 云原生服务治理团队
微服务的历史与演变
微服务是一种软件架构设计模式,通过微服务,大型应用可以被拆分成多个独立的小组件,以便于构建、测试、部署和更新。自 2014 年概念被提出以来,它经历了几个主要的发展阶段:
第一阶段是 面向服务的 SOA 架构 ,通过部署集中式的 ESB 服务总线实现。 虽然结构相对简单,但性能 ESB 本身负担较重,可扩展性不足。
随着以 Dubbo/Spring Cloud 为代表的 微服务 SDK 架构 成为主流,微服务架构也开始进入第二阶段。微服务 SDK 架构与 SOA 最大区别是将总线上的功能分摊到了各个终端上(微服务 SDK)实现。 这种架构虽然功能强大,性能优异,但需要侵入式改造应用,并常常遇到版本冲突问题。
如今, Service Mesh 服务网格 架构受到了广泛的关注和应用,逐渐成为云原生微服务的社区标准。 它通过在微服务旁边部署独立的 Sidecar 进程,来接管各项服务治理功能,极大提高了研发和迭代效率。而在技术选型方面 ,Istio 成为了当前最流行的开源服务网格, 虽然该架构对应用的改造成本较低,能够有效解决微服务的侵入改造问题,但它的资源消耗量较大,而且增加的网络代理开销和运维成本也不容忽视。
针对上述问题,近几年社区又兴起了对新架构的讨论: Proxyless Mesh 。这是从 Proxy 模式的 Service Mesh 发展而来的新型架构,它融合了微服务 SDK 架构和 Service Mesh 架构的优势,为大量传统微服务应用无痛迁移至云原生环境提供了切实可行的轻量级解决方案。
基于 JavaAgent 的 Proxyless 方案
基于字节跳动内部应用实践和外部客户服务经验,火山引擎云原生团队将 JavaAgent 技术和 Proxyless Mesh 技术结合,在微服务引擎 MSE 中实现了一种高效、灵活、易于管理的 Java 服务网格解决方案 MSE Agent 。
注:JavaAgent 是 Java 平台提供的强大机制,开发者无需修改应用程序代码,即可动态修改和增强 Java 应用程序的行为。
MSE Agent 既有微服务 SDK 架构的高性能和多功能优势,又有 Service Mesh 架构的无侵入优势,并且完全适配了主流开源服务网格框架 Istio:
- 性能高,稳定性强,适用于几乎任何部署环境;
- 无侵入,一键配置;
- 高阶功能丰富,可针对特殊业务场景定制;
- Java 领域框架生态丰富;
- 兼容标准 xDS,拥抱社区。
可以说,以火山引擎 MSE Agent 为代表的 Java Agent Proxyless 方案是目前 Jave 领域微服务治理的最优解。
高性能与稳定性
MSE Agent 采用字节码增强技术来实现流量拦截,采用了 Proxyless 架构。与 Envoy 这种独立的 Sidecar 架构不同,MSE Agent 与用户应用程序在同一个进程中运行,这种模式相对传统的 Proxy 模式来说带来了不少优点:
- 首先,用户应用接入 Mesh,省去了 Sidecar 这一跳带来的请求延迟,可以通过框架直接通信,天生就具备高性能的优势,更适合性能敏感场景;
- 其次,少了 Sidecar 组件本身带来的运维复杂度及其故障率,在稳定性和资源占用方面也会更有优势。
丰富的个性化治理
相比 Proxy 模式,Proxyless 还有一个很重要但容易被忽视的优点,即更 丰富的个性化治理能力 。
在 Proxy 模式中,HTTP 协议是一等公民,其他协议的治理能力都相对薄弱。同时,Proxy 模式背后的主要概念是将一组服务间的通信能力标准化。但是其带来的缺点就是一旦涉及到代码业务层面的治理能力,用户往往会发现自己并不能无痛迁移至 Service Mesh 上。这也是为什么 Envoy+Istio 组合虽然很早就成为社区事实标准,但真正落地的往往是一些企业的非核心新业务。
以一个常见的重试场景来说,很多时候需要通过业务逻辑(例如只有 vip 流量才需要重试)去判断是否实现重试策略,而不是简单的错误即重试。对于 Proxy 模式来说,首先业务参数需要通过协议适配来传递到 Sidecar,其次将业务相关的重试策略放到通用 Sidecar 里显然是不合适的,其他的譬如 WASM 扩展机制,由于其学习与改造成本,对于业务方来说往往也是不可接受的。
而在 Proxyless 模式下,由于对应逻辑已经集成在客户端里面了,我们只需要找到合适的切面打上 patch 补丁即可,实现成本低了很多。与此同时,如果业务用户后续需要开发更定制化的治理能力,MSE Agent 也提供了基于字节码增强的 SPI 方式来进行插件开发,在 MSE Agent 这边通过回调用户实现的 predicate 策略来使业务重试逻辑生效。
MSE Agent 功能矩阵
得益于 Java 类隔离技术与 SPI 插件机制,我们能轻松实现各个模块之间以及模块与业务代码之间的解耦。如此一来,用户无需担心业务应用与 Mesh 治理能力之间的冲突。
目前,功能矩阵中已经涵盖了认证鉴权、灰度路由、限流熔断、优雅上下线等关键治理能力。同时,由于 MSE Agent 的 SPI 插件底座,第三方也很容易基于此开发自己的 Agent 插件,并同样享受无侵入带来的便利,例如给火山引擎微服务引擎 MSE 注册中心的客户端添加一种加解密方式。
Java 领域框架生态
当然,单纯的 Proxyless 架构相对来说还存在一些缺点,例如:
- 无法处理多语言问题;
- 会被特定框架所绑定,例如 grpc-proxyless。
针对第二个问题,Agent 字节码技术就极大地扩展了对 Java 生态框架的支持范围。目前 MSE Agent 支持包括 SpringCloud、Dubbo、Vert.x 等在内的主流 Java 框架,并且仍在不断扩展。
多语言
诚然,JavaAgent Proxyless 并不是银弹,它在多语言领域还是有所欠缺。对于企业来说,如果业务主流使用的是 Java 语言,同时还有一些其他长尾语言应用,这时可以考虑采取 JavaAgent Proxyless + 传统 Sidecar 方案相结合,并通过对接标准的 xDS 协议来实现两者的服务治理打通。
基于标准 xDS 实现的 Proxyless
MSE Agent 的治理能力实现依赖于控制面治理配置的下发,它的统一动态配置源目前兼容了社区云原生标准解决方案,基于标准 xDS 协议,支持整套 Istio 控制面的治理能力。在云原生时代,这可以帮助企业有效避免被单一厂商捆绑,从而享受更加 简单高效、灵活敏捷、低成本的云服务 。
此外,通过自定义 xDS 类型,MSE Agent 还实现了参数限流/自适应下线等额外的高阶治理能力,弥补了社区 Istio+Envoy 标准治理能力语义的缺失与不足。
在实现 xDS 的过程中,与 Istio+Envoy 相比,Proxyless 模式可以几乎零成本地实现懒加载特性,能够更好地支持大规模 Pod 集群。在 ROI 方面,Proxyless 模式几乎是碾压式的存在。
当然,懒加载特性中 MSE Agent 也做了一些优化,包括并发处理、聚合 xDS 请求等,以适配多种多样的业务场景,这一点会在后续文章中具体展开。
无侵入一键接入
MSE Agent 是基于 JavaAgent 实现的,用户无需修改应用代码即可获得 Mesh 的全套治理能力,这对开发者来说是几乎无感的。同时,MSE Agent 适用于几乎任何部署模式,目前适配了虚拟机和容器两种场景,无论应用是否基于 Kubernetes,都能实现一键接入。
在虚拟机场景下,用户只需在 java -jar 启动应用程序的命令前添加 -javaagent 启动参数,指定 mse agent 的 JAR 包路径,即可在应用运行时挂载 mse agent。
而在容器场景下,部署 mse webhook 组件后,创建容器时只需在 Deployment 中添加一行 Label,就能在创建 Pod 时让业务应用挂载 mse agent 启动,实现无侵入一键接入。
MSE Agent 在全链路灰度中的应用
全链路灰度在微服务治理中是一个非常常见且实用的能力,MSE Agent 也能在扮演关键角色,核心过程主要包括流量染色、标签透传和流量路由。MSE Agent 通过模块化将这些能力整合在一起,与控制面灰度配置配合,形成了一套完整的全链路灰度解决方案。
值得一提的是,这也是 JavaAgent 技术相比 Proxy Sidecar 架构的优势区间之一。
流量染色
MSE Agent 通过染色模块来实现流量染色。它 主要支持对 SpringCloud Gateway 网关进行染色,其流程如下:
- 通过请求匹配染色规则,例如 header 中 uid=100 的匹配为 gray,而 uid=101 的匹配为 prod;
- 若匹配,则在透传上下文中添加对应的染色标签;
- 向 upstream 转发请求的时候携带对应的染色标签。
MSE Agent 染色规则兼容 VirtualService 的匹配规则,在上面这个例子中,对应染色规则的数据模型如下:
http:
- match:
- headers:
uid:
exact: 100
dyeing:
mesh_env_key: mse.tag
mesh_env_val: gray
- match:
- headers:
uid:
exact: 101
dyeing:
mesh_env_key: mse.tag
mesh_env_val: prod
当然,MSE Agent 不仅仅支持网关染色这一种能力。针对定时任务等场景,它还支持了“根据灰度环境变量进行自动染色”的能力。如果遇到一些特定的业务场景,也可开放针对服务进行规则染色的能力。
有了这样一套统一流量染色机制,开发人员在配置路由规则时,无需关注具体的业务属性标识,仅需根据染色标识进行配置。
标签透传
标签透传模块负责把流量染色标识在全链路透传,这里包含两块内容:
- 跨进程在多种介质之间做透传,目前支持 SpringCloud-HTTP、Dubbo、RocketMQ 等;
- 进程内通过上下文 context 进行透传,这里同时也包括跨线程传递。 跨线程场景目前包括新建线程、线程池、reactor 响应式等。
除了标准化的灰度路由场景标签 mseTag 透传能力外,MSE Agent 还支持标准的 w3cBaggage 标准,以及通过规则配置的自定义标签透传,给予用户最大的自定义程度。
有了这样一套通用的全链路透传机制,用户在透传标识发生变化时,只需要修改动态配置即可,而无需业务方配合全量改造。
流量路由
灰度实现的关键在于请求的路由分流功能,目前支持 Spring Cloud、Dubbo、RocketMQ 等。在 RPC 远程调用方面,依赖 Istio VirtualService 的语义来表达路由。而在 MQ 消息队列方面,MSE Agent 目前通过 topic 和 consumer group 来完成对应路由。
全链路透传
MSE Agent 将流量染色和标签透传能力整合在一起,形成了一套完整的全链路透传方案。通过该解决方案,我们可以将流量标签传遍整个拓扑链路。除了流量路由外,结合其他插件,如限流插件、流量录制插件等,那么它在灰度场景以及限流熔断、诊断恢复、流量录制回放等场景中都能发挥重要作用。
如果您对 MSE Agent 有体验需求,请扫描下方 二维码 联系我们!
- END -
相关链接
[1] 基于火山引擎微服务引擎 MSE 的全链路灰度落地实践
云原生服务治理团队
火山引擎服务治理团队致力于为企业业务开发、应用运维、基础架构团队提供一站式云原生应用服务治理技术支撑能力,通过火山引擎 API 网关、微服务引擎、服务网格多款产品对外输出字节跳动丰富服务治理场景实践和技术沉淀,助力用户快速构建稳定、安全、高效的微服务应用架构,解决中大型企业在云原生时代下的微服务架构转型问题。