ARTS | week 15

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mike_learns_to_rock/article/details/89077898

Algorithm

https://leetcode.com/problems/trapping-rain-water/
一道hard,不过用stack做的。
当然有好几种解法,后面我慢慢补上吧

public class P42_TrappingRainWater {
    public int trap(int[] height) {
        // increase: if h[i] <= h[i + 1]: drop h[i], continue;
        // increase -> finding; recording left = h[i];
        // finding:
        // if h[i] >= h[i+1] continue;
        // if h[i] < h[i+1]; right = h[i+1];
        //
        Stack<Integer> index = new Stack<>();
        int res = 0;
        for (int i = 0; i < height.length; i++) {
            if (index.empty() || height[index.peek()] >= height[i]
                    ) {
                index.add(i);
            } else {
                int last = 0;
                while (!index.empty() && height[index.peek()] <= height[i]) {
                    int in = index.pop();
                    int tmp = (height[in] - last) * (i - in - 1);
                    last = height[in];
                    if (tmp > 0) {
                        res += tmp;
                    }
                }
                if (!index.empty()) {
                    int in = index.peek();
                    int tmp = (height[i] - last) * (i - in - 1);
                    if (tmp > 0) {
                        res += tmp;
                    }
                }
                index.add(i);
            }
        }

        return res;
    }
}

Review

Design a system that scales to millions of users on AWS
这篇适合多读几次。
题目解读:如何设计可扩展的百万用户的图片视频网站?(忽略AWS)
约束:网站从1个用户 - 一千万用户(10亿写请求/月,1000亿读请求,每个写数据是1KB);
所以

  • 1TB数据/月(10亿大概是2^31,1024是2 ^10,所以1KB * 1024 * 1024 * 1024 = 1TB)
  • 400 写/秒
  • 40,000 读/秒

架构

0: DNS + WEB_SERVER + MYSQL

  • 1: DNS + WEB_SERVER + MYSQL + 对象存储
  • 2: 高可用和副本:DNS + LB + WEB_SERVER(反向代理) + 写API + 读API + MYSQL_MASTER + MYSQL_SLAVE + CDN + 对象存储
  • 3:读性能瓶颈:+ memory cache集群(mysql的热点数据以及web server的session数据) + MYSQL_READ副本
  • 4:自动扩缩容,运维以及监控
  • 5: 写存在瓶颈:+ nosql + 消息队列 (异步处理写入请求,例如上传图片然后异步压缩图片)

诊断工具很重要,可以及时发现瓶颈;
一定规模后日志分析以及监控运维,弹性集群管理都是问题;
缓存以及存储的高可用有很多东西需要挖掘。

附录
1 request per second = 2.5 million requests per month
40 requests per second = 100 million requests per month

Tips

  • JVM:java8 默认垃圾回收器是Parallel GC,建议使用G1,jvm参数-XX:+UseG1GC
  • effective java:java中尽量使用静态工厂方法来创建对象;好处是1.命名清晰 2.避免重复创建对象(享元模式) 3.返回多个子类型;

享元模式

Share

jvm垃圾回收简介

  1. 运行时数据区域
  • 程序计数器:记录当前线程的正在执行的字节码指令地址(如果是native方法,则值为空)
  • Java 虚拟机栈:每个java方法执行的依赖的局部变量,操作数和常量池引用:-Xss(StackOverflowError/OutOfMemoryError)
  • 本地方法栈:类似上面
  • 堆:线程共享区域,主要的GC区域;新生代和老年代;物理内存不需要连续;
    • -Xms 堆大小初始值
    • -Xmx 堆大小最大值(OutOfMemoryError)
  • 方法区
    • 用于存放已被加载的类信息、常量、静态变量等数据。
    • 从 JDK 1.8 开始,移除永久代,并把方法区移至元空间,它位于本地内存中,而不是虚拟机内存中。
  1. 垃圾回收
  • 垃圾收集主要是针对堆和方法区进行
  • 如何判断对象可以回收
    • 引用计数法:循环引用导致计数器无法为0,JVM不实用引用计数
    • 可达性分析算法:以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。
    • 方法区回收:因为方法区主要存放永久代对象,而永久代对象的回收率比新生代低很多,所以在方法区上进行回收性价比不高。
    • finalize(): 最开始兼容C++,类似 C++ 的析构函数,用于关闭外部资源。但是 try-finally 等方式可以做得更好;该方法可认为被废弃了。
  • 引用类型:判断回收的依据
    • 强引用:不会回收
    • 软引用:内存不够的情况下才会被回收
    • 弱引用:一定回收,只能存活到下一次垃圾回收发生之前
    • 虚引用:一定回收,唯一目的是能在这个对象被回收时收到一个系统通知,诊断系统使用
  • 垃圾回收算法
    • 标记-清除:最原始的算法,两个阶段效率都低,内存碎片问题
      • docker distribution里默认是这种方法GC镜像layer,当镜像很多时,标记时间特别长。不建议使用。
    • 标记-整理:解决内存碎片问题,但是需要移动大量对象,效率低
    • 复制:AB区域,A的存活对象复制到B区域,然后清除A;缺点是内存浪费;
      • 扩展:docker distribution里建议的这种方法GC镜像layer,需要把存储设置为只读模式,然后切换存储。不建议使用。
    • 分代收集
      • 新生代:复制算法, Eden 和 Survivor 大小比例默认为 8:1,保证了内存的利用率达到 90%。
      • 老年代:标记-清除/标记-整理
  1. 垃圾回收器
    • server强调停顿时间短,后台运算任务强调高吞吐量,希望尽快计算结束;
    • 缩短停顿时间是以牺牲吞吐量和新生代空间来换取的:新生代空间变小,垃圾回收变得频繁,导致吞吐量下降。
  • serial 收集器:串行 + 单线程
    • Client 场景下的默认新生代收集器,小内存场景,停顿时间较短
  • parnew 收集器:serial多线程版本
    • 它是 Server 场景下默认的新生代收集器
    • 能与 CMS 收集器配合使用
  • parallel scavenge 收集器:多线程 + 自适应GC策略
  • CMS(并发标记清除)收集器:基本不需要停顿
    • 并发标记和并发清理和用户线程一起运行,基本不需要停顿
    • 缺点明显:吞吐量低,无法处理浮动垃圾,内存碎片可以提前触发full gc
  • G1收集器:服务端的首选
    • 其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
    • 堆重定义为多个region,新老代物理不隔离;空间整合,无内存碎片
    • Set数据结构,提高可达性分析的效率,避免全堆扫描
    • 空间整合:整体来看是基于“标记 - 整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复制”算法实现的,这意味着运行期间不会产生内存空间碎片。
    • 可预测的停顿:能让使用者明确指定在一个长度为 M 毫秒的时间片段内,消耗在 GC 上的时间不得超过 N 毫秒。

猜你喜欢

转载自blog.csdn.net/mike_learns_to_rock/article/details/89077898