1.背景

什么是API网关,它的作用是什么,产生的背景是啥?

从架构的角度来看,API网关暴露http接口服务,其本身不涉及业务逻辑,只负责包括请求路由、负载均衡、权限验证、流量控制、缓存等等功能。其定位类似于Nginx请求转发、但功能要多于Nginx,背后连接了成百上千个后台服务,这些服务协议可能是rest的,也可能是rpc协议等等。

网关的定位决定了它生来就需要高性能、高效率的。网关对接着成百上千的服务接口,承受者高并发的业务需求,因此我们对其性能要求严苛,其基本功能如下:

协议转换

一般从前端请求来的都是HTTP接口,而在分布式构建的背景下,我们后台服务基本上都是以RPC协议而开发的服务。这样就需要网关作为中间层对请求和响应作转换。

将HTTP协议转换为RPC,然后返回时将RPC协议转换为HTTP协议

请求路由

网关背后可能连接着成本上千个服务,其需要根据前端请求url来将请求路由到后端节点中去,这其中需要做到负载均衡

统一鉴权

对于鉴权操作不涉及到业务逻辑,那么可以在网关层进行处理,不用下层到业务逻辑。

统一监控

由于网关是外部服务的入口,所以我们可以在这里监控我们想要的数据,比如入参出参,链路时间。

流量控制,熔断降级

对于流量控制,熔断降级非业务逻辑可以统一放到网关层。

有很多业务都会自己去实现一层网关层,用来接入自己的服务,但是对于整个公司来说这还不够。

2.Flurry Dubbo API网关

Flurry是云集自研的一款轻量级、异步流式化、针对Dubbo的高性能API网关。与业界大多数网关不同的是,flurry自己实现了 http与dubbo协议互转的流式化的dubbo-json协议,可高性能、低内存要求的对http和dubbo协议进行转换。除此之外,其基于 netty作为服务容器,提供服务元数据模型等等都是非常具有特点的。下面我们将详细介绍 flurry的特性:

2.1 基于Netty容器

传统网关大多采用tomcat作为容器,其请求于响应没有做到异步,tomcat会有一个核心线程池来处理请求和响应,如果RT比较高的话,将会对性能有一定的影响。

Flurry 网关请求响应基于Netty线程模型,后者是实现了Reactive,反应式模式规范的,其设计就是来榨干CPU的,可以大幅提升单机请求响应的处理能力。

最终,Flurry通过使用Netty线程模型和NIO通讯协议实现了HTTP请求和响应的异步化。

每一次http请求最终都会由Netty的一个Client Handler来处理,其最终以异步模式请求后台服务,并返回一个CompletableFuture,当有结果返回时才会将结果返回给前端。

见下面一段例子:

ServerProcessHandler

public class ServerProcessHandler extends SimpleChannelInboundHandler {

public void handlerPostAsync(RequestContext context, ChannelHandlerContext ctx) throws RpcException {

CompletableFuture jsonResponse = asyncSender.sendAsync(context, ctx);

jsonResponse.whenComplete((result, t) -> {

long et = System.currentTimeMillis();

if (t != null) {

String errorMessage = HttpHandlerUtil.wrapCode(GateWayErrorCode.RemotingError);

doResponse(ctx, errorMessage, context.request());

} else {

doResponse(ctx, HttpHandlerUtil.wrapSuccess(context.requestUrl(), result), context.request());

}

});

}

//省略部分代码

public static void sendHttpResponse(ChannelHandlerContext ctx, String content, FullHttpRequest request) {

//将结果写回Client,返回前端

ctx.writeAndFlush(response);

}

}

2.2 服务元数据模型

所谓的服务元数据信息,是指服务接口的方法列表、每个方法的输入输出参数信息、每个参数的字段信息以及上述(方法、参数以及字段)的注释,其非常类似于Java Class的反射信息。

元数据的作用

有了服务元数据,我们就可以不必需要服务的API包,并能够清晰的知道整个服务API的定义。

