「架构师训练营第 1 期」第九周作业
作业一:
(至少完成一个)
请简述 JVM 垃圾回收原理。
JVM 垃圾回收和大多数GC一样,首先有一个内存容器-堆,在不同的垃圾收集器中有不同的分代模式,但就像Java中的容器一样,不同的实现是为了解决不同的问题。
首先我们有了内存的容器堆,然后需要对垃圾进行清理,这里就涉及到两个问题:
怎么标记垃圾?
怎么清理垃圾?
垃圾的标记有多种算法:
引用计数法:统计对象被引用的数量,存在循环引用问题,jvm没有使用,redis里面用了。
可达性分析发:从GC Root对象往下扫描,标记对象为不能GC的,未标记的清除了。
垃圾的清理也有多种方式:
标记-清除:会有内存碎片
复制算法:有一部分内存闲置。
标记-整理:在1结束后进行一次内存压缩。
G1中标记阶段和清理阶段都做了很大的迭代,但是总体思路还是一样的,容器+标记+清除(整理),不同的实现解决不同的问题。
设计一个秒杀系统,主要的挑战和问题有哪些?核心的架构方案或者思路有哪些?
并发读问题
秒杀系统,高并发读不是问题,通过缓存基本可以解决。
并发写问题
问题在于并发写,如库存扣减这些操作,会存在大量的锁竞争,即便是使用redis等支持高并发写的组件,也会有瓶颈存在。
在代码没问题的情况下,要从业务逻辑或者中间件的角度来优化高并发写效果不会很理想,因为不管怎么优化,中间件的性能始终会变成一个瓶颈。所以思路应该是分治,如果单位节点能支持的并发度为1,要支持100倍的秒杀流量,那就根据用户ID或者商品ID分流100份,上游分流量,DB层分库分表。
直接通过业务逻辑、中间件优化使系统从支持并发度1变到支持并发度100,成本是极高的,而且会严重干扰业务逻辑,增加复杂度,风险很高,通过分治的方法分流在业务逻辑层面是不需要做太大的变更的,都是中间件层面的操作,理想情况下是可以配置化解决的。
限流
虽然上述通过分流可以降低单点的并发度,但是仍然是有风险的,我们单点的并发度仍然是1,所以还需加上限流、降级、熔断等措施,防止单点故障引起雪崩。
非核心流程异步化
在高并发写入过程中,如库存、金额之类要求强一致性的我们必须通过同步的方式来解决,但对于其他对强一致性要求低的场景,我们可以使用异步的方式来处理,比如消息队列,可以对消息的消费再次进行限流,如秒杀订单流水数据10000条,1秒消费完,并发度就是1万,10秒消费完,并发度就变成1000了,负载下降90%,是很可观的。
批处理
可以拦截流量,打包批量处理,如1s内QPS 10000,服务端每100个请求打包处理一次,服务端实际QPS就变成100了,缺点是同一个批次靠前的请求会因为等待打包而响应时间上升。
评论