vivo 互联网业务就近路由技术实战
一、问题背景
在vivo互联网业务高速发展的同时,支撑的服务实例规模也越来越大,然而单个机房能承载的机器容量是有限的,于是同城多机房甚至多地域部署就成为了业务在实际部署过程中不得不面临的场景。
一般情况下,同一个机房内部的网络调用平均时延在0.1ms左右,同城多个机房之间的平均时延在1ms左右,跨地域机房之间的网络时延则更大,例如北京到上海的平均时延达到了30ms以上。
在业务多机房部署场景中,内部服务如果存在大量的跨机房、甚至跨地域的网络调用,则请求时延会显著加大,会直接影响到服务质量,甚至是用户体验。
二、解决方案
要解决以上问题,只需要实现服务消费者和服务提供者之间的网络调用尽量是同机房内部、或者是同地域即可,即服务消费者在调用服务提供者时,优先调用部署在本机房的服务提供者,当本机房没有部署该服务提供者时,再跨机房调用同地域的同城机房、甚至是跨地域机房的服务。
以上策略我们内部称为 就近路由。业务的就近路由示意图如下:
为了简单易用,vivo内部的服务间调用均使用了RPC框架来实现,在Java技术栈方向,我们选择了阿里巴巴开源的RPC框架 Dubbo,针对该场景的问题,我们扩展了Dubbo框架的源码实现,提供了 Dubbo就近路由能力。
三、技术原理说明
在服务提供者注册服务时,把该实例节点的机房信息【我们内部将机房标签定义为 app_loc 字段】注册到注册中心,在开启了就近路由策略后,消费者在过滤服务列表时,会自动筛选、匹配和消费者自己 app_loc 字段相同的服务提供者列表,从而实现就近路由访问。我们实现的就近路由策略,在本机房存在对应服务提供者的情况下,消费者会优先调用本机房的服务。
四、实现方案
开源版本的Dubbo框架并不提供就近路由能力,我们需要基于Dubbo框架源码扩展实现。Dubbo框架整体设计如下:【左侧为服务消费者使用的接口,右侧为服务提供方使用的接口】。
我们知道,Dubbo框架中服务消费者选择具体的服务提供者实例调用的匹配、筛选逻辑是在 Consumer 侧完成的,在 Cluster 层中,消费者会先应用用户配置的 Router 规则,然后再符合规则的服务提供者列表中,使用 LoadBalance 策略选择具体的服务提供者节点进行调用。
结合Dubbo框架源码实现,我们选择基于Dubbo 2.7.x版本的router层扩展口 org.apache.dubbo.rpc.cluster.Router 实现一种新的路由方式,即就近路由(我们内部标识为 NearestRouter)。
有了具体的解决方案,我们很快就完成了代码开发,内部也发布了一个集成就近路由策略的Dubbo版本,但在实际的线上灰度和业务推广过程中,我们实现的初版就近路由碰到了新的问题:
- 基于机房容量、机器成本等因素考虑,并不是所有的业务都实现了多机房部署,即有部分业务只实现了单机房部署,这部分业务的消费方无法实现同机房内部调用;
- 即使部分业务实现了多机房部署,但多个机房之间能提供的服务容量并不是相同的,对于服务容量较小的机房,如果一部分服务节点不可用,剩下的服务节点能提供的服务容量无法支撑本机房的消费方调用时,会造成该机房内的服务节点雪崩;
- 业务侧在开启就近路由策略时,希望消费服务的业务方能逐个开启,有一段时间的灰度观察过程,保证更平滑的升级验证;而不是比较粗暴的要么开启,要么关闭;
- 部分消费者的Dubbo版本较低,不支持就近路由功能,或者不支持配置应用维度的就近路由,在业务灰度过程中,希望能实现向前兼容,业务侧不报错。
基于以上问题,我们细化了实现方案:
- 就近路由策略默认不强制执行,即当本机房不存在服务提供者时,不再区分本机房、跨机房,就近路由策略自动失效,优先保障服务之间的正常调用;
- 支持设置就近路由策略的降级阈值,在调用本机房服务的过程中,当 本机房服务实例数量 / 集群服务实例数量 得到的数值小于设置的降级阈值时,我们认为当前机房的服务容量无法支撑本机房的消费方调用,就近路由策略自动失效;
- 支持配置应用维度的就近路由策略,即配置的就近路由策略可只针对配置的应用生效,实现应用维度的灰度效果;
- 实现Dubbo版本自动校验能力,不满足开启就近路由策略条件的业务,提示用户不开启。
有了以上细化方案,我们梳理的就近路由大致逻辑流程如下:
扩展Dubbo框架 Router 接口实现的 NearestRouter 核心代码如下:
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL consumerUrl, Invocation invocation) throws RpcException {
// validate application name (this.url -> routerUrl)
String applicationName = getProperty(APP_NAME, consumerUrl.getParameter(CommonConstants.APPLICATION_KEY, ""));
boolean validAppFlag = application.equals(applicationName) || CommonConstants.ANY_VALUE.equals(application);
if (!validAppFlag) {
return invokers;
} String local = getProperty(APP_LOC);
if (invokers == null || invokers.size() == 0) {
return invokers;
}
List<Invoker<T>> result = new ArrayList<Invoker<T>>();
for (Invoker invoker: invokers) {
String invokerLoc = getProperty(invoker, invocation, APP_LOC);
if (local.equals(invokerLoc)) {
result.add(invoker);
}
} if (result.size() > 0) {
if (fallback){
// 开启服务降级,available.ratio = 当前机房可用服务节点数量 / 集群可用服务节点数量
int curAvailableRatio = (int) Math.floor(result.size() * 100.0d / invokers.size());
if (curAvailableRatio <= availableRatio) {
return invokers;
}
} return result;
} else if (force) {
LOGGER.warn("The route result is empty and force execute. consumerIp: " + NetUtils.getLocalHost()
+ ", service: " + consumerUrl.getServiceKey() + ", appLoc: " + local
+ ", routerName: " + this.getUrl().getParameterAndDecoded("name"));
return result;
} else {
return invokers;
}
}
在vivo内部的服务治理平台上,我们提供了可视化的配置能力,页面内容如下:
通过扩展Dubbo框架,服务治理平台能力支持,我们以上问题都得到了较好的解决。
五、写在将来
虽然以上解决方案能覆盖我们当前业务场景中的大部分问题,随着业务的高速发展,新的业务问题也接踵而至。
- 当前就近路由策略代码实现集成在Dubbo框架中,业务侧需升级Dubbo框架版本才能完成升级,升级周期长,框架碎片化问题趋向严重;
- 当前业务服务注册时携带的机房信息比较有限,例如缺失服务实例所在的机架信息,和当前服务同城的其他机房信息等,该类信息可支持我们实现更丰富的就近路由策略;
- 业务侧的流量灰度策略较丰富,除了就近路由策略之外、往往还需要结合Dubbo框架自带的条件路由、标签路由策略才能实现;
- 在特定场景下,就近路由策略失效由框架自动完成,业务侧缺少及时的感知能力。
针对以上问题,我们的解决思路如下:
- 适配云原生ServiceMesh技术方案,实现RPC框架复杂逻辑和业务代码的分层解耦,业务侧集成的SDK功能偏向简单,版本迭代较少,版本碎片化问题能得到较好解决;框架的复杂逻辑下沉到Agent端,框架升级业务基本无感知。幸运的是Dubbo 3.0 版本已规划增加对云原生的支持,我们将持续关注;
- Dubbo框架的注册中心和内部CMDB系统结合,可以获取到更多维度的信息,不限于该服务节点所在的机架、同城的其他机房信息等。目前vivo内部已启动自研注册中心,可在该场景的能力建设上走的更远;
- 服务治理平台结合业务侧常用的流量灰度策略,提供结合就近路由、条件路由、标签路由的组合式路由策略,提供更丰富的流量路由能力;
- 针对框架错误、异常、自适应变更等的告警需求,vivo内部规划建设统一的框架SDK侧的监控告警能力,对于常见的错误、异常、自适应变更等,从SDK侧直接捕获,并和告警中心进行联动,缩短整个监控告警的链路路径,让业务侧能及时感知,甚至是提前感知。
作者:LuoLiang
vivo 互联网业务就近路由技术实战的更多相关文章
- 异构混排在vivo互联网的技术实践
作者:vivo 互联网算法团队- Shen Jiyi 本文根据沈技毅老师在"2022 vivo开发者大会"现场演讲内容整理而成. 混排层负责将多个异构队列的结果如广告.游戏.自然量 ...
- 从RabbitMQ平滑迁移到RocketMQ技术实战
作者:vivo 互联网中间件团队- Liu Runyun 大量业务使用消息中间件进行系统间的解耦.异步化.削峰填谷设计实现.公司内部前期基于RabbitMQ实现了一套高可用的消息中间件平台.随着业务的 ...
- 阿里聚安全受邀参加SFDC安全大会,分享互联网业务面临问题和安全创新实践
现今,技术引领的商业变革已无缝渗透入我们的日常生活,「技术改变生活」的开发者们被推向了创新浪潮的顶端.国内知名的开发者技术社区 SegmentFault 至今已有四年多了,自技术问答开始,他们已经发展 ...
- vivo互联网机器学习平台的建设与实践
vivo 互联网产品团队 - Wang xiao 随着广告和内容等推荐场景的扩展,算法模型也在不断演进迭代中.业务的不断增长,模型的训练.产出迫切需要进行平台化管理.vivo互联网机器学习平台主要业务 ...
- 什么是业务运维,企业如何实现互联网+业务与IT的融合
业务运维并不是一个新概念,针对传统信息架构提出的业务服务管理就是把以业务为核心的IT系统与IT基础设施性能进行整合运维的解决方案.然而随着互联网+转型的不断推进,基础设施的智能化和广泛云化成为IT发展 ...
- 总结linux路由技术
Linux系统的route命令用于显示和操作IP路由表,要实现两个不同的网段之间的通信,需要一台连接两个网络的路由器,或者同时连接位于两个网络的网关来实现. 在Linux系统中,设置路由通常是为了解决 ...
- HBase在共享经济互联网业务的应用
HDFS 与 Hbase HDFS容错率很高,即便是在系统崩溃的情况下,也能够在节点之间快速传输数据.HBase是非关系数据库,是开源的Not-Only-SQL数据库,它的运行建立在Hadoop上.H ...
- 业务与IT技术
最近听一个同事又再次提问关于业务比技术重要,是真的吗? 今天我们再来看一下. 一,什么是业务? 业务意指某种有目的的工作或工作项目.技术可以指人类对机器.硬件或人造器皿的运用,但它也可以包含 ...
- ELK技术实战-安装Elk 5.x平台
ELK技术实战–了解Elk各组件 转载 http://www.ywnds.com/?p=9776 ELK技术实战-部署Elk 2.x平台 ELK Stack是软件集合Elasticsearch. ...
- Cisco路由技术基础知识详解
第一部分 请写出568A的线序(接触网络第一天就应该会的,只要你掐过,想都能想出来) .网卡MAC地址长度是( )个二进制位(16进制与2进制的换算关系,只是换种方式问,不用你拿笔去算) A.12 ...
随机推荐
- 最好用的oa办公系统?
OA办公系统是一种集成办公自动化.协同办公.信息管理等功能于一体的软件系统,旨在提高办公效率,优化流程管理,提供更好的团队协作和信息共享.下面将详细介绍几个目前市场上认为较为优秀的OA办公系统. 一. ...
- java协程操作mysql数据库
我的项目: nanshaws/nettyWeb: 复习一下netty,并打算做一个web项目出来 (github.com) 最近在项目中分别添加了虚拟线程操作mysql数据库,和用协程操作mysql数 ...
- [CF1168C] And Reachability
And Reachability 题面翻译 题目描述 Toad Pimple 有一个整数数组 \(a_1,\dots,a_n\). 当 \(x < y\) 且存在 \(x = p_1 < ...
- 开源地图库OpenLayers的简单使用
引言 最近在学习可视化的东西,这让我想起了一些以前用过的图表库,其实我在日常做的大多是普通的需求,可视化方面应用的并不多,只是偶尔会因为个别特殊的需求,去借助一些图表库来实现图表的展示,这些普通的图表 ...
- Git提交修正
应用场景 日常开发中我们可能会遇到这样的问题 1.提交了代码有错误 2.提交的信息写错了 3.漏了一些文件没有提交 ...... 再或者我们写一个功能时,中间有很多小的提交,这中间就会产生特别多的co ...
- MySQL运维8-Mycat范围分表
一.范围分片 根据指定的字段及其配置的范围与数据节点的对应情况,来决定该数据属于哪一个分片. 说明1:范围分片会提前提供一个分片的范围默认是0-500万是一个分片,500万-1000万是一个分片,10 ...
- ElasticSearch之cat recovery API
命令样例如下: curl -X GET "https://localhost:9200/_cat/recovery?v=true&pretty" --cacert $ES_ ...
- 初识HTML5(2)
在本文中,我将介绍HTML5的超链接标记和表格的相关标记. 超链接标记 超链接是HTML中非常重要的元素,它用于在不同网页或不同部分之间创建链接.以下是一些与超链接相关的标记和属性: 使用<a& ...
- MySQL 基础(二)日志
在操作系统和数据库管理系统中,为了提高数据的容灾性,一般都会通过写入相关日志的方式来记录数据的修改,使得系统受到灾难时能够从之前的数据中恢复过来.MySQL 也提供了日志的机制来提高数据的容灾性,主要 ...
- 04 链表(上):如何实现LRU缓存淘汰算法?
一.什么是链表? 1.和数组一样,链表也是一种线性表. 2.从内存结构来看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构. 3.链表中的每一个内存块被称为 ...