东亚银行、岚图汽车带你解锁 AIGC 时代的数字化人才培养各赛道新模式! 了解详情
写点什么

羽量级实现灵活通用的微服务流量分发

  • 2020-07-13
  • 本文字数:3311 字

    阅读完需:约 11 分钟

羽量级实现灵活通用的微服务流量分发

背景

伴随着业务的飞速发展,达达集团(NASDAQ: DADA) 内部的微服务数量和节点个数也都在不断增长。经历了六年时间,我们也从公司成立最开始的单一大服务,逐步发展到了几百个云服务,几千台云主机的规模。


当业务逻辑和运行环境越来越复杂,简单的服务发现和治理功能已不能满足我们的需求。相信和许多公司一样,一路走来我们碰到了许多问题:


  1. 在线压测流量隔离:我们希望在与生产保持一致的环境下进行完整的压力测试,但是却苦于没有好的办法将线上真实的生产流量与压测流量隔离开来,我们只能选择耗费大量的人力物力来部署一套与生产一模一样的环境,极度影响压力测试的效率。

  2. 同服务并行测试:随着团队扩大,同一业务服务中会有多个功能在被同时开发和测试,但是因为缺乏好的方法将同一服务的不同版本在测试环境中隔离,这些不同功能只能被串行独立测试,严重影响了测试的效率,让产品的迭代周期变长。

  3. 核心服务无法冷热分离:我们有部分的核心服务同时承载着在线的实时业务流量与内部一些离线 job 的查询流量。其中,前者需要保证性能和功能的稳定,而后者的流量一般会消耗很多的计算资源但是对性能没有严苛的要求。在高峰时期,来自后者的流量会因为占用大量资源而对前者的在线流量产生负面影响。

  4. 多服务灰度发布:一些业务的变动往往需要多个微服务系统代码同时更新,而在灰度发布过程中,我们没办法控制新版本的调用方只调用新版本的服务,使得很多问题不能在灰度发布的过程中被发现,全量上线后引发线上故障。

  5. 服务间的限流:在异常场景下,来自一些非核心项目的大量流量可以让核心服务瘫痪。在没有灵活的限流手段之前,我们只能通过紧急扩容和代码修复来解决问题,拉长了事故恢复的时间,给业务带来损失。


要解决以上的痛点,本质上其实是要求我们在微服务体系内部进行(基于服务组,接口等多个维度的)灵活流量分发。

需求与架构设计

我们调研了市面上已有的一些现成解决方案,如阿里巴巴的 Dubbo,但是因为各种原因(如接入成本高昂,以及达达内部微服务的实现语言多样)没办法被我们直接使用。所以我们最终决定自己实现一套通用灵活的服务治理和流量分发引擎。


由于我们的业务服务情况复杂,业务功能的发展和变化非常快,且可分配在这个项目上的工程师资源并不充裕,所以我们从设计初期,就订立了几个大的原则:


  1. 我们希望这套引擎除了可以解决我们自身已经遇到的问题之外,还可以尽量多的覆盖未来可能遇到的各类同质化问题。

  2. 这套引擎的实现应该与与编程语言无关,否则无法适应达达内部复杂多样的应用服务技术栈。

  3. 实现需要轻量,不要引入过多的外部依赖,舍弃不必要的功能。否则工期太长业务等不了,且越复杂的系统,稳定性的风险就越大。


在此之前,我们有一套基于 consul 的服务发现框架,它已经包含了服务发现最核心的功能,只是流量分发的最小粒度只能到服务级别。但是由于 consul 天生拥有 kv 存储和元数据(metadata)更新的能力,使其具备了一定的扩展能力。而一些需要动态变化的路由规则等配置,我们决定利用配置中心的能力来进行存储,以便我们可以实时更新和分发。


基于这些现状和原则,我们对整体系统的架构做出了如下图所示的设计:



  1. 我们最终决定将新功能的所有逻辑做到客户端中,而 consul 服务只用来关心节点的健康状态以及存储元数据(metadata)。这样做的好处是核心的服务发现可以与业务逻辑最大程度的解耦,且对服务端最小限度的修改也使得整体的成本和风险相对可控。

  2. 除 metadata 外,流量分发策略都以配置形式存储在我们的配置中心中,且提供了一系列管理配置工具供用户去查询和修改。这样可以让我们实时灵活的在运行时来管控整个集群中的流量。

详细设计

元数据模型

