(业务层)异步并行加载技术分析和设计
背景
?? 前段时间在做应用的性能优化时,分析了下整体请求,profile看到90%的时间更多的是一些外部服务的I/O等待,cpu利用率其实不高,在10%以下。 单次请求的响应时间在50ms左右,所以tps也不会太高,测试环境压力测试过程,受限于环境因素撑死只能到200tps,20并发下。
?
I/O目前一般的I/O的访问速度: L1 > L2 > memory -> disk or network常见的IO:?
- nas上文件 (共享文件存储)output/xxx (磁盘文件)memcache client / ?cat client ?(cache服务)database (oracle , mysql) ?(数据库)dubbo client ?(外部服务)search client (搜索引擎)
思路
?
正因为考虑到I/O阻塞,长的外部环境单个请求处理基本都是在几十ms,刚开始的第一个思路是页面做ajax处理。?
?
使用ajax的几个缺陷:
?
- 功能代码需进行重构,按照页面需求进行分块处理。 一次ajax请求返回一块的页面数据数据重复请求。因为代码是分块,两次ajax中获取的member对象等,可能就没法共用,会造成重复请求。ajax加载对seo不优化,公司还是比较注重seo,因为这会给客户带来流量价值,而且是免费的流量。ajax技术本身存在一些磕磕碰碰的点: 跨域问题,返回数据问题,超时处理等。
ajax处理需要有嵌入性,每个开发都需要按照ajax特有的规范或者机制进行编码,有一定的约束
顺着ajax的思路,是否有一种方式可以很好的解决I/O阻塞,并且又尽量的透明化,也不存在ajax如上的一些问题。?
?
所以就有了本文的异步并行加载机制的研究。原理其实和ajax的有点类似:?
?
?
一般ajax的请求:?
?
request就代表html页面的一次渲染过程首先给页面的一块区域渲染一块空的div id=A内容和一块div id=B的内容浏览器继续渲染页面的其他内容在页面底部执行具体的js时,发起div id=A的请求,等A返回后填充对应的div内容,发起div id=B的请求,返回后同样填充。说明:不同浏览器有不同的机制,默认执行js都是串行处理。
?
看一下异步并行机制的设计时序图:?
说明: 结合ajax的思路,异步并行加载机制在原理设计上有点不同,就是针对ajax的请求发起都是并行的。?
引入的问题:
?? 但同样,引入并行加载的设计后,需要考虑的一个点就是如果A和B的数据之间是有一定的依赖关系时怎么处理。?
?? 例子
很明显,一次request请求总的响应时间就等于最长的依赖关系请求链的相应时间。?
?
(业务层)异步并行机制的优点:
继承了ajax异步加载的优点增加了并行加载的特性
相比于ajax的其他优势:
同时不会对页面seo有任何的影响,页面输出时都是一次性输出html页面减少了ajax异步发起的http请求两块代码的资源不会存在重复请求,允许进行资源共享
从目前来看,异步并行机制还是有比较大的应用场景。具体是否能做到对一线开发者透明,以及对应业务的开发成本,那就得看一下具体的代码实现实现根据以上分析,分析核心模型:
?说明:原本服务service。 这个不用多解释,就是原本存在的一些需要被代理的对象,比如DAO,rpc调用客户端等。代理参数设置。 比如设置一些超时时间等并行执行容器。 一个多线程处理的容器,执行并行加载代理服务。 ?对服务service的一个包装过后的代理对象代理服务Model 。 ?代理对象根据客户端的一些请求返回对应的代理Model,用于代理控制。
具体的类图设计:
?说明:?AsyncLoadProxy就是模型中对应的代理服务AsyncLoadConfig就是模型中对应的代理参数设置AsyncLoadExecutor就是模型中对应的并行执行容器。
一些技术描述:AsyncLoadEnhanceProxy是目前代理服务的一种技术实现,基于cglib的动态代理。后续可以研究下javassist技术,据说性能上比cglib要高。AsyncLoadMethodMatch是针对参数设置的一个细化,类似于spring的aop的切面点(PointCut)的概念,在具体的切面上执行异步并行加载机制。AsyncLoadExecutor目前是采用了jdk1.5中cocurrent包的pool池技术。支持两个队列设置:running队列,就绪队列。 针对就绪队列满了后,提供REJECT(拒绝后续请求)/BLOCK(阻塞等待队列有空位置)两种处理模式。
一个使用例子:?
思考: 后续可考虑,基于通配符拦截对应的目标service。
扩展二:?AsyncLoadTemplate基于模板模式,提供异步并行机制。可以编程方式指定进行异步并行加载的执行单元。 比如针对好几个service的调用合并为一次并行加载。
事例代码:
?
这个你可以看看主文中的代码例子。
因底层技术是采用字节码增强方式,包括service和model都会织入一定的代码,具体开发者是感觉不到的。就和正常的写代码是一样的方式,至于依赖关系的串行处理,也是植入代码内部的。
原先设计的理念就是尽量做到无嵌入,对开发透明。
理想的情况就是普通开发人员完成业务编码开发后,由项目的技术经理或者架构师,配置一份xml,决定哪些service的哪几个方法要进行异步并行加载。
这个你可以看看主文中的代码例子。
因底层技术是采用字节码增强方式,包括service和model都会织入一定的代码,具体开发者是感觉不到的。就和正常的写代码是一样的方式,至于依赖关系的串行处理,也是植入代码内部的。
原先设计的理念就是尽量做到无嵌入,对开发透明。
理想的情况就是普通开发人员完成业务编码开发后,由项目的技术经理或者架构师,配置一份xml,决定哪些service的哪几个方法要进行异步并行加载。
这也是一种方法,何必不让开发者自己在applicationContext.xml中配置,决定哪些service以及方法需要异步并行加载呢?
这个你可以看看主文中的代码例子。
因底层技术是采用字节码增强方式,包括service和model都会织入一定的代码,具体开发者是感觉不到的。就和正常的写代码是一样的方式,至于依赖关系的串行处理,也是植入代码内部的。
原先设计的理念就是尽量做到无嵌入,对开发透明。
理想的情况就是普通开发人员完成业务编码开发后,由项目的技术经理或者架构师,配置一份xml,决定哪些service的哪几个方法要进行异步并行加载。
这也是一种方法,何必不让开发者自己在applicationContext.xml中配置,决定哪些service以及方法需要异步并行加载呢?
支持的阿,你看下首页中关于 扩展一:AsyncLoadFactoryBean 描述这一块。
基于spring FactoryBean接口,配置方式就是纯spring ioc那一套,对哪个service的哪些方法进行异步加载。