斗鱼 API 网关演进之路

2019 年 5 月 11 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙武汉站,斗鱼资深工程师张壮壮在活动上做了《 斗鱼 API 网关演进之路 》的分享。

OpenResty x Open Talk 全国巡回沙龙是由 OpenResty 社区、又拍云发起,邀请业内资深的 OpenResty 技术专家,分享 OpenResty 实战经验,增进 OpenResty 使用者的交流与学习,推动 OpenResty 开源项目的发展。活动已先后在深圳、北京、武汉举办,后续还将陆续在上海、广州、杭州等城市巡回举办。

张壮壮,斗鱼数据平台部资深工程师,负责打点、API 网关及后端服务架构建设。

以下是分享全文:

大家下午好,先简单做下自我介绍,我是来自斗鱼的张壮壮,曾就职于拉勾网和滴滴出行,2017 年 3 月加入斗鱼,主要负责 API 网关和数据采集等工作。

今天给大家带来斗鱼 API 网关的一些细节,在分享之前,先感谢刚才的邵海杨老师,因为我们的 API 网关基于 Slardar 二次开发的,刚才海杨老师已经详细介绍了 Slardar 的基础原理,所以这块内容我不再重复介绍,直接介绍斗鱼在此基础上做的更细节的工作。

今天我主要从三个方面来分享:

  • 斗鱼使用 API 网关的背景
  • 网关的架构&功能
  • 斗鱼 API 网关远期规划

为什么是 API 网关?

为什么是 API 网关?这要从微服务化遇到的两个问题说起,第一,怎样保证服务的无宕机更新部署;第二,怎样保证服务的自动扩容及故障恢复。这两个问题,又拍云已经有了解决方案:只需要在服务之上做服务路由,让路由支持服务的无宕机更新部署,保证服务的扩容及故障恢复,我们也是按照这个思路来实现的。

但是只有这个不能解决所有问题,比如服务的性能监控、系统的资源调度等问题,还需要其他基础设施来支撑。所以 Docker 和 Kubernetes 进入了我们的视野。由于本次活动主题是 OpenResty,对容器技术选型就不做展开了。服务上容器,在更新和迁移中 IP 和 Port 是变化的、不确定的,这是必须要解决的问题。

服务路由

服务路由要支持服务注册、服务发现和负载均衡。经过多方调研,我们发现又拍云开源的动态负载均衡组件 Slardar 非常适合业务场景,主要解决了容器环境服务 IP 和 Port 均变化的问题。

  • 服务注册是服务需要主动上报服务相关信息,最重要的是 IP 和端口;
  • 服务发现是把服务注册的信息集中起来,最好能持久化;
  • 为了避免单点故障,服务会启动多个实例,因此还需要做负载均衡。

服务发现有很多开源的工具可以用,比如 Consul、etcd 和 Apache Zookeeper。由于我们选型是 K8S,所以服务发现选择 etcd。

负载均衡,基本上就是三个:LVS、HAProxy 和 Nginx。

接下来我们简单了解下 Slardar,它由四个部分组成:

  • 第一部分是官方的 Nginx,没有任何改动;
  • 第二部分是 Nginx Lua 模块,核心是 Lua 版本的负载均衡算法+ balance_by_lua
  • 第三部分是 lua-resty-checkups,它是把 Nginx upstream 模块常用的功能单独抽出来,用 lua 重新实现了一遍;
  • 第四部分是 luacocket,用于加载配置信息。

Slardar 在启动过程中先拉取服务配置,拉取完配置就可以对外进行服务了。如果我们的服务因为扩容或者异常宕机又起了一个新的实例,此时 IP和 Port 都会变化,需要把服务 IP 和 Port 等信息注册到 Slardar 和 Consul。逻辑清晰,结构简单,这是选择 Slardar 的原因,不过想要真正应用,仅仅有动态负载均衡远远不够,还需要解决以下的问题:

  • 服务如何在启动后自动上报信息到 Consul;
  • Slardar 如何解决自身单点问题;
  • 怎样应对 Consul 集群故障、或者网络故障;
  • 没有可视化管理;
  • 灰度测试、AB 测试、流量复制等等功能的实现(考虑未来使用场景)。