我们对想要解决的问题做了进一步的抽象后,发现我们只需要对现有的服务注册模型做以下两个维度的扩充,就足以让我们在客户端中实现灵活的控制逻辑来管控流量:


  1. “链路”:在压力测试和灰度测试的场景下,我们需要将多个服务的不同节点组合在一起形成一个虚拟的隔离环境。我们将这个包含多个服务不同节点的容器称为“链路”,如下图所示:



在上面的示例图中,请求可以被分发到两个不同的链路(“链路 A”与“链路 B”)中。在默认情况下,流量只会在同一链路下流转(身处"链路 A"中的服务只会发送请求给"链路 A"中的下游服务)。在达达的真实环境中,除微服务外,我们的数据源以及核心中间件如消息队列等也被纳入了链路管理之中,所以任何请求都可以在一个完整的链路中被处理。


但是在真实场景中,不是所有的链路都会包含完整的微服务拓扑(如在测试环境中,测试人员只需要对需要测试的服务创建一个链路即可)。此时就需要我们根据链路的不同特点和需求,来决定流量(在本链路中找不到下游服务节点的情况下)是否需要被转向至其他链路中。于是我们将“链路”又细分为两种类型:“强链路”(不允许流量转向到其他链路,比如生产链路和压测链路,他们二者之间流量完全不允许互串)与“弱链路”(可以将流量转向至其他链路,比如测试环境中同一服务的不同分支)。


  1. “服务实例分组”:为了解决服务冷热分离等问题,需要我们对同一服务下的实例节点进一步细分为不同的分组。一个典型的场景如下图所示:



在上面的示例图中可以看出,通过对服务 B 的实例节点进行分组后,我们就可以对流量进行灵活的调度和分发了。


以上的元数据信息因为不会经常变动,且都是与实例节点相关的属性,所以我们决定将这些元数据信息作为实例节点的属性,与实例信息一起存储在 consul 中。

路由规则和逻辑

在对实例节点的元数据进行了扩充和完善之后,我们只需要在这些元数据的基础上构建我们自己的路由规则逻辑就可以了。


为了便于扩展以及可以动态分发,我们将路由规则以 json 形式存储于配置中心中。并且为了更便于研发工程师操作和配置,我们还提供了一套在线工具。具体的路由规则举例如下:



在有了定义好的路由规则之后,我们就可以很轻松的在客户端来撰写路由的业务逻辑了,具体路由逻辑如下图所示:



具体来说,在一个请求即将从 A 服务发送到 B 服务之前,需要做如下的逻辑判断才能决定该请求的真正去向:


  1. 根据发送方本机所处的“链路”:默认只会选择和自己处于相同链路的 B 服务节点。如果未找到可用节点,则会根据自身所处链路的强/弱(前一章节有介绍)属性来判断。

  2. 根据发送方自身的服务名,本机的 IP,请求的接口等信息匹配路由规则:如果匹配到规则,则根据该路由规则指定的目标来进行路由。

真实场景应用

结合我们的解决方案,让我们再次回顾一下第一章中描述的各个问题。


通过“链路”这个简单的概念模型,我们可以:


  • 在生产环境中分配隔离一批节点加入到“压测链路”,其作为一个与“线上流量链路”共处于生产环境中的强链路,两者的流量被完美的隔离。

  • 在测试环境中,同一服务的不同开发分支可以被隔离到不同的链路中,使得针对同一服务的并行测试成为可能。

  • 灰度发布过程中,只需要将一同参与发布的服务都加入到灰度链路中,那么就可以确保进入灰度链路的流量只会在灰度的服务中流转。


通过服务实例分组和灵活的路由功能,我们可以通过动态配置规则就可以实时调控集群中的流量,来实现服务冷热分离和限流等。


这套解决方案也给我们的业务提供了巨大的价值。举例来说,通过使用“链路”系统在线上压测中的应用,不但让我们可以完美的在线上真实环境中进行压力测试,同时还极大的缩短了压测环境准备,应用调试等环节所需要的时间,使得我们整个压测流程的资源投入从 2018 年双 11 的 250 人日缩短到了 2019 年双 11 的 70 人日,效率提升了 350%。

总结

针对我们在业务和系统发展中遇到的各类流量调控需求和问题,我们提出了一套简单易懂的数据模型,通过低成本轻量的逻辑实现,使得这些需求和问题得以被非常好地解决。同时这套解决方案因为足够简单通用,让我们在几乎不需要任何扩展的情况下就可以支持未来可能出现的各类流量相关的需求。


