关于dubbo:政采云基于-Dubbo-的混合云跨网方案实践

32次阅读

共计 7590 个字符,预计需要花费 19 分钟才能阅读完成。

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

本文将介绍政采云基于 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 计划看起来不错,必定会有许多值得咱们学习的货色。

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

原文链接

本文为阿里云原创内容,未经容许不得转载。

正文完
 0