基于service mesh的服务治理体系实现详解

1

序言


着微服务和容器化技术的迅速发展,传统的基于SDK和服务框架的微服务架构在面对多元化的技术和逐步增多的服务数量时弊端逐渐显现,为了解决这些问题,service mesh作为新一代的微服务框架逐渐展露头角。这种架构模式可以将其视为微服务时代的TCP/IP协议,通过将网络通信层下沉,来屏蔽分布式系统带来的复杂性。因此各大厂纷纷向这种微服务架构模式升级,用该种模式解决东西向流量(server-server)和南北向流量(client-server)问题,期望可以让开发者回归业务,更聚焦业务。但在软件开发中并没有银弹,从传统微服务模式升级到service mesh架构模式可谓困难重重。鉴于以上问题,结合集团现状,集团针对RPC流量的服务治理体系已经很成熟,但是缺少针对HTTP流量的统一治理体系,同时集团针对南北向流量处理的微服务治理框架也已经很成熟,因此团队直接聚焦于使用该种架构模式解决HTTP东西向流量的治理问题。考虑到实现成本与推广难度问题,在实现过程中团队并不想要重复造轮子,因此期望能够在兼容现有的架构情况下实现MESH化,同时,致力于在对业务零侵入的情况下,丰富现有的服务治理能力,解决多语言多框架这种异构系统下产生的服务治理难题,实现业务与基础服务解耦,让业务开发可以更专注于核心业务。


2

技术选型

团队在2020年开始调研service mesh并进行技术选型。旨在不减弱当前治理能力的前提下尽可能复用现有架构,对齐多语言能力,逐渐提供更精细化、更易用的系统。同时,在技术落地时能够尽可能规避大规模的技术升级,实现无感知升级和低成本改动。

因此,为满足上述要求,综合业界方案,团队结合了社区的SDN的架构思想,采用数据平面和控制平面分离的架构模式。

2.1 数据平面选型

考虑到当时业界已经有比较成熟的产品,所以没有选择重复造轮子,而是基于业界已有的开源软件进行了二次开发。在选择数据平面代理时,团队综合考虑了以下因素:产品的成熟度、社区活跃度、性能是否满足公司需求等,衡量后决定在Envoy和蚂蚁开源的MOSN中选择。考虑到Envoy是使用C++实现,与团队的技术栈不匹配,从开发和维护的角度综合考量后最终选择了蚂蚁开源的MOSN作为数据平面代理。同时为了更好的适配公司的架构模式,团队对MOSN进行了二次开发。一方面能够充分利用开源软件的优势,同时能够定制和调整以满足公司特定需求,并与现有架构无缝集成,实现更好的技术匹配。综上,选择MOSN作为数据平面代理,并对其进行二次开发。

2.2 控制平面选型

考虑到集团已建立了比较成熟的服务治理体系,并已经具备了对业务零侵入的服务发现能力。因此,从学习成本、维护复杂度、用户切换成本、改动成本等多方面考虑,并没有选择当时业界开源呼声最高的istio作为控制平面,而是选择对接集团现有的服务治理功能同时结合自研新功能的方式来实现控制平面。通过对接现有功能,可以降低学习成本和用户切换成本,同时减少改动现有服务带来的线上风险。通过增加自研来满足集团特定的需求和业务场景,定制开发所需的功能模块,可以实现更全面、更灵活的控制和管理能力。综上,控制平面选择对接现有服务治理体系并结合自研的方式。


3

整体架构

整体架构如下:


上面这张图展示了集团MESH化的整体架构,采用控制平面和数据平面分离的方式。下面详细介绍数据平面和控制平面具体的分工及内部的架构模式。

3.1 数据平面

数据平面是运行时组件,主要负责对服务的进出口流量进行拦截,并根据控制平面下发的规则进行处理。同时,它也负责将流量相关的信息上报给控制平面进行统计和监控。

  • 数据平面代理以单独的容器部署,并采用一对一的方式,即每个服务进程对应一个数据代理。这样可以确保服务之间的隔离和独立性。

  • 数据平面与控制平面之间使用双向流进行通信。数据平面代理与管理服务进行通信,获取相关策略和配置信息。数据代理程序与规则服务进行通信,通过推拉结合的方式获取用户配置的治理规则。同时,数据代理定时向监控服务上报数据流量信息,用于监控和统计分析。

  • 数据代理与业务进程之间使用UDS(UNIX Domain Socket)进行通信,这样可以减少通信性能损耗,并提高数据传输的效率。

3.2 控制平面

