乐趣区

关于云原生:全国首个政企采购云平台政采云基于-Dubbo-的混合云跨网方案实践

作者:王晓彬:政采云资深开发工程师,负责根底服务相干工作

徐锡平:政采云资深开发工程师,负责根底服务相干工作

对云岛业务构造的公司来说,云平台属于公司外部、齐全可控的局域网,而岛端则是有本人平安网络策略的独立外部网络。须要云岛通信时,会基于需要,按客户要求走流程开明一些端口,这个过程须要肯定的老本且不齐全可控。业务上,如果这种跨网需要增多,则会逐步变成痛点。如果能够搭建一个通明的跨网传输网络,配合良好的顶层设计,就能够在业务撑持、平安管控和运维老本中寻求较好的均衡。

本文将介绍政采云基于 Dubbo 的跨网计划落地过程中面临的技术挑战、社区单干以及更深层次形象的一些思考。 在政采云这种政企业务场景中的数据跨网,与业界私有云、自建公有云的公司相比,既有共性又有本人的特点,心愿能为大家提供新的思路或者启发。

前言

稳固、高效、牢靠的基础设施是互联网企业应答业务顶峰流量的底层基石。作为政采云的根底技术平台,根底平台部始终致力于通过业内前沿技术的落地,保障公司外部所有业务在线生产零碎所依赖的根底技术平台能稳固、平安、低成本、可继续地运行与倒退。

因为公司对 Dubbo 框架的重度应用,跨网数据传输零碎 个别基于 Dubbo 个性开发,在政采云外部就有多个版本的实现。

早在几年前,政采云就上线了基于 Dubbo Filter 转发的计划,它解决了岛到云的单向数据传输,平安认证等问题。另外,业务部门也有依照本人的需要,推出网状点对点的计划,实现了肯定水平的通明传输。

联合前两年的摸索实际以及业界相干畛域技术的成熟度,2022 年下半年,咱们对各跨岛计划,进行了整合降级,也就是当初的高速公路计划,保障跨岛标准化同时,解决了之前计划实际过程中面临的很多业务痛点,包含:

  • 单向传输:因为架构起因,如需双向须要对等重新部署一套,老本较大。
  • 白名单开明老本高:点对点的网状架构,须要两两开明白名单,因为政企网络特殊性,开明流程简单且慢。
  • 平台保护老本高:业务各自一套数据传输平台,反复建设且运维老本高。
  • 公共性能的缺失:外围性能,业务能够按需开发,然而数据审计、链路追踪、可观测性等公共个性,往往没有足够投入。

跨网数据传输零碎演进

1.1 历史架构

图一

自左向右、自下而上进行模块介绍:

  • 业务 Web:业务 Web 作为数据发送方,调本地集群 Provider 时,携带跨岛信息过来(Dubbo 上下文)。
  • 岛业务 Center:本地虚构 Provider,通过 Filter 拦挡跨岛申请,通过 http 传送到云平台 Dubbo 网关,返回数据后反序列化返回岛业务 web。
  • Dubbo 网关:接管 Http 申请,通过泛化调用云端 Provider,解决数据后返回业务 Center。
  • 云业务 Center:一般 Dubbo Provider。

1.2 高速公路架构

图二

1.2.1 隧道机制

隧道技术是一种通过应用 互联网络的基础设施 在网络之间传递数据的形式。应用隧道传递的数据 (或负载) 能够是不同协定的数据帧或包。

高速公路架构中,应用了隧道这个概念。两端(业务层)是 Dubbo 公有协定,跨网传输过程中,则应用了 http 协定,http 协定能够更好的被中间设备、网关辨认转发。这个机制的最大便当在于对业务的低侵入性。对于业务集群的利用齐全不须要批改。

图三

除了路由标记,进口 / 入口 Dubbo 协定字节流没有任何业务外信息,所以能够路由任何 Dubbo 申请。

图四

1.2.2 次要节点

  • 客户端 Sdk:不扭转用户应用 Dubbo 的形式,多种形式提供 Dubbo 的路由。
  • Dubbo 进口网关:代理 Dubbo 流量进口。
  • Dubbo 入口网关:代理 Dubbo 流量入口。
  • 对立网关:基于 Apisix,代理跨网间所有流量,能够扩大鉴权、审计、限流等个性。

挑战与应答之策

如前言中所述,已有的几个方案设计上存在了一些问题,落地后也限度了应用了场景。在架构上,咱们提出了高速公路计划,抉择了全双工的对等网络传输框架。角色上,云平台定位一个非凡的岛端利用,遵循 P2P 施行准则。而对用户而言,高速公路是一个通往岛端的隧道,遵循对用户通明准则。咱们能够先来看下在搭建平台的过程中面临的一些挑战以及解法。

