1 / 21

淘宝 GCIH : 直接共享 Java 对象,提升 GC 性能

淘宝 GCIH : 直接共享 Java 对象,提升 GC 性能. // 阿里程序员 *2 // 莫简豪(坤谷) // 孙宇(洪熙) // jvm.taobao.org // GreenTeaJUG. 目标. 不做产品推广 不讲项目故事 分享技术实践 开阔技术思路 欢迎讨论指正. 议程. 术语 问题 分析 方案比较: JNI 、 MappedByteBuffer 方案选择: GCIH 解决 基础:对象模型 、 CMS GC 算法 如何移入 :遍历对象图 阻止 GC 扫描 如何共享:对象共享 、元信息处理

trung
Download Presentation

淘宝 GCIH : 直接共享 Java 对象,提升 GC 性能

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 淘宝GCIH:直接共享 Java 对象,提升 GC 性能 // 阿里程序员*2 //莫简豪(坤谷) // 孙宇(洪熙) // jvm.taobao.org // GreenTeaJUG

  2. 目标 • 不做产品推广 • 不讲项目故事 • 分享技术实践 • 开阔技术思路 • 欢迎讨论指正

  3. 议程 • 术语 • 问题 • 分析 • 方案比较:JNI、 MappedByteBuffer • 方案选择:GCIH • 解决 • 基础:对象模型 、CMS GC算法 • 如何移入 :遍历对象图 • 阻止GC扫描 • 如何共享:对象共享 、元信息处理 • 实际问题:分布式单点、部署 、异常处理 • 结果 • POC:SideDataDemo • 实际结果

  4. 术语 • JVM:Java虚拟机,从操作系统看,是一个用户进程 • Java Heap:存放Java对象的堆 • GC:垃圾回收,回收Java Heap中没用的Java对象 • Full GC:GC的一种,全停机,时间长,对性能影响大,应尽量避免 • Hadoop:Java实现的分布式计算系统,高容错,高可扩展 • master节点:控制节点,少数相对高配的机器 • slave节点:计算和存储节点,大量相对低配机器 • map/reduce:在slave节点上运行的基本计算单元,每个map/reduce是一个JVM进程 • slot数:可以并发的map/reduce数 • 作业:一个完整的计算任务,分解成多组map/reduce,分布到slave上并发执行

  5. 问题 • 淘宝搜索某系统(基于Hadoop)slave内存瓶颈 • 集群大,增加物理内存贵 • 若调大slot数,则需要调小Java Heap,结果FullGC严重,作业执行慢 • 若为避免FullGC,调大JavaHeap,则需调小slot数,结果还是作业执行慢 • 一些只读对象在每个JVM中都有一份。内存冗余严重 • 如果JVM间共享这些对象,可以节约内存并提升GC性能

  6. 分析(一)方案比较 • JNI:读取频繁,调用JNI效率低  • MappedByteBuffer:实现依赖JNI,同上 • 将需要共享的Java对象移出Java堆,放在GC看不到的共享堆(GCInvisible Heap) • 不经过JNI调用 • 没有序列化和反序列化 • GC性能提高 • 数据更集中,cache命中率提高

  7. 分析(二)方案选择:GCIH(1) • 对象的直接移动 • 程序中直接访问GCIH内的Java对象,完全没差异 • 阻止GC收集GCIH中的对象,减少GC收集的负载

  8. 分析(二)方案选择:GCIH(2) Sharable Objs • Java对象可在JVM进程间直接共享 共享前 共享后

  9. 解决(一)基础:Java对象模型(1) • header主要用于表示对象的当前的状态,也用于存储一些gc及存储对象的age,hash值等数据。 • klass是Java对象的元数据指针,指向perm区的klass对象。

  10. 解决(一)基础:Java对象模型(2)

  11. 解决(一)基础:CMS 算法简介 • init-mark:标记old和perm区的root对象,stop the world • concurrent-mark:并发递归标记init-mark的标记结果 • remark:并发重新标记concurrent-mark阶段后某些对象状态的更新而遗漏标记的对象,stop the world • sweep:实际回收内存的操作 • reset

  12. 解决(二)如何移入:遍历对象图(1)

  13. 解决(二)如何移入:遍历对象图(2) • 接口 object moveIn(object obj) • 从根对象开始,根据对象的引用关系,递归moveIn • 如果某个对象被moveIn则将其在GCIH的地址encode到该对象的header上,并设置header的最低2位(二进制位)为01 • 如果发现要移入的的header的最低2位为01,则从其header中decode出其在GCIH内部的地址,并直接修改相关的引用为正确的地址

  14. 解决(三)阻止GC扫描 • GC过程:从root对象出发,标记活的对象,同时将这个对象push到queue,以便于该gc线程后续处理其引用到的其他对象 • GCIH修改了GC过程:当某个对象的地址在gcih地址空间内的时候,直接返回,而且不将此对象push到gc线程的queue • 要求对象从jvm角度来看必须只读

  15. 解决(四)如何共享 • 对象共享 • mmap共享内存 • 不同JVM的GCIH映射到相同基地址 • 元信息klass的处理(难点) • klass指针用于FastSubTypeCheck,不可以用二级索引 • 保证klass基地址一致,并preload共享klass • 阻止gc unload 共享对象的klass

  16. 解决(四)实际问题 • 分布式单点 • 创建并初始化共享GCIH只能由一个JVM完成(单点),与分布式系统思想不一致 • 通过文件锁,多JVM并发抢锁,抢到锁的做初试化移入后释放锁,其他JVM直接映射GCIH • 部署 • GCIH修改JVM,部署阻力大 • 同时部署原版和GCIH版JVM • Hadoop框架使用原版JVM,需共享的作业通过参数设置其map/reduce使用GCIH版JVM • 异常处理 • 启动异常快速exit并打印原因 • 运行异常抛Java异常 • 由于双JVM部署,用户可选择异常时自动回滚到原版JVM(到目前没回滚过) • 只读保护异常,若用户不小心修改共享对象,测试中可快速发现,避免产生难以发现的bug

  17. 结果(一)POC:SideDataDemo(1) • reduce需要一个只读的SideData对象 • 共享前,由于内存成为瓶颈,只能开3个reduce,再开就OOM • GCIH共享后可以解决这瓶颈,提高了并发度

  18. 结果(一)POC:SideDataDemo(2) • 机器空闲内存约1.4G,只读对象SideData大约400M • 开3个reduce task内存还够用,Job complete • $ bin/hadoop jar ../GCIHDemo2.jar com.taobao.demo.SideDataDemo input output 3 • …11/05/09 14:56:50 INFO mapred.JobClient: map 100% reduce 100% • 11/05/09 14:57:10 INFO mapred.JobClient: Job complete: … • 开4个reduce task则内存不足,FAILED • $ bin/hadoop jar ../GCIHDemo2.jar com.taobao.demo.SideDataDemo input output 4 • …11/05/09 15:03:03 INFO mapred.JobClient: Task Id : attempt_201105091440_0002_r_000001_1, Status : FAILED • java.io.IOException: Cannot run program "bash": java.io.IOException: error=12, Cannot allocate memory …

  19. 结果(一)POC:SideDataDemo(3) • 将对象SideData移入GCIH • 设置child JVM与GCIH相关的启动参数 • 开4个reduce task可以正常执行,top命令观察到4个同时运行的task • PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND • 8650 kungu.mj 20 0 1338m 429m 393m S 33.3 24.6 0:17.25 java • 8682 kungu.mj 19 0 1400m 427m 393m S 33.3 24.4 0:15.82 java • 8618 kungu.mj 23 0 1339m 427m 393m S 32.9 24.4 0:15.79 java • 8714 kungu.mj 18 0 1336m 427m 393m S 32.6 24.4 0:15.29 java • 验证的计算结果也正确

  20. 结果(二)实际结果 • 淘宝搜索某系统(基于Hadoop)使用GCIH解决了内存瓶颈 • 在单机多reduce共享只读对象,每台机器共享约2GB的只读对象(Map、List、Set、String、Integer等) • 单机slot越多,节约内存越多 • 性能也越高,因为这2GB的对象只需创建和初始化一次 • 已经在生产上稳定运行多时,并通过了淘宝双十一、双十二的考验

  21. Q&A 谢谢!

More Related