我们拿到了 Slardar 进行了大刀阔斧地调整:

  1. 取消 Consul,实现注册中心,并持久化配置到数据库;
  2. 开发 Java agent,实现 Java 服务自动上报;
  3. 对接 Kubernetes API,实现非 Java 服务自动上报;
  4. 提供可视化管理后台;
  5. 配置定时落盘,当网络故障时作为托底;
  6. 定时全量拉取配置,增加集群(机房)概念,可一键切换流量;
  7. 支持集群部署,应对单点问题;
  8. upstrem 列表 key 由 Host 改为 Host+URI(前缀);
  9. 引入插件模式,新增了很多功能,如灰度测试、AB测试、流量复制、服务限流等。

斗鱼 API 网关的架构&功能

下面介绍斗鱼的 API 网关的部署架构,以及内部功能细节。

抽象来看,服务接入 API 网关的架构非常清晰,和原生 Nginx 架构一样,所有流量必须经过 API 网关后,才能访问到真实的后端。经服务端处理,并将响应返回给 API 网关之后,再交给客户端。这是单机房的部署架构。实际上使用 Nginx 作为入口网关,API 网关作为内网网关,Nginx 负责处理复杂的 location 逻辑、SSL 认证等,API 网关负责抽象后台服务间通用功能。

这是多机房部署架构,上游使用 CDN 来做流量分配,方便机房故障时进行一键流量切换。

这张图很好的展示了斗鱼 API 网关生态体系。

上图左侧是 API 网关的内部功能,绿色部分是已实现的功能,包括限流、OA 认证、请求限制、AB 测试、灰度测试、流量复制、蓝绿发布、API 开放平台等。灰色部分是即将实现的功能,蓝色部分是 Slardar 原生的功能,当然我们也做了大量的优化工作,比如:路由算法支持动态的权重更新。

上图右侧 API 网关的支撑服务,其中网关管理 MIS 系统是可视化管理后台。日志聚合提供了接入服务的性能图表,比如状态码 4XX,5XX 统计,以及请求不同水位线耗时分布,俗称 P90,P99。天眼是 Java agent,负责实现服务对接下面的注册中心、实现服务优雅停机。

上图下侧是 API 网关代理的服务,如搜索、推荐、风控、流量分发等等。

以上整个罗列了我们已经实现且在线使用的重要功能。因为时间关系,后面我会挑选其中三个功能详细介绍实现原理。

OA 认证:为了解决后端服务各自对接 OA 认证繁琐,比较典型的是内部使用的开源系统,如Kibana、zabbix、Dubbo Admin 等,这些开源组件我们不可能投入人力去二次开发,但是需要接 OA,还需要进行一些 ACL 权限控制。

QPS 限流:用的是非常简单的计数器模式,是单机版的,限流是为了保证斗鱼的核心服务,比如视频拉流,还有刚才提到的推荐、搜索免受洪峰攻击。

服务兜底:这个功能想必大家非常了解,它能保证上游的数据服务永不消失,它与 QPS 限流其实是结合在一起的,触发限流的请求会直接返回兜底数据,这可以保证在极端情况下,我们的后端服务不会被瞬时流量打垮,同时保证友好的用户体验。典型的场景就是 S 级主播的首秀,例如 3 月份PDD 的首播就给我们带来了非常大的流量冲击,通过 QPS 限流保证了我们的核心服务不受影响。

流量复制:在不影响用户正常请求的前提下,将原始请求复制一份或者多份,供开发人员在线对服务进行功能测试、性能测试和压力测试。功能上支持自身复制及跨域名复制,流量的放大和缩小。

AB测试、灰度测试和蓝绿发布,可以归为一类,均是维护多套 upstream 列表,通过某种策略,将不同的请求代理到不同 upstream 。

签名认证:对外暴露的接口,需要一套签名算法,避免服务直接裸露在外,所以这里面做了一个功能抽象。

服务高可用

我们保证服务高可用其实就是要处理两个场景:第一个场景是它的更新部署;第二个场景就是运行期间故障。

我们从服务更新部署和服务下线来看考虑第一个场景。

更新部署

想要避免服务更新部署导致请求异常,其实满足两个条件即可:

  • 第一保证注册到注册中心的服务都是已经可以对外提供服务的
  • 第二下线之前,先从反向代理列表中剔除

