写点什么

架构师训练营:第九周作业

用户头像
zcj
关注
发布于: 2020 年 08 月 02 日

请简述 JVM 垃圾回收原理。

VM的垃圾回收就是讲JVM堆中的已经不再被使用的对象清理掉,释放宝贵的内存资源。

JVM 通过一种可达性分析算法进行垃圾对象的识别,具体过程是:从线程栈桢中的局部变量,或者方法区的静态变量出发,将这些变量引用的对象进行标记,然后看这些被标记的对象是否引用了其他对象,继续进行标记,所有被标记的对象都是被使用的对象,而那些没有被标记的对象就是可回收的对象。



垃圾对象标记的方法:

  1. 引用计数法: 基本想法就是 一个对象,如果有地方在引用它,那么它就不是垃圾,因此呢,我给这个对象创建一个引用计数器,对象 被引用一次,计数器就+1,引用失效,计数器-1,垃圾回收的时候一看这个对象计数器值为0,说明这个对象没被引用了,就被当作垃圾回收了。这个算法非常高效,但是存在的问题就是两个对象互相引用,这样这两个对象就永远无法被回收。

  2. 根搜索法: 这个方法的基本思路是,从一些根节点,称为“GC Roots”,为起始点往下搜索,形成一条引用链,在引用链之外的对象被视作垃圾。java语言中的“GC Roots”有如下几种:帧栈中本地变量表中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI引用的对象。

垃圾回收使用的算法

  1. 标记清除算法:在这种回收机制中,分为两个过程,一是标记,再就是清除,标记阶段就是用根搜索法来判断对象是否需要回收,清除就是回收内存空间。这个算法是垃圾回收中最基本的算法,许多高级的垃圾回收算法都是根据它为基础。这个算法的缺点是效率低,回收后的内存空间过于碎片化。

  2. 复制算法:针对标记清除算法的效率问题,复制算法给出的解决方法是,将内存空间一分为二,每次只用其中一块空间,当进行垃圾回收时,把活着的对象复制到另一块空间中,清除时将原空间全部清除,这样效率既高也解决了内存碎片,缺点就是太废内存了。

  3. 标记整理算法:过程和标记清除算法类似,区别就是它不直接把垃圾空间清除掉,而是将活着的对象都移动到一起,剩下的空间就是垃圾空间了,这时候直接清除掉就行。

  4. 分代回收算法:分代回收法就是根据对象的生存周期,分为老年代和新生代两个内存空间,对于新生代这种对象生成和死亡都比较快的区域使用复制算法进行回收,对于老年代则使用标记清除或标记整理算法。

垃圾回收器分类及回收过程:

串行回收器:一个垃圾回收线程,stw(stop-the-world)停止所有的用户线程回收。

并行回收器:多个垃圾回收线程,stw停止所有线程回收垃圾。

并发回收期CMS:分为以下4个阶段:

  • 初始标记:标记一下GC Roots能直接关联到的对象,会“Stop The World”。

  • 并发标记:GC Roots Tracing,可以和用户线程并发执行。

  • 重新标记:标记期间产生的对象存活的再次判断,修正对这些对象的标记,执行时间相对并发标记短,会“Stop The World”。

  • 并发清除:清除对象,可以和用户线程并发执行。

G1回收器:其他收集器的工作范围是整个新生代或者老年代、G1收集器的工作范围是整个Java堆。

在使用G1收集器时,它将整个Java堆划分为多个大小相等的独立区域(Region)器垃圾回收过程如下:

  1. 初始标记:仅标记GC Roots能直接到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象。(需要线程停顿,但耗时很短。)

  2. 并发标记:从GC Roots开始对堆中对象进行可达性分析,找出存活对象。(耗时较长,但可与用户程序并发执行)

  3. 最终标记:为了修正在并发标记期间因用户程序执行而导致标记产生变化的那一部分标记记录。且对象的变化记录在线程Remembered Set  Logs里面,把Remembered Set  Logs里面的数据合并到Remembered Set中。(需要线程停顿,但可并行执行。)

  4. 筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。(可并发执行)



设计一个秒杀系统,主要的挑战和问题有哪些?核心的架构方案或者思路有哪些?

秒杀是电子商务网站常见的一种营销手段:将少量商品(通常只有一件)以极低的价格,在特定的时间点开始出售。比如一元钱的手机,五元钱的电脑,十元钱的汽车等。因为商品价格诱人,而且数量有限,所以很多人趋之若鹜,在秒杀活动开始前涌入网站,等到秒杀活动开始的一瞬间,点下购买按钮(在此之前购买按钮为灰色,不可以点击),抢购商品。这些商品因为在活动开始的一秒内就被卖光了,所以被称作秒杀。网站通过这种营销手段,制造某种轰动效应,从而达到网站推广的目的。而最终能够被幸运之神眷顾,秒到商品的只有一两个人而已。很多电子商务网站已经把秒杀活动常态化了,经常性地举行秒杀活动。

秒杀虽然对网站推广有很多好处,也能给消费者带来利益(虽然是很少的几个人),但是对网站技术却是极大的挑战:网站是为正常运营设计的,而秒杀活动带来的并发访问用户却是平时的数百倍甚至上千倍。网站如果为秒杀时的最高并发访问量进行设计部署,就需要比正常运营多得多的服务器,而这些服务器在绝大部分时候都是用不着的,浪费惊人。所以网站的秒杀业务不能使用正常的网站业务流程,也不能和正常的网站交易业务共用服务器,必须设计部署专门的秒杀系统,进行专门应对。

秒杀活动的技术挑战