这在Dubbo服务Mock调用、服务测试、文档站点、流式调用等等场景下都可以发挥抢到的作用。

元数据与注册中心数据比较

\

服务元数据

注册中心数据

变化频率

基本不变,随着服务迭代更改而更改

随着服务节点上下线而随时进行变化

职责

描述服务,定义服务的基本属性

存储地址列表

使用场景

无API依赖包模式调用(直接json),文档站点,Mock测试等

服务治理和调用

交互模型

服务编译期生成元信息,client通过接口调用模式获取

发布订阅模型,线上进行交互

元数据中心的价值

小孩子才分对错,成年人只看利弊。额外引入一个元数据生成机制,必然带来运维成本、理解成本、迁移成本等问题,那么它具备怎样的价值,来说服大家选择它呢?上面我们介绍元数据中心时已经提到了服务测试、服务 MOCK 等场景,这一节我们重点探讨一下元数据中心的价值和使用场景。

那么,Dubbo服务元数据能够利用到哪些场景呢?下面我们来详细描述。

2.3 流式协议转换

flurry网关对外提供的是HTTP Rest风格的接口,并辅以JSON数据的形式进行传输。因此flurry需要做到将外部的HTTP协议请求转换为dubbo RPC协议,然后再将dubbo协议的返回结果转换为HTTP协议返回给前端。

Dubbo原生泛化实现

泛化模式就是针对Dubbo Consumer端没有服务接口API包的情况下,使用Map的形式将POJO的每一个属性映射为Key,Value的模式来请求Dubbo服务端,在Dubbo服务端处理完成请求之后,再将结果POJO转为Map的形式返回给消费端。

使用泛化模式来实现对Http Dubbo的转换流程大致如下图所示:

Http请求,数据通过JSON传输,其格式严格按照接口POJO属性。返回结果再序列化为Json返回前端。现在大多数开源的网关,在dubbo协议适配上都是采用的泛化模式来做到协议转换的,这其中就包括 Soul 等。

泛化模式的协议转换数据流动流程:

JsonString -> JSONObject(Map) -> Binary

将JSON 字符串转换为 JSON 对象模型(JSONObject),此处通过第三方JSON映射框架(如Google的Gson, 阿里的FastJSON等)来做,然后将Map通过Hessian2 协议序列化为Binaray。

泛化缺点

泛化过程数据流会经过了三次转换, 会产生大量的临时对象, 有很大的内存要求。使用反射方式对于旨在榨干服务器性能以获取高吞吐量的系统来说, 难以达到性能最佳。

同时服务端也会对泛化请求多一重 Map POJO 的来回转换的过程。整体上,与普通的Dubbo调用相比有10-20%的损耗。

自定义Dubbo-Json协议

我们的需求是要打造一款高性能、异步、流式的Dubbo API网关,当然要对不能容忍上述泛化带来的序列化的痛点,针对http与dubbo协议转换,我们的要求如下:

自定义的Dubbo-Json协议参考了dapeng-soa 的流式解析协议的思想,详情请参考:dapeng-json

针对上述泛化模式转换Dubbo协议的缺点,我们在flurry-core 中的 Dubbo-Json 序列化协议做到了这点,下面我们来讲解它是如何高效率的完成JsonString到 dubbo hessian2 序列化buffer的转换的。

高性能

此协议用来在网关中作为http和rpc协议的转换,要求其能实现高效的序列化以及反序列化, 以支持网关海量请求的处理.

低内存使用

虽然大部分情况下的JSON请求、返回都是数据量较小的场景, 但作为平台框架, 也需要应对更大的JSON请求和返回, 比如1M、甚至10M. 在这些场景下, 如果需要占用大量的内存, 那么势必导致巨大的内存需求, 同时引发频繁的GC操作, 也会联动影响到整个网关的性能.

Dubbo-Json参考了XML SAX API的设计思想, 创造性的引入了JSON Stream API, 采用流式的处理模式, 实现JSON 对 hessian2 的双向转换, 无论数据包有多大, 都可以在一定固定的内存规模内完成.

