Velovity优化实践

Velocity将模板根据语法分析器解析成AST树,然后遍历这棵树来渲染整个页面。但是对于一些复杂的页面时,执行效率比较低,通过继承Velocity的语法标准,重新制定它的渲染机制,这样既能不改变模板的开发方式,又能提高模板的执行效率,这个模板引擎被命名为sketch。

现实存在的问题

淘宝使用的就是Velocity,当网站的规模比较大,只有一台提升10%,那整个系统会提升明显,但是使用Velocity存在一些问题:

  1. 整个页面输出比较大,平均在80KB左右,大部分时间都在out.print
  2. CPU压力较大时,压力测试在80%左右时,用检测工具发现模板渲染占用了60%以上的CPU时间
  3. 模板中含有大量变量的方法调用,根本就不要动态的解析
  4. 模板渲染时产生很多临时对象,对JVM的GC影响很大,导致系统频繁的GC
  5. 在页面模板中空字符比较多,浪费网络传输量
    这是导致Velocity在渲染模板时效率上不去的原因

优化的理论基础

程序语言的三角形结构

Velovity优化实践
程序的语言层次结构和这个语言的执行效率形成一对倒立的三角形结构,越是上层的高级语言,它的执行效率往往越低。

数据结构减少抽象化

程序=数据结构+算法,算法是过程,而数据结构是载体。数据结构去抽象化是指把需要调用底层的接口的程序改由我们自己去实现,减少这个程序的封装程度,从而达到提升性能的目的。

简单的程序复杂化

写一个简单的JDBC会比实现ibatisi作为数据层调用数据库查询数据执行效率高。

减少翻译的代价

程序设计存在翻译问题,就是编解码问题,为了减少错误减少这种翻译,去提升效率

变的转化为不变的

将一些变化的内容转化不变的内容,动态网页中的有很多静态的部分。

高效的模板引擎实现思路

Sketch的整体设计分为;两部分:运行时环境和编译时环境。运行时环境主要用来将模板渲染成HTML,编译时环境主要把模板编译成Java类。
Velovity优化实践

vm模板如何被编译

优化Velocity模板的一个目的就是将模板的解释执行变为编译执行,在vm中的语法最终被解释成一棵语法树,然后通过执行这颗语法树来渲染结果。
沿用Velocity中将一个vm模板解释成一颗AST语法树,但是重修修改这棵树的渲染规则,将重新定义每个语法节点生成对应的Java语法,而不是渲染结果。
Velovity优化实践

方法调用的无反射优化

Velocity的处理方式是找到$exampleDO变量对应的Java对象,然后查找在这个对象中是否存在getItemList()方法,如存在调用method的invoke方法,通过反射执行得到这个方法的执行结果。利用反射调用很耗时。

将字符输出改成字节输出

静态字符串直接是out.write(_S0),-S0是一个字节数组,而在vm模板中是字符串,将字符串转成字节数组是在这个模板类初始化完成的。字符的编码是非常耗时的,如将静态字符串提前编码好,最终写在Socket流时就会省去编码时间,从而提高执行效率。从实际的测试来看,这对提升性能很有帮助。

优化的成果

将char转成byte

将char转成byte输出的性能发现,比字节流输出提升100%,字符编码是多么耗时的。

无反射执行

整个系统的性能提升接近50%左右

其他优化手段

  1. 去掉页面输出中多余的非中文空格。
  2. 压缩TAB和换行。
  3. 合并相同的数据,避免相同的数据在循环输出
  4. 异步渲染,将一些静态内容抽取出来改成异步渲染。