控制平面是管理组件,主要负责数据平面代理的管理和全局策略的决策与规则下发。主要包含规则下发、监控数据处理和数据平面代理管理三类功能,每类功能对应一个服务:

规则服务:负责实时全量/增量下发用户页面配置的治理规则给数据代理。它与数据代理程序进行双向通信,确保规则的正确下发和更新。

监控服务:负责对数据平面上报的监控数据进行聚合统计和存储等操作。它接收数据代理定时上报的监控数据,并进行统计和分析,以提供监控和报表功能。

管理服务:负责数据代理的版本管理、运行状态管理、操作管理和登录权限管理等。它与数据平面代理进行双向通信,以获取数据代理的相关信息。

此外,当前架构还对接了已有的告警服务、服务发现服务、监控采集服务和统一门户服务,确保在快速集成的前提下提供更全面的功能支持。


4

关键设计

在service mesh服务治理体系落地过程中,通过对接当前架构和透明流量拦截方式,已经能够做到用户无感知接入。然而,我们的目标不仅仅是实现零成本接入,更重要的是在保证当前服务治理能力的前提下,提供更精细化的功能。本节将着重介绍几个在功能实现上遇到的问题及解决方案。

4.1 HTTPS流量拦截

流量拦截的主要思想是通过配置iptables规则来实现。http流量拦截,可以直接配置iptables的NAT表规则来实现,而对于https流量则使用的是iptables+dnsmasq+ipset的方式进行拦截,下面将详细介绍一下HTTPS流量拦截的实现。

数据平面代理使用iptables的NAT表做透明流量拦截,对于http流量拦截是没有问题的,但是如果要拦截https请求时,上述方案无法满足需求。这是因为https请求在握手阶段进行证书校验,如果直接拦截请求,代理程序缺少相应的证书,会导致主动请求方的证书校验失败,从而断开连接,严重影响业务流量。因此,团队采用了以下处理方式:使用iptables+dnsmasq+ipset的组合方式进行流量拦截,并结合中间人机制进行代理,来实现对https请求的解析。

该模式的实现难点及解决方案:

  • 需要客户端进程信任根证书。由于不同语言使用不同的方式信任证书,所以调研了不同语言信任证书的方式,并在容器启动时启动脚本会默认按照不同语言的信任方式配置证书,确保使用任何语言启动的服务进程都能够信任根证书。

  • 必须保证业务进程信任证书成功后才可以拦截https的流量。为了避免仅代理容器配置成功而业务进程所在容器未成功信任根证书而导致的流量问题,我们采用多容器共享文件的方式进行容器间通信,确保只有在业务进程成功信任根证书后,代理容器才开始拦截流量。

  • 生成需要拦截域名的证书并加载到代理服务进程中。规则服务一旦发现用户配置的域名变更则与证书签发服务通信获取域名证书,同时,代理服务与规则服务进行双向通信,保证一旦用户域名变更时能够及时将变更的信息推送给数据平面代理并生效,生效包括加载变更后的域名证书到进程中,同时配置相应的拦截规则。

  • 根证书的安全性。直接暴露根证书于容器中存在重大安全隐患,因此必须确保根证书不会暴露给每个用户和网络,并定期更新证书的过期时间。为此,我们引入了证书签发能力和根证书更新能力,确保根证书的签发和更新都在安全的环境中进行,并通过定期更换根证书的方式提高安全性。

整体架构如下:


各模块简介:

证书服务:负责根证书、私钥的保存、更新,域名证书的签发

规则服务:负责将域名配置和域名证书下发给数据平面代理

数据平面代理:负责接收规则服务下发的规则,并生效,包括动态实时加载域名证书,同时配置流量拦截规则

详细流程:


详细流程主要从以下两部分进行描述:

规则生效流程:

  1.  启动业务进程前会从证书服务获取到根证书,并将根证书添加到本地信任库

  2.  根证书添加成功后会将结果写到共享路径,然后启动业务服务

  3.  数据平面代理启动时会阻塞等待读取共享路径中的结果,结果成功则加载从规则服务获取到的域名证书,并设置拦截规则,启动成功

  4.  一旦发现证书添加失败,则自动降级告警,确保对业务无影响

https数据拦截流程如下:

  1.  当客户端发起https请求时,配置的iptables首先将流量定向到数据平面代理

  2.  代理使用dnsmasq进行DNS解析,并将域名与IP地址的映射关系添加到ipset中

  3.  然后,代理服务器使用中间人机制,与目标服务器建立https连接

  4.  代理服务器使用从规则服务获取到的域名证书与客户端进行握手,模拟目标服务器的证书

  5.  一旦与客户端建立安全连接,代理服务器同时与目标服务器建立安全连接,并在两个连接之间进行数据转发

  6.  代理服务器能够解密和分析https流量,并根据需要进行修改或拦截

  7.  最后,代理服务器将修改后的HTTPS流量重新加密,并转发给目标服务器,同时将响应返回给客户端

