架构师训练营 - 第 9 周学习总结
一、JVM
1.JVM 组成架构:Java 是一种跨平台的语言,JVM 屏蔽了底层系统的不同,为 Java 字节码文件构造了一个统一的运行环境。
通过 tomcat 容器会执行 main 方法,类加载器会把 main 下相关的方法和类都加载到方法区中,然后开始执行 main 里面的方法,如果 new 一个对象当前线程的栈帧会将对象放入到堆中,并指向堆中的地址,java 栈和程序计数器都是线程私有的
2.Java 字节码文件
java 所有的指令 200 多个,一个字节(8 位)就可以表示 256 个指令。在代码执行过程中,JVM 将字节码解释执行,摒弃对操作系统的依赖,也可以将字节码编译执行,如果是热点代码会通过 JIT 动态编译为机器码,来提升效率
java 字节码 开头为 coffee baby 0037 是魔术
字节码执行过程:
字节码编译过程:
3.类加载器的双亲委托模型
低层次的当前类加载器,不能覆盖更高层次类加载器已经加载的类。如果低层次的类加载器想加载一个未知类,需要上级类加载器确认,只有当上级类加载器没有加载过这个类,也允许加载的时候,才让当前类加载器加载这个未知类。
4.自定义类加载器
隔离加载类:同一个 JVM 中不同组件加载同一个类的不同版本。
扩展加载源:从网络、数据库等处加载字节码。
字节码加密:加载自定义的加密字节码,在 ClassLoader 中解密。
5.栈、堆、方法区之间的关系图
6.线程工作内存 & volatile
Java 内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行。
一个共享变量 (类的成员变量、类的静态成员变量)被 volatile 修饰之后,那么就具备了两层语义:
保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
禁止进行指令重排序。
正常来说每个线程都有一个工作内存,当访问堆中的元素的时候 都会先更改工作内存中的,然后才会刷到主存中
但使用了 volatile 的时候就会直接刷到主存,然后各个线程的工作内存都会去主存中读取
二、垃圾回收
1.JVM 的垃圾回收
JVM 垃圾回收就是将 JVM 堆中的已经不再被使用的对象清理掉,释放宝贵的内存资源。
JVM 通过一种可达性分析算法进行垃圾对象的识别,具体过程是:从线程栈帧中的局部变量,或者是方法区的静态变量出发,将这些变量引用的对象进行标记,然后看这些
被标记的对象是否引用了其他对象,继续进行标记,所有被标记过的对象都是被使用的对象,而那些没有被标记的对象就是可回收的垃圾对象了。
2.进行完标记以后, JVM 就会对垃圾对象占用的内存进行回收,回收主要有三种方法
清理:将垃圾对象占据的内存清理掉,其实 JVM 并不会真的将这些垃圾内存进行清理,而是将这些垃圾对象占用的内存空间标记为空闲,记录在一个空闲列表里,当应用程序需要创建新对象的时候,就从空闲列表中找一-段空闲内存分配给这个新对象。
压缩:从堆空间的头部开始,将存活的对象拷贝放在一-段连续的内存空间中,那么其余的空间就是连续的空闲空间。
复制:将堆空间分成两部分,只在其中一部分创建对象,当这个部分空间用完的时候,将标记过的可用对象复制到另一个空间中。
3.Jvm 分代垃圾回收:java 不断创建的对象大部分都是很快回收的(一个请求几百 ms 会创建很多对象),对象已创建出来就放到新生代。在 Eden 创先对象当 Eden 满了之后会执行 yung gc 然后把活的对象放到 from 区,然后下次当 Eden 满了之后,进行 gc 然后 Eden 跟 from 会再次进行标记,放入到 to 区域,然后下次会将 Eden 和 to 放到 from,一直重复过程,多次之后就会拷贝到老年代,当 Eden+from 都拷贝不到老年代就会进行一次 Full gc
4.JVM 垃圾收集器
串行收集器中间 stop the world 的时间会很长
并行收集器,采用多线程的方式来缩短 stop the world 的时间 但还是会有停顿
CMS 并发回收器,会进行初始化标记(停顿标记 root 节点),并发标记和重标记的过程,大幅度缩小停顿时间,在并发的时候进行清理
G1 收集器
G1 收集器内存机制
二、诊断工具
基本工具: JPS, JSTAT, JMAP
集成工具: JConsole, JVisualVM
1.JPS
JPS 用来查看 host. 上运行的所有 java 进程的 pid (jvmid) ,一般情况下使用这个工具的目的只是为了找出运行的 jyvm 进程 ID,即 Ivmid,然后可以进一步使用其它的工具来
监控和分析 JVM。
常用的几个参数:
-|输出 java 应用程序的 main class 的完整包
-q 仅显示 pid, 不显示其它任何相关信息
-m 输出传递给 main 方法的参数
-V 输出传递给 JVM 的参数。在诊断 JVM 相关问题的时候,这个参数可以查看 JVM 相关参数的设置
2.JSTAT
JSTAT (“Java Virtual Machine statistics monitoring tool”)是 JDK 自带的一个轻量级小工具。主要对 Java 应用程序的资源和性能进行实时的命令行的监控,包括了对 Heap
size 和垃圾回收状况的监控。
语法结构如下: jstat [Options] vmid [interval] [count]
Options --选项,我们一般使用- gcutil 查看 gc 情况
vmid-- VM 的进程号,即当前运行的 java 进程号
interval--间隔时间,单位为毫秒
count--打印次数,如果缺省则打印无数次
S0-Heap 上的 Survivor space 0 区已使用空间的百分比
S1 -- Heap 上的 Survivor space 1 区已使用空间的百分比
E -- Heap 上的 Eden space 区已使用空间的百分比
O -- Heap 上的 Old space 区已使用空间的百分比
YGC --从应用程序启动到采样时发生 Young GC 的次数
YGCT--从应用程序启动到采样时 Young GC 所用的时间( 单位秒)
FGC --从应用程序启动到采样时发生 Full GC 的次数
FGCT--从应用程序启动到采样时 Full GC 所用的时间( 单位秒)
GCT --从应用程序启动到采样时用于垃圾回收的总时间(单位秒)
3.JMAP
JMAP 是一个可以输出所有内存中对象的工具,甚至可以将 VM 中的 heap,以二进制输出成文本。
使用方法
jmap -histo pid>a.log 可以将其保存到文本中去,在一段时间后,使用文本对比工具,可以对比出 GC 回收了哪些对象。
jmap -dump:format=b,file=f1 PID 可以将该 PID 进程的内存 heap 输出出来到 f1 文件里。
4.JConsole、JVisualVM 都是可视化的工具
创建一个 Threadlocal 变量:
private ThreadL ocal myThreadL ocal = new ThreadL ocal();
存储此对象的值:
my Threadlocal.set("A thread local value");
读取一个 ThreadLocal 对象的值:
String threadLocalValue = (String) my ThreadL ocal.get();
用 map 是如何实现的?
Java 内存泄漏
如果程序保留对永远不再使用的对象的引用,这些对象将会占用并耗尽内存。
长生命周期对象
静态容器
缓存
三、秒杀
1.秒杀带来的问题
瞬间高并发
瞬时流量并发量是原有的 100 倍
如果有一些需要加载的资源如图片一个就是 1M,会导致带宽资源耗尽
服务器崩溃,自己给自己准备 ddos 攻击
秒杀器
秒杀前不断刷页面,直到秒杀开始,抢着下单
跳过秒杀页面,直接进入下单页面,下单
2.解决方法
快速方案 做新秒杀系统:
服务器和网络准备
style 服务器(Lighttpd 集群)5 台 css、html
图片服务器(Nginx 集群)5 台
静态服务器(Apache 集群)5 台 接入 http 请求
交易服务(JBoss 集群)10 台
宽带准备
图片出口带宽 2.5G
CDN 准备 ChainCache 沟通;借用 CCCC CDN
架构目标:
图片控制在 1G 左右
每件商品秒杀页面大小不能超过 1000000/(1000*8) = 125K/每件商品 1000 是运营预估的单件商品的并发量
总并发量 1000(人/商品) * 8(件商品) = 8000
秒杀系统组成页面:秒杀商品列表(静态集群)、商品介绍页面(静态集群)、下单(动态集群)
设计原则:
静态化
采用 JS 自动更新技术将动态页面转化为静态页面(将动态数据录入系统然后转换为静态页面上传到静态集群)
并发控制,防秒杀器
设置阀门,只放最前面的一部分人进入秒杀系统(设置三个阀门,通过++的方式 分别放在三个页面进行分级控制)
简化流程
砍掉不重要的分支流程,如下单页面的所有数据库查询
以下单成功作为秒杀成功标志。支付流程只要在 1 天内完成即可。
前端优化
采用 YSLOW 原则提升页面响应速度
秒杀器的预防
秒杀 Detail 页面
URL:随机
秒杀前 2 秒放出,脚本生成,秒杀前。
1000 次访问上限控制( 每件商品只能放入 1000 人浏览)
下单页面
订单 ID 随机
不能直接跳过秒杀 Detail 页面进入
每个秒杀商品
带预先生成的随机 Token 作 URL 参数。
如果秒杀过,直接跳到秒杀结束页面。
100 次访问上限控制[每件商品只能放入 1000 人下单]
WebServer 调优(apache、jboss)
静态页面调优:8 张图片合成一张 通过偏移量展示、减少 http 请求次数、减少 cookie 的量、html 的内容压缩
下单页面优化
数据库操作:全部砍掉
原下单页面要访问 8 次数据库,全部砍掉。
秒杀流程精简
砍掉填写或选择收货地址,放在秒杀成功后填写。
砍掉调用是否开通支付接口,秒杀首页文案提示必须开通。
采用内存缓存
秒杀 Offer 数据,支付相关信息,缓存。
四、搜索引擎
1.搜索引擎架构
2.倒排索引:正排相当于某个页面都有哪些词,而倒排则是那个词后面都有那些页面
3.lucene 架构
4.lucene 倒排索引
5.elasticSearch 架构
索引分片,实现分布式
索引备份,实现高可用
API 更简单、更高级
版权声明: 本文为 InfoQ 作者【红了哟】的原创文章。
原文链接:【http://xie.infoq.cn/article/01ec28bf6e385871a82ed9e2e】。文章转载请联系作者。
评论