极客时间《架构师训练营》第九周课后作业
作业一
请简述 JVM 垃圾回收原理
垃圾回收就是清除 JVM 堆内不再被引用的对象。
可达性分析
从GC Roots
对象出发一路向下遍历,将遍历到的对象标记为可达,其他对象即不可达。其中GC Root
包括:栈中引用对象、方法区中的静态或是常量引用,以及本地方法栈中的 JNI 引用对象。
GC 算法
经可达性分析后,那些不可达的对象将等待回收。常用的回收算法有:
-
mark-sweep 标记清除法:将标记的回收区域直接清空
-
mark-copy 标记拷贝法:将内存对半分,总保留一半是空闲的;回收时,将零散存活的对象连续地复制到另一半的空闲内存区。
-
mark-compact 标记合并法:先清理垃圾对象,再挪动存活对象,并保证连续存储
-
generation-collect 分代收集算法
内存被分为三大块:新生代、老年代、永久代;新生代又细分为 Eden 区和两个 Survivor 区:
分代收集算法分代收集算法提供了两种模式:
-
Minor GC 也叫 Young GC,顾名思义主要在新生代活动的回收机制:
- Eden 满了,标记复制到 S0;Eden 清空
- Eden+S0 满了,标记复制到 S1;Eden 和 S0 清空
- Eden+S1 满了,标记复制 S0;Eden 和 S1 清空
- 循环往复步骤 2、3
- 将 S0 和 S1 间多次往复的标记块晋升到老年代
-
Major GC:老年代也满了,就整体标记清除或是标记合并一下,但是会比较耗时
-
垃圾回收器
垃圾回收器一直在发展,一共经历了四个阶段:
- Serial(串行)收集器
- Parallel(并行)收集器
- CMS(并发)收集器
- G1 收集器
主要说说 G1 收集器。G1 之前的 JVM 堆模型如上面分代收集算法提到的,分为新生代、老年代和永久代。G1 改变了这个模型,堆被分为多个大小连续的区域,这些区域被标记为 E、S、O 和 H,分别对应 Eden,Survivor,Old 区和巨型区。
G1收集器G1 也有两种收集模式:
-
Young GC: 当 Eden 区达到一定阈值时触发;会将 Eden 和 Survivor 清理,并复制到 Old 区以及一部分 Survivor 区。
-
MixedGC:Old 区也达到一定阈值时,回收所有 Eden区、Survivor 区,以及部分 Old 区的内存。
作业二
设计一个秒杀系统,主要的挑战和问题有哪些?核心的架构方案或者思路有哪些?
挑战
秒杀系统的核心挑战就是高并发:在极短时间内有大量请求达到,可能导致全站奔溃。其他的问题还包括:
- 超卖
- 恶意请求
- 链接暴露
解决方案
核心问题是高并发,所以解决方案的中心思想就是流量控制和性能优化。
-
服务单一职责
给秒杀系统部署一个单独的服务,至少保证秒杀系统挂了,站点的其他服务依旧可行
-
扩容
就是加机器了。先扩容服务和 cache。
-
静态化资源
前后端分离,页面尽可能的静态化,减少动态数据请求。把能静态的资源——html、js、css、img 等等——全部放到 CDN 上。
-
加盐:通俗来说就是秒杀请求的 URL 必需带一个加密的参数,比如添加一个动态生成的 token,经后端校验请求才能通过。这个主要是防止事先暴露 URL。
-
限流
- 前端限流:按钮在秒杀开始前必须是 disabled 的,开始后每次点按钮要隔两秒才能再点,或是秒杀开始三秒后的点击全部导航到其他页面
- 后端限流:加个计数器,比如卖 100 个产品,10000 后的请求都 return false,后端直接关闭无效请求。
-
库存预热
将库存事先放入 Redis 里,秒杀开始后,减库存的操作只作用于 Redis 上,并利分布式锁保证原子操作。一旦库存耗尽,之后的流量全部返回 false。等秒杀当刻结束,再通过定时器,慢慢写回数据库。如果秒杀的商品数量极多,也可以利用 MQ 写回。