Java后端技术栈
2021-05-23 12:45:48 0 举报
AI智能生成
Java后端技术栈, 整理知识点
作者其他创作
大纲/内容
Java后端技术栈
JUC
线程池
多线程
锁
集合
IO
反射
泛型
异常
Servlet
类
接口
抽象类
面向对象
lambda
stream
Optional类
default
任意位置都可使用注解
类型注解
省略后面<>
泛型类型推断优化
本地内存存储类元数据信息
元空间
移除永久代
LocalDateTime
Instant
...
日期
Java8新特性
Java
加载
验证class文件的正确性
验证
准备
把类的符号引用转化为直接引用
解析
给静态变量赋真正的初值
初始化
使用
卸载
类的生命周期
类加载器(组合)
全盘负责
父类委托
加载过的Class会缓存起来
缓存机制
防止内存中出现多份相同的字节码文件
安全
优点
缺点
双亲委派机制
继承 ClassLoader
重写findClass方法
自定义类加载器
类加载机制
JVM启动时加载
Class.forName()
ClassLoader.loadClass()
类加载方式
java8
总览图
Program Counter Register
存储指向下一条指令的地址
每个线程私有
生命周期和线程一样
它是唯一一个在 JVM 规范中没有规定任何 OutOfMemoryError 情况的区域
程序计数器
Java Virtual Machine Stacks
每个线程在创建时都会创建一个虚拟机栈
它保存方法的局部变量、部分结果,并参与方法的调用和返回
不存在垃圾回收问题
-Xss配置线程最大栈大小
Java虚拟机栈的大小是动态的或者是固定不变的
概述
Stack Frame
栈帧
一个线程上正在执行的方法对应一个栈帧
存储单位
对栈帧的压栈和出栈
先进后出/后进先出原则
JVM对Java栈的操作
字节码指令只对当前栈帧操作
栈运行原理
基本数据类型
对象引用
存储方法参数和定义在方法内的局部变量
32位占用一个Slot
64位占用另个Slot
变量槽Slot
最基存储单元
局部变量表
后进先出(Last-In-First-Out)的操作数栈
操作数栈,在方法执行过程中,根据字节码指令,往操作数栈中写入数据或提取数据,即入栈(push)、出栈(pop)
操作数栈
运行时常量池的方法引用
动态链接
方法正常退出或异常退出的地址
方法返回地址
一些附加信息
栈帧的内部结构
Java虚拟机栈
Unsafe类
Java调用非Java代码的接口
Native Method
栈是运行时的单位,而堆是存储的单位
栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。堆解决的是数据存储的问题,即数据怎么放、放在哪。
本地方法栈
线程共享
8
Eden
1
S0
S1
新对象和没达到一定年龄的对象
-Xmn设置新生代大小
垃圾回收称为Minor GC
新生代
需要大量连续内存空间的对象
大对象
内存大小一般比新生代大
垃圾回收称为Major GC
老年代
一些方法中的操作临时对象.
内存划分
-Xmx 和 -Xms 设置堆最大和最小内存大小
-Xmx 和 -Xms一般设置相同大小
–XX:NewRatio配置
新生代和老年代比例默认1:2
-XX:SurvivorRatio
新生代中的 Eden:From Survivor:To Survivor 的比例是 8:1:1
-XX:+UseAdaptiveSizePolicy
JDK8 动态调整堆内存分配
堆内存大小设置
JVM 会给对象定义一个对象年轻计数器(-XX:MaxTenuringThreshold)
1. 新创建对象 先到Eden区
对象年龄+1
3. JVM把存活的对象转移到Survivor区
每经历一次Minor GC 对象年龄+1
4. Survivor也会Minor GC
默认0
大对象一般是指字符串和数组
对象在堆中的生命周期
对象优先进入Eden区
大对象直接进入老年代
长期存活的对象进入老年代
动态对象年龄判定
在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。
如果不成立的话虚拟机会查看 HandlePromotionFailure 设置值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 设置不允许冒险,那么就要进行一次 Full GC。
空间分配担保
内存分配策略
堆内存
Java 虚拟机规范把方法区描述为堆的一个逻辑部分
Non-Heap(非堆)
文本字符
final修饰的常量
放编译期生成的各种字面量
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
符号引用
运行时常量池(Runtime Constant Pool)
类信息
静态变量
JIT编译后的代码
存什么?
类型信息
域Field信息
方法Method信息
内部结构
方法区
-XX:MetaspaceSize
-XX:MaxMetaspaceSize
参数设置
类型信息、字段、方法、常量
元空间1.8
一种可以有效减少 Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法
通过逃逸分析,Java Hotspot 编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。
没有逃逸
逃逸
被外部方法使用
分析对象的动态作用域
-XX:+DoEscapeAnalysis
jdk6之后默认开启
同步省略/锁消除
标量: 不能再分解的数据
聚合量: 包括其他聚合量和标量
-XX:+EliminateAllocations
开启标量替代
-XX:+PrintEliminateAllocations
查看标量替代情况
标量替换
影响应用性能
栈上分配
编译器对代码的优化
逃逸分析
逃逸分析 Escape Analysis
Thread Local Allocation Buffer
为什么要有TLAB?
-XX:UseTLAB
开启TLAB
-XX:TLABWasteTargetPercent 设置百分比
默认TLAB空间只占Eden区的1%
TLAB
OOM的情况
优化手段
JVM内存结构
共享内存
消息传递
线程间通讯
图
编译器
指令级
内存
哪些重排序
如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性
数据依赖性
不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守 as-if-serial 语义。
编译器和处理器不会对存在数据依赖关系的操作做重排序
as-if-serial语义
重排序
顺序一致性
顺序一致性内存模型
处理器内存模型
为了保证内存可见性,java 编译器在生成指令序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序
LoadLoad Barriers
StoreStore Barriers
LoadStore Barriers
Store1; StoreLoad; Load2
该屏障之前的所有内存访问指令(存储和装载指令)完成之后,才执行该屏障之后的内存访问指令
StoreLoad Barriers
指令类别
内存屏障
如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在 happens-before 关系
前一个操作happens- before后续操作
程序顺序规则
解锁happens- before加锁
监视器锁规则
volite的写happens- beforev votile的读
volatile 变量规则
A happens- before C
传递性
规则
happens-before
Java内存模型
JMM
没有被使用的对象
什么是垃圾
计数器
计数器为0时对象可被回收
可通过 Recycler 算法解决
存在循环引用问题
引用计数法
通过 GC Roots 作为起始点进行搜索,能够到达到的对象都是存活的,不可达的对象可被回收。
虚拟机栈中引用的对象
本地方法栈中引用的对象
方法区中类静态属性引用的对象
方法区中的常量引用的对象
GC ROOTS对象
可达性分析法
如何确认垃圾
Eden区满就触发
G1 GC
Minor GC
CMS GC
Major GC
新生代和老年代
Mixed GC
整个堆和方法区
调用 System.gc()
老年代空间不足
使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC
空间分配担保失败
JDK 1.7 及以前的永久代空间不足
Concurrent Mode Failure
触发条件
尽量不创建过大的对象和数组
-Xmn128M调大新生代的大小
默认15
如何避免Full GC
Full GC
堆
常量池中的常量没有使用就会被回收
对常量池的回收和对类的卸载
该类所有的实例都已经被回收,也就是堆中不存在该类的任何实例。
加载该类的 ClassLoader 已经被回收。
该类对应的 Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。
类的卸载条件
什么时候回收垃圾
Object obj = new Object();
new
不会被回收
强引用
SoftReference<Object> sf = new SoftReference<Object>(obj);
SoftReference
内存不够时会被回收
软引用
WeakReference<Object> wf = new WeakReference<Object>(obj);
WeakReference
弱引用
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
PhantomReference
对象被回收时收到一个系统通知
用途?
虚引用
引用类型
从GC ROOT查找存活的对象并标记
追踪
再清除未标记的对象
清除
整个过程对象不移动
标记和清除效率不高
不足
标记-清除
对象移动
标记-整理
内存分为大小相等两块
复制
复制算法
标记-清除/标记-整理
分代
回收算法
怎么回收垃圾
大概图
会停顿
垃圾收集器和用户程序交替执行
串行
单线程
client模式
Serial 收集器
Serial 收集器的多线程版本
Server模式
只有ParNew可和CMS配合工作
默认线程数和CPU数一样
-XX:ParallelGCThreads设置线程数
ParNew 收集器
吞吐量优先?
Parallel Scavenge 收集器
Serial 收集器的老年代版本
span style=\
Serial Old 收集器
Parallel Scavenge 收集器的老年代版本。
Parallel Old 收集器
标记-清除算法
CMS(Concurrent Mark Sweep)
停顿
标记一下 GC Roots 能直接关联到的对象
初始标记
不停地
进行 GC Roots Tracing 的过程
并发标记
为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录
重新标记
不停顿
清除垃圾
并发清除
流程
低停顿时间是以牺牲吞吐量为代价的
吞吐量底
可能出现 Concurrent Mode Failure
浮动垃圾只能等待下一次GC
需要预留内存
无法处理浮动垃圾
需提前Full GC
标记清除产生内存碎片
CMS
CMS 收集器
G1 可以直接对新生代和老年代一起回收
每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。
筛选回收
G1收集器
用什么东西回收垃圾
GC
jps -l
jstack -pid
Java System属性和JVM命令行参数
jinfo -flags pid
dump 文件
jmap -heap pid
查看堆内对象
jmap -histo 2815 | head -10
查看堆的占用
jmap
jstat -gcutil 2815 1000
对Heap size和垃圾回收状况的监控
jstat -gc pid
查看gc次数
jstat
jdb
分析工具
堆最大内存
-Xmx1g
堆最小内存
-Xms1g
默认堆的1/4或1/3
新生代内存
-Xmn341M
新生代占堆的1/5
新生代与老年代比例1:4
与-Xmn128M选其一
-XX:NewRatio=4
线程堆栈大小
-Xss256k
G1默认15
新生代中的对象存活次数
一次Minor GC +1
-XX:MaxTenuringThreshold=15
新生代 Eden区和Survivor区的比例8:2
-XX:SurvivorRatio=8
大于3M的对象直接进入老年代
默认为0
-XX:PretenureSizeThreshold=3M
加大Integer Cache
strong style=\
默认是G1
回收器
生成gc日志文件
-Xloggc:/home/gc.log
gc日志
-XX:+PrintGCDetails
gc日志打印日期
XX:+PrintGCDateStamps
日志相关
-Dcom.sun.management.jmxremote.port=7001 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1
JMX
发生OOM时自动dump到文件
-XX:+HeapDumpOnOutOfMemoryError
dump文件
jhat heap.hprof
查看dump文件
XX:HeapDumpPath=/opt/heap.hprof
dump
jvm优化启动参数
分析gc日志
https://gceasy.io/
远程debug
工具
性能调优
JVM
TCP/IP
Linux常见命令
CAP
SOLID
ACID
DDD
理论
基础知识
数据结构与算法
Mybatis
Mybatis Plus
Spring Data Jpa
ORM框架
Spring
SpringMVC
SpringBoot
Spring Security
Spring Framework
Spring Cloud Gateway
Nacos
sentinel
Seata
OpenFeign
Spring Cloud Stream
SkyWalking
Spring Cloud Alibaba
Netty
Shiro
框架
RocketMQ
Kafka
RabbitMQ
MQ
Dubbo
Zookeeper
Nginx
Tomcat
Undertow
Jetty
web容器
Sharding-JDBC
中间件
安装redis
string
hash
set
zset
list
bitmap 布隆过滤器
数据结构
命令
Redis DataBase 快照
内存较大的话会长时间组设
不建议使用
save命令
fork一个子进程
RDB由子进程完成
主进程仍可以写数据
阻塞只在fork阶段
bgsave命令
手动触发
配置 save m n m秒有n次修改
主从复制
debug reload命令
shutdown命令
自动触发bgsave
触发方式
save <seconds> <changes>
save \"\" 关闭RDB
# 如果持久化出错,主进程是否停止写入stop-writes-on-bgsave-error yes
配置
fork一个bgsave子进程
开辟一个临时内存空间存放RDB文件
写时复制Copy-on-Write
RDB完成替换旧的RDB文件
RDB过程
RDB
执行一个命令 把命令追加到aof_buf 缓冲区
命令追加append
将aof_buf 缓冲区的内容写入aof文件(磁盘)
文件写入write
文件同步sync
实现AOF
同步每条命令
Always
每秒
Everysec
由操作系统决定
No
写回策略
# appendonly参数开启AOF持久化appendonly no
# 同步策略# appendfsync alwaysappendfsync everysec# appendfsync no
# 重写触发配置auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb
1. 主进程fork一个bgrewriteaof子进程(会阻塞)
2. 把主进程的内存拷贝一份给bgrewriteaof子进程
6. 主进程把AOF重写缓存区里的命令追加到新的AOF文件
7. 替换旧的AOF文件
后台进程bgrewriteaof完成
旧文件 主进程
新文件 bgrewriteaof进程
一个拷贝,两处日志
AOF重写
AOF
4.0
第一次RDB全量快照
AOF记录两次快照之间产生的命令
RDB与AOF混合
优先AOF
恢复数据
redis持久化
持久化
读
写
采用读写分离模式
在从库 replicaof 主库IP:PORT (5.0)slaveof (5.0之前)
从节点配置 replicaof 172.16.19.3 6379
确立主从关系
从->主 psync ? -1
主->从 FULLRESYNC runID offset
从库清空全部数据
加载RDB
主库发送RDB文件给从库
从库接收
三个阶段
全量复制
增量复制2.8
原理
概念
节点故障 不会恢复
存在问题
主节点自动故障转移
监控 主从节点状态
配置提供者
哨兵可以将故障转移的结果发送给客户端
通知
功能
发布订阅机制
主库有一个__sentinel__:hello的频道
其他哨兵订阅
至少三个且奇数个sentinel节点
哨兵集群搭建
其他哨兵也做出判断
sentinel monitor mymaster 172.16.251.15 9011 2quorum=2
主观下线
哨兵集群共同决定master节点是否下线
客观下线
主库下线判断
Raft选举算法
半数以上赞成票
票数 >=quorum
成为Leader必要条件
哨兵集群选举
salve-priority 优先级最高的
选出新主库
每个哨兵节点每10秒会向主节点和从节点发送info命令获取最拓扑结构图
每个哨兵节点每隔2秒会向redis数据节点的指定频道上发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息,同时每个哨兵节点也会订阅该频道,来了解其它哨兵节点的信息及对主节点的判断
每隔1秒每个哨兵会向主节点、从节点及其余哨兵节点发送一次ping命令做一次心跳检测
定时监控任务
sentinel 哨兵模式
有16384(即2的14次方)个哈希槽
每个key通过CRC16校验后对16383取模来决定放置哪个槽。
哈希槽 Hash Slot
用来将多个(相关的)key分配到相同的hash slot中
计算user1000
{user1000}.following和{user1000}.followers
Keys hash tags
每个节点 会生成一个唯一ID
查看集群状态以及每个节点的信息
d289c575dcbc4bdd2931585fd4339089e461a27d 127.0.0.1:6381 master - 1318428931 1318428931 3 connected 2730-4095
CLUSTER NODES
Gossip协议
cluster meet 新节点ip:端口
redis-trib add node添加
默认添加主节点
添加新节点
数据迁移
扩容
cluster集群模式
集群
缓存和数据库都没有数据
恶意请求
参数校验
IP白名单
解决
缓存穿透
热点key永不过期
加互斥锁?
缓存击穿
大量key同时过期了
缓存雪崩
提前刷新数据库数据到缓存
项目启动时刷新到缓存
留个接口 按钮
缓存预热
淘汰策略
缓存污染(或满了)
把更新缓存的操作交给用户
方式一
使用canal binlog
2. 发送到mq
4. 失败重试
方式二
数据一致性
存在的问题
定期删除
使用时才判断是否过期
惰性删除
key 过期策略
随机
volatile-random
过期时间最小的
volatile-ttl
Least Recently Used 最近最少使用
volatile_lru
Least Frequently Used 最不经常使用
volatile-lfu
volatile
allkeys-random
allkeys-lfu
allkeys-fru
allkeys
不淘汰
no-eviction
内存不足时淘汰策略
缓存
计数
分布式锁
用途
redis集群之间数据同步
Redis
MySQL
MongoDB
ES
canl
数据库
Git
Maven
Docker
Jenkins
K8S
常用工具
设计模式
0 条评论
回复 删除
下一页