2.1 技术挑战

联合当下跨网数据传输零碎面临的处境,并对业界 Dubbo 跨网计划做过一番调研后,在平台搭建上确定了如下三期指标:

  • 一期指标:网络能力建设,简略来说是搭建基于 Dubbo 的传输通道,下层性能先维持不变。
  • 二期指标:业务上,找业务后行试点,基于反馈,小步快跑,疾速迭代;技术上,寻求 Dubbo 社区合作,加强对 Dubbo 相干技术危险的把控,同时抽离通用个性,反馈社区。
  • 三期指标:形象出更通用的网络框架,从而使语言层,传输协定层、及中间件层独立扩大,一键切换。

在上述三期指标根本落地后,高速公路零碎不仅能够跑起来,同时领有十分弱小的扩展性,更好的承接业务需要及共建。在这过程中,咱们须要解决不少技术问题。

2.1.1 客户端路由

如后面历史计划所述,其场景被限度为岛到云的单向数据传输,特点如下:

  • 客户端无路由能力:Consumer 端只能指定是否路由到云平台,而不能指定其余岛端。
  • 基于 filter 的扩大:Dubbo 的 Filter 并不是为路由设计的,在此基础上较难扩大。
  • 须要本地 Provider 角色:Consumer 端收回的申请,必须由一个注册在 Zookeeper 下的 Provider 兜住,而后 Filter 依据上下文决定是否转发,这就限度了业务方必须部署一个本地 Provider 利用(哪怕是空利用),能力做到跨网拜访。

咱们要解决的问题之一,就是突破单向传输瓶颈,客户端能够更自在的路由到指标云 / 岛。咱们设计了以下几种路由形式:

  • 注解形式:应用 @DubboReference 提供的通用 parameters 参数,设置路由指标,能够达到办法粒度的路由。
@DubboReference(check = false, parameters = {"ENV_SHANGHAI", "ALL"}) //all 示意所有办法,能够独自指定
private DemoService demoService;
  • 配置核心指定:把以上 parameters = {“ENV_SHANGHAI”, “ALL”} 信息,在配置核心配置,达到同样的成果,这种形式对代码齐全无侵入。
  • 线程指定:这种形式最灵便。
AddressZoneSpecify.setAddress(Enviroment.SHANGHAI);
demoService.play();

无论哪种路由形式,基于“用户通明“的准则,都不扭转用户应用 dubbo 的形式。

2.1.2 Dubbo 申请地址切换

客户端路由最小限度地侵入业务代码,达到了通明调用近程服务的指标。然而,用户仍旧须要部署一套虚构 Provider 利用,接管申请后按规定进行路由。

为了防止部署多余的利用,咱们须要有肯定的机制,间接把 dubbo 流量切换到近程。

图五

解决了切换问题后,本地的 APP2 不再须要,甚至 zk 也能够移除。当然,如果业务同时有本地和近程的调用须要,也能够持续存在。

图四原先,咱们筹备通过 Dubbo 的 Route 自定义扩大,去实现动静切换地址的能力。查阅材料后,发现 Dubbo 曾经提供了相似能力。

https://cn.dubbo.apache.org/zh-cn/docs3-v2/java-sdk/advanced-…

该个性放在 Dubbo 的子工程 dubbo-spi-extensions 中,同样以 Route 扩大模式实现。

但在理论应用过程中,咱们遇到如下问题:

  • 不反对 Dubbo2:应用 Dubbo2 时,间接以异样的模式揭示暂不反对。
  • NPE 异样:某些场景下调用呈现了 NPE 异样。
  • 失落局部信息:Router 下构建新 Invocation 时,失落了 version、group 等信息。
  • 重试异样:近程 Provider 如果产生了异样,客户端在重试的时候,抉择了本地集群 Provider 调用,造成谬误。

作为一个尝鲜新个性,咱们了解性能存在不稳固的状况。但这个性能作为咱们跨网计划的技术要点,又必须解决。所以,咱们通过 PR 的模式,把相应补丁提交到 Dubbo 社区。这个过程中,咱们分割到了 Dubbo PMC 远云大佬,一起探讨和欠缺 PR,直到解决所有已知问题。

2.1.3 进口网关的实现

在图 4 中,通过切换地址,咱们仿佛能够间接拜访近程利用,并且架构非常简单。然而遗憾的是,存在几个难以解决的问题:

  • 网关组件的限度:在云岛 / 岛岛间,存在一系列网关组件,来提供转发、负载平衡的性能,比方 SLB、NGINX、WAF。这些组件并不能辨认公有的 Dubbo 流量并转发。
  • ip 白名单开明老本高:相似 P2P 计划,须要点对点开明 IP 白名单,老本微小。
  • 降级保护简单:客户端通过集成 SDK 的模式转发,后续如须要劫持流量进行扩大,须要同时对每个接入利用进行降级。