容错性好

前面我们引入了服务元数据的概念,因此在此基础上,通过元数据提供的接口文档站点,自动生成请求数据模板,每一个属性的类型精确定义,譬如必须使用正确的数据类型, 有的字段是必填的等。

那么在Json -> Hessian2Buffer的转换过程中,如果出现与元数据定义不符合的情况,就回直接报错,定位方便。

流式协议解析过程

流式协议,顾名思义就是边读取边解析,数据像水流一样在管道中流动,边流动边解析,最后,数据解析完成时,转换成的hessian协议也已全部写入到了buffer中。

这里处理的核心思想就是实现自己的Json to hessian2 buffer 的语法和此法解析器,并配合前文提及的元数据功能,对每一个读取到的json片段通过元数据获取到其类型,并使用 hessian2协议以具体的方式写入到buffer中。

JSON结构简述

首先我们来看看JSON的结构. 一个典型的JSON结构体如下

{

"request": {

"orderNo": "1023101",

"productCount": 13,

"totalAmount: 16.54

}

}

其对应Java POJO 自然就是上述三个属性,这里我们略过。下面是POJO生成的元数据信息

STRING

INTEGER

DOUBLE

Json解析器

相比XML而言,JSON数据类型比较简单, 由Object/Array/Value/String/Boolean/Number等元素组成, 每种元素都由特定的字符开和结束. 例如Object以'{'以及'}'这两个字符标志开始以及结束, 而Array是'['以及']'. 简单的结构使得JSON比较容易组装以及解析。

如图,我们可以清晰的了解JSON的结构,那么对上述JSON进行解析时,当每一次解析到一个基本类型时,先解析到key,然后根据key到元数据信息中获取到其value类型,然后直接根据对应类型的hessian2序列化器将其序列化到byte buffer中。

当解析到引用类型,即 Struct类型时,我们将其压入栈顶,就和java方法调用压栈操作类似。

通过上面的步骤一步一步,每解析一步Json,就将其写入到byte buffer中,最终完成整个流式的解析过程。

拿上面json为例:

{

"request": {

"orderNo": "1023101",

"productCount": 13,

"totalAmount: 16.54

}

}

解析器每一步会解析一个单元,首先解析到request,然后根据请求附带的接口、版本等信息找到当前请求服务的元数据信息(元数据信息缓存在网关之中,定期刷新)。

开始解析属性,解析到 orderNo key时,通过元数据中得知其数据类型为String,然后再解析完value之后,通过调用hessian2的writeString API将其写入到hessian2序列化的byte buffer 缓存中。

依次解析后面的属性,当全部属性解析完成之后,解析到最后一个 } 时,此时证明数据全部解析完毕,于是hessian buffer 通过flush 将数据全部写入到bytebuffer中,请求直接发送出去。

Dubbo服务端再接收到这个序列化的buffer之后,会像其他普通dubbo consumer调用服务的模式一样的去解析,然后反序列化为请求实体,进行业务逻辑处理。

flurry网关再接受到返回的数据时,在没有反序列化之前,其是一个hessian2的二级制字节流,我们仍然通过dubbo-json的解析模式,直接将反序列化出来的属性写为Json String

总结:

上述整个请求和响应,网关处理如下:

request: Json -> hessian2二进制字节流

response:hessian2二进制字节流 -> json

请求和响应中没有像泛化模式中的中间对象转换,直接一步到位,没有多余的临时对象占用内存,没有多余的数据转换,整个过程像在管道中流式的进行。

2.4 flurry网关与tomcat接入层比较

传统的dubbo服务接入层是采用tomcat作为容器来实现,每一个业务模块对应一个tomcat应用,其本身需要以来dubbo各个服务的API接口包,tomcat中启动几十个传统的dubbo consumer 服务,然后通过webmvc的模式提供http接口。

如上图所示,flurry dubbo网关不必依赖任何dubbo接口API包,而是直接通过获取服务元数据、并通过dubbo-json流式协议来调用后端服务。其本身不会耦合业务逻辑。

