.vip域名的网站排名,那里可以做旅游网站的吗,网站建设耂首先金手指,网站拓展关键词怎么做1 重构背景
原有的开发人员早已离职#xff0c;代码细节没人知道#xff0c;经过了一段时间的维护#xff0c;发现有以下问题#xff1a; 个人中心系统的特征就是组装各个业务的接口#xff0c;输出个人中心业务需要的数据#xff0c;整个系统调用了几十个第三方业务线的…1 重构背景
原有的开发人员早已离职代码细节没人知道经过了一段时间的维护发现有以下问题 个人中心系统的特征就是组装各个业务的接口输出个人中心业务需要的数据整个系统调用了几十个第三方业务线的接口如果编排不合理可能会导致响应时间急剧上涨尤其是弹窗业务新的弹窗会不断接入整个接口可能会不可用。
2 整体架构 service是最小的业务编排单元request方法对infrastructure第三方接口进行编排调用apply 方法对第三方接口调用的结果进行组装结果是service的业务返回
infrastructure是对第三方的异步非阻塞调用不包含业务逻辑。一个service内部根据实际业务可以编排0个或者多个infrastructure服务。
在实际优化过程中我们抽象了30多个infrastructure第三方调用40多个service。他们都是小而且独立的类减轻了开发同学尤其是新同学熟悉的成本。边界也比较清晰逻辑内聚。
2 编排举例
每个 service 内部都是由一个或者多个 infrastructure 第三方调用组装编排的业务单元内部处理能异步处理的全是使用异步处理实在不能异步处理的使用串行并行的方式。
2.1 串行
需要串行的可以使用 flatMap 方法可以参考以下格式。
这种方式会执行S1然后S2。 伪代码如下
Mono.from(service1.func()).flatMap(service1Res- {return service2.func();})2.2 并行
zip 和 zipWithzipWith一次组装一个Monozip 一次可以组装多个Mono。 示例代码如下
service1.zipWith(service2)Mono.zip(service1, service2, service3)一个使用 zip 组装多个service的示例代码并行执行service1, service2, …, service6使用doOnError处理错误onErrorReturn 处理异常返回doOnFinally 监控整个接口调用量、耗时情况。
Mono.zip(service1, service2, service3, service4, service5, service6).map(t - {String service1Ret t.getT1();String service2Ret t.getT2();// ....return 组合结果;})// 异常返回.onErrorReturn(new DTO()).doOnError(e - {// 异常详情日志异常请求量监控}).doFinally(e - {// 请求量、耗时监控});2.3 并行-但只取第一个有数据的结果
弹窗类业务与一般service不通它需要调用很多的业务的数据出不同的弹窗但是每次都只能给用户展示确定的一个。但是如果串行的话随着上线的弹窗越来越多整个弹窗接口的耗时会越来越长。
但是如果改成异步的话又无法控制弹窗之间的优先级优先级对于公司整体业务来说是必要的把重要的业务放在高优的位置上做到资源最大利用才能实现利润的最大化从而做到基业长青。
Flux 有个flatMapSequential方法它能完美解决这个问题看看它的注释 Transform the elements emitted by this Flux asynchronously into Publishers, then flatten these inner publishers into a single Flux, but merge them in the order of their source element. 将此Flux发出的元素异步地转换为 publisher然后将这些内部 publisher 扁平化为单个Flux但按照源元素的顺序合并它们。 如上图所示总共有S1、S2、S3、S4按顺序的四个弹窗会并行执行S1到S4如果S1和S2没有数据S3有数据则会返回S3。
伪代码如下
FluxMapString, Object monoFlux Flux.fromIterable(serviceList).flatMapSequential(serviceName - {}).onErrorContinue((err, i) - {// 某个service异常或者无数据继续执行});}).onErrorContinue((err, i) - {// 服务异常继续执行});
MonoMapString, Object mono monoFlux.elementAt(0, Maps.newHashMap()); 这里就是异步执行所有弹窗service运行过程中某个弹窗异常或者无数据返回则继续下一个。通过monoFlux.elementAt(0, Maps.newHashMap())获取第一个有数据的弹窗。
4 重构效果
4.1 后端指标
相比于原来的后端系统所有接口耗时都有大幅度降低
头部身份信息接口响应速度提升26%。卡片各业务线入口接口响应速度提升87%。弹窗和浮标接口响应速度提升146%。
经过 flatMapSequential 编排弹窗之后耗时从220ms降到160ms绝对值下降了60ms下降了 28% 4.2 新需求开发和维护
新需求开发更快QA 测试更快。
原来开发一个弹窗需要考虑的事情很多
开发的时候需要考虑代码放在哪个层级上是否与其他弹窗有耦合弹窗优先级需要通过if-else实现很容易出错弹窗自测很麻烦需要注释调其他弹窗QA 需要测试所有弹窗的优先级是否有问题
现在开发一个弹窗只需要增加一个service类然后把service配置再优先级列表中即可。
4.3 其他
框架使用了响应式框架 Spring WebFlux也支持本地启动编写了service层和基础设施层的单测case提升开发效率。
删除了原来的业务网关层使用公司层面的网关系统配置即生效删除了原来业务网关中的业务逻辑代码把相关逻辑移动到业务层中解除了原来的多层之间的耦合关系。
现在各个service之前相互独立异常不会相互影响。