图六

针对以上问题,咱们的设计中,须要退出 Dubbo 网关的角色,来实现以下指标。

两端 ip 收敛

  • 显著缩小网关长连贯数量
  • 弱化服务注册发现流程(每个环境只有一个 Dubbo 网关,间接配置即可相互发现)
  • 简化鉴权、认证流程。一条链路能够应用白名单,一群则只能配置较简单的鉴权

② 两端性能收敛

  • 客户端的 SDK 专一路由性能,根本不必降级
  • 扩大性能放在 Dubbo-Proxy,对立降级,业务端无感知

Dubbo-Proxy 作为业务网关,能够加重对业务端的侵入,起到相似分布式运行时(Dapr)作用。然而,在引入之前,须要解决一些事实的技术问题。其中,最重要的问题是如何接管生疏的 Dubbo 流量,而后进行转发。做了一些相干调研后,有两个计划可用:

  • 通用 Provider

间接在 Dubbo-Proxy 注册一个一般的通用 Service,客户端的 SDK 利用 Filter,劫持流量,间接调用通用 Service 后处理数据返回。

  • 注册虚构节点

该计划来源于远云。客户端在本地 zk 订阅近程节点时,告诉 Proxy,Proxy 获取订阅的信息后(事后订阅所有 zk 变更),被动注册相应虚构 Service(对 zk 来说,注册一个节点的参数只是字符串)到 zk 上。这样,能够把客户端的近程流量“骗”到 Proxy,Proxy 再应用服务端泛化,接管申请并转发。

以上两种计划,都能够实现进口网关。然而,在设计上,角色间须要屡次交互,能力达到目标。那么,是否有更简洁的形式,间接反对这种接管和转发呢?

首先,咱们对 Dubbo 源码进行了调研,看 Provider 接管到生疏流量(无相应 Service)后会如何解决,是否有扩大点能够拦挡。发现在 Byte 流解析阶段,Dubbo 即对 Service 进行了查看,不存在间接抛异样返回。

图七

在 Provider 解决的生命周期中,Decode 出于十分晚期的阶段,简直没有什么扩大点能够拦挡解决。因为疾速失败的理念,晚期的检测的确能够防止前面无谓的代码执行耗费。然而,比照 Spring,Dubbo 在扩展性上是有有余的,即对于一个通用的异样,却没有相应的扩大机制。

咱们决定在 decode 的根底上,加上对这个异样的扩大。次要思路是,在 decode 被调用处,catch 住这块异样,通过 SPI 的模式,获取扩大实现,能够定制异样信息,也能够管制 decode 流程重试。这块批改难度并不大,公有版本上顺利通过测试,同时提交 PR 到社区。这个过程中,远云大佬帮忙发现了一个并发平安的 bug,并给了不少缩小危险的倡议。

// 解码完结后,无论是否异样,都将进入这个办法
void handleRequest(final ExchangeChannel channel, Request req) throws RemotingException {if (req.error != null) {
            // Give ExceptionProcessors a chance to retry request handle or custom exception information.
            String exPs = System.getProperty(EXCEPTION_PROCESSOR_KEY);
            if (StringUtils.isNotBlank(exPs)) {ExtensionLoader<ExceptionProcessor> extensionLoader = channel.getUrl().getOrDefaultFrameworkModel().getExtensionLoader(ExceptionProcessor.class);
                ExceptionProcessor expProcessor = extensionLoader.getOrDefaultExtension(exPs);
                boolean handleError = expProcessor.shouldHandleError(error);
                if (handleError) {
                    // 获取异样扩大,执行 wrapAndHandleException 操作,须要重试的场景能够抛出 retry 异样
                    msg = Optional.ofNullable(expProcessor.wrapAndHandleException(channel, req)).orElse(msg);
                }
            }
        }

        res.setErrorMessage("Fail to decode request due to:" + msg);
        res.setStatus(Response.BAD_REQUEST);

        channel.send(res);
    }
}

 //handleRequest 过程中的 retry 管制
 public void received(Channel channel, Object message) throws RemotingException {
       // 解码 
       decode(message);
        try {handler.handleRequest(channel, message);
        } catch (RetryHandleException e) {if (message instanceof Request) {ErrorData errorData = (ErrorData) ((Request) message).getData();
                // 有定制,进行重试
                retry(errorData.getData());
            } else {
                // Retry only once, and only Request will throw an RetryHandleException
                throw new RemotingException(channel, "Unknown error encountered when retry handle:" + e.getMessage());
            }
            handler.received(channel, message);
        }
    }