2.5 性能测试

测试环境

硬件部署与参数调整

机型

角色

CPU

内存

带宽

CVM虚拟机

API网关

8核

16GB

10Mbp/s

CVM虚拟机 X2

Dubbo Provider

4核

8GB

10Mbp/s

CVM虚拟机

wrk压测机

8核

16GB

10Mbp/s

测试目的

对基于Y-Hessian的 异步化、流式转换的Yunji Dubbo API网关进行性能压测,了解它的处理能力极限是多少,这样有便于我们推断其上线后的处理能力,以及对照现有的Tomcat接入层模式的优势,能够节约多少资源,做到心里有数。

测试脚本

性能测试场景

网关入参0.5k请求json,深度为3层嵌套结构,服务端接收请求,返回0.5k返回包

网关入参2k请求json,深度为3层嵌套结构,服务端接收请求,返回0.5k返回包

上述场景均使用wrk在压测节点上进行5~10min钟的压测,压测参数基本为12线程256连接或者512连接,以发挥最大的压测性能。

测试结果

性能指标(量化)

场景名称

wrk压测参数

Avg RT

实际QPS值

0.5k数据

-t12 -c256

3.77ms

69625

0.5k数据

-t12 -c 512

7.26ms

71019

2k数据

-t12 -c256

5.48ms

46576

2k数据

-t12 -c512

10.80ms

46976

运行状况(非量化)

API网关(8c16g)运行良好,压测期间CPU占用为550%左右

两个 Dubbo Provider 服务运行良好,CPU占用为100%左右

各个角色内存运行稳定,无OOM,无不合理的大内存占用等。

3.总结

flurry集Dubbo网关、异步、流式、高性能于一身,其目标就是替代一些以tomcat作为dubbo消费者的接入层,以更少的节点获得更多的性能提升,节约硬件资源和软件资源。

4.后续

后续在flurry的基础上,将实现鉴权管理、流量控制、限流熔断、监控收集等等功能

5.参考项目

Flurry: 基于Dubbo服务的高性能、异步、流式网关

dubbo-json: 自定义的Dubbo协议,支持流式序列化模式,为flurry网关序列化/反序列化组件。

Yunji-doc-site: 与元数据集成相关的项目,以及文档站点

dapeng-soa: Dapeng-soa 是一个轻量级、高性能的微服务框架,构建在Netty以及定制的精简版Thrift之上。 同时,从Thrift IDL文件自动生成的服务元数据信息是本框架的一个重要特性,很多其它重要特性都依赖于服务元数据信息。 最后,作为一站式的微服务解决方案,Dapeng-soa还提供了一系列的脚手架工具以支持用户快速的搭建微服务系统

dapeng-json:dapeng-json协议介绍