假设某网站秒杀活动只推出一件商品,预计会吸引 1 万人参加活动,也就是说最大

并发请求数是 10,000,秒杀系统需要面对的技术挑战有如下几点。

1.对现有网站业务造成冲击

秒杀活动只是网站营销的一个附加活动,这个活动具有时间短,并发访问量大的特

点,如果和网站原有应用部署在一起,必然会对现有业务造成冲击,稍有不慎可能导致

整个网站瘫痪。

2.高并发下的应用、数据库负载

用户在秒杀开始前,通过不停刷新浏览器页面以保证不会错过秒杀,这些请求如果

按照一般的网站应用架构,访问应用服务器、连接数据库,会对应用服务器和数据库服

务器造成极大的负载压力。

3.突然增加的网络及服务器带宽

假设商品页面大小 200K(主要是商品图片大小),那么需要的网络和服务器带宽是

2G(200K×10,000),这些网络带宽是因为秒杀活动新增的,超过网站平时使用的带宽。

4.直接下单

秒杀的游戏规则是到了秒杀时间才能开始对商品下单购买,在此时间点之前,只能

浏览商品信息,不能下单。而下单页面也是一个普通的 URL,如果得到这个 URL,不用

等到秒杀开始就可以下单了。

秒杀系统的应对策略

为了应对上述挑战,秒杀系统的应对策略有如下几点。

1.秒杀系统独立部署

为了避免因为秒杀活动的高并发访问而拖垮整个网站,使整个网站不必面对蜂拥而

来的用户访问,可将秒杀系统独立部署;如果需要,还可以使用独立的域名,使其与网

站完全隔离,即使秒杀系统崩溃了,也不会对网站造成任何影响。

2.秒杀商品页面静态化

重新设计秒杀商品页面,不使用网站原来的商品详情页面,页面内容静态化:将商

品描述、商品参数、成交记录和用户评价全部写入一个静态页面,用户请求不需要经过

应用服务器的业务逻辑处理,也不需要访问数据库。所以秒杀商品服务不需要部署动态

的 Web 服务器和数据库服务器。

3.租借秒杀活动网络带宽

因为秒杀新增的网络带宽,必须和运营商重新购买或者租借。为了减轻网站服务器

的压力,需要将秒杀商品页面缓存在 CDN,同样需要和 CDN 服务商临时租借新增的出口

带宽。

4.动态生成随机下单页面 URL

为了避免用户直接访问下单页面 URL,需要将该 URL 动态化,即使秒杀系统的开发

者也无法在秒杀开始前访问下单页面的 URL。办法是在下单页面 URL 加入由服务器端生

成的随机数作为参数,在秒杀开始的时候才能得到。



秒杀系统架构设计

秒杀系统为秒杀而设计,不同于一般的网购行为,参与秒杀活动的用户更关心地是

如何能快速刷新商品页面,在秒杀开始的时候抢先进入下单页面,而不是商品详情等用

户体验细节,因此秒杀系统的页面设计应尽可能简单。如图 12.1 所示。





商品页面中的购买按钮只有在秒杀活动开始的时候才变亮,在此之前及秒杀商品卖

出后,该按钮都是灰色的,不可以点击。

下单表单也尽可能简单,购买数量只能是一个且不可以修改,送货地址和付款方式

都使用用户默认设置,没有默认也可以不填,允许等订单提交后修改;只有第一个提交

的订单发送给网站的订单子系统,其余用户提交订单后只能看到秒杀结束页面,如图 12.2

所示。



除了上面提到的秒杀系统的技术挑战及应对策略,还有一些其他问题需要处理。

1.如何控制秒杀商品页面购买按钮的点亮

购买按钮只有在秒杀活动开始的时候才能点亮,在此之前是灰色的。如果该页面是

动态生成的,当然可以在服务器端构造响应页面输出,控制该按钮是灰色还是点亮,但

是为了减轻服务器端负载压力,更好地利用 CDN、反向代理等性能优化手段,该页面被

设计为静态页面,缓存在 CDN、反向代理服务器上,甚至用户浏览器上。秒杀开始时,

用户刷新页面,请求根本不会到达应用服务器。



解决办法是使用 JavaScript 脚本控制,在秒杀商品静态页面中加入一个 JavaScript 文

件引用,该 JavaScript 文件中加入秒杀是否开始的标志和下单页面 URL 的随机数参数,

当秒杀开始的时候生成一个新的 JavaScript 文件并被用户浏览器加载,控制秒杀商品页面

的展示。这个 JavaScript 文件使用随机版本号,并且不被浏览器、CDN 和反向代理服务

器缓存。如图 12.3 所示。



这个 JavaScript 文件非常小,即使每次浏览器刷新都访问 JavaScript 文件服务器也不

会对服务器集群和网络带宽造成太大压力。

2.如何只允许第一个提交的订单被发送到订单子系统

由于最终能够成功秒杀到商品的用户只有一个,因此需要在用户提交订单时,检查

是否已经有订单提交。事实上,由于最终能够成功提交订单的用户只有一个,为了减轻

下单页面服务器的负载压力,可以控制进入下单页面的入口,只有少数用户能进入下单

页面,其他用户直接进入秒杀结束页面。假设下单服务器集群有 10 台服务器,每台服务

器只接受最多 10 个下单请求,如图 12.4 所示。



秒杀系统的整体架构如图 12.5 所示。



参考文献

《大型网站技术架构 核心原理与案例分析》李智慧

https://blog.csdn.net/iva_brother/article/details/87886525



用户头像

zcj

关注

还未添加个人签名 2019.10.12 加入

精神小伙

评论

发布
暂无评论
架构师训练营:第九周作业