第一个是保证服务注册到注册中心的实例,一定是可以对外服务的状态,即某些服务一定要在启动完成后才能加入到中心。另一个场景是一些服务需要热加载,启动完了后不能立即对外进行服务,这时服务有一个预热的过程,一定是预热完了后才能注册到注册中心。

第二个是下线时通过 trap 命令,在接收到程序结束(terminate)和程序终止(interrupt)时执行 shutdown 函数,这里 shutdown 函数会先通知注册中心下线改实例,然后 hang 住 5-10 秒,等待下线事件更新到网关。

这里特别说明一下服务更新流程,因为 API 网关是基于 Nginx 的,所以控制单个 worker 进程全量从注册中心拉取 upstream 配置信息,并写入 lua_shared_dict,其他的 worker 定时同步lua_shared_dict 配置信息到本地缓存。为了反向代理的高性能,网关是从本地缓存获取 upstream 信息,而不是从 lua_shared_dict 。

运行期

接下来我们看运行期故障怎么处理。

我们是这样做的:心跳探活+状态回溯,我们知道只有心跳探活是不能完全保证服务的高可用的,于是加上了“状态回溯”。

另外说一句:“状态回溯”是我自己想的,不知道用的对不对,即一次请求过来,如果反向代理失败,就将该服务标记为不可用。

加上之前启动和停止的操作,就保证了在任何情况下,正常的发布或者某台实例异常故障不会出现服务不可用的瞬间。这里就解决了之前提到的保证服务的无宕机更新部署和保证服务的自动扩容和故障恢复这两个问题。

AB 测试

AB 测试我们只是做了一个通用的功能。我们的 AB 测试是基于 Nginx rewrite 命令,主要使用场景有:

  • 需测试的 ABCD…策略(或算法,或模型,或服务)会长期且同时存在于生产环境;
  • 不想同时维护多套代码分支;
  • 客户端无需改造。

目前网关对外提供 AB Test 功能是面向 HTTP 服务的,其实现原理是:后台服务提供一个默认接口,同时提供多种需要在线验证的其他接口,请求到达API网关,根据命中规则,重定向至对应的接口。其中,源 URI 作为对外暴露的接口,保持固定不变。

AB 测试规则支持白名单、尾数、轮询策略——一致性哈希等等。当然,业界还是另外一种实现方式,比如马蜂窝根据策略访问不同的 upstream 列表。

服务兜底