对于 ExceptionProcessor 扩大,咱们在官网扩大包 Dubbo-Spi-Extensions 中,提供了一个默认实现,容许管制重试解码,并自定义异样解决。

2.1.4 核心网关

图 6 的架构,曾经十分靠近最终实现了,然而缺了一个核心网关角色。引入这个网关 (基于 Apisix) 的起因:

  • 白名单问题:尽管 Dubbo 网关收敛了终端 IP,然而要实现岛岛互通,还是得两两互开白名单。引入核心网关(云平台)后,每个岛独自和云平台互开即可。白名单开明复杂度从 O(n*n) 变为 O(n)。
  • 对立网关的益处:作为公司级网关,能够对立对所有利用进行限流、鉴权、审计、可观测性等性能拓展。

更多思考

无论公司内外,能抉择的跨网计划十分多,咱们会去抉择一个能解决痛点的,而不是完满的计划。落地计划个别比拟激进,然而对于架构的思考,肯定是须要更超前的。

http 协定导致的性能损失

后面说到,在 Dubbo 网关和核心网关间,咱们应用了 Http 协定。比照 Dubbo 等精简协定,Http 协定显然更臃肿。然而,兴许这是现阶段最合适的计划。除了防止公有协定在网络设备中的“艰巨前行”,Http 协定开发成本更低,相应落地危险也更小。一些新技术,兴许是咱们后续倒退的方向。比方 Higress,反对 Triple 协定(基于 Http2)替换信息,在取得更高性能的同时,也解决了设施辨认问题。然而抉择 Higress,须要面对学习认知老本、新开源 BUG 多等问题,同时它可能更适宜外部网络(即便跨公网也能搭建 VPN),而不是咱们各公有岛端(客户自定义安全策略)的网络互通。

扩展性有余

高速公路是一个基于 Dubbo 的跨网计划,在协定与框架层,与 Dubbo 的绑定比拟深,然而它应该能做的更多。兴许很快,会接入 Http、Mq 等利用协定的流量,或者 Python、Go 等语言的客户端,甚至是 Mysql 的数据互通。这个时候,要么对架构大改,要么各种兼容,这都不是咱们想看到的。参考网络分层协定,咱们也粗略地做了一个分层形象布局。

图八

  • 物理层买通:次要解决网络异构问题,即约定不同安全策略的子域如何通信。
  • 通信协定层减速:后面讲到的应用层协定,须要做到容许独立扩大及切换。
  • 语言层编译减速:业务网关可能更适宜应用 Golang,而后 Java 节点是否能够用 Native 优化性能?
  • 框架层性能降级:比方以后对 Dubbo 的定制开发,应用的 Apisix 核心网关是否能够扩大 dubbo 转 dubbo?
  • 工作编排:业务的跨网调度,不肯定是 A->B->C->D,会不会是 A、B 同时实现后能力 ->C->D?
  • 更下层的管制面 / 治理面 / 运维面

将来布局

随着高速公路计划在政采云的逐步落地,咱们将来会从稳定性、性能加强、新技术摸索三个方面去做深、做广:

1. 稳定性:根底服务的稳定性是所有的基石,而这往往是不少研发同学容易漠视的一点,研发同学需“在晴天时修屋顶”。

  • 零碎本身的健壮性:资源池化隔离、QoS 保障能力建设。
  • 节点实例的稳定性:加固发现能力,继续欠缺异样检测工具(除了惯例的衰弱检测,会从观测指标的不同纬度综合决策),主动进行异样实例的替换;增强数据经营,晋升反馈能力。

2. 性能加强

  • 协定加强:以后只能对 Dubbo 流量转发,打算减少对 Http/Grpc 等协定等反对,从而反对更多的场景(已有业务提此类需要)。
  • 安全性加强:在核心网关 Apisix 开发鉴权、审计等插件,更好的管制跨网的调用与被调。
  • 易用性加强:开发自动工单零碎,对须要配置的事项,由业务测提工单,相应人员审核后主动配置,解放劳动力同时缩小出错概率。

3. 新技术摸索

网关场景,通常有个两个比拟显著的特点:

  • 并发量高:多个利用复用同一个网关
  • 行为轻量:个别只有转发、权限校验等轻量操作

基于这两个特点,语言层性能开销在总性能开销中的占比,往往会业务利用更大,这个时候,Golang 等语言会比 Java 更有劣势。以后也在对 Dubbo-Go 调研,将来替换基于 Java 版 Dubbo 的网关利用。

另外,Higress 计划看起来不错,必定会有许多值得咱们学习的货色。

欢送感兴趣的同学扫描下方二维码退出钉钉交换群,一起参加探讨交换。

退出移动版