下载asp网站,做网站手机版,wordpress 高亮插件,呼和浩特北京网站建设网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技术#xff0c;提供稳定流畅、低时延、高并发的视频直播、录制、存储、转码及点播等音视频的PAAS服务#xff0c;在线教育、远程医疗、娱乐秀网易视频云是网易倾力打造的一款基于云计算的分布式…网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技术提供稳定流畅、低时延、高并发的视频直播、录制、存储、转码及点播等音视频的PAAS服务在线教育、远程医疗、娱乐秀网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技术提供稳定流畅、低时延、高并发的视频直播、录制、存储、转码及点播等音视频的PAAS服务在线教育、远程医疗、娱乐秀场、在线金融等各行业及企业用户只需经过简单的开发即可打造在线音视频平台。现在网易视频云的技术专家给大家分享一则技术文HBase GC的前生今世 身世篇。在之前的HBase BlockCache系列文章中已经简单提到使用LRUBlockCache缓存机制会因为CMS GC策略导致内存碎片过多从而可能引发臭名昭著的Full GC触发可怕的’stop-the-world’暂停严重影响上层业务而Bucket Cache缓存机制因为在初始化的时候就申请了一片固定大小的内存作为缓存缓存淘汰不再由 JVM管理数据Block的缓存操作只是对这篇空间的访问和覆盖因而大大减少了内存碎片的出现降低了Full GC发生的频率。那CMSGC策略如何导致内存碎片过多内存碎片过多如何触发Full GCHBase在演进的道路上又如何不断优化CMS GC接下来这个系列《HBase GC的前生今生》将会为你一一揭开谜底这个系列一共两篇文章本篇文章’身世篇’将会带你全面了解HBase的GC机制后面一篇’演进篇’将会给你道出HBase在发展的道路上如何不断对Full GC进行优化。Java GC概述整个HBase是构建在JVM虚拟机上的因此了解HBase的内存管理机制以及不同缓存机制对GC的影响就必须对Java GC有一个全面的了解。至于深入地理解Java GC 的工作原理不在本文的讨论范围之内当然如果已经对Java GC比较熟悉也可以跳过此节。Java GC建立在这样一个假设基础上的大多数内存对象要么生存周期比较短很快就会没人引用比如处理RPC请求的buffer可能只会生存几微秒要么生存周期比较长比如Block Cache中的热点Block可能就会生存几分钟甚至更长时间。基于这样的事实JVM将整个堆内存分为两个部分新生代(young generation)和老生代(tenured generation)除此之外JVM还有一个非堆内存区Perm区主要存放class信息以及其他meta元信息内存结构如下图所示其中Young区又分为Eden区和两个Survivor 区S0和S1。一个内存对象在创建之后首先会为其在新生代申请一块内存空间如果这个对象在新生代存活了很长时间会将其迁移到老生代。 在大多数对延迟敏感的业务场景下(比如HBase)建议使用如下JVM参数-XX:UseParNewGC和XX:UseConcMarkSweepGC其中前者表示对新生代执行并行的垃圾回收机制而后者表示对老生代执行并行标记清除垃圾回收机制。可见JVM允许针对不同内存区执行不同的GC策略。新生代GC策略 – Parallel New Collector根据上文所述对象初始化之后会被放入Young区更具体的话应该是Eden区当Eden区满了之后会进行一次GC。GC算法会检查所有对象的引用情况如果某个对象还有被引用表示该对象存活。检查完成之后会将这些存活的对象移到S0区并且回收整个Eden区空间称为一次Minor GC接着新对象进来又会放入Eden区满了之后会检查S0和Eden区存活的对象将所有存活的对象移到S1区再回收整个S0和Eden区空间很容易理解S0和S1两个区总会有一个区是预留给下次存放存活对象用的。整个过程可以使用如下图示这种算法称为复制算法对于这种算法有两点需要关注1. 算法会执行’stop-the-world’暂停但时间非常短。因为Young区通常会设置的比较小(一般不建议不超过512M)而且JVM会启动大量线程并发执行一次Minor GC一般都会在几毫秒内完成2. 不会产生碎片每次GC之后都会将存活的对象放入连续的空间(S0或S1)内存中所有对象都会维护一个计数器每次Minor GC移动一个对象之后都会为这个对象的计数器加一。当计数器增加到一定阈值之后算法就会认为该对象生命周期很长会将其移入老生代。该阈值可以通过JVM参数XX:MaxTenuringThreshold指定。老生代GC策略 – Concurrent Mark-Sweep每次执行Minor GC之后都会有部分生命周期较长的对象被移入老生代一段时间之后老生代空间也会被占满。此时就需要针对老生代空间执行GC操作此处我们介绍Concurrent Mark-Sweep(CMS)算法。CMS算法整个流程分为6个阶段其中部分阶段会执行 ‘stop-the-world’ 暂停部分阶段会和应用线程一起并发执行1. initial-mark这个阶段虚拟机会暂停所有正在执行的任务。这一过程虚拟机会标记所有 ‘根对象’所谓‘根对象’一般是指一个运行线程直接引用到的对象。虽然会暂停整个JVM但因为’根对象’相对较少这个过程通常很快。2. concurrent mark垃圾回收器会从‘根节点’开始将所有引用到的对象都打上标记。这个阶段应用程序的线程和标记线程并发执行因此用户并不会感到停顿。3. concurrent precleaning并发预清理阶段仍然是并发的。在这个阶段虚拟机查找在执行mark阶段新进入老年代的对象(可能会有一些对象从新生代晋升到老年代 或者有一些对象被分配到老年代)。4. remark在阶段3的基础上对查找到的对象进行重新标记这一阶段会暂停整个JVM但是因为阶段3已经欲检查出了所有新进入的对象因此这个过程也会很快。5. concurrent sweep上述3阶段完成了引用对象的标记此阶段会将所有没有标记的对象作为垃圾回收掉。这个阶段应用程序的线程和标记线程并发执行。6. concurrent reset重置CMS收集器的数据结构等待下一次垃圾回收。相应的对于CMS算法也需要关注两点1. ‘stoptheworld’暂停时间也很短暂耗时较长的标记和清理都是并发执行的。2. CMS算法在标记清理之后并没有重新压缩分配存活对象因此整个老生代会产生很多的内存碎片。CMS Failure Mode上文提到在正常的情况下CMS整个流程的暂停时间都是很短的一般也就在10ms100ms左右。然而这与线上的情况并不相符线上集群在读写压力很大的情况下经常会出现长时间的卡顿有些卡顿甚至长达几分钟导致很严重的读写阻塞甚至会造成Region Server和Zookeeper之间Session超时使得Region Server异常离线。实际上CMS并不是很完美它会在两种场景下产生严重的Full GC接下来分别进行介绍。Concurrent Failure这种场景其实比较简单假如现在系统正在执行CMS回收老生代空间在回收的过程中新生代来了一批对象进来不巧的是老生代已经没有空间再容纳这些对象了。这种场景下CMS回收器会停止继续工作系统进入 ’stop-the-world’ 模式并且回收算法会退化为单线程复制算法重新分配整个堆内存的存活对象到S0中释放所有其他空间。很显然整个过程会非常’漫长’。但是这种问题也很容易解决只需要让CMS回收器更早一点回收就可以避免。JVM提供了参数-XX:CMSInitiatingOccupancyFractionN来设置CMS回收的时机其中N表示当前老生代已使用内存占新生代总内存的比例该值默认为68可以将该值修改的更小使得回收更早进行。Promotion Failure假设此时设置XX:CMSInitiatingOccupancyFraction60但是在已使用内存还没有达到总内存60%的时候已经没有空间容纳从新生代迁移的对象了。ohmy god怎么会这样罪魁祸首就是内存碎片上文中提到CMS算法会产生大量碎片当碎片容量积累到一定大小之后就会造成上面的场景。这种场景下CMS回收器一样会停止工作进入漫长的 ’stop-the-world’ 模式。JVM也提供了参数 -XX: UseCMSCompactAtFullCollection来减少碎片的产生这个参数表示会在每次CMS回收垃圾之后执行一次碎片整理很显然这个参数会对性能有比较大的影响对HBase这种对延迟敏感的业务来说并不是一个完美解决方案。HBase内存碎片统计实验在实际线上环境中很少出现Concurrent Failure模式的Full GC大多数Full GC场景都是Promotion Failure。我们线上集群也会每隔半个月左右就会因为Promotion Failure触发一次Full GC。为了更好地理解CMS策略下内存碎片是如何触发Promotion Failure接下来我们做一个简单的实验JVM提供了参数 -XX:PrintFLSStatistics1来打印每次GC前后内存碎片的统计信息统计信息主要包括3个维度FreeSpace、Max Chunk Size和Num Chunks其中Free Space表示老生代当前空闲的总内存容量Max Chunk Size表示老生代中最大的内存碎片所占的内存容量大小Num Chunks表示老生代中总的内存碎片数。我们在测试环境集群(共4台Region Server)将这个参数设置为1然后使用一个客户端YCSB执行Read-And-Write操作分别统计日志中Free Space和Max Chunk Size两个指标随时间的变化情况。测试结果如下图所示其中第一张图表示Total Free Space随时间的变化曲线图第二张图表示Max Chunk Size随时间变化曲线图。其中横坐标表示时间纵坐标表示相应内存大小。根据第一张曲线图可知老生代总的空闲内存容量维持在300M~400M之间当内存容量到达300M左右时就会进行一次GCGC后内存容量就会又回到400M左右。而第二张曲线图会更加形象地说明内存碎片导致的Promotion Failure刚开始随着数据不断写入Max Chunk Size会不断变小之后很长一段时间基本维持在30M左右。在横坐标为1093那点人为地将写入的单条数据大小由500Byte变为5M大小此后Max Chunk Size会再次减小当减小到一定程度之后曲线会忽然升高到350M左右经过日志确认此时JVM发生了PromotionFailure模式的Full GC持续时间约4.91s。此后一段时间Full GC还在持续发生。经过上述分析可以知道CMS GC会不断产生内存碎片当碎片小到一定程度之后就会基本维持不变如果此时业务写入一些单条数据量很大的KeyValue就有可能触发Promotion Failure模式Full GC。总结本文首先介绍了两种常见的Java GC策略再接着介绍了CMS策略可能引起两种模式的Full GC最后通过一个小实验说明了CMS GC确实产生了内存碎片而且会导致长时间的Full GC发生。接下来《演进篇》会详细介绍从一开始HBase是如何针对CMS进行优化处理的敬请期待Categories:更多技术交流请关注我们进行交流与咨询哦本条技术文章来源于互联网如果无意侵犯您的权益请点击此处反馈版权投诉本文系统来源php中文网