请求到达网关之后,会反向代理给后端,如果是错误状态码,比如 500、502、503,我们直接拿到兜底数据,返回给客户端就可以了。由于 OpenResty 的限制,无法在 header_filter_by_lua* 和 body_filter_by_lua 中使用发起非阻塞的 HTTP 请求或者其他依赖 TCP 的协议(如 Redis)去查询兜底数据(原因请点击https://github.com/openresty/lua-Nginx-module),有过 OpenResty 或者 Nginx 模块开发经验的同学应该都知道:阻塞 API 的使用将会大大的降低 Nginx 的性能。

业界是怎么处理这个问题的?我见到的有基于 OpenResty 实现的兜底功能,均是使用ngx.location.capture 来主动发起请求给上游服务,而非使用 Nginx 原生的命令 proxy_pass 来实现反向代理。ngx.location.capture 的返回结果包含了响应状态码,如果状态码属于 Error Code,则去查询兜底数据,并返回给 C 端用户。

--子查询代理完成请求
local res = ngx.location.capture(‘/backend‘ .. request_uri, {
    method = method,
    always_forward_body = true
})

if 504 == res.status then
    return bottom_value
end

使用 ngx.location.capture 替换 proxy_pass 的问题在于,HTTP 协议的应用场景非常广泛,Nginx 实现反向代理时已经做了大量的适配和场景覆盖,使用 ngx.location.capture 相当于重新 Nginx 的反向代理模块,需要考虑诸如:文件上传下载、静态资源和动态资源、是否传递 Cookie 等等场景。任何一个应用场景的遗漏都将是一个线上 BUG。

我们要做服务兜底的时候,网关已经上线了一年多,这个时候如果想要重写,无异于火中取栗。比较幸运的是,在查看 Nignx 官方文档的时候,发现原生命令 error_page。

示例中请求 location / 如果上游服务返回 404,则会内部重定向至 @fallback,而 @fallback 接口中可以发起二次 HTTP 请求,例如获取兜底数据,并且是可以使用非阻塞类库的。最后实现的核心代码如下:

location / {
    proxy_pass  http://backend;
    error_page 500 502 503 504 =200 @janus_bottom;
}
location @janus_bottom {
    content_by_lua ‘
        local bottom = require "bottom";
        --非阻塞获取兜底数据,并返回给client
        bottom.bottom();
    ‘;
}

总结一下斗鱼的 API 网关,就是运行在所有的 HTTP 服务上,提供通用、可抽象的服务治理功能。

斗鱼 API 网关的远期规划

2018 年我参加了杭州的 OpenResty 大会,当时受到了很大的启发。

现在 API 网关已经全面应用到斗鱼整个后端架构,我们对其做了一些规划。首先网关是分集群的,由于请求量非常大,磁盘的性能不高,反而会反向影响 API 网关吞吐性能。因此我们做了很多优化,比如上 SSD,精简日志等,这些功能都已经上线了,日志精简完后大概是原来体量的 2/3,效果非常明显,当然 SSD 才是“银弹”。

我们后期的一个想法是将网关日志直接写入 MQ,后续用专门的服务消费 MQ,把日志落地到本地磁盘。另外一个想法是从 MQ 里面直接消费到 ES 里面,做一些其他的分析。

然后,就是将请求分同步和异步两条线路。客户端请求到达 API 网关,网关会经过如限流,服务兜底,AB测试,灰度测试等功能,这些功能都是在同步的逻辑线路中。显然,同步逻辑功能越多,势必会影响客户端请求 HTTP 的时延。所以我们在 API 网关这一块,将请求日志放到 MQ,由一些模块直接消费这个 MQ,比如经过风控、流量控制、限流分析,产生一些 API 网关可以使用的配置,写入到 DB 里。网关通过拉取 DB 的配置,对后续的请求做一些限制。我们现在的同步链路已经比较完善,下一步重点是异步链路,而且我相信异步链路应该是整个 API 网关体系中更加庞大的生态链。

观看视频和 ppt 下载,请点击:

斗鱼 API 网关演进之路 - 又拍云

原文地址:https://www.cnblogs.com/upyun/p/10948756.html

时间: 2024-08-04 13:49:14

斗鱼 API 网关演进之路的相关文章

买单侠微服务的API网关演化之路

伴随着买单侠业务的快速发展,能够支持独立开发.独立部署.独立扩展的微服务在秦苍得到了广泛应用和蓬勃发展,短短3年左右时间,已经发展到了300+个微服务,并且还在快速增长中. 研发逐渐意识到伴随着微服务规模化的增长,必需要重视微服务的基础设施建设(API网关.服务注册中心.调用链跟踪等)才能保持开发效率和产品的质量. API网关作为访问微服务的大门, 是访问后台服务的入口,作为最常用的基础服务之一,其重要性不言而喻.在买单侠微服务的发展道路上,经过了以下摸索发展阶段,希望能给规模化应用微服务的攻城

华为架构师8年经验谈:从单体架构到微服务的服务化演进之路

华为架构师8年经验谈:从单体架构到微服务的服务化演进之路 目录技术文章2016年6月28日 转自:http://www.58maisui.com/2016/06/28/a-327/?ref=myread 本次分享的大纲如下: 传统应用开发面临的挑战 服务化实践 服务化不是银弹 服务化架构的演进方向 一 .传统应用开发面临的挑战 挑战1– 研发成本高 主要体现在如下几个方面: 代码重复率高 在实际项目分工时,开发都是各自负责几个功能,即便开发之间存在功能重叠,往往也会选择自己实现,而不是类库共享,

大数据平台演进之路 | 淘宝 & 滴滴 & 美团

声明:本文参考了淘宝/滴滴/美团发表的关于大数据平台建设的文章基础上予以整理.参考链接和作者在文末给出. 在此对三家公司的技术人员无私奉献精神表示感谢,如果文章造成了侵权行为,请联系本人删除.本人在尊重事实的基础上重新组织了语言和内容,旨在给读者揭开一个完善的大数据平台的组成和发展过程. 本文在未经本人允许情况下不得转载,否则追究版权责任. By 大数据技术与架构 场景描述:希望本文对那些正在建设大数据平台的同学们有所启发. 关键词:大数据平台 大数据平台是为了计算,现今社会所产生的越来越大的数

Net分布式系统之六:微服务之API网关

本人建立了个人技术.工作经验的分享微信号,计划后续公众号同步更新分享,比在此更多具体.欢迎有兴趣的同学一起加入相互学习.基于上篇微服务架构分享,今天分享其中一个重要的基础组件“API网关”. 一.引言 随着互联网的快速发展,当前以步入移动互联.物联网时代.用户访问系统入口也变得多种方式,由原来单一的PC客户端,变化到PC客户端.各种浏览器.手机移动端及智能终端等.同时系统之间大部分都不是单独运行,经常会涉及与其他系统对接.共享数据的需求.所以系统需要升级框架满足日新月异需求变化,支持业务发展,并

API网关

微服务之API网关 一.引言 随着互联网的快速发展,当前以步入移动互联.物联网时代.用户访问系统入口也变得多种方式,由原来单一的PC客户端,变化到PC客户端.各种浏览器.手机移动端及智能终端等.同时系统之间大部分都不是单独运行,经常会涉及与其他系统对接.共享数据的需求.所以系统需要升级框架满足日新月异需求变化,支持业务发展,并将框架升级为微服务架构."API网关"核心组件是架构用于满足此些需求. 很多互联网平台已基于网关的设计思路,构建自身平台的API网关,国内主要有京东.携程.唯品会

嵌入式操作系统与物联网演进之路

文/屠敏 物联网是新一代信息技术的重要组成部分,回顾其发展,其中不得不提的必然是嵌入式系统.传统的嵌入式系统与互联网的发展衍生出物联网,而在如今的物联网热潮之下,嵌入式系统也面临着全新的机遇与挑战.那么,两者的碰撞融合究竟会带来怎样的火花?对于传统的嵌入式开发者,我们应该如何改变应对新格局?在此我们采访了著名的嵌入式系统专家何小庆,跟他一起探索嵌入式操作系统与物联网演进之路. 何小庆,著名的嵌入式系统专家,国内最早涉足嵌入式 OS 者之一,创办了北京麦克泰软件技术有限公司,有 30 年嵌入式技术

【IT名人堂】何云飞:阿里云数据库的架构演进之路

[IT名人堂]何云飞:阿里云数据库的架构演进之路 原文转载自:IT168 ? 如果说淘宝革了零售的命,那么DT革了企业IT消费的命.在阿里巴巴看来,DT时代,企业IT消费的模式变成了“云服务+数据”,阿里云将打造一个像淘宝电商一样多方共赢的云生态.而作为阿里云庞大帝国的重要成员,阿里云RDS为社交网站.电子商务网站.手机App提供了可靠的数据存储服务.好的架构不是设计出来的,而是演化出来的,那么RDS经历了怎样的架构演进?本期名人堂我们邀请到了阿里云RDS首席产品架构师何云飞,为我们揭秘RDS的

Java企业级电商项目架构演进之路 Tomcat集群与Redis分布式百度云实战分享

muke慕课实战课程分享QQ313675301 新增课程: Java企业级电商项目架构演进之路 Tomcat集群与Redis分布式百度云实战分享 后端开发: 1.高级java软件架构师实战培训视频教程2.大型SpringMVC,Mybatis,Redis,Solr,Nginx,SSM分布式电商项目视频教程3.Spark Streaming实时流处理项目实战4.Java校招面试 Google面试官亲授5.Java开发企业级权限管理系统6.Java大牛 带你从0到上线开发企业级电商项目7.Java

.NET微服务架构及API网关

一.MSA简介 1.1.MSA是什么 微服务架构MSA是Microservice Architecture的简称,它是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相通讯.互相配合,为用户提供最终价值.它与SOA之间的区别如下: SOA实现 微服务架构实现   企业级,自顶向下开展实施 团队级,自底向上开展实施   粒度大:服务由多个子系统组成 粒度细:一个系统被拆分成多个服务,且服务的定义更加清晰   重ESB:企业服务总线,集中式的服务架构 轻网关:无集中式总线,松散的服务