前言

路由(Route)的设计广泛存在于众多领域,以 RPC 框架 Dubbo 为例,就有标签路由、脚本路由、权重路由、同机房路由等实现。

在框架设计层面,路由层往往位于负载均衡层之前,在进行选址时,路由完成的是 N 选 M(M <= N),而负载均衡完成的是 M 选一,共同影响选址逻辑,最后触发调用。

在业务层面,路由往往是为了实现一定的业务语义,对流量进行调度,所以服务治理框架通常提供的都是基础的路由扩展能力,使用者根据业务场景进行扩展。

路由过程

今天这篇文章将会围绕路由层该如何设计展开。

路由的抽象建模

先参考 Dubbo 2.7 的实现,进行第一个版本的路由设计,该版本也最直观,非常容易理解。

public interface Router {List<Invoker> route(List<Invoker> invokers, Invocation invocation);
}
  • Invoker:服务提供方地址的抽象

  • Invocation:调用的抽象

上述的 route 方法实现的便是 N 选 M 的逻辑。

接下来,以业务上比较常见的同机房路由为例继续建模。顾名思义,在部署时,提供者采用多机房部署,起到容灾的效果,同机房路由最简单的版本即过滤筛选出跟调用方同一机房的地址。

伪代码实现如下:

List<Invoker> route(List<Invoker> invokers, Invocation invocation) {String site = invocation.getSite();List<Invoker> result = new ArrayList<>();for (Invoker invoker: invokers) {if (invoker.getSite().equals(site)) {result.add(invoker);}}return result;
}

Dubbo 在较新的 2.7 版本中,也是采用了这样的实现方式。这种实现的弊端也是非常明显的:**每一次调用,都需要对全量的地址进行一次循环遍历!注意,这是调用级别!**在超大规模的集群下,开销之大,可想而知。

路由的改进方案

基于之前路由的抽象建模,可以直观地理解路由选址的过程,其实也就是 2 步:

  1. 根据流量特性与路由规则特性选出对应的路由标。

  2. 根据路由标过滤对应的服务端地址列表

纵观整个调用过程:

第一步:一定是动态的,Invocation 可能来自于不同的机房,自然会携带不同的机房标。

第二步:根据路由标过滤对应的服务地址列表,完全是可以优化的,因为服务端的地址列表基本是固定的(在不发生上下线时),可以提前计算好每个机房的地址列表,这样就完成了算法复杂度从 O(N) 到 O(1) 的优化。

基于这个优化思路继续完善,路由选址的过程不应该发生在调用级别,而应该发生在下面两个场景:

  1. 地址列表变化时。需要重新计算路由地址列表。

  2. 路由规则发生变化时。例如路由规则不再是静态的,可以接受动态配置的推送,此时路由地址列表也需要重新计算。

但无论是哪个场景,相比调用级别的计算量,都是九牛一毛的存在。

优化过后的路由方案,伪代码如下:

Map<String, List<Invoker>> invokerMap = new ArrayList<>();
String originRule;
List<Invoker> originInvokers;void generateRoute(List<Invoker> invokers, String rule) {// 不同路由有不同的路由地址列表计算方式invokerMap = calculate(invokers, rule);
}// 地址推送
void addressNotify(List<Invoker> invokers) {originInvokers = invokers;generateRoute(originInvokers, originRule);
}// 规则变化
void ruleChange(String rule) {originRule = rule;generateRoute(originInvokers, originRule);
}List<Invoker> route(Invocation invocation) {String site = invocation.getSite();return invokerMap.get(site);
}

这份伪代码仅供参考,如果需要实现,仍然需要考虑非常多的细节,例如:

  • 下一级路由如何触发构建

  • 如何确保路由的可观测性

优化过后的方案,路由过程如下:

路由树选址

对比之前,主要是两个变化:

  1. 路由的代码组织结构从 pipeline 的链式结构,变成树型结构

  2. 建树的过程发生在地址 notify 和规则推送时,在 invocation 级别无需计算

静态路由和动态路由

上述的新方案,并不是特别新奇的概念,正是我们熟知的”打表“。这里也要进行说明,并不是所有的路由场景都可以提前打表,如果某一个路由的实现中,服务地址列表的切分依赖了调用时的信息,自然需要将 N 选 M 的过程延迟到调用时。但根据我个人的经验,大多数的路由实现,基本都是标的匹配过程,无非是路由标的类型,计算标的逻辑不一样而已。

对于这类可以提前打表的路由实现,我们不妨称之为静态路由;而必须在调用级别计算的路由实现,可以称之为动态路由。

上述的优化方案,适用于静态路由场景,并且在真实业务场景中,几乎 90% 的路由实现都是静态路由。

总结

本文以 Dubbo2.7 为例,在其基础上提出了一种静态路由策略的优化方案,可以大大减少路由过程中的计算量。这里也给大家卖个关子,Dubbo 3.0 有没有对这块进行优化呢,采取的是不是本文的静态路由方案呢,背后会不会有其他的思考呢?嘿嘿,本文先不给结论,有知道的小伙伴可以留言告诉大家哦。