通过这种方式,数据平面代理在https请求中扮演了中间人角色,成功解决了证书校验的问题。同时,团队利用iptables、dnsmasq和ipset的组合方式实现了流量拦截和代理的功能,确保对HTTPS流量的拦截和处理不会对业务流量产生影响。

4.2 精确的URL监控

在HTTP服务中,用户可以通过接口路径配置来定义访问规则,而各大MVC框架也提供了更灵活的配置方式,比如:支持配置通配和正则的方式等。这种方式使用户的使用更灵活,但是在无侵入多语言场景下给监控带来了很大的挑战。比如:

用户配置的接口为:/hello/{userId}

代理拦截到的请求为:/hello/1,/hello/2,/hello/3等等。

因此,如果直接按照拦截到的请求进行落库和展示,一是给数据库带来了巨大的存储压力,另外也无法满足用户的期望,用户期望看到的是针对/hello/{userId}这个接口的监控,而不是每个具体的 /hello/1、/hello/2的监控。

上述的问题可以拆分成两个问题考虑:

问题一:如何对具体的接口规则进行统计和监控

当前对于数据上报有两种实现方式,方式一:业界开源通用方式,数据平面代理对收到的所有原始请求信息统计后直接上报给监控服务,监控服务对收到的所有接口信息进行聚合处理并存储的数据库中;方式二:规则服务将各个服务的接口通过规则下发给数据平面代理,数据平面代理对收到的原始请求解析出接口后,根据规则服务下发的规则进行匹配,对匹配后的接口进行统计上报。两种方式的架构如下图所示:


方式一,对于以通配方式提供接口的服务,由于数据平面拦截的每个请求的接口规则都不一致,会导致数据平面代理每分钟上报的监控数据量巨大,将占用大量的网络带宽资源,同时所有节点的数据规则转换和汇总统计放到监控服务每分钟进行处理,也增大了监控服务的实现复杂度,因此选择方式二的这种架构模式,这种架构模式一是能够减少数据平面每分钟上报的监控数据量,二是将监控服务统计汇总的压力分散到每一个数据平面代理上,简化监控服务的实现复杂度。

问题二:如何保证在无侵入的情况下,获取不同语言、不同框架配置的接口规则

在问题一确定监控上报的模式中,有一个默认的条件为规则服务能够获取到所有WEB类型服务的接口规则。但是集团的WEB类型服务使用不同的技术栈实现,因此如何获取是个问题。考虑到当前集团已经有基础服务部门提供了成熟的服务治理体系,所有我们将WEB服务分为两大类,一类为可以通过当前已有服务治理体系获取到接口信息的服务,一类为无法通过当前已有治理体系获取到详细接口规则的服务。针对这两类的处理方式如下:

可以获取到接口规则的服务:直接对接当前的服务治理体系,将获取到的规则转化成数据平面代理可解析规则存储下发

无法获取到详细接口规则的服务:引入自动识别服务,若无规则下发给数据平面代理,当数据平面代理接收到请求时,会根据请求量降序排序,并上报一定量的监控数据给监控服务,对于请求量非常小的请求,如果上报的接口规则为非精确URL,则监控服务会将这部分接口发送给自动识别服务,自动识别服务会对这些接口规则进行分析,聚合成通配规则,并将生成的规则发送给规则服务,规则服务一旦发现有新的规则出现,则会触发规则自动下发操作,将该规则下发给数据平面代理。至此,整体架构如下:


这种实现方式可以满足不同语言、不同框架接口规则监控的准确性和实时性,形成了一个闭环的规则管理和下发系统。

4.3 插件易用性

为了克服传统服务治理体系的限制,service mesh服务治理体系引入了插件扩展能力。插件扩展允许开发人员编写自定义的插件,以增强服务治理定制化功能。与传统的SDK绑定方式不同,插件扩展能力更加灵活、可扩展,并且不受特定编程语言和框架的限制。然而,实现这一目标面临以下挑战:

  • 支持多语言,考虑到集团技术栈的多元化,插件的支持不能限制编写语言

  • 多插件共存,需要支持多种语言插件在同一业务服务中共存的场景

为了应对这些挑战,团队经过调研后选择了使用多容器多进程的方式来支持扩展插件。这种方式具有以下优势:

  • 高隔离性:插件与插件之间以及插件与业务进程之间都能够互不影响,实现高度隔离

  • 解除语言和框架限制:采用多进程的方式,解除了插件编写受数据代理和其他插件编写语言的限制

