架构师第一期作业(第 9 周)
请简述 JVM 垃圾回收原理。
JVM 垃圾回收即将 JVM 堆中不再使用的堆对象清理掉,以释放内存资源。
1、垃圾回收的第一步是对垃圾对象进行识别,JVM 是通过可达性分析算法来识别垃圾对象的。算法如下:
从线程栈帧中的局部变量或方法区的静态变量出发,将这些变量引用的对象进行标记,然后沿着这些对象看这些对象中是否又引用到来其他对象,继续进行标记,这样循环递归地进行,直到所有有被引用的对象都标记完成,这样剩下没被标记的对象就是可回收的垃圾对象了。
2、标记完成后,JVM 会对垃圾对象占用的内存进行回收。主要有三种方法:清理、压缩和复制。
清理:将垃圾对象占用的内存空间标记为空闲,记录到空闲列表中,当程序需要创建新对象时,从空闲内存中分配
压缩:从堆空间头部开始,将存活对象拷贝放到一段连续的内存空间中,这样剩下的空间也是连续的
复制:将堆空间分为两部分,只在其中一部分创建对象,当这部分空间用完时,将存活对象复制到另一个空间中,当前这部分空间又变成可用的连续空间了。
这几个方法中,清理是最简单的,但容易造成内存空间碎片化,实际使用中往往需要进行压缩或复制。
3、JVM 采用分代垃圾回收机制,将堆内存空间分为两块:新生代和老年代。采用不同的垃圾回收策略。
具体说来,新生代又分为三个区:Eden 区、From 区、To 区,操作如下:
对象新建时都在 Eden 区创建,Eden 区满的时候会触发垃圾回收(YoungGC),采用复制算法将存活对象复制到 From 区,这样 Eden 区又变为可用区。
一段时间后,当 From 区满时,垃圾回收操作会将 Eden 区和 From 区的存活对象都复制到 To 区,From 区清空。后面再垃圾回收时,将 Edon 区存活对象复制到 To 区。
再过一段时间,To 区满了,垃圾回收又将 Eden 区和 To 区存活对象复制 From 区,To 区清空,如此反复操作。
当 From 区/To 区中存活的对象复制次数超过一定的值时,就不再在 From 区和 To 区来回复制了,而是会被转移复制到老年代。
再过段时间,老年代也满了,这时会触发全量垃圾回收(FullGC),新生代和老年代一起进行垃圾回收。
设计一个秒杀系统,主要的挑战和问题有哪些?核心的架构方案或者思路有哪些?
秒杀场景最主要挑战在于瞬时访问量的暴增,短时间内访问流量可能是平常的 100 倍以上,没有良好设计,服务很容易被击穿,造成无法访问。另一个就是要能够阻止用户跳过秒杀开始页面直接进入下单页面,造成不公平竞争。
首先秒杀系统和常规业务系统的处理是很不一样的,需要不同的设计,通常需要独立部署服务器集群,和平常的业务系统做隔离,不影响现有业务系统。
秒杀系统实现上,大致有如下几个思路方法:
1、简化系统
秒杀系统通常只需要秒杀商品列表、商品介绍和下单这三个页面。客户下单成功后进入支付系统,可以使用原有业务系统来处理,因为最终能够下单成功的客户是极少数的,原有的系统可以处理的过来。
2、页面静态化
将动态页面转换为静态页面,一方面可以极大地减少数据库访问压力,另一方面静态页面可以使用 CDN 缓存和反向代理缓存,可以进一步减少服务器压力。
3、CDN 缓存
对图片、CSS、JS、网页等静态资源文件使用 CDN 缓存,将数据压力分散到 CDN 节点上,可以极大减轻服务器压力。
4、限流
设计阀门,限制可进入下一阶段的请求数,请求顺序超过阀值的部分直接进入秒杀结束页面。具体可以做三道阀门,第一道是点击秒杀按钮时,第二道是点击购买时,第三道是提交订单时,根据实际可秒杀商品数,逐步收窄阀门值,最终只有实际可秒杀商品数的用户可以下单成功,成功秒杀。
5、控制下单使能
可通过 JS 文件动态件加载实现(将该 JS 文件关闭浏览器缓存,静态页面加载时带随机版本号)
秒杀未开始时,文件内容是空的。秒杀开始时才将下单地址或关键信息写到文件中,点亮秒杀按钮,这样同时也能防止用户跳过秒杀开始页面直接进入下单页面。
版权声明: 本文为 InfoQ 作者【Cheer】的原创文章。
原文链接:【http://xie.infoq.cn/article/57a007efcd074e6ec2cb72878】。未经作者许可,禁止转载。
评论