- END -

聊聊服务治理中的路由设计相关推荐

  1. 【微服务架构】在微服务架构中最小化设计时间耦合

    理查森:我是克里斯·理查森.欢迎来到我关于在微服务架构中最小化设计时耦合的演讲.在这次演讲中,我将回答三个问题.什么是设计时耦合?这会造成什么问题?我们如何设计松散耦合的服务?这些年来我做了一些事情. ...

  2. RocketMQ 千锤百炼--哈啰在分布式消息治理和微服务治理中的实践

    作者|梁勇 ​ 背景 ​ 哈啰已进化为包括两轮出行(哈啰单车.哈啰助力车.哈啰电动车.小哈换电).四轮出行(哈啰顺风车.全网叫车.哈啰打车)等的综合化移动出行平台,并向酒店.到店团购等众多本地生活化生 ...

  3. 哈啰在分布式消息治理和微服务治理中的实践

    简介:随着公司业务的不断发展,流量也在不断增长.我们发现生产中的一些重大事故,往往是被突发的流量冲跨的,对流量的治理和防护,保障系统高可用就尤为重要. 作者|梁勇 ​ 背景 ​ 哈啰已进化为包括两轮出 ...

  4. 架构专家梁勇:哈啰在分布式消息治理和微服务治理中的实践

    背景介绍 哈啰已进化为包括两轮出行(哈啰单车.哈啰助力车.哈啰电动车.小哈换电).四轮出行(哈啰顺风车.全网叫车.哈啰打车)等的综合化移动出行平台,并向酒店.到店团购等众多本地生活化生态探索. 随着公 ...

  5. 基于Asp.Net Core打造轻量级内部服务治理RPC(二 远程服务设计)

    紧接上一篇<基于Asp.Net Core打造轻量级内部服务治理RPC(一)>文章.本文主要讲解基于Asp.Net Core的远程服务设计和实现. 在上一篇中讲过,服务提供者提供的服务实际上 ...

  6. 微服务体系中的分层设计和领域划分!

    上一篇:一个90后员工猝死的全过程 0.2T架构师学习资料干货分享 作者:汤波 来源:https://tbwork.org/2018/10/25/layed-dev-arch/ 本文获得阿里巴巴< ...

  7. 电商系统中微服务体系中的分层设计和领域划分

    说明:在Java生鲜电商平台中,微服务体系的分层设计与领域划分应该怎么样呢? 看标题感觉这个东西很理论,比起"高并发.多线程"."分布式CAP.一致性.Paxos&quo ...

  8. 浅谈微服务体系中的分层设计和领域划分

    1.摘要 本文阐述了一种将分层设计和DDD领域设计应用于微服务体系架构的方案实践,也是个人的最佳实践.对于互联网公司来说,我们主张将其Web服务架构分为五层:基础设施层.领域服务层.应用服务层.网关层 ...

  9. 基于 Spring Cloud 的服务治理实践

    http://www.infoq.com/cn/articles/spring-cloud-based-service-governance 大家好,我是来自贝壳金控的赵文乐,目前主要从事架构方面的工 ...

最新文章

  1. 剑指Offer_Python实现
  2. JMS(1)——基本实例
  3. 多视图几何总结——摄像机模型
  4. Google API 设计指南 - 前言
  5. Sublime text无法自动通过package control安装插件的研究
  6. Capture images using V4L2 on Linux
  7. C#LeetCode刷题之#172-阶乘后的零(Factorial Trailing Zeroes)
  8. Ranger开源流水线docker化实践案例
  9. 视镜:华为云媒体质量管理最新实践
  10. python处理分组_Python中的groupby分组功能的实例代码
  11. 旷视科技提出双向网络BiSeNet:实现实时语义分割
  12. 这几款好加密软件让你不再担心担心隐私泄露!
  13. WEB应用之JSP+Servlet
  14. 使用Eclipse编译运行MapReduce程序
  15. Notification使用举例
  16. 远程服务器连接计算机和用户名填写,windos系统服务器:添加远程连接用户名方法...
  17. 快看,这是我为你准备的Python爬取图片教程
  18. AD域内禁用所有计算机445端口,勒索病毒“永恒之蓝”变种再来,该如何关闭445端口(收藏)(示例代码)...
  19. 2015年App Store审核被拒的23个理由
  20. Excel如何隔一行或几行填充颜色

热门文章

  1. php自动到某个时间提醒,2周后,php脚本cron作业将提醒消息发送到特定的电子邮件地址...
  2. sql镶嵌查询_sql数据库的嵌套查询
  3. nginx alias php,Nginx Alias 无法解析PHP的解决办法
  4. C语言中的关键字详略
  5. linux ftp显示进度条,在Python中显示FTP下载进度(ProgressBar)
  6. python实现密码的强度_字符串处理函数(二)python语言实现密码强度校验
  7. 学习python一开始枯燥_编程零基础应当怎样开始学python?他说,看这三个经典方法...
  8. 强势 图解 AC自动机(保证您一次就能学会!)
  9. 1.1 内存的四个分区
  10. C - Catch That Cow(BFS)