本文由携程技术Butters分享,原题“干货 | 日均流量200亿,携程高性能全异步网关实践”,即时通讯网有修订和重新排版。
cover_opti.png (11.8 KB, 下载次数: 17)
下载附件 保存到相册
1 个月前 上传
1.png (20.57 KB, 下载次数: 18)
2.png (7.83 KB, 下载次数: 17)
全异步 = server端异步 + 业务流程异步 + client端异步
3.png (26.71 KB, 下载次数: 17)
public interface Processor<T> { ProcessorType getType(); int getOrder(); boolean shouldProcess(RequestContext context); //对外统一封装为Maybe Maybe<T> process(RequestContext context) throws Exception; }
public abstract class AbstractProcessor implements Processor { //同步&无响应,继承此方法 //场景:常规业务处理 protected void processSync(RequestContext context) throws Exception {} //同步&有响应,继承此方法,健康检测 //场景:健康检测、未通过校验时的静态响应 protected T processSyncAndGetReponse(RequestContext context) throws Exception { process(context); return null; }; //异步,继承此方法 //场景:认证、鉴权等涉及远程调用的模块 protected Maybe<T> processAsync(RequestContext context) throws Exception { T response = processSyncAndGetReponse(context); if (response == null) { return Maybe.empty(); } else { return Maybe.just(response); } }; @Override public Maybe<T> process(RequestContext context) throws Exception { Maybe<T> maybe = processAsync(context); if (maybe instanceof ScalarCallable) { //标识同步方法,无需额外封装 return maybe; } else { //统一加超时,默认忽略错误 return maybe.timeout(getAsyncTimeout(context), TimeUnit.MILLISECONDS, Schedulers.from(context.getEventloop()), timeoutFallback(context)); } } protected long getAsyncTimeout(RequestContext context) { return 2000; } protected Maybe<T> timeoutFallback(RequestContext context) { return Maybe.empty(); }
public class RxUtil{ //组合某阶段(如Inbound)内的多个filter(即Callable<Maybe<T>>) public static <T> Maybe<T> concat(Iterable<? extends Callable<Maybe<T>>> iterable) { Iterator<? extends Callable<Maybe<T>>> sources = iterable.iterator(); while (sources.hasNext()) { Maybe<T> maybe; try { maybe = sources.next().call(); } catch (Exception e) { return Maybe.error(e); } if (maybe != null) { if (maybe instanceof ScalarCallable) { //同步方法 T response = ((ScalarCallable<T>)maybe).call(); if (response != null) { //有response,中断 return maybe; } } else { //异步方法 if (sources.hasNext()) { //将sources传入回调,后续filter重复此逻辑 return new ConcattedMaybe(maybe, sources); } else { return maybe; } } } } return Maybe.empty(); } }
public class ProcessEngine{ //各个阶段,增加默认超时与错误处理 private void process(RequestContext context) { List<Callable<Maybe<Response>>> inboundTask = get(ProcessorType.INBOUND, context); List<Callable<Maybe<Void>>> outboundTask = get(ProcessorType.OUTBOUND, context); List<Callable<Maybe<Response>>> errorTask = get(ProcessorType.ERROR, context); List<Callable<Maybe<Void>>> logTask = get(ProcessorType.LOG, context); RxUtil.concat(inboundTask) //inbound阶段 .toSingle() //获取response .flatMapMaybe(response -> { context.setOriginResponse(response); return RxUtil.concat(outboundTask); }) //进入outbound .onErrorResumeNext(e -> { context.setThrowable(e); return RxUtil.concat(errorTask).flatMap(response -> { context.resetResponse(response); return RxUtil.concat(outboundTask); }); }) //异常则进入error,并重新进入outbound .flatMap(response -> RxUtil.concat(logTask)) //日志阶段 .timeout(asyncTimeout.get(), TimeUnit.MILLISECONDS, Schedulers.from(context.getEventloop()), Maybe.error(new ServerException(500, "Async-Timeout-Processing")) ) //全局兜底超时 .subscribe( //释放资源 unused -> { logger.error("this should not happen, " + context); context.release(); }, e -> { logger.error("this should not happen, " + context, e); context.release(); }, () -> context.release() ); } }
4.png (9.8 KB, 下载次数: 17)
5.png (11.75 KB, 下载次数: 17)
6.png (12.51 KB, 下载次数: 18)
7.png (11.68 KB, 下载次数: 16)
8.png (100.86 KB, 下载次数: 18)
9.png (121.86 KB, 下载次数: 18)
10.png (30.72 KB, 下载次数: 19)
11.png (31.5 KB, 下载次数: 18)
12.png (12.49 KB, 下载次数: 17)
13.png (25.01 KB, 下载次数: 15)
{ //匹配方式 "type": "uri", //HTTP默认采用uri前缀匹配,内部通过树结构寻址;私有协议(SOTP)通过服务唯一标识定位。 "value": "/hotel/order", "matcherType": "prefix", //标签与属性 //用于portal端权限管理、切面逻辑运行(如按核心/非核心)等 "tags": [ "owner_admin", "org_framework", "appId_123456" ], "properties": { "core": "true" }, //endpoint信息 "routes": [{ //condition用于二级路由,如按app版本划分、按query重分配等 "condition": "true", "conditionParam": {}, "zone": "PRO", //具体服务地址,权重用于灰度场景 "targets": [{ "url": "http://test.ctrip.com/hotel", "weight": 100 } ] }] }
14.png (28.86 KB, 下载次数: 17)
{ //模块名称,对应网关内部某个具体模块 "name": "addResponseHeader", //执行阶段 "stage": "PRE_RESPONSE", //执行顺序 "ruleOrder": 0, //灰度比例 "grayRatio": 100, //执行条件 "condition": "true", "conditionParam": {}, //执行参数 //大量${}形式的内置模板,用于获取运行时数据 "actionParam": { "connection": "keep-alive", "x-service-call": "${request.func.remoteCost}", "Access-Control-Expose-Headers": "x-service-call", "x-gate-root-id": "${func.catRootMessageId}" }, //异常处理方式,可以抛出或忽略 "exceptionHandle": "return" }
来源:即时通讯网 - 即时通讯开发者社区!
轻量级开源移动端即时通讯框架。
快速入门 / 性能 / 指南 / 提问
轻量级Web端即时通讯框架。
详细介绍 / 精编源码 / 手册教程
移动端实时音视频框架。
详细介绍 / 性能测试 / 安装体验
基于MobileIMSDK的移动IM系统。
详细介绍 / 产品截图 / 安装体验
一套产品级Web端IM系统。
详细介绍 / 产品截图 / 演示视频
一套纯血鸿蒙NEXT产品级IM系统。
详细介绍 / 产品截图 / 安装
精华主题数超过100个。
连续任职达2年以上的合格正式版主
为论区做出突出贡献的开发者、版主等。
Copyright © 2014-2024 即时通讯网 - 即时通讯开发者社区 / 版本 V4.4
苏州网际时代信息科技有限公司 (苏ICP备16005070号-1)
Processed in 0.155279 second(s), 44 queries , Gzip On.