数据平面通过这样的设计,确保了用户可以根据自身需求选择适合自己技术栈的语言编写插件,从而降低了用户的学习成本,增加插件的易用性。这样,用户可以更快速地开发和集成自定义功能,满足其特定的业务需求。同时控制平面直接对接当前的mesh架构,从而实现对插件的管理和监控。

整体架构如下:


详细描述:

  • 部署服务在部署时,会从管理服务获取到业务配置的插件信息,将插件自动注入到服务节点中

  • 数据平面代理启动时会从当前环境中获取到需要部署的插件信息,对插件状态进行健康检测,一旦插件状态异常会与管理服务的异常处理策略通信,获取执行策略,并执行

  • 数据平面代理与插件服务通过uds进行通信,降低通信损耗

  • 规则服务会与数据平面代理通信,将变更的插件配置动态下发给数据平面代理,以实现实时生效

  • 数据平面代理服务会定时上报插件的监控信息给监控服务,心跳信息给管理服务

在设计该架构时,插件的无感知升级是一个重要挑战。为了实现无感知升级,结合当前架构有两种方式可供选择:

第一种方式是需要业务配合,提供平滑升级接口,由业务保证在插件进程升级过程中仍然能够稳定提供服务。这种方式对于业务开发的技术水平要求高,升级风险性高,但是基础服务改动小。

第二种方式是将升级过程全托管给基础服务,基础服务与服务发现服务和部署服务进行联动,实现插件的平滑升级。在整个升级过程中,业务容器无需进行重启,但类似于滚动升级的方式,业务节点在插件升级过程中会被移除流量,升级完成后再重新发布。相较于第一种方式,这种方式在升级过程中会操作线上节点移除流量,但是降低了业务方的技术门槛,更易于实施。

鉴于第二种方案在升级过程中虽然会操作线上节点,但是当前架构中滚动升级功能已经是非常成熟的功能,因此该操作对线上服务的影响基本上可以忽略不计,并且降低了业务方的技术要求,因此选择第二种方案作为插件的无感知升级策略。通过基础服务与服务发现服务和部署服务的协同工作,可以确保插件的平滑升级,保证服务的稳定性和持续可用性。

整体架构:


详细描述:

1、用户下发平滑升级需求,部署服务收到升级请求,使用Kubernetes提供的patch方式修改相应的pod及rc中插件容器的镜像版本,触发Kubernetes拉取最新的插件镜像对插件容器进行升级

2、插件平滑升级过程中,部署服务通过与服务发现服务交互将该节点的流量摘除,确保在升级过程中不会将流量发送到正在升级的插件容器上。一旦升级完成并确认插件达到预期版本,部署服务将调用服务发现服务来恢复该节点的流量

3、整个升级过程通过数据平面代理和管理服务的心跳上报来确定升级是否达到预期,以及新版本插件是否正常运行


5

未来与展望

service mesh在集团的应用未来主要会向着以下几个方向发展:

性能提升:随着微服务规模的增长,service mesh需要提供更优的性能。这包括减少代理对网络延迟的影响、提高消息吞吐量等方面的改进。当前业界也已经有很多优秀的底层网络通信相关的优化方案,可以借鉴和集成,从而减少引入service mesh所带来的性能损耗。

安全性和合规性的增强:随着对安全性和合规性要求的提高,service mesh将会加强对服务间通信的安全性和合规性的支持,包括对数据加密、访问控制等方面的增强。

更加开放的生态系统:将会更加开放和灵活,支持更多的第三方插件和扩展,以满足不同场景和需求的多样性。比如:协议转换等。

本文分享自微信公众号 - 58技术(architects_58)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

微软开源基于 Rust 的 OpenHCL 字节跳动商业化团队模型训练被“投毒”,内部人士称未影响豆包大模型 华为正式发布原生鸿蒙系统 OpenJDK 新提案:将 JDK 大小减少约 25% Node.js 23 正式发布,不再支持 32 位 Windows 系统 Linux 大规模移除疑似俄开发者,开源药丸? QUIC 在高速网络下不够快 RustDesk 远程桌面 Web 客户端 V2 预览 前端开发框架 Svelte 5 发布,历史上最重要的版本 开源日报 | 北大实习生攻击字节AI训练集群;Bitwarden进一步脱离开源;新一代MoE架构;给手机装Linux;英伟达真正的护城河是什么?
{{o.name}}
{{m.name}}

猜你喜欢

转载自my.oschina.net/u/5359019/blog/11047505