这套系统自上线以来,帮公司节约了大量的技术成本,提升了人效,还规避了很多事故可能造成的潜在损失。

团队成员

  • bowl-gu: 达达集团架构师。微服务治理,数据源高可用等模块的负责人

  • doubleMing: 达达集团架构师。主要负责服务治理,数据源高可用等系统的设计开发与维护

  • superbool: 达达集团架构师。主要负责监控报警平台,流量动态路由等系统


2020-07-13 14:173497

评论 9 条评论

发布
用户头像
对于mq这种异步回调能做到隔离吗?
2022-03-24 14:49
回复
用户头像
想知道这个链路是怎么来串起来的呢?如何做到足够灵活?
2022-01-20 13:55
回复
用户头像
superbool大神
2020-07-14 23:11
回复
用户头像
superbool就是传说中的大神
2020-07-14 18:26
回复
用户头像
学习
2020-07-14 18:26
回复
用户头像
真大佬
2020-07-14 18:20
回复
用户头像
学习了
2020-07-14 18:17
回复
用户头像
好高深的赶脚
2020-07-14 15:27
回复
用户头像
好奇这个框架用什么语言或技术解决 【不用dubbo是因为“内部微服务的实现语言多样”】的?以及 羽量级 由来。
2020-07-14 10:40
回复
没有更多了
发现更多内容

测试人生 | 00后0经验应届毕业生拿下2线城市15W offer,好励志~

霍格沃兹测试开发学社

Android动态权限详解

霍格沃兹测试开发学社

Tensorflow 2.x 模型-部署与实践

霍格沃兹测试开发学社

技术分享 | web自动化测试-执行 JavaScript 脚本

霍格沃兹测试开发学社

JAR 文件规范详解

霍格沃兹测试开发学社

【Java面试宝典】带你拿offer

钟奕礼

Java 面试 java;

GOPS现场 | 大规模团队如何实现Jenkins的集中管理——对话龙智技术顾问

龙智—DevSecOps解决方案

jenkins 管理Jenkins

Baklib每日分享|在线产品手册的制作技巧

Baklib

技术分享 | web 控件的交互进阶

霍格沃兹测试开发学社

Golang开发入门(一)

霍格沃兹测试开发学社

APK 逆向工程 - 解析 apk 基本信息和方法调用图

霍格沃兹测试开发学社

图像匹配几种常见算法与实践

霍格沃兹测试开发学社

探究 PHP_CodeSniffer 的代码静态分析原理

霍格沃兹测试开发学社

通过Inotify-tools 监听文件夹并同步文件至FTP服务器

皮特王

行业方案|“医疗”行业智能运维解决方案介绍

云智慧AIOps社区

监控 智能运维 智能优化算法 自动化运维 IT解决方案

Mongodb的分页优化及索引使用

霍格沃兹测试开发学社

ITSM | Atlassian ITSM终极指南,重构IT、运营和支持的工作方式

龙智—DevSecOps解决方案

ITSM ITSM解决方案

重铸资源合集之荣光,吾辈义不容辞!!

掘金安东尼

前端 9月月更

Jenkins实践——创建Pipeline的两种方式

霍格沃兹测试开发学社

技术分享 | 网页 frame 与多窗口处理

霍格沃兹测试开发学社

羊了个羊NFT系统链游开发技术

薇電13242772558

游戏 NFT

leetcode 208. Implement Trie (Prefix Tree) 实现 Trie (前缀树) (中等)

okokabcd

LeetCode 数据结构与算法

GOPS现场 | 芯片行业需要怎样的版本管理工具——对话龙智大规模安全研发技术专家

龙智—DevSecOps解决方案

版本控制 版本管理工具 版本管理 版本控制工具

JDK RMI探索与使用--序列化

霍格沃兹测试开发学社

技术分享 | Web 控件定位与常见操作

霍格沃兹测试开发学社

Windows-Python 应用:使用消息操作窗口

霍格沃兹测试开发学社

史上最全的Java容器集合之基础数据结构(手撕链表)

自然

9月日更

史上最全的Java容器集合之ArrayList(源码解读)

自然

9月月更

栓Q了,大厂被强制毕业,空窗一个月死背八股文,还好拿到了Offer

Geek_0c76c3

Java 数据库 开源 架构 开发

Baklib知识分享|知识库对企业来说有哪些意义?

Baklib

知识管理在企业业务中如何体现其价值

Baklib

羽量级实现灵活通用的微服务流量分发_架构_达达集团架构团队_InfoQ精选文章