dubbo 服务压测_Dubbo高性能网关--Flurry介绍相关推荐

  1. dubbo 服务压测_全链路压测资料汇总——业内大厂解决方案

    最近忙于公司的全链路压测平台调研和技术规划文档输出工作,参考了全网能搜到的业内大厂的全链路压测方案,这里做个汇总,以及将个人认为可以落地的方案做一个关键点整理. 技术链接 滴滴全链路压测解决之道 阿里 ...

  2. dubbo 服务压测_不可忽视的Dubbo线程池

    问题描述 线上突然出现Dubbo超时调用,时间刚好为Consumer端设置的超时时间. 有好几个不同的接口都报超时了 第1次调用超时,第2次(或第3次)重试调用非常快(正常水平) Dubbo调用超时的 ...

  3. 如何使用 PTS 快速发起微服务压测

    作者:亦炎 什么是微服务 通常而言,微服务架构是一种架构模式或者说是一种架构风格. 本文阐述了: 什么是微服务架构 微服务架构对系统稳定性带来的影响,以及用性能测试验证稳定性的必要性 用户进行微服务压 ...

  4. 服务压测发现怪异现象,一顿排查,揪出“TIME_WAIT”这个内鬼

    点击关注公众号,Java干货及时送达 最近有同事在用 ab 进行服务压测,到 QPS 瓶颈后怀疑是起压机的问题,来跟我借测试机,于是我就趁机分析了一波起压机可能成为压测瓶颈的可能,除了网络 I/O.机 ...

  5. 服务压测发现怪异现象,一顿排查,揪出“TIME_WAIT”这个内鬼~

    点击关注公众号,回复"2T"获取2TB学习资源! 互联网架构师后台回复 2T 有特别礼包 上一篇:深夜看了张一鸣的微博,让我越想越后怕 来源:https://zhenbianshu ...

  6. Beetlex之tcp/tls服务压测工具

    在编写tcp服务的时候经常需要对服务的基础性能进行一个压力测试,虽然网上这些工具有很多,但具备使用方便和高强度的测试工具则不多.为了方便这方面的高强度压测所以在beetlex的基础扩展这样一个工具. ...

  7. Web服务压测神器wrk

    wrk是一款开源的高性能http压测工具(也支持https),非常小巧,可以执行文件只有3M(其中主要是luajit和openssl占用绝大多数空间),别看核心代码3-5年没更新了,但依旧非常好用.虽 ...

  8. 常用的HTTP服务压测工具

    文章目录 一.压测介绍 1.简介 2.压测相关术语 3.压测常用工具 二.压测工具介绍 1.ab压测 1.1 介绍 1.2 ab压测使用 2.wrk压测 2.1 介绍 2.2 安装 2.3 wrk压测 ...

  9. web版本 开源压测工具_Web服务压测神器wrk

    wrk是一款开源的高性能http压测工具(也支持https),很是小巧,能够执行文件只有3M(其中主要是luajit和openssl占用绝大多数空间),别看核心代码3-5年没更新了,但依旧很是好用.虽 ...

最新文章

  1. 归纳整理--第2篇--QQ好友
  2. OleDbHelper类
  3. (转载)聊聊Git原理
  4. ASP.NET MVC编程——视图
  5. 性能调优工具类TimeStone
  6. 怎么把一个控件放到tab页面上去?_移动端页面内容切换
  7. npm 查看当前生效的配置
  8. 解决 List 执行 remove 时报异常 java.lang.UnsupportedOperationException
  9. matlab采集网口数据,使用Signal Tap II采集到的数据进行Matlab仿真(转载)
  10. xml文件怎么转换成wps_Office 12使用XML格式存储文件 正式回击WPS
  11. vue全家桶网易严选,体验网易严选购物流程
  12. c语言编程计算圆柱体的表面积,c语言求圆柱体的表面积和体积
  13. AJAX 聊天室实现原理终极解析
  14. Linux服务器搭建项目运行环境
  15. 修改服务器的返回数据,使用charles 修改服务器返回数据
  16. Java有序数组——原地去重——不使用额外空间
  17. solaris启动过程详解
  18. c#如何wmf图片转换成png图片_C#图片格式转换(支持bmp/gif/jpeg/png/tiff/wmf文件)
  19. 数据库实验报告【学会使用企业管理器和查询分析器管理工具】
  20. 诺基亚论坛PRO数位红

热门文章

  1. qt插件开发框架搭建_Flutter框架之:开发环境搭建
  2. 力改变物体形状举例_对旋转问题的思考-在离心力确定的情况下,物体的旋转情况如何通过宇宙中的相对运动情况和质量分布确定?...
  3. 左右布局图文排版设计灵感案例
  4. 可提高效率的网页设计PS插件
  5. java一维打地鼠_Java编程实现打地鼠文字游戏实例代码
  6. SU数据新旧格式转换问题
  7. DPDK无锁队列rte_ring相关代码及示例程序(rte_ring.h,rte_ring.c,main.c,makefile)
  8. reg51.h和reg52.h头文件
  9. 从select函数谈及系统调用原理
  10. Java判断字符串是否为纯数字(0-9)