架构师训练营 - 第 9 周学习总结
一、JVM
1.JVM 组成架构:Java 是一种跨平台的语言,JVM 屏蔽了底层系统的不同,为 Java 字节码文件构造了一个统一的运行环境。
通过 tomcat 容器会执行 main 方法,类加载器会把 main 下相关的方法和类都加载到方法区中,然后开始执行 main 里面的方法,如果 new 一个对象当前线程的栈帧会将对象放入到堆中,并指向堆中的地址,java 栈和程序计数器都是线程私有的
![](https://static001.geekbang.org/infoq/c5/c571d156b6cfc3fdd39fcec69a24b479.png)
2.Java 字节码文件
java 所有的指令 200 多个,一个字节(8 位)就可以表示 256 个指令。在代码执行过程中,JVM 将字节码解释执行,摒弃对操作系统的依赖,也可以将字节码编译执行,如果是热点代码会通过 JIT 动态编译为机器码,来提升效率
java 字节码 开头为 coffee baby 0037 是魔术
字节码执行过程:
![](https://static001.geekbang.org/infoq/c5/c53db8b631e12ca5704901fc8a6affba.png)
字节码编译过程:
![](https://static001.geekbang.org/infoq/8b/8bacaef51911b61824dc9e934a99b122.png)
3.类加载器的双亲委托模型
低层次的当前类加载器,不能覆盖更高层次类加载器已经加载的类。如果低层次的类加载器想加载一个未知类,需要上级类加载器确认,只有当上级类加载器没有加载过这个类,也允许加载的时候,才让当前类加载器加载这个未知类。
![](https://static001.geekbang.org/infoq/e3/e3387b91066a37b8805d73d0d6786d83.png)
4.自定义类加载器
隔离加载类:同一个 JVM 中不同组件加载同一个类的不同版本。
扩展加载源:从网络、数据库等处加载字节码。
字节码加密:加载自定义的加密字节码,在 ClassLoader 中解密。
![](https://static001.geekbang.org/infoq/70/70aa25a21d2f5dc4ece9954c5f43cf28.png)
5.栈、堆、方法区之间的关系图
![](https://static001.geekbang.org/infoq/d1/d1d8c2035594501f7b14be43cda434e3.png)
6.线程工作内存 & volatile
Java 内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行。
一个共享变量 (类的成员变量、类的静态成员变量)被 volatile 修饰之后,那么就具备了两层语义:
保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
禁止进行指令重排序。
![](https://static001.geekbang.org/infoq/90/901dc29b1abb84ba2f14ca187edf771a.png)
正常来说每个线程都有一个工作内存,当访问堆中的元素的时候 都会先更改工作内存中的,然后才会刷到主存中
但使用了 volatile 的时候就会直接刷到主存,然后各个线程的工作内存都会去主存中读取
二、垃圾回收
1.JVM 的垃圾回收
JVM 垃圾回收就是将 JVM 堆中的已经不再被使用的对象清理掉,释放宝贵的内存资源。
JVM 通过一种可达性分析算法进行垃圾对象的识别,具体过程是:从线程栈帧中的局部变量,或者是方法区的静态变量出发,将这些变量引用的对象进行标记,然后看这些
被标记的对象是否引用了其他对象,继续进行标记,所有被标记过的对象都是被使用的对象,而那些没有被标记的对象就是可回收的垃圾对象了。
2.进行完标记以后, JVM 就会对垃圾对象占用的内存进行回收,回收主要有三种方法
清理:将垃圾对象占据的内存清理掉,其实 JVM 并不会真的将这些垃圾内存进行清理,而是将这些垃圾对象占用的内存空间标记为空闲,记录在一个空闲列表里,当应用程序需要创建新对象的时候,就从空闲列表中找一-段空闲内存分配给这个新对象。
压缩:从堆空间的头部开始,将存活的对象拷贝放在一-段连续的内存空间中,那么其余的空间就是连续的空闲空间。
复制:将堆空间分成两部分,只在其中一部分创建对象,当这个部分空间用完的时候,将标记过的可用对象复制到另一个空间中。
![](https://static001.geekbang.org/infoq/62/62857ca94f99c5cbe9dc671aee465b97.png)
3.Jvm 分代垃圾回收:java 不断创建的对象大部分都是很快回收的(一个请求几百 ms 会创建很多对象),对象已创建出来就放到新生代。在 Eden 创先对象当 Eden 满了之后会执行 yung gc 然后把活的对象放到 from 区,然后下次当 Eden 满了之后,进行 gc 然后 Eden 跟 from 会再次进行标记,放入到 to 区域,然后下次会将 Eden 和 to 放到 from,一直重复过程,多次之后就会拷贝到老年代,当 Eden+from 都拷贝不到老年代就会进行一次 Full gc
![](https://static001.geekbang.org/infoq/83/83da7f88c93cb833ec361ce48608f34b.png)
4.JVM 垃圾收集器
串行收集器中间 stop the world 的时间会很长
并行收集器,采用多线程的方式来缩短 stop the world 的时间 但还是会有停顿
CMS 并发回收器,会进行初始化标记(停顿标记 root 节点),并发标记和重标记的过程,大幅度缩小停顿时间,在并发的时候进行清理
G1 收集器
![](https://static001.geekbang.org/infoq/74/7425b915ce6d96b6149ead69797ae558.png)
G1 收集器内存机制
![](https://static001.geekbang.org/infoq/05/05921c7cad00055233d225ac3f4bdc63.png)
二、诊断工具
基本工具: 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 都是可视化的工具
![](https://static001.geekbang.org/infoq/0a/0aeb2761f97fa021b5a47d26d180e1b1.png)
创建一个 Threadlocal 变量:
private ThreadL ocal myThreadL ocal = new ThreadL ocal();
存储此对象的值:
my Threadlocal.set("A thread local value");
读取一个 ThreadLocal 对象的值:
String threadLocalValue = (String) my ThreadL ocal.get();
![](https://static001.geekbang.org/infoq/bc/bcd7e08001b04cc1cf6c3385c7b99fb9.png)
![](https://static001.geekbang.org/infoq/18/189278bb27f29de1965ef409516bc676.png)
用 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 原则提升页面响应速度
![](https://static001.geekbang.org/infoq/c0/c0e8e99cd0c292fa5701f27b91d1e950.png)
秒杀器的预防
秒杀 Detail 页面
URL:随机
秒杀前 2 秒放出,脚本生成,秒杀前。
1000 次访问上限控制( 每件商品只能放入 1000 人浏览)
下单页面
订单 ID 随机
不能直接跳过秒杀 Detail 页面进入
每个秒杀商品
带预先生成的随机 Token 作 URL 参数。
如果秒杀过,直接跳到秒杀结束页面。
100 次访问上限控制[每件商品只能放入 1000 人下单]
WebServer 调优(apache、jboss)
静态页面调优:8 张图片合成一张 通过偏移量展示、减少 http 请求次数、减少 cookie 的量、html 的内容压缩
下单页面优化
数据库操作:全部砍掉
原下单页面要访问 8 次数据库,全部砍掉。
秒杀流程精简
砍掉填写或选择收货地址,放在秒杀成功后填写。
砍掉调用是否开通支付接口,秒杀首页文案提示必须开通。
采用内存缓存
秒杀 Offer 数据,支付相关信息,缓存。
四、搜索引擎
1.搜索引擎架构
![](https://static001.geekbang.org/infoq/81/8126118065ffcb1b87042f5b3e981dba.png)
2.倒排索引:正排相当于某个页面都有哪些词,而倒排则是那个词后面都有那些页面
![](https://static001.geekbang.org/infoq/c1/c16d4ad3113fcddecea4d7a14d922006.png)
3.lucene 架构
![](https://static001.geekbang.org/infoq/b1/b1a5a193f01f1be6789add743dd71440.png)
4.lucene 倒排索引
![](https://static001.geekbang.org/infoq/e3/e3deb4033e9fe99e158e54cd35eeed0d.png)
5.elasticSearch 架构
索引分片,实现分布式
索引备份,实现高可用
API 更简单、更高级
![](https://static001.geekbang.org/infoq/9b/9bcc45dcd1e19f53d263aad20e78ae39.png)
版权声明: 本文为 InfoQ 作者【红了哟】的原创文章。
原文链接:【http://xie.infoq.cn/article/01ec28bf6e385871a82ed9e2e】。文章转载请联系作者。
评论