导图社区 Java架构师p5-p7进阶之路年薪50-70万
Java架构师p5-p7进阶之路年薪50-70万,数据结构与算法实战,微服务解决方案数据结构模型,JVM虚拟机实战性能调优。并发编程实战,微服务框架源码解读集合框架源码解读,分布式架构解决方案。互联网分布式事务架构设计与实战,分布式消息中间件原理,MySQL实战性能优化,Netty深度源码解读。
编辑于2023-11-21 16:53:38Java架构师p5-p7进阶之路年薪50-70万,数据结构与算法实战,微服务解决方案数据结构模型,JVM虚拟机实战性能调优。并发编程实战,微服务框架源码解读集合框架源码解读,分布式架构解决方案。互联网分布式事务架构设计与实战,分布式消息中间件原理,MySQL实战性能优化,Netty深度源码解读。
干洗店概要设计,干洗店管理系统是一款可以让开干洗店的用户起到全自动化管理的软件。使用这款干洗店管理软件可以让你管理系统化
软考高项-第三章 项目立项管理知识总结,包括信息化和信息系统、可研究性得内容、可行性研究的步骤等等。
社区模板帮助中心,点此进入>>
Java架构师p5-p7进阶之路年薪50-70万,数据结构与算法实战,微服务解决方案数据结构模型,JVM虚拟机实战性能调优。并发编程实战,微服务框架源码解读集合框架源码解读,分布式架构解决方案。互联网分布式事务架构设计与实战,分布式消息中间件原理,MySQL实战性能优化,Netty深度源码解读。
干洗店概要设计,干洗店管理系统是一款可以让开干洗店的用户起到全自动化管理的软件。使用这款干洗店管理软件可以让你管理系统化
软考高项-第三章 项目立项管理知识总结,包括信息化和信息系统、可研究性得内容、可行性研究的步骤等等。
JAVA 架构师进阶之路
数据结构与算法实战
数学知识回顾
指数
对数
级数
模运算
复杂度
时间复杂度
空间复杂度
数据结构
栈模型
先进后出原则
出栈/压栈
栈的应用
队列模型
先进先出原则
顺序队列
链式队列
双端队列
优先队列
树模型
二叉树
AVL树
线索二叉树
红黑树
伸展树
散列模型
散列函数
线性探测法
平方探测法
双散列
散列函数方法
直接定址法
数字分析法
平方取中法
折叠法
除留余数法
随机数法
处理冲突的方法
线性探测再散列
平方探测再散列
堆模型
左式堆
斜堆
算法实战
排序算法
插入排序
希尔排序
堆排序
归并排序
快速排序
冒泡排序
实战算法
贪婪算法
哈夫曼编码
近似装箱问题
分治算法
分治算法的运行时间
最近点问题
选择问题
动态规划
用一个表代替递归
矩阵乘法的顺序安排
最优二叉查找树
所有点对最短路径
随机化算法
随机数发生器
跳跃表
素性测试
微服务解决方案数据结构模型
注册中心集群算法
Nacos集群选举Raft算法
疫情传播算法P2P-Gossip协议
Eureka 消息广播一致性协议
分布式事务一致性协议
强一致性协议
弱一致性协议
最终一致性协议
Zookeeper一致性协议算法
ZAB原子广播协议
Paxos一致性协议
分布式缓存淘汰算法
LRU(最近少使用)缓存淘汰算法
LFU(最不经常使用算法)缓存淘汰算法
ARC(自适应缓存替换算法)缓存淘汰算法
FIFO(先进先出算法)缓存淘汰算法
MRU(最近最常使用算法)缓存淘汰算法
分布式缓存击穿协议
布隆过滤器
布谷鸟过滤器
负载均衡算法
轮询机制算法
随机算法
固定ip算法
权重算法
微服务限流算法
计数器(固定窗口)算法
滑动窗口算法
漏桶算法
令牌桶算法
分布式计算任务调度算法(xxl-job)
轮转法
加权法
散列法
最少连接法
最低缺失法
最快响应法
遗传算法
蚁群算法求解
分布式数据同步一致性协议
MySQL
半同步复制
异步复制
全局同步
缓存
canal
otter
(openresty/tengine)实战高并发
原生Nginx核心模块
Nginx模块类型
标准Http模块
可选Http模块
第三方模块(lua)
Nginx 事件驱动模型及特性
Nginx核心配置
虚拟主机配置
upstream
location
静态目录配置
https协议配置
Nginx负载均衡算法配置
轮询机制算法
随机算法
固定ip算法
权重算法
openresty/tengine
openresty结合lua实现亿级商品详情页面
Tengine是由阿里Web服务器项目
JVM虚拟机实战性能调优
编程语言发展历程
汇编语言/机器语言
C/C++语言
java/php/易语言/ython
JVM类加载器ClassLoader
从HotSpot虚拟机(C++)源码分析类加载器实现原理
什么是类加载器
将我们的class文件读取到内存中
类加载器的分类
启动(Bootstrap)类加载器(C++编写的)
$JAVA_HOME/jre/lib
扩展(Extension)类加载器(Java编写的)
JAVA_HOME/jre/lib/ext
(应用)AppClassLoader 类加载器(Java编写的)
classpath下的class及jar包
自定义类加载器(java编写的)
自定义class文件目录
双亲委派机制机制的好处
目的就是为了防御开发者为定义的类与jdk定义源码类产生冲突问题,保证该类在内存中的唯一性。
类加载器双亲委派原则及如何打破
spi机制
启动类/扩展/应用类加载器深度源码解析
Java SPIService Provider Interface 原理
Tomcat/Jetty类加载器实现原理
如何自定义一个类加载器加载字节码与手写热部署插件
本地磁盘
网络获取
数据库
动态代理生成
war/jar
JVM内存结构原理分析
JVM运行时区
程序计数器
记录当前线程执行代码的行号,方便下次cpu上下文切换恢复执行的位置
堆
new 对象存放在堆中(线程共享)
生产环境排查堆内存泄漏
内存泄漏
什么是堆内存泄漏
堆内存申请空间,GC无法释放该内存
内存泄漏发生的场景
threadlocal内存泄漏
hashMap自定义key对象内存泄漏
生产环境排查堆内存泄漏
Jps/Jmap
Jvisualvm /jconsole
内存溢出
什么是堆内存溢出
向堆内存申请空间时,没有足够的空间
堆内存溢出
内存中加载的数据量过于庞大,如一次从数据库取出过多数据
集合类中有对对象的引用,使用完后未清空,使得JVM不能回收
代码中存在死循环或循环产生过多重复的对象实体
启动参数内存值设定堆内存的过小
内存溢出解决办法
加大堆内存
堆内存结构细节
堆结构划分
新生代/老年代
新生代
刚new出对象存放在新生代
老年代
经常被使用的对象存放老年代
JDK版本
jdk1.7
eden(伊甸园)+from(s0)+to(s1)+永久代(方法区)
jdk1.8
eden(伊甸园)+from(s0)+to(s1)+永久代(元空间)
特性:
默认新生代与老年代比例1:2
-XX:NewRatio
默认伊甸园与s0/s1 8:1:1
-XX:SurvivorRatio
常见单词
YoungGen(新生代)
oldGen(老年代)
s0(from)
s1(to)
PermGen(永久代)
Metaspace(元空间)
GC的分类
部分收集
新生代收集(Minor GC/Young GC)
老年代收集(Major GC/Old GC)
CMS GC会有单独收集老年代的行为
堆和方法区收集
(Full GC):收集整个java堆和方法区(元空间)的垃圾收集
常见面试题
full gc 与Minor GC/Young GC区别
full gc 会触发新生代和老年代回收
Minor GC 触发新生代 gc回收
Minor GC 回收次数非常频繁
full gc 当老年代或者方法区(元空间)内存不足触发回收
full gc的gc回收效率非常低
尽量不要触发full gc回收
大对象存放在哪里?
如果eden区不能存下,则直接存入晋升老年代
GC日志的分析
内存逃逸
空间担保
线程栈及栈帧内部结构分析
局部变量表
操作数栈
动态连接
方法出口
本地方法栈(JNI调用C代码)技术
字符串常量池
常量池分类
静态常量池
运行常量池
字符串常量池
常量池到不同JDK版本存放区域
JDK1.6及之前字符串常量池存放在方法区(永久代)中
JDK1.7中字符串常量池开始存放堆中
JDK1.8中字符串常量池存放堆中
常见的String面试题
为什么JDK1.7开始字符串常量池改为存放堆中
JDK7中将字符串常量池放到了堆空间中。因为永久代的回收效率很低,在Full GC的时候才会执行永久代的垃圾回收,而Full GC是老年代的空间不足、永久代不足时才会触发。
这就导致字符串常量池回收效率不高,而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。
String s1 = "mayikt";
String s1 = "mayikt"; s1 指向字符串常量池
new String("mayikt");
在堆中创建一个堆空间地址返回给s2 s2 获取到是 堆内存地址,在String类中 mayikt引入 字符串常量池
JVM对象内存布局
对象的布局的
对象头
实例数据
对齐填充
new一个对象到底占多少字节
对象的访问定位
句柄方式
Java堆中将可能会划分出一块内存来作为句柄池,局部变量中reference中存储的就是对象的句柄地址
直接指针方式
reference中存储的直接就是对象地址
对象创建的方式
1.new对象
2.使用反射创建对象
3.使用clone()克隆对象
4.使用反序列化对象
5.第三方库 Objenesls创建对象
创建对象的细节内容
1.检查该对象的类是否已被加载、解析和初始化过
1.当Java虚拟机遇到一条字节码new指令时,首先将去检查这个指令的参数是否能在(元空间中)常量池中定位到该类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过(判断该类是否被元空间加载过)
如果没有,那必须先执行相应的类加载过程(则使用双亲委派机制 查找该类(类的全路径),如果没有查询到则报错:ClassNotFoundException)。
2.在类加载检查通过后,接下来虚拟机将为新生对象分配内存
如果堆内存规整则使用
指针碰撞
如果堆内存不规整则使用
空闲列表
3.对象创建在虚拟机中是非常频繁的行为,即使仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的
1.采用CAS+失败重试保证更新的原子性;
2.为每个线程在eden(伊甸园区)分配一块 当前线程独有的TLAB空间
4.属性设置默认值,内存分配完成之后,虚拟机必须将分配到的内存空间(但不包括对象头)都初始化为零值,如果使用了TLAB的话,这一项工作也可以提前至TLAB分配时顺便进行。这步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,使程序能访问到这些字段的数据类型所对应的零值。
5.设置对象头信息,Java虚拟机还要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码(实际上对象的哈希码会延后到真正调用Object::hashCode()方法时才计算)、对象的GC分代年龄等信息。这些信息存放在对象的对象头(Object Header)之中。根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。
6.执行init方法进行初始化
JVM垃圾回收算法
垃圾收集算法
标记清除算法
优点:效率高/不移动内存地址
缺点:容易产生碎片化
标记整理算法
优点:避免碎片化问题
缺点:移动内存地址,效率低
标记复制算法
优点:避免碎片化问题
缺点:移动内存地址,效率高
分代算法原理
新生代
老年代
JDK1.0-14收集器
垃圾收集器组合
(新生代并行)ParNew(老年代串行)Serial old
(新生代串行)Serial、(老年代)Serial old
(新生代串行)Serial/CMS(老年代并发)
(JDK9废弃)
(新生代并行)ParNew/CMS(老年代并发)
(JDK9不推荐)
(新生代并行)Parallel/SerialOld(老年代串行)
不推荐
(新生代并行)Parallel Scavenge/Parallel Old(老年代并行)
JDK8默认
G1(JDK9默认) 整堆收集
JDK8默认
串行(单个GC线程回收)
Serial垃圾收集器详解
组合
新生代(Serial)-标记复制算法
老年代(Serial old)-标记压缩算法
应用场景
使用单核cpu、小内存
并行(多个GC线程回收)
ParNew垃圾收集器详解
应用场景
新生代
适合于多核cpu
组合
(老年代)Serial old(标记压缩算法)
(老年代)CMS(标记清除算法)
Parallel垃圾收集器详解
应用场景
新生代/老年代 多个GC同时回收
组合
Parallel
Parallel oldGC
并发(GC与用户线程同时执行)
CMS垃圾收集器原理(重点)
实现原理
初始标记
并发标记
重新标记
并发清除
CMS收集器有那些缺点
标记清除算法引发碎片化问题
备选方案SerialOld效率低
基于增量更新方式解决漏标问题
G1收集器原理(重点)
实现原理
n多个不同region
Region记忆集(Remember Set)
卡表(Cardtable)详解
基于原始快照(satb)解决楼标问题
ZGC垃圾收集器详解
Epsilon与Shenandoah垃圾收集器详解
垃圾复制算法
垃圾回收机制三色标记算法原理
三色标记算法产生的多标/漏标问题
浮动垃圾
漏标问题
对象漏标解决方案
基于增量更新方式(CMS)
基于原始快照方式satb(G1)
Region记忆集(Remember Set)与卡表(Cardtable)详解
stop the world
为什么会发生stop the world问题
如何避免stop the world问题
JVM调优工具详解
JDK自带Jstat、Jinfo、Jmap、Jhat及Jstack调优命令详解
Jvisualvm、Jconsole调优工具详解
阿里工具arthas使用详解
GC日志分析工具
如何阅读GC日志详细信息
GCEasy日志分析工具使用
GCViewer日志分析工具使用
JVM参数调优实战
亿级流量项目堆内存年轻代与老年代垃圾回收参数设置与调优
线上生产环境OMM内存溢出监控工具及定位解决方案
线上生产环境如何减少严重Full GC导致系统直接卡死的优化实战
高并发系统,线上生产环境如何避免频繁GC操作
高并发系统,如何优化G1/CMS收集器
日均百万PV服务如何设置JVM堆初始内存大小
并发编程实战
操作系统基础
用户态与内核态切换过程
linux进程模型管理
linux进程间通信原理
linux网络通讯原理
多线程基础
多线程快速入门
什么是进程/线程
进程是资源分配最小单位
线程是程序执行的最小单位
多线程应用场景
客户端(移动App端/)开发
异步发送短信/发送邮件
将执行比较耗时的代码改用多线程异步执行
异步写入日志
多线程下载
多线程与单线程之间的区别
多线程(并行执行)
单线程(同步执行)
如何理解多线程cpu切换概念
当前cpu切换执行另外线程
多线程真的开的越多越好吗
不一定,开多了线程容易发生cpu的上下文切换
用户线程与守护线程的区别
如何优雅的停止一个线程
多线程七种状态分析
初始状态
就绪状态
运行状态
<font face="宋体"><span style="font-size: 14px;">死亡状态</span></font><br>
阻塞状态
超时等待
等待状态
创建多线程五种方式
继承Thread类创建线程
实现Runnable接口创建线程
使用Callable和Future创建线程
使用线程池例如用Executor框架
使用@Async异步注解创建线程
使用lambda表达式创建线程
多线程线程安全
什么是线程安全问题
多线程同时对同一个全局变量做写的操作,可能会受到其他<br>线程的干扰,就会发生线程安全性问题
lock与Synchronized锁区别
lock手动获取锁与释放锁
Synchronized自动获取锁与释放锁
SynchronizedJDK6开始自动锁的升级过程
lock锁底层基于aqs锁实现需要自己手动实现锁的升级
多线程死锁的问题
多线程如何排查死锁的现象
jconsole.exe诊断死锁
多线程死锁线程产生的原因
同步中嵌套同步
如何解决线程安全问题(如何保证线程同步)
Synchronized解决线程安全问题
synchronized同步代码快
synchronized 修饰实例方法
synchronized 修饰静态方法
Lock锁解决线程安全问题
多线程之间通讯
wait和notify
wait释放当前锁,阻塞当前线程
notify唤醒正在阻塞的线程
join方法的原理
底层基于wait封装
synchronized原理
一个对象是如何组成的
对象头
Mark Word
哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳
Klass Pointer<br>
实例数据
成员属性
对齐填充
对象的大小必须是8字节的整数倍,不是8字节整数倍则对齐填充
Synchronized锁的升级过程
偏向锁
加锁和解锁不需要额外的开销,只适合于同一个线程访问同步代码块,无需额外的开销,如果多个线程同时竞争的时候,会撤销该锁
轻量锁
竞争的线程不会阻塞,提高了程序响应速度,如果始终得不到锁的竞争线程,则使用自旋的形式,消耗cpu资源,适合于同步代码块执行非常快的情况下,自旋(jdk1.7以后智能自转)
重量锁
线程的竞争不会使用自旋,不会消耗cpu资源,适合于同步代码执行比较长的时间。
Synchronized锁膨胀过程原理分析
偏向锁(101)
1.当前线程从对象头中markword获取是否是为偏向锁,如果是为偏向锁,则判断线程的id===当前线程id
2.如果等于当前的线程id,则不会重复的执行CAS操作,而是直接进入到我们的同步代码快
3.如果不等于当前的线程id 如果是为无锁的情况,没有其他的线程与我竞争的话,直接使用CAS修改markword中锁的标识位状态为101同时也存放当前线程的id在markword中
4.其他的线程与偏向锁线程开始竞争,撤销偏向锁次数达到了20次,则后面开始直接批量重偏向T2线程(注意事项:没有其他的线程与t2做竞争),如果撤销偏向锁次数达到了40次,则后面开始批量撤销
5.撤销偏向锁需要在一个全局的安全点 停止我们偏向锁线程,在修改我们markword中为轻量级锁,在唤醒偏向锁的线程
6.注意:JDK15 默认关闭偏向锁优化原因
轻量锁(000)
1.多个线程同时竞争同一把锁,则升级过轻量锁 使用CAS(修改markword 锁的状态=00)如果成功,则与markword 替换 将HashCode值等 直接存放在我们的栈帧中,而当前markword 中存放锁记录地址
2.当我们使用轻量级锁释放锁时,则还原markword 值内容
重量级(010)(C++Monitor)
1.当前我们的线程重试了多次还是没有获取到锁,则当前锁会升级为重量级锁
2.2.没有获取到锁的线程 会存放在C++Monitor对象 EntryList 集合中 同时当前线程会直接阻塞释放了cpu执行权,在后期唤醒从新进入竞争锁的流程成本是非常高的,因为需要发生cpu上下文切换 用户态到内核切换 改我们对象头中markword 值为C++Monitor 内存地址指针Java对象与C++Monitor关联起来
C++Monitor监视器锁(重量级锁)
Monitor(对象重量级锁)
recursions(递归次数/重入次数)
owner(记录当前持有锁的线程ID)
waitSet(等待池处于wait状态的线程,会被加入到_WaitSet)
entryList(锁池:处于等待锁block状态的线程,会被加入到该列表)
等待池中的线程被唤醒,会立即获取到锁吗
等待池的线程被唤醒之后 等待池转移到锁池排队从新竞争锁
锁的粗化、与消除及性能优化
锁的粗化
每个线程持有锁的时间尽可能短
锁的消除
锁消除是发生在编译器级别的一种锁优化方式
volatile关键字原理
关键字特性
保证可见性
禁止重排序
不保证原子性
java内存模型
CPU多核硬件架构剖析
jmm八大同步的规范
Volatile缓存一致性协议
总线锁
MESI协议
伪共享的问题
缓存行基本的概念
存行填充方案
重排序/内存屏障/双重检验锁为什么需要加上volatile
synchronized 与volatile存在的区别
为什么Volatile不能保证原子性
并发锁的分类
悲观锁
乐观锁
自旋锁
重入锁
公平锁
非公平锁
aqs源码解读
LockSupport源码解读
AbstractQueuedSynchronizer源码解读
ReentrantLock/ReentrantReadWriteLock、ReadWriteLock源码解读
Semaphore/CountDownLatch/CyclicBarrie源码解读
AQS底层如何实现
A.Cas 保证AQS的线程安全问题
B.双向链表 存放阻塞的线程
C.LockSupport 阻塞和唤醒线程
核心属性
State 状态值
Node 状态(waitStatus)
-2 当前线程阻塞同时释放锁
-1 唤醒后续节点的线程<br>
AQS应用场景
lock锁底层实现
公平锁与非公平锁
默认的情况下是为非公平锁
竞争锁时
公平锁:在竞争锁时如果这把锁已经被其他的线程持有则直接存放在双向链表的尾部
非公平锁:在竞争锁时,如果这把锁已经被其他线程持有还是会继续CAS尝试一次
核心设计原理
lock方法()
使用CAS修改AQS类中的状态值从0,改成为1
改成功的话(获取锁成功)
改失败的话(获取锁失败)
存放AQS双向链表中
unlock方法()
使用CAS修改AQS类中的状态从0,改成为1
CAS成功的话
需要唤醒AQS双向链表中头节点的下一个node节点缓存的线程
疑问:为什么unlock释放锁,只唤醒一个线程而不是多个线程呢?
底层采用双向链表存放阻塞的线程,如果唤醒所有的线程成本是非常高
lock锁中没有锁的升级过程的,需要开发者自己扩展
ConcurrentHashMap1.7源码底层Lock
Condition
注意事项:Condition与lock不是使用同一个双向链表
锁池与等待池
锁池:指的就是lock锁中 竞争锁失败的线程 存放AQS双向链表中
等待池:指的就是当前线程调用await方法,主动释放锁(aqs状态值=0),存放等待池双向链表中
如何唤醒等待池中的线程呢?
调用该signal()只是将等待池中node节点(线程)转移存放到AQS双向链表锁池中从新竞争锁的资源
调用该signal()在调用unlock方法之后,唤醒锁池中的线程开始竞争锁资源
CountDownLatch(计数器)
通过构造函数new CountDownLatch(1)
底层基于AQS实现给AQS类中的状态值设置为1
await方法
将当前线程阻塞存放在AQS双向链表中
countDown
对AQS类中的状态值-1操作 如果AQS状态改为0的话 则唤醒AQS类中双向链表存放的线程
Semaphore(信号量)
通过构造函数 new Semaphore(3)
底层基于AQS实现给AQS类中的状态值设置为3
acquire 底层在修改AQS类中的状态值-1的操作,如果AQS类中状态值改为0之后当前线程需要阻塞,存放在AQS类中双向链表中
release底层对AQS类中的状态+1操作<br>
同时唤醒AQS类中阻塞线程(只会唤醒一个)
CyclicBarrier(同步屏障)
通过 构造函数 new CyclicBarrier(2)<br>
底层给CyclicBarrier count属性赋值=2
调用await底层
对CyclicBarrier count-1操作
count=0
继续执行同时 唤醒等待池中所有的线程
count!=0
存放在等待池中
并发atomic原子操作
Atomic原子类
CAS(乐观锁)原理
Unsafe魔法类详解
阻塞队列BlockingQueue原理
阻塞队列分类
ArrayBlockingQueue 数组有界队列
ConcurrentLinkedQueue 链表有界队列
PriorityBlockingQueue 优先级排序无界队列
DelayQueue 延时无界队列
框架应用
基于BlockingQueue手写线程池
基于BlockingQueue手写消息中间件
基于BlockingQueue手写日志框架
Executor线程池详解及核心源码剖析
为什么要使用线程池
复用性
统一管理
提高响应
线程池四种创建方式
newCachedThreadPool(); 可缓存线程池
newFixedThreadPool();可定长度 限制最大线程数
newScheduledThreadPool() ; 可定时
newSingleThreadExecutor(); 单例
真实底层都是基于 ThreadPoolExecutor 构造函数封装 线程池
线程池核心原理分析
LinkedBlockingQueue
生产者与消费者模型
为什么阿里不建议使用Executors
底层使用LinkedBlockingQueue无界队列容易内存溢出
线程池队列满了怎么办
拒绝策略
AbortPolicy 丢弃任务,抛运行时异常
CallerRunsPolicy 执行任务
DiscardPolicy 忽视,什么都不会发生
DiscardOldestPolicy 从队列中踢出最先进入队列
实现RejectedExecutionHandler接口,可自定义处理器
线程池参数如何合理配置
CPU密集型
最佳线程数=cpu核数或者cpu核数±1
密集型型
最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目
如何基于ThreadPoolExecutor自定义线程池
FutureTask源码解读
基于LockSupport实现FutureTask
基于Wait/Notify实现FutureTask
ForkJoin源码解读
并发编程发展
工作窃取机制
Fork Join原理
Threadlocal源码解读
什么是Threadlocal
Threadlocal应用场景
1.Spring事务模板类
2.获取httprequest
3.Aop调用链传递参数
Threadlocal与Synchronized区别
如何防御Threadlocal内存泄漏问题
1.调用remove方法
2.set方法的时候会清除之前 key为null
微服务框架源码解读
SpringBoot源码解读
SpringBoot自动配置运作原理
SpringBoot核心模块源码解读
SpringBoot核心注解源码解读
SpringBoot内嵌Servlet容器源码解读
SpringBoot打包部署与运维管理
Servlet容器如何过度webflux
SpringCloudNetfilix(第一代)核心组件源码解读
Eureka服务注册与发现源码解读
Eureka服务续约(心跳)
Eureka服务器端服务剔除
Eureka服务自我保护机制
如果服务真的宕机了怎么办?
本地服务采用重试机制
本地服务实现地址故障转移
Eureka服务下线通知
Eureka集群数据同步
Fegin 声明式服务调用源码解读
Hystrix实现服务限流,降级,熔断源码解读
Zuul统一网关详解,服务路由,过滤器源码解读
Config分布式配置中心源码解读
Sleuth分布式链路跟踪源码解读
Ribbon 客户端负载均衡详解及源码分析
SpringCloudAlibaba(第二代)源码解读
Nacos 分布式注册中心源码解读
服务注册与发现
Nacos服务注册与发现源码解读
服务注册原理
eurekaClient端
使用jerseyClient发送请求注册
eurekaServer端
使用ConcurrentHashMap缓存接口地址
key为服务名称
value为缓存接口地址
Naocs服务心跳检测与续约源码解读
EurekaClient端默认每隔30s发送心跳续约包延长时间,告诉EurekaServer我还在存活
EurekaServer端默认每隔60s查找缓存地址中的过期地址,存放到一个新集合中 使用随机算法清除
Naocs服务下线与健康检查源码解读
Nacos集群Raft选举算法源码解读
Nacos服务端长轮询处理机制
Nacos集群节点之间数据同步原理
Nacos中AP模式源码解读
Nacos中CP模式源码解读
Nacos集群脑裂解决方案
分布式配置中心
Nacos分布式配置中心实现原理
Nacos如何实现动态刷新配置文件
Gateway 新一代微服务网关源码解读
为什么Gateway性能比Zuul性能要强
Gateway动态路由源码分析
指定时间规则匹配路由
cookie匹配路由
Header匹配路由
Host匹配路由
请求方法匹配路由
请求路径匹配路由
Gateway过滤器源码分析
自定义GatewayFilter
Gateway集成Nacos实现负载均衡
Gateway集成Sentinel实现网关限流
Seata分布式事务框架源码解读
Seata解决分布式事务三大核心组件源码解读
Seata基于undo_log表逆向生成sql语句回滚源码解读
Seata分支事务全局锁设计源码解读
GlobalTransactionalInterceptor源码解读
TM如何远程连接TC获取全局事务id源码解读
Seata前置和后置镜像源码深度源码解读
Seata与LCN回滚之间的存在那些区别
Canal分布式数据同步框架源码解读
Canal整体架构源码解读
MySQL主从复制原理架构分析
Canal如何伪装从节点订阅BinLog文件
EventParser与EventSink设计原理
Canal增量订阅/消费设计原理
Canal高并发数据同步性能优化
如何降低数据之间同步的延迟
如何避免数据同步消息顺序一致性
如何避免数据同步丢失问题
Sentinel
服务隔离
限流算法
令牌桶
漏桶
基于信号量Semaphore实现
固定计数窗口
滑动技术窗口
流控规则
线程数
基于信号量Semaphore实现
QPS
令牌桶
Hystrix
流控规则
信号量隔离
在Sentinel
QPS
令牌桶
线程池隔离
缺陷消耗cpu资源
限流方式
谷歌Guava(RateLimiter)
阿里巴巴 Sentinel
Nginx
Redis+lua实现限流
推荐限流是在nginx或者网关做
集合框架源码解读
Hash(散列函数)Map集合框架源码解读
基础知识
==与equals之间区别与底层实现
为什么重写equals还要重写hashcode
二进制与十进制转换/^(异或运算)/>>>(无符号右移)/ &(与运算)
底层实现方式
JDK1.7
数组+链表
头插入方式(并发扩容死循环问题)
代码写法简单
JDK1.8
数组+链表+红黑树
尾插入方式
代码写法高大上
红黑树转换
(数组容量>=64 &链表长度大于8)
红黑树节点个数<6转换链表
Hash函数计算
(h = key.hashCode()) ^ (h >>> 16)
i = (n - 1) & hash
时间复杂度
Key没有产生冲突
时间复杂度则为O(1)
Key产生冲突
链表存放则为O(N)
红黑树存放则为O(LogN)
hashcode碰撞问题
hashcode值相同,内容值不等
特点:
key为null存放数组0位置
采用单向链表实现
无序散列存放
性能优化
HashMap如何避免内存泄露问题
HashMap如何降低Hash冲突概率
HashMap如何合理指定集合初始值大小
HashMap常见面试题
为什么重写Equals还要重写HashCode方法
HashMap如何避免内存泄漏问题
HashMap1.7底层是如何实现的
HashMapKey为null存放在什么位置
HashMap1.7底层是如何实现的
HashMapKey为null存放在什么位置
HashMap如何解决Hash冲突问题
HashMap如何实现数组扩容问题
HashMap底层采用单链表还是双链表
HashMap根据key查询的时间复杂度
HashMap1.7与1.8有那些区别?
HashMap1.8如何避免多线程扩容死循环问题
为什么HashMap1.8需要引入红黑树
为什么加载因子是0.75而不是1
HashMap底层如何降低Hash冲突概率
HashMap如何存放1万条key效率最高
HashMap高低位与取模运算有那些好处
为什么不直接将key作为哈希值而是与高16位做异或运算?
HashMap中hash函数是怎么实现的?
HashMap底层是有序存放的吗?<br>
LinkedHashMap 和 TreeMap底层如何实现有序的
如何在高并发的情况下使用HashMap
ConcurrentHashMap底层实现的原理
ConcurrentHashMap集合框架源码解读
基础知识
synchronized与lock锁
如何理解分段锁概念
CAS算法和volatile
底层实现
JDK1.7
数据结构
数组+Segments分段锁+HashEntry链表实现
锁的实现
Lock锁+CAS乐观锁+UNSAFE类
扩容实现
支持多个Segment同时扩容
Jdk1.8
数据结构
直接使用Node数组来保存数据
数组+链表+红黑树
锁的实现
取消segment分段设计
index没有发生冲突使用cas锁
index发生冲突使用synchronized
扩容实现
支持并发扩容
特点:支持多线程效率高、默认分成16个Segments
特点:
ConcurrentHashMap 不支持key为null
List集合源码分析
Arraylist底层实现
数据结构
数组
时间复杂度
下标查询时间复杂度o(1)
扩容
扩容是原来1.5倍
线程不安全
优缺点
增删效率低需要扩容,查询效率比较高
Vector底层实现
数据结构
数组
时间复杂度
下标查询时间复杂度o(1)
扩容
扩容是原来2倍
线程安全
LinkedList底层实现
基于链表数据结构,下标查询时间复杂度()
数据结构
链表
时间复杂度
下标查询时间复杂度log2(n) 二分查找
线程不安全
优缺点
增删改效率高,查询效率比较低
分布式架构解决方案
互联网微服务幂等架构设计与实战
什么是幂等设计?幂等产生背景
客户端响应超时
业务执行时间非常长的情况下建议改用mq异步
重试策
解决服务接口幂等问题核心原因
数据库层面
从架构层面分析幂等产生的原因
网关层
接口层
根据全局id提前查询该业务逻辑是否有执行过
DB层
insert类型 唯一注解约束
update类型 乐观锁机制
全局id真的保证接口幂等性吗?
不一定,需要考虑数据库层面
如何保证RPC接口幂等性问题
全局id
锁的机制(不推荐效率执行比较低)
根据真实业务场景实现幂等设计
互联网分布式锁架构设计与实战
什么场景使用分布式锁
保证定时任务调度幂等性问题
保证秒杀抢购防止超卖的问题
分布锁本质实现原理
重试策略
适合于业务执行非常快
超时控制
续命设计
续命如何避免死锁问题
性能优化
考虑羊群效应的问题
高可用
设置阻塞超时时间
锁的粒度降低
公平性
分布式锁兼容性测试与恢复设计
分布式锁实现方案
Zookeeper实现分布式锁(CP模式)
核心思想
临时节点
路径唯一性
watcher事件
特点
采用cp模式
优点
先天性解决脑裂问题(过半机制)
更加可靠稳定
缺点
集群同步数据效率偏低
性能偏低
两种实现方式
基于同一个临时节点实现
有可能会发生羊群效应问题
基于临时顺序节点实现
避免羊群效应问题
临时顺序编号节点
当前节点是最小的节点就表示获取锁成功
如果当前节点不是最小节点的情况下,订阅上一个节点
Curator框架分布式锁
获取锁
基于临时顺序编号节点实现
创建临时顺序节点,谁最小谁就获取锁
阻塞
当前自己创建临时顺序节点不是最小,订阅上一个节点
释放锁
删除该临时顺序编号节点
面试难点
如何zk主节点宕机,有那些影响
zk从新发生选举,整个zk环境短暂无法使用
需要考虑zab协议
先比较zxid,在比较myid
如何避免zk客户端死锁的问题
zkserver端宕机
zk客户端设置阻塞超时时间
通过监听zk宕机之后,主动被唤醒
zk客户端宕机
zk先天性特性避免死锁问题 主动释放锁
其他zk客户端设置阻塞超时时间
获取到锁的jvm 一直不释放锁
控制续命次数,续命多次主动释放锁 事务随着回滚
Redis实现分布式锁(AP模式)
核心思想
Setnx实现分布式锁
获取锁
多个jvm同时setnx 最终只有一个jvm成功
释放锁
删除该key
特点
采用AP模式
优点
支撑高并发
效率还可以
采用异步同步数据方式
缺点
先天性存在脑裂问题(Redis集群没有过半机制)
稳定性不是很强
redis先天性单线能够保证setnx线程安全性问题
Redisson框架
获取锁
使用lua脚本创建hash key
释放锁
删除该key
续命设计
默认每隔10s 看门狗线程 实现续命防止key过期
面试难点
如何避免客户端死锁问题
设置过期key
限制续命次数
回滚事务
key过期了,但是业务还没有执行完毕如何处理
续命设计
全局续命(不推荐)
增量续命(推荐)
默认每隔10s提前续命 防止key过期
续命多次为了死锁问题 限制续命次数
回滚事务
主动释放锁
redis集群,主节点宕机了如何处理?<br>
使用RedLock红锁算法
redis集群没有主从之分
客户端对多个redis服务器满足过半setnx 获取锁成功
如果客户端设获取锁总耗时时间>key过期时间,自动释放锁
该算法实际上就是借鉴ZK实现分布式锁
互联网分布式事务架构设计与实战
分布式事务产生的背景
单体项目多数据源
jta+ Atomikos解决分布式事务
RPC远程调用接口
分布式事务一致性协议
强一致性协议
集群中,每台节点副本数据必须要一致
弱一致性协议
集群中,允许部分节点副本数据不一致
最终一致性协议
短暂数据延迟允许,但是最终需要数据一致性
分布式事务设计思想
Base与CAP理论
Base理论
基本可用<br>
软状态
最终一致性
CAP
基本理论
一致性(C)
集群中,每台节点副本数据必须要一致
可用性(A)
在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求
分区容错性(P)
分区容错性(P)主要代表网络波动产生的错误,这是不可避免的,且这个三个模式不可兼得,所以目前就只有两种模式:CP和AP模式
模式选择
CP(保证数据一致性)
不能保证可用性
Ap(保证可用性)
但是不能保证每个副本数据数据一致性<br>
对比分析
Nacos
Nacos从1.0版本开始支持CP/AP混合模式集群 默认的情况下 Ap模式
Eureka
Ap模式
Zookeeper
Cp模式
注册中心推荐为Ap模式
柔性与刚性事务
刚性事务满足ACID理论
柔性事务满足BASE理论(基本可用,最终一致)
2PC/3PC/TCC<br>
分布式事务解决框架
LCN解决分布式事务难题
Seata解决分布式事务难题
MQ解决分布式事务难题
TCC解决分布式事务难题
重试回调方式解决分布式事务难题<br>
互联网分布式任务调度架构设计与实战
传统定时任务缺点
消耗cpu资源
非解耦影响业务逻辑
分布式任务调度核心设计思想
日志可追溯
弹性扩容缩容
支持并行调度
高可用策略
失败处理策略
动态分片策略
分布式任务调度框架
XXLJob源码解读
ElasticJob源码解读
mysql与Redis数据一致性协议
解决方案
1.更新mysql数据,在手动清除Redis缓存
优点:延迟低
缺点:不解耦
2.更新mysql数据,在采用mq异步的形式 同步数据到Redis中
优点:实现解耦、重试补偿策略、提高接口响应
缺点:延迟高
3.基于订阅MySQLBinLog结合mq异步的形式将数据同步到Redis中(canal框架实现)
优点:更加解耦、重试补偿策略、提高接口响应
缺点:延迟越来越高
核心设计思想
最终一致性思想,短暂数据不一致性是允许的,最终数据一定要一致性
双写一致性协议原理
先删除缓存,在更新db(不推荐)
需要延迟双删,删除两次
第一次先删除缓存
第二次避免其他线程并发情况下,将脏读数据同步到Redis中,所以延迟几秒(第二个线程业务更新老数据到Redis时间)删除缓存
先更新db,在删除缓存
需要结合mq且 确保消息顺序一致性,删除缓存 一定成功
双写一致性协议
什么是双写
先更新db、在更新缓存
会产生哪些问题
在并发的情况下,多个线程同时写 可能另外线程会将脏读数据写入缓存中
如何解决脏读
使用mysql 事务行锁机制,多个线程同时写操作,最终只有一个线程获取到行锁,获取到行锁之后 必须同步Redis成功,才可以释放行锁 另外线程才可以写
使用分布式锁实现(不推荐,可以直接基于mysql行锁实现)
canal框架设计原理
canal解决mysql与Redis数据同步原理
1.canal伪装成mysql从节点 订阅mysql主节点的binlog文件;
2.当我们的mysql主节点binlog文件发生了变化,则将该binlog文件<br>发送给canal服务器端;
3.canal服务器端将该binlog文件二进制转化成json格式给canal客户端;
4.canal客户端在将该数据同步到Redis/ES;
canal的同步模式
tcp(效率低)
kafka(推荐)
如何提高canal整合kafka同步数据效率
整合MQ主题模式
单topic单分区(全局binlog严格顺序)
多topic单分区,可以保证表级别的顺序性
相同表名称落地到同一个分区中,最终被同一个消费者消费
单topic、多topic的多分区结合hash模式
如何解决消息顺序一致性问题
设定多个分区,根据表中的字段例如 主键id 计算hash 相同的 id落地到同一个分区中,在被同一个消费者消费。
mysql与redis同步数据是否存在延迟呢
数据同步过程中,会存在短暂的延迟,这属于正常的现象。很难做到强一致性,遵循最终一致性思想。
分布式消息中间件原理
MQ基础概念模型
同步与异步
流量削峰
扩展性/解耦
缓冲/可恢复性
生产者与消费者
MQ常见解决方案
MQ如何避免消息堆积
提高消费者速率(集群)
消费者批量获取消息
MQ如何避免消费者重复消费(幂等问题)
全局id+业务场景保证唯一性
MQ如何保证消息不丢失
消息确认机制
持久化
消息ack
MQ如何保证消息顺序一致性
绑定同一个消费者和队列
MQ推与拉取架构模型
生产者如何获取消费结果
异步返回一个全局id,前端使用ajax定时主动查询
主流MQ框架
Rabbitmq
架构思想
Rabbitmq管理平台中心
Virtual Hosts
分团队开发路径存放消息队列
Exchange
路由分发消息
路由key
RabitMQ队列模型
simple模式<br>
work 模式
广播模式---fanout
路由模式--direct
主题模式--topic
RabitMQ四种交换机类型
Direct exchange(直连交换机)
Fanout exchange(扇型交换机)
Topic exchange(主题交换机)
Headers exchange(头交换机)
RabbitMQ常见面试题
RabbitMQ如何保证消息不丢失
生产者
确保生产者投递消息到MQ服务器端成功
Ack 消息确认机制(Confirms)
同步或者异步的形式
事务消息
消费者
消费手动签收模式
自动签收(不推荐)
手动签收(推荐)
MQ服务器端消息持久化
RabbitMQ死信队列
消息投递到MQ中存放 消息已经过期
队列容器已经满了
消费者消费多次消息失败,就会转移存放到死信队列中
RabbitMQ消息自动重试机制
重试多次还是失败,如何处理
转移到死信队列中
记录到日志表中定时补偿或者人工补偿
如何避免消费者幂等问题呢?
全局id+业务场景保证唯一性
Kafka
Kafka核心架构设计模型
Broker(MQ服务器端)
Topic(主题根据业务分类)
Partiiton(分区存储消息)
Producer(生产者)
Consumer(消费者)
Consumer Group(消费者组)
Replica(副本机制)
Offset(消费记录)
为什么kafka能够支撑高并发
存储结构层面
消息会实现压缩,减少带宽传输
kafka分区partition存储结构模型
.log存储消息文件
.index存储消息的索引
.timeIndex,时间索引文件
分段存储日志(segment file)
使用稀疏索引查找消息物理位置(不会为每个消息创建索引)
好处可以节约空间
消息存储之后,消费成功不会立即删除 根据offset获取消息(需要考虑配置日志清理策略)
java应用层面
生产者
生产者批量投递消息(缓冲池设计)
消费者
消费者批量获取消息(多个offset)
每个分区对应一个消费者(可扩展性)
linux内核层面
采用顺序读写方式
使用零拷贝机制
sendfile+mmap 用户态与内核态映射
不需要cpu拷贝数据
减少用户态与内核态切换次数
利用Page Cache缓存提高读写
需要考虑刷盘问题
Kafka如何保证可靠消息
副本机制(Replication)
ISR副本可靠机制
分区中副本选举
HW高水位线 消费者能够消费最大offset
LEO队列中最大的offset值
生产者投递消息ack
0表示生产者不等待(可能会丢失消息)
1表示生产者等待,Leader刷盘(建议默认配置)
-1表示生产者需要等待所有节点同步完成
Kafka选举原理控制器原理
依托于Zookeeper临时节点实现选举
消费者手动提交offset
Kafka如何查找指定offset的Message的
1.根据offset查找Segment分段文件(二分查找)
2.访问到index文件(稀疏索引),查找到对应物理存放位置
3.根据物理访问位置,访问log日志查找物理对应消息
查找到该消息索引值
直接返回物理消息(时间复杂度o(1))
没有查找到该消息索引值
依次顺序查找(时间复杂度o(N))
Kafka的性能优化
生产者
生产者内存缓冲的大小
重试策略“retries”和“retries.backoff.ms”
该参数设置定重试的次数、间隔时间
确认机制:acks 建议设置为1比较平衡
消费者
消费者分区的个数
消费者根据多个offset批量获取消息
消费者开启手动提交offset
Broker(MQ服务器端)
日志保留策略配置
log数据文件刷盘策略
replica复制配置
网络和IO线程配置优化
MySQL实战性能优化
MySQL性能优化
MySQL架构与执行流程原理
SQL 语句是如何执行的
内置查询缓存
语法和词法解析
语义处理器
优化器/执行计划
查询执行引擎
InnoDb内存结构和磁盘结构
缓冲器设计
缓存区 Buffer Pool 作用
内存缓冲器满了,如何处理?
如何配置你的Buffer Pool的大小?
MySQL延迟问题和数据刷盘策略
如何理解MySQL中抽象出来的数据页单位
磁盘上的数据页和缓存页是如何对应起来的
缓存页对应的描述信息是什么?
如何基于机器配置来合理设置Buffer Pool
生产环境中应该给buffer pool设置多少内存
总大小=(chunk大小 * buffer pool数量)的2倍数
MySQL底层通信协议原理
linux
TCP/IP套接字
mysql报文
三次握手认证
Unix套接字
windows
命名管道
内存共享
MySQL底层模块划分
初始化模块
核心API
网络交互模块
Client & Server 交互协议模块
用户模块
访问控制模块
连接管理、连接线程和线程管理
Query 解析和转发模块
Query 优化器模块
日志记录模块
存储引擎接口模块
MySQL索引底层实现原理
索引的数据结构模型
hash表
二叉搜索树
红黑树
平衡多叉搜索树
B+ Trees
索引有那些分类
全文索引
主键索引
组合索引
唯一索引
innodb和myisam的区别 索引的差异<br>
MySQL索引建立和使用的基本原则
MySQL事务底层原理
Spring声明与编程事务区别
事务只begin,不commit/rollback会发生那些问题
mysql 多版本控制MVCC原理
MySQL事务隔离级别
可重复读
读提交
读未提交
串行化
MySQL加锁与释放锁原理
行锁、表锁、页锁
悲观锁/乐观锁
Gap Lock
什么叫间隙锁
为什么说gap锁是RR隔离级别下防止幻读的主要原因
主键索引/唯一索引+当前读会加上Gap锁吗?
通过范围查询是否会加上Gap锁
检索条件并不存在的当前读会加上Gap吗?
死锁分析原理
Two-Phase Locking
为什么会发生死锁
MySQLUndo日志底层原理
Undo-log与Redo-log区别
UndoLog实现事务原子性原理
RedoLog实现事务持久性原理
MySQL实战性能优化
SQL慢查询分析与解决方案
如何开启MySQL慢查询
执行计划explain原理解读
id:列越大执行优先级越高,id相同则从上往下执行,id为NULL最后执
select_type:表示查询的类型
table:explain 的一行正在访问哪个表。
type列
system
const
eq_ref
ref
<p class="MsoNormal"><b><span style="font-family: "Times New Roman"; font-size: 10.5pt;">range </span></b></p>
index
ALL
Extra表示附加信息
SQL与索引优化的原则
遵循最佳左前缀法则防止索引失效
尽量使用覆盖索引,避兔回表查询
排序遵循最佳左前缀法避免filesort
type最低 满足 range 范围查询级别
分页优化 where id 条件过滤offSet或者子查询定位id关联
连表查询优化小表驱动大表数据,超过三张表禁止使用 join
Like 模糊遵循最佳左前缀法则 或者使用使用复合索引模糊查询
MySQL配置优化原理
存储引擎与表结构优化
阿里巴巴开发手册角度优化MySQL
MySQL分表分库
单表达到多大量开始分表分库
水平与垂直拆分区别
分表分库策略
取余/范围取模
按照范围分片
按照日期进行分片
按照月份进行分片
按照枚举值分片
二进制取模范围分片
一致性hash分片
按照目标字段前缀指定的进行分区<br>
按照前缀ASCII码和值进行取模范围分片
开发者自定义
常见问题
分表分库后查询存在那些优缺点
分表分库后如何实现分页查询
分表分库后如何实现连表查询
为什么不推荐使用MyCat
Netty深度源码解读
网络模型概念基础
TCP/IP 五层架构模型
应用层
传输层
网络层
数据链路层
物理层
Socket网络编程
TCP协议
UDP协议
输入一个url地址如何解决ip地址原理
Http协议底层原理
HTTPS 协议请求与响应原理
HTTPS 与 SSL/TLS原理
http协议与Socket区别
IO模型原理
阻塞 I/O 模型
非阻塞 I/O 模型
多路复用 I/O 模型
信号驱动 I/O 模型
异步 I/O 模型
NIO 和 BIO区别
AIO 基本原理
BIO 到 NIO 的演进
面向流与面向缓冲
阻塞与非阻塞
NIO实现原理(操作系统内核)
内核概念
内核缓冲
进程缓冲区
linux内核
select
时间复杂度为o(n),监听文件描述符有一定限制
poll
时间复杂度为o(n),监听文件描述符没有限制
epoll
时间复杂度为o(1),监听文件描述符没有限制
Netty源码解读
Netty 常见使用场景
RPC框架
Tomcat服务器
网络游戏
NIO架构原理
缓冲区
选择器
通道
Netty 高性能设计
异步非阻塞通信
零拷贝/内存池
MMAP+write
Sendfile
思考点:
如何减少cpu拷贝次数
直接内存dma拷贝原理
如何减少内核切换次数
高效的 Reactor 线程模型
单Reactor单线程
单Reactor多线程
Reactor主从模型
无锁化的串行设计理念
序列化框架的支持
Netty源码解读
Netty线程模型及源码剖析
高性能序列化协议protobuf及源码分析
粘包拆包现象及解决方案、编解码器源码分析
直接内存与Netty零拷贝详解
Netty框架实战
基于Netty手写RPC框架(高仿Dubbo)
基于Netty手写多人联机版五子棋游戏
基于Netty手写Web服务器(高仿Tomcat)
Linux系统内核原理分析
Linux内核预备工作
Linux内核体系结构简析简析
Linux体系结构和内核结构区别
Linux驱动的platform机制
Linux内核体系结构
Spring体系框架源码解读
Spring5源码解读
SpringMVC源码解读
SpringBoot源码解读
新零售电商项目
架构设计思想
新零售概念<br>
技术架构方案
SpringBoot
SpringCloudAlibaba
中台化设计
技术中台
业务中台
组织中台
云计算
Saas(软件服务)
PaaS(平台服务)
IaaS(基础设施服务)
Devops与K8S运维与开发一体化
Apm
实现服务追踪
监控报警
前后端分离
前端-----vue 类似于ajax技术 前端工程师实现
后端------ 接口形式 后端工程师实现 java
构建基础设施服务
部署Nacos服务注册中心/配置中心
构建企业级Maven私服
实现微服务团队中RPC接口的调用
定义API接口规范协议
构建企业级代码仓库管理平台
po/do/vo/dto/bo选择应用
目的是为了保证RPC传输数据的安全性的问题
选择应用
DO(Data Object):与数据库表结构一一对应,通过DAO层向上传输数据源对象。
DTO(Data Transfer Object):数据传输对象,service或manager向外传输的对象
BO(Business Object):业务对象。由service层输出的封装业务逻辑的对象
AO(Application Object):应用对象。在web层与service层之间抽象的复用对象模型
VO(View Object):显示层对象,通常是web向模板渲染引擎层传输的对象
会员中台设计
登录接口实现
为什么不用session
session保存jvm服务器端中,需要考虑节点集群同步问题
Token实现方式
实现原理
随机生成一个令牌(UUID)做为Redis的key value为userid
返回token给客户端,客户端每次传递token令牌调用接口
优缺点
优点
隐藏参数真实性
缺点
需要经过Redis查询
JWT实现方式
组成的部分
header(头)
Payload(有效载荷)
Signature(签名)
优缺点
优点
无需再服务器存放用户的数据,减轻服务器端压力
轻量级、json风格比较简单
跨语言
缺点
无法更新 有效期
无法销毁一个jwt
Jwt如何实现注销
浏览器cookie清除(但是服务器还是存在)
建议将时间设置稍微短一点
整合多线程与线程池
使用多线程将处理登录之后异发送邮件、短信、优惠券,从而提高接口响应效率
大项目采用mq异步异步耗时处理,减少服务器cpu的资源
SSO单点登录
web端的形式
基于cookie实现
前后端分离
基于token或者jwt实现
常见问题
如何获取到真实客户端的ip信息
通过在nginx设定用户真实ip
前后端分离跨域问题如何解决
使用 jsonp 但是不支持post请求 ( 不推荐使用)
使用SpringMVC @CrossOrigin 注解(推荐)
基于网关解决跨域的问题 (推荐)
基于Nginx 根据不同项目访问(推荐)
联合登录实现
oauth2开放协议
1.根据appid生成授权链接地址
2.获取授权码
3.根据授权码获取accessToken
4.根据授权码获取用户信息
分布式解决方案
传统采集日志缺点
使用tail 每台服务器搜索日志
解决方案
aop+elk+kafka实现分布式日志采集
为什么elk需要加上kafka
减少在每台Logstash安装的运维的成本
注意事项
aop将采集的日志缓存在并发队列中,在异步的单独线程将日志投递到kafka中
聚合支付设计
支付架构流程
验证签名方式
RSA非对称加密
MD5
回调方式
同步回调
第三方支付成功之后以支付浏览器重定向的形式跳转到商户端
异步回调
第三方支付发送类似于HttpClient技术通知商户端
设计模式
策略模式
模板方法模式
常见问题
同步回调与异步回调如何保证接口安全性
同步回调以浏览器的形式跳转不会修改订单状态
异步回调验证签名成功之后,注意幂等问题修改订单状态
如何防止用户重复支付的问题
相同的订单号码from表单提交到第三方支付,第三方支付会根据该订单号码保证全局唯一
用户支付成功,但是订单状态还是未支付状态如何处理
这种现象正常的,通过最终一致性的思想,可以主动调用支付宝接口查询,该笔订单是否已经<br>支付过
用户支付金额与下单金额不一致如何处理
在异步回调中,会根据订单查询到用户真实的订单号码与用户支付金额是否一致<br>如果不一致则是为异常订单
支付表金额字段有哪些类型比较合适
直接存分整数类型后期可以转化为元
decimal类型
订单超时30分钟未支付如何处理
基于MQ延迟队列实现(推荐)
1.下单成功之后,向MQ投递一条延迟队列消息
2.当该消息过期时,会转移存放到死信队列中
3.死信队列消费者监听该消息,检查该订单状态是否为已支付
基于Redis过期key实现(不推荐)
1.下单成功之后,向Redis设置一个30分钟过期key
2.客户端监听该key过期时,检查该订单状态是否为已支付
3.开启过期key监听需要注意前缀、订阅单独的Redis库
常见问题
用户卡在30分钟支付,如何保证订单状态一致性问题
1.设置跳转支付宝订单超时为30分钟
2.延迟队列在31-35分钟左右根据订单号码主动调用支付宝接口查询支付状态
3.调用支付宝接口如果还是未支付,则认为该笔订单耗时
商品服务系统架构设计
如何实现抗高并发
前端层
优化方案
动静分离架构
静态资源服务器
动态资源服务器
静态资源压缩
生成.min文件
CDN缓存
遵循就近原则访问
最终作用
减少带宽的传输
接口层
优化方案
JVM参数调优,减少GC回收次数 stw问题
多线程/MQ异步解耦的形式处理耗时操作
使用Redis缓存减轻DB访问的压力
MySQL海量数据考虑分表分库/索引优化
最终作用
运维层
使用docker或者K8S弹性扩容/缩容部署
JavaSE
基础语法
数据类型
基本数据类型
数值类型
整数(byte,short,int,long)
浮点数(float,double)
字符(char)
非数值类型
布尔(boolean)
引用数据类型
类(class)
接口(interface)
数组[]
面向对象
集合框架
IO流
反射机制
多线程
JDBC
JavaWeb
基础
Servlet
JSP
框架
Spring5
Spring5与SpringBoot关系
SpringBean的注入方式
SpringBean的注入方式
有参构造注入属性
p名称空间注入
注入空值和特殊符号
注入内部bean
注入外部bean
注入级联赋值
注入集合类型属性
Spring的工厂Bean
SpringBean的生命周期
第一步:使用反射技术初始化对象调用无参构造函数
第二步: 使用反射调用set方法对属性实现赋值
第三步执行:bean的后置处理器 前置方法
第四步执行:调用对象中init方法
第五步:bean的后置处理器 后置方法
第六步:销毁该对象,调用销毁方法
SpringBean的作用域
单例对象
多例对象
SpringBean的自动装配
SpringBean的外部属性文件
SpringBean的注解形式
SpringBean的注解启动方式
SpringBean的注解启动作用
SpringBean的注解扫描配置
Autowired与Qualifier注解
@Resource用法
SpringBean的AOP
AOP基本的概念
AOP基本的作用
静态代理与动态代理
@AspectJ注解用法
使用aop统一打印日志
SpringBean的事务操作
事务的分类
手动事务
编程事务
事务七种传播行为
PROPAGATION_REQUIRED(默认传播行为)
当前线程如果存在事务,则加入当前事务
如果当前线程不存在事务则创建一个新的事务
PROPAGATION_SUPPORTS
当前线程如果存在事务,则加入当前事务
如果当前线程不存在事务,则以非事务<br>方式执行
PROPAGATION_MANDATORY
当前线程如果存在事务,则加入当前事务
如果当前线程存在事务则抛出异常
PROPAGATION_REQUIRES_NEW
当前线程如果存在事务,则会挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED
总是以非事务的方式执行
PROPAGATION_NEVER
总是以非事务方式执行,如果当前线程存在事务则会抛出异常
PROPAGATION_NESTED
当前线程如果存在事务,则会嵌套一个事务
SpringMVC
Mybatis
Hibernate
微服务
SpringBoot2.0
为什么需要使用SpringBoot框架
能够帮助开发者实现快速整合第三方框架 (原理:Maven依赖封装)
去除xml配置 完全采用注解化 (原理:Spring体系中内置注解方式)
无需外部Tomcat、内部实现服务器(原理:Java语言支持内嵌入Tomcat服务器)
SpringBoot与SpringCloud的区别
SpringCloud依赖与SpringBoot组件
使用SpringMVC编写Http协议接口
时SpringCloud是一套完整的微服务解决框架
SpringBoot依赖引入介绍
spring-boot-start-parent,
spring-boot-starter-web
@RestController作用
Controller所有的方法返回JSON格式
SpringBoot启动方式
@EnableAutoConfiguration
@ComponentScan
@SpringBootApplication
当前包下或者子包下所有的类都可以扫到
SpringBoot整合静态资源访问
什么模板引擎框架
渲染web,有利于seo搜索
整合ftl模板引擎
整合thymeleaf模板引擎
SpringBoot整合数据源
JdbcTemplate
mybatis
hibernate
SpringBoot整合热部署
整合devtools工具
类加载器实现
整合lombok
SpringBoot整合配置文件
使用@value注解读取配置文件
Properties转换yml格式
@ConfigurationProperties
配置文件占位符用法
整合多环境不同配置文件
修改端口与上下文路径
SpringBoot整合日志框架
logback
log4j
使用aop统一打印日志信息
SpringBoot定时任务
整合定时任务@Scheduled注解
定时整任务合Quartz 表达式
SpringBoot整合异步多线程
注意@Async失效问题
@Async整合线程池
整合全局捕获异常
打包运行发布
项目工具
docker
基本概念
为什么需要使用docker
使用docker的好处
容器与虚拟机区别
环境安装
Linux环境安装docker
Win环境安装docker
三大要素
镜像文件
容器
仓库
镜像原理
Docker下载镜像原理
Docker加载镜像原理
bootfs
rootfs
Union fs
云加速镜像配置
阿里云加速镜像
华为云加速镜像
科大加速镜像
Docker常用命令
docker --help(帮助命令)
docker --version(查看版本)
docker images(查看镜像)
docker search(搜索镜像)
docker pull(下载镜像)
latest -----tag 最新版本的镜像文件
docker 容器
docker run(启动容器)
docker start 启动容器id
docker stop 容器id
docker rm 容器id
docker exec -it [CONTAINER ID] bash (进入容器)
docker logs --since 30m CONTAINER_ID(查看容器日志)
Docker Commit(根据当前容器制作为镜像文件)
Docker数据卷 -v
安装常用软件
Tomcat
docker run -p 8081:8080 -d tomcat:8
Nginx
docker run --name nginx81 -d -p 81:80
MySQL
docker create --name mysql3308 -e MYSQL_ROOT_PASSWORD=root -p 3308:3306 mysql:5.7
DockerFile 解析
DockerFile编写规范
DockerFile指令
根据Dockerfile构建springboot项目
Docker Compose
Compose常用命令
docker-compose -h
docker-compose up
docker-compose down
docker-compose logs
docker-compose pull
dokcer-compose config
docker-compose restar
docker-compose start
Compose模板文件
部署SpringBoot+MySQL+Nginx微服务项目
Docker可视化工具使用
Portainer
DockerUI
k8s
元原生概念
微服务
应用程序之间restful 通讯
可独立部署/弹性扩容与缩容
devops
自动发布管道、Ci/CD工具
快速部署生产环境
开发与运维一体化
持续交付
频繁发布、快速交付、快速反馈、降低发布风险
容器化
微服务的最佳的载体
设计模式
代理模式