Skip to content

架构

昆仑中间件架构如图,其主要分为数据面和控制面。

  • 数据面:以 Vert.x 为基础库,通过插件机制来实现各种流量处理和分发的功能:限流限速、安全防护、故障注入等,同时支持用户编写自定义插件或 Lua 脚本来对数据面进行扩充。
  • 控制面:使用 etcd 或 Zookeeper 来存储和同步配置数据,管理员通过数据面的 gRPC 接口发布配置到所有的数据面节点。

基本架构

数据同步

网关作为流量入口,在系统架构中承担了非常重要的角色,其高可用的重要性不言而喻。而如何实现配置的热更新是保障网关高可用的重要因素之一。

目前数据同步特性如下:

  • 配置使用 etcd 或 Zookeeper 存储与同步
  • 配置通过网关 gRPC 接口发布至 etcd 或 Zookeeper
  • 配置(路由、上游、插件、服务发现等)全量缓存在网关内存中,请求处理时只使用本地缓存

线程模型

昆仑中间件在 Vert.x Event-loop 基础上,参考 Nginx worker(进程)架构将 Event-loop 细分为:

  • Master:处理配置请求,线程数为1
  • Worker:处理网络请求,线程数为 cpu 核数 线程模型

连接重用

连接重用指通过重用之前从连接池建立的连接,跳过新连接所需的 TCP 和 TLS 握手,来加快请求的 TTFB(首字节时间)。如果连接分散在所有 Worker 的更多孤立的连接池中,可能会导致更慢的 TTFB 以及维护更多的连接,进而消耗更多的资源。

在昆仑中间件中,默认的连接重用策略如下:

  • HTTP/1.1:每个 Worker 一个连接池,可通过 CLIENT_HTTP_SHARED=on 调整为共用连接池
  • HTTP/2:所有 Worker 共用一个连接池,可通过 CLIENT_HTTP2_SHARED=off 调整为独享连接池

队头阻塞

HTTP 队头阻塞(Head-of-Line Blocking)是指在 HTTP/1.1 中,由于请求 - 响应的严格顺序性,如果一个请求的处理被延迟,后续的请求就会被阻塞,直到前面的请求完成。


管道化

HTTP 管道化(HTTP Pipelining)是将多个 HTTP 请求整批送出的技术。在支持管道化的情况下,客户端可以不必等待前一个请求的响应返回,就可以发送下一个请求,多个请求可以在一个连接上连续发送。服务器收到这些请求后,按照请求到达的顺序依次处理和响应。

然而,HTTP 管道化并没有完全解决队头阻塞问题 。因为如果管道化中的一个请求出现问题(例如请求丢失、服务器处理异常等),那么这个请求之后的请求都会受到影响,仍然会在该请求处发生阻塞。


为了缓解或解决上游 HTTP 队头阻塞问题,昆仑中间件采取了以下一些措施:

  • HTTP/1.1 客户端默认禁用管道化
  • 支持 HTTP/2 版本的上游服务:HTTP/2 的多路复用(Multiplexing)特性可以避免队头阻塞问题

即时响应

即时响应(Responsive)指,无论系统处于何种状态,都应当向用户及时做出响应。其作为 反应式宣言 的最终价值输出,始终贯穿在昆仑中间件的设计与实现中。

故障检测

为了使系统对故障(网络分区,进程暂停等)做出适当的反应,即回弹性(Resilient),应该及时检测故障。其他进程可能联系发生错误的进程,即使它无法响应,这会增加延迟并降低整个系统的可用性。

Phi 增量故障检测器(Phi-Accrual failure detector)

收集和采样心跳的到达时间,创建出一个可用于对节点健康状况做出可靠判断的视图,然后使用这些采样结果计算Φ值:如果该值达到阈值,则节点被标记为宕机。

这种方法是由日本高级科学技术研究所的研究人员开发,现在已用于许多分布式系统中,例如,Cassandra 和 Akka。

截止时间故障检测器(Deadline failure detector)

使用心跳机制,如果进程在某一固定时间间隔内未能成功注册,它将报告进程故障。

如下图所示,其中 服务运行时之间 以及 服务到服务运行时之间 均启用故障探测机制:

  • 服务(运行时)之间主动式故障探测:被动式容错往往会增加延迟
  • 服务(运行时)网络拓扑调整为星形 + 网状:避免或减轻网状拓扑下的心跳风暴

故障探测

此外,服务(运行时)也提供了心跳间隔,心跳暂停时间等运行参数配置。

故障隔离

当一个服务的用户请求瞬间激增时,其响应延迟会增加,最终服务将会开始失败。用户也将收到延迟更大的响应,这反过来会增加用户自身的延迟,直到接近极限。增加断路器或熔断机制不仅有利于用户将其从故障服务中隔离出来,而且还具有减轻故障服务的负载的效果,给它一些恢复和清空请求队列的时间,从而确保系统某部分的失败不会危及整个系统,并能独立恢复。

昆仑中间件通过 弹性熔断 算法,实现对(上游)服务的故障隔离及过载保护。相比断路器模式算法存在过于一刀切的问题,弹性熔断算法则是一种自适应限制的技术,根据系统的实际负载情况自动调整限流策略,避免了断路器模式的过于严格的限制,从而提高了系统的弹性和可靠性。

服务发现

服务发现作为分布式系统不可或缺的一部分,它应当具备以下作用:

  • 简化系统的配置与管理
  • 提高系统的灵活性和可扩展性
  • 增强系统的容错性

而从 Dubbo 2(接口级服务发现) 到 Dubbo 3(应用级服务发现)的升级变化中,可以得到应用级服务发现有以下好处:

  • 更轻量的元数据
  • 更易实现容错性

昆仑中间件目前采用应用级服务发现,结合节点故障检测及隔离,提升系统故障时(网络分区、进程暂停等)的可用性。

服务调用

除上文提到的服务发现外,服务调用过程中,通常会涉及到以下关键技术点:

  • 通信协议

    • 例如 HTTP、TCP 等,它们决定了数据传输的方式和规则。
    • 不同的协议在性能、可靠性、复杂性等方面有所差异。
  • 序列化和反序列化

    • 将数据对象转换为可以在网络中传输的字节序列(序列化),以及接收端将字节序列还原为数据对象(反序列化)。
    • 常见的序列化方式如 JSON、XML、Protobuf 等。
  • 监控和日志

    • 用于跟踪调用的状态、性能指标和排查问题。
  • 跨平台和跨语言支持

    • 确保不同的平台和编程语言能够进行有效的远程调用。

昆仑中间件使用 gRPC 作为服务间通信协议,在此基础上,通过提供 SDK /代码生成等手段,降低开发及集成成本。