一、面试岗位选择
1.公司&团队:
第一维度为业务/团队
小公司 | 大公司 | |
---|---|---|
核心业务/团队 | 〇 | ✔ |
边缘业务/团队 | ✖ | 〇 |
2.岗位匹配度:
与自己发展方向越匹配越好
面试准备
面试准备决定面试成功与否
影响面试成败三大基石:能力,面试,沟通
第一,优秀的技术基本功是必要条件,没有技术能力其他的无从谈起。
第二,注重平衡心态,过于紧张会导致平时会的内容都答不上来。
第三,与面试官顺畅的沟通,开行的交流,能给你的面试加分,反之可能影响整个面试。
面试准备主要包括:
一、能力
1. 了解应试公司及其岗位
2. 系统化复习基础知识
3. 对原公司负责的项目进行梳理总结
4. 学习典型框架案例
5. 阅读常考考点源码
6. 针对性准备加分项
二、心态
尽量收集应试公司岗位所属团队、平均福利等资料信息,知己知彼有助于增加信心。
面对压力面试时,可进行自我暗示。如:
这个面试官我可能永远不会遇到。
失败了也并不可怕。
三、沟通
1. 提前准备一个简短有特色的自我介绍,包括兴趣特长、技术优势
2. 避免冷场,回答不上来的问题可主动坦白,并提供应对或处理办法,亦或是询问面试官能否换一个问题。
3. 当没有听清或不理解问题时,不应强行作答,应与面试官沟通再次确认问题。
4. 面试细节。包括面部微表情、坐姿、手势,说话语速不要过快或过慢,表达逻辑清晰观点明确,不可随意打断面试官以及谦虚有礼的态度等。
ps.及时观察面试官的反映。面试官奋笔疾书可能是你给与的信息有用,反之,长时间未有反应,应反思是否跑题。面试官表情不耐烦或深呼吸,可能意味着未能领会考察意图,可以再次询问。
面试考察点
面试考察点相对综合,一般分为两大块:
硬技能:
指基础知识、项目经验、架构能力、应用能力等
软实力:
指逻辑思维、沟通协作、管理推进、学习思考、培养潜力等、
二、操作系统与网络知识
- 知识点汇总
- 知识点详解
- HTTP
- TCP
- 三次握手
- 四次挥手
知识点汇总
操作系统对于服务问题的排查定位很重要,在面试时,一般以了解和应用考察为主,面试题目占的比重不会过高.
线程共享同一进程资源
进程间的通信IPC,中间件研发相关职位。6钟原理和使用场景。eg:进程间共享可以使用共享内存,进程间交换可以使用Unix socket或消息队列。
协程更轻量化,是在用户态进行,调度切换的代价比线程上下文切换要低很多。
服务之间通过不同的网络协议进行交互,在面试中被考的几率非常大.
知识点详解
HTTP
1. 需要知道协议中的Method,Header,Cookies.
2. 知道常见状态码含义404:未找到503:服务不可用302:临时移动
3. 了解HTTPs的交互流程
4. QUIC基于UDP实现原HTTP功能,现已被标准化为HTTP3协议,类似tcp的流量控制、可靠性保证
TCP
1. TCP和HTTP在服务交互中使用最多.了解报文标志状态和链接状态有利于抓包分析.
2. Nagel和ACK 延迟算法是为了解决小包问题和数据载荷比.对于延迟比较敏感且发送频率比较低,可以关闭nagel
3. KeepALive是在长时间没有数据发送的情况下保持连接可用的机制.需要了解开启和设置方式.
4. 了解如何通过滑动窗口机制实现流量控制.
-
位于OSI模型的第四层-传输层
-
面向连接
- 每次发送数据先要建立连接
-
双工通信
- 连接建立后可进行双向通信
-
可靠
- 通过对数据包编号,并按序号接受,可确保数据的完整性和有序性
-
流量控制
- 通过滑动窗口控制数据的发送速率.滑动窗口的本质是动态缓冲区,接收端根据自己的处理能力,在tcp的Header中动态调整大小,通过ACK应答包通知发送端,进而调整发送速度
-
拥塞控制
- 主要通过慢启动,拥塞避免,拥塞发生,快速恢复算法实现
-
基于字节流
将数据按字节大小进行编号,接收端通过AKC确认收到的数据编号,保证接收数据的有序性完整性
除了以上特点,还可以了解tcp协议的报文状态,滑动窗口的工作流程,KeepAlive的参数设置,Nagel算法的细节
三次握手
tcp是基于链接的所以在传输数据前需要先建立链接(三次握手是为了建立双向的链接)
首先建立链接前需要server端先监听端口,因此初始状态就是listen状态。client端准备建立链接,发送SYN同步包,之后client端的链接状态就变成了SYN_SEND状态.server端收到SYN后同意建立链接,会向client端回复一个ACK.由于tcp是双工传输server端也会同时向client端发送一个同步请求SYN.client端收到后变为established状态,同时client端向server端发送ACK响应回复,收到后server端的链接状态也就变成了established的状态。此时建联完成双方随时可以进行数据传输。
回答建连的问题时,可以提到syn洪水攻击.即请求端只发送SYN包,而不对接收端的SYNACK包进行回复,使得接收端大量连接处于半连接状态,影响其他正常请求的建连.
解决方法:设置linux的tcp参数
tcp_synack_retries=0,加快对于半连接的回收速度,或加大tcp_max_syn_backlog应对少量的syn洪水攻击
四次挥手
关闭通信双方都可以先发起,首先链接状态都是established状态。然后可client端先发起了关闭链接请求,向server发送了一个FIN包表示client端已经没有数据要发送。然后client端就进入了FIN_WAIT_1状态。server端收到FIN后返回ACK然后进入close_wait状态。此时server属于半关闭状态,因为此时client不会向server发送数据,server有可能向client端发送数据。当server端数据发送完毕,向client端发送FIN,进入LAST_ACK状态,等待应答就可以关闭链接了。client端收到server端的FIN后,回复ACK然后进入time_wait状态(等待两倍的msl,即最大报文段生存时间来保证链接的可靠关闭)之后才会进入close状态。而server端收到ACK后直接就可以进入close状态。
为什么需要4次:两端并不是同时都不需要发送数据了
处于CLOSE_WAIT状态时,HOSTB仍有可能向HOSTA发送数据,HOSTB发送完数据后,才会向HOSTA发送FIN包
发送关闭连接请求,表示没有数据需要发送,进入wait1,进入last_ACK等待应答,之后就可以closed,
为何HOSTA要在2MSL(Maximum Segment Lifetime 最大报文生存时长)后才关闭连接?
- 要保证TCP的全双工连接能可靠关闭
- 要保证这次连接中重复的数据段从网络中消失,防止端口重用时可能的数据混淆
回答问题是也可以提到,有可能大量socket会处于TIME_WAIT和CLOSE_WAIT的问题.
解决TIME_WAIT过多,可通过开启Linux的tcp参数tw_reuse或tw_recycle能加快TIME_WAIT状态的回收.
CLOSE_WAIT过多则可能是被动关闭的一方存在代码BUG,没有正确关闭连接导致的
三、设计模式与Java语言特性
- 知识点汇总
- 知识点详解
- 常用设计模式
- 单例模式
- 工厂模式
- 代理模式
- 责任链模式
- 适配器模式
- 观察者模式
- 构造者模式
- Java语言特性
- Java基础常考点–Map
- HashMap
- ConcurrentHashMap
- Java版本特性
- 1.8
- 1.9-1.10
- 1.11
- 面试考察点
- 加分项
- 真题汇总
知识点汇总
该内容需掌握主要两点
- 常用设计模式的实现
- 各设计模式的使用场景
常见集合类和Java并发工具包(JUC)是常见考点
知识点详解
常用设计模式
有**单例模式,工厂模式,代理模式,观察者模式,**构造者模式,责任链模式,适配器模式等.
在回答设计模式问题时,可结合实际业务场景,体现对设计模式的理解和应用能力.
单例模式
线程安全实现的常见三种方法:
1. 静态初始化(饿汉).不管是否使用都会创建
2. 双检锁(懒汉).单例变量必须要用volatile修饰.
3. 单例注册表.spring中bean的单例模式就是用该方法实现.
工厂模式
在实际业务中经常用到,也是面试的主要考察点.是创建不同类型实例常用的方式.
spring中的bean都是由不同工厂类创建的.
代理模式
在不适合或不能直接引用另一个对象的场景,可以用代理模式对被代理的对象进行访问行为的控制.Java的代理模式分为静态代理和动态代理,静态代理是指在编译时就创建好的代理类,例如在源代码中编写的类.动态代理指在JVM运行过程中动态创建的代理类,如JDK动态代理,CDLIB,javaasist等.
例如,在Mybatis中getMapper时会通过MapperProxyFactory及配置文件动态生成的Mapper代理对象,代理对象会拦截Mapper接口的方法调用,创建对应方法的MapperMethod类并执行exe cute方法,然后返回结果.
责任链模式
类似工厂流水线,其中的每个节点完成对对象的某一种处理.
Netty框架的处理消息的Pipeline就是采用的责任链模式.
适配器模式
类似于转接头,将两种不匹配的对象进行适配,也可以起到对两个不同的对象进行解耦的作用.
SLF4J可使项目与Log4、logback等具体日志实现框架进行解耦,其通过不同适配器与不同框架进行适配,完成日志功能的使用.
观察者模式
也可称为发布订阅模式,适用于一个对象某个行为需要触发一系列操作的场景.
GRPC中stream流式请求的处理.
构造者模式
适用于一个对象拥有很多复杂的属性,需要根据不同情况创建不同的具体对象.
创建Protocol Buffer对象时,需要用到Builder
Java语言特性
-
集合类
主要掌握如何实现. -
动态代理与反射
是java语言的特色,需要掌握动态代理与反射的使用场景.ORM框架中会大量使用代理类,PRC调用时使用反射机制调用实现类的方法.
-
数据类型
也是面试的常见问题.如每种数据类型占用多大空间,数据类型的自动转换与强制转换,基础数据类型与Wrapper数据类型的自动装箱与拆箱等. -
对象引用
(可自行搜索)
Java基础常考点–Map
能考查到数据结构,java的基础实现以及对并发问题的处理思路的掌握程度.
HashMap
-
通过数组加链表实现.
数组中的元素为一个链表,通过计算存入对象的hashcode,确认存入位置,用链表解决散列冲突.链表的节点存入的是键值对.
-
填充因子的作用???
-
Map扩容的rehash机制
-
容量是二的幂次方.
是为了方便按位与操作计算余数,比求模更快
-
多线程风险的原因
对线程put时,会在超过填充因子的情况下rehash.HashMap为避免尾部遍历,链表插入采用头插法,多线程场景下可能产生死循环.
ConcurrentHashMap
-
分段锁思想
1.7中采用segment分段加锁,降低并发锁定程度.
-
CAS自旋锁
1.8中采用CAS自旋锁(一种乐观锁实现模式)提高性能.但在并发度较高时,性能一般.
-
红黑树
1.8引入红黑树解决hash冲突时的链表查找问题.在链表长度大于8且总容量大于64时启用.扩容后链表长度小于6时重新转为一般链表.(8,6,64为默认参数)
Java版本特性
1.8:长期支持版本
* Lambda表达式:简洁并行计算
* StreamAPI
* 方法引用
* 接口默认方法:简化掉简单的抽象类
* Metaspace替换PremGen
M使用本地内存,不在虚拟机中,目的提升对原数据的处理,提成GC效率;以后hotSport与Jrocket合并
1.9-1.10
* 模块系统
* 默认G1回收器
* 接口私有方法
* 局部变量判断
* Graal编译器
1.11:长期支持版本
* ZGC:新的垃圾回收器,大堆内存设计
* 字符串API增强
* 内建HTTP Client
面试考察点
-
基本概念和基本原理
要求:正确清晰* 网络协议4/7层模型的概念 * TCP协议流量控制的实现原理
-
实现方法和使用方式
* HashMap在JDK1.8中的实现方式 * 单例模式有哪几种实现方式,什么场景该使用静态方法实现,什么场景该使用双检锁实现
-
经常用到的知识点
* 常用的Linux命令有哪些,用来解决什么样的问题
-
实际应用中容易犯错的点
* ==与equals区别是什么 * 对象强引用使用不当会导致内存泄露,考察不同引用方式和作用的理解
-
与面试方向相关的知识点
* 中间件:存储,网络相关的考察
加分项
-
知识点与典型的业务场景关联.
如,谈到设计模型时,可以讲XX框架在解决XX问题时使用了那种设计模式.
-
以反例来描述实际场景中误用的危害.
如,大量使用反射会影响性能.
-
与知识点相关的优化点.
如,讲到tcp建连和断连时,如遇到洪水攻击或大量TIME_WAIT时,可以调整系统参数预防.
-
与知识点相关的最新技术趋势.
如,讲到ConcurrentHashMap,可以介绍1.8的改进细节. 或,讲到HTTP时,能说出HTTP2和QUIC的特点和实现.
-
在了解的前提下,尽量增加回答内容深度.
如,讲到tcp的滑动窗口时,能讲到流量与拥塞控制,进一步能指出解决拥塞的不同算法.
ps.面试官可能会顺着细节追问,回答不上来会适得其反.
真题汇总
-
进程和线程的区别和联系
从资源占用,切换效率,通信方式等方面解答
-
简单介绍一下进程的切换过程
线程上下文的切换代价,要回答,切换会保存寄存器,栈等线程相关的现场,需要由用户态切换到内核态,可以用vmstat命令查看线程上下文的切换状况
-
你经常使用哪些Linux命令,主要用来解决哪些问题?
参考之前操作系统汇总中提到的命令
-
为什么TCP建连需要3次握手而断连需要4次?
参考之前内容
-
为什么TCP关闭链接时需要TIME_WAIT状态,为什么要等2MSL?
参考之前内容
-
一次完整的HTTP请求过程是怎样的?
DNS解析,TCP建连,HTTP请求,HTTP响应等.
-
HTTP2和HTTP的区别有哪些?
-
在你的项目中你使用过那些设计模式?主要用来解决哪些问题?
-
Object中的equals和hashcode的作用分别是什么?
-
final,finally,finalize的区别与使用场景
-
简单表述一下Java的异常机制
-
先上使用的那个版本jdk,为什么使用这个版本(有什么特色)?
四、JVM
- 知识点汇总
- 知识点详解
- JVM内存模型
- 栈
- 本地方法栈
- 程序计数器
- 堆
- 方法区
- JMM与内存可见性
- 类加载与卸载
- 加载过程
- 加载机制-双亲委派模式
- 分代回收
- 回收算法
- 考察点
- 加分项
- 真题汇总
知识点汇总
JVM是Java运行基础,面试时一定会遇到JVM的有关问题,内容相对集中,但对只是深度要求较高.
其中内存模型,类加载机制,GC是重点方面.性能调优部分更偏向应用,重点突出实践能力.编译器优化和执行模式部分偏向于理论基础,重点掌握知识点.
需了解
内存模型
各部分作用,保存哪些数据.
类加载
双亲委派加载机制,常用加载器分别加载哪种类型的类.
GC
分代回收的思想和依据以及不同垃圾回收算法的回收思路和适合场景.
性能调优
常有JVM优化参数作用,参数调优的依据,常用的JVM分析工具能分析哪些问题以及使用方法.
执行模式
解释/编译/混合模式的优缺点,Java7提供的分层编译技术,JIT即时编译技术,OSR栈上替换,C1/C2编译器针对的场景,C2针对的是server模式,优化更激进.新技术方面Java10的graal编译器
编译器优化
javac的编译过程,ast抽象语法树,编译器优化和运行器优化.
知识点详解
JVM内存模型(Java虚拟机内存模型)
线程独占:栈,本地方法栈,程序计数器
线程共享:堆,方法区
栈
又称方法栈,线程私有的,线程执行方法是都会创建一个栈阵,用来存储局部变量表,操作栈,动态链接,方法出口等信息.调用方法时执行入栈,方法返回式执行出栈.
本地方法栈
与栈类似,也是用来保存执行方法的信息.执行Java方法是使用栈,执行Native方法时使用本地方法栈.
程序计数器
保存着当前线程执行的字节码位置,每个线程工作时都有独立的计数器,只为执行Java方法服务,执行Native方法时,程序计数器为空.
堆
JVM内存管理最大的一块,对所有线程共享,目的是存放对象的实例,几乎所欲的对象实例都会放在这里,当堆没有可用空间时,会抛出OOM异常.根据对象的存活周期不同,JVM把对象进行分代管理,由垃圾回收器进行垃圾的回收管理
方法区
又称非堆区,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器优化后的代码等数据.1.7的永久代和1.8的元空间都是方法区的一种实现
回答以上问题是需回答两个要点:
- 各部分功能
- 是否是线程共享
JMM与内存可见性
[外链图片转存失败(img-iomYGzAw-1565101632758)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555596294412.png)]
JMM是定义程序中变量的访问规则。所有共享变量都存在主内存中共享,每个线程有自己的工作内存,保存的是主内存中变量的工作副本。线程对于变量的读写等操作只能在自己的工作内存中进行,而不能直接对主内存操作。只有从A的工作内存区写回到主内存,B从主内存区读取到自己的工作内存区,才能进一步的操作。由于指令重排序,读写的顺序会被打乱,因此JMM需要提供原子性,可见性,有序性保证.
[外链图片转存失败(img-3Zyimc80-1565101632759)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1554779864119.png)]
volatile强制变量的赋值会同步刷新回主内存,强制变量的读取会从主内存中重新加载,保证不同的线程总是能够看到该变量的最新值。
volatile另一个作用就是阻止指令重排续这样就可以保证变量读写的有序性。
happens before 原则包括一系列规则比如
- 程序顺序原则:就是一个线程内必须保证语义串行性
- 锁规则就是对同把锁的解锁一定要发生在再次加锁之前
- 此外还包括happens-before原则的传递性
- 线程的启动中断中止规则等
类加载与卸载
class字节码读入到内存,放到方法区内,并创建对应的class对象
加载过程:加载-链接(验证,准备,解析)-初始化
[外链图片转存失败(img-ZaeMvGXg-1565101632760)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1554779890785.png)]
-
加载通过类的完全限定名,查找此类字节码文件,利用字节码文件创建Class对象.
-
验证确保Class文件符合当前虚拟机的要求,不会危害到虚拟机自身安全.
-
准备进行内存分配,为static修饰的类变量分配内存,并设置初始值(0或null).
不包含final修饰的静态变量,因为final变量在编译时分配.
-
解析将常量池中的符号引用替换为直接引用的过程.直接引用为直接指向目标的指针或者相对偏移量等.
-
初始化主要完成静态块执行以及静态变量的赋值.先初始化父类,再初始化当前类.
只有对类主动使用时才会初始化,触发条件包括,创建类的实例时,访问类的静态方法或静态变量的时候,使用Class.forName反射类的时候,或者某个子类初始化的时候.
JVM自带的3种类加载器加载的类,在虚拟机的生命周期中是不会被卸载的,只有用户自定义的加载器加载的类才可被卸载
加载机制-双亲委派模式
[外链图片转存失败(img-MlCj4Pi9-1565101632761)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555596268040.png)]
双亲委派模式,即加载器加载类时先把请求委托给自己的父类加载器执行,直到顶层的启动类加载器.父类加载器能够完成加载则成功返回,不能则子类加载器才自己尝试加载.
优点:
- 避免类的重复加载
- 避免Java的核心API被篡改
分代回收:方便垃圾回收
分代回收基于两个事实:大部分对象很快就不使用了,还有一部分不会立即无用,但也不会持续很长时间.
堆分代 | |||
---|---|---|---|
年轻代 | Dden | Survivor1 | Survivor2 |
老年代 | Tenured | Tenured | Tenured |
永久代 | PremGen/MetaSpace | PremGen/MetaSpace | PremGen/MetaSpace |
- 年轻代主要用来存放新创建的对象,分为Eden区和两个survivor区,大部分对象在Eden区生成,当Eden区满时,还存活的对象会在两个surval区交替保存,达到定次数后对象会晋升到老年代。
- 老年代用来存放从年轻代晋升而来的存活时间较长的对象。
- 永久带主要保存类信息等内容。这里的永久代是指对象划分方式不是专指1.7的PremGen或者1 8之后的MetaSpace。
垃圾回收算法:根据年轻代与老年代的特点JVM提供了不同的垃圾回收算法。
- 引用计数法:对象被引用的次数确定对象是否再被使用,缺点是无法解决循环引用的问题
- 标记复制算法:需要from和to两块大小相同的内存空间,对象分配时只在from块进行,回收时把存活对象复制到to块,并清空from块。然后交换两块的分工,from变为to。缺点是内存使用率低。
- 标记清除法:分为标记对象和清除不再使用的对象两个阶段。缺点是会产生内存碎片。
年轻代->标记-复制:
老年代->标记-清除:CMS、G1、ZGC
回收算法
1.CMS算法
1.7前主流垃圾回收算法,为标记-清楚算法,优点是并发收集,停顿小.
[外链图片转存失败(img-0bQHOg5m-1565101632761)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555643016840.png)]
初始标记
会StopTheWorld,标记的对象是root即最直接可达的对象.并发标记
GC线程和应用线程并发执行,标记可达的对象.重新标记
第二个StopTheWorld,停顿时间比并发标记
小很多,但比初始标记
稍长.主要对对象重新扫描并标记.并发清理
进行并发的垃圾清理.并发重置
为下一次GC重置相关数据结构.
2.G1算法
1.9后默认的垃圾回收算法,特点保持高回收率的同时减少停顿.采用每次只清理一部分,而不是清理全部的增量式清理,以保证停顿时间不会过长
[外链图片转存失败(img-3ByOThvl-1565101632761)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555643173106.png)]
其取消了年轻代与老年代的物理划分(改为了逻辑分代),但仍属于分代收集器,算法将堆分为若干个逻辑区域(region),一部分用作年轻代,一部分用作老年代,还有用来存储巨型对象的分区.
同CMS相同,会遍历所有对象,标记引用情况,清除对象后会对区域进行复制移动,以整合碎片空间.
- 年轻代回收:
并行复制
采用复制算法,并行收集,会StopTheWorld. - 老年代回收:
会对年轻代一并回收
初始标记
完成堆root对象的标记,会StopTheWorld.
并发标记
GC线程和应用线程并发执行.
最终标记
完成三色标记周期,会StopTheWorld.
复制/清楚
会优先对可回收空间较大的区域进行回收(garbage first)
只清理一部分的增量式清理,保证每次清理停顿时间不会过长
可以通过JVM算法设置region的大小,1-32m,还可以设置最大GC停顿时间
CMS、G1三色标记算法
3.ZGC
1.11中提供的高效垃圾回收算法,针对大堆内存设计,可以处理TB级别的堆,可以做到10ms以下的回收停顿时间.
特点:
- 着色指针:最大4TB堆(寻址需要42位),剩下22位保存额外信息,对象进行着色标记
- 读屏障:GC线程和应用线程可能并发修改对象状态的问题,而非简单的STW,只有单个对象处理有概率减速
- 并发处理:读屏障,大部分不需要STW
- 基于region:并未进行分代,动态决定大小(G1固定大小),动态创建销毁,更好的管理大对象
- 内存压缩(整理):CMS原地清理,内存碎片。ZGC同G1清理后移动合并,解决碎片问题。
[外链图片转存失败(img-QCdDYj8O-1565101632762)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555643934423.png)]
初始划分为许多小大不用的region
- roots标记`标记root对象,会StopTheWorld.
并发标记
对对象指针进行着色进行标记。结合读屏障(解决单个对象的并发问题)与应用线程一起运行标记,最后可能会有StopTheWorld用来处理边缘部分.清除
会清理标记为不可用的对象.roots重定位
是对存活的对象进行移动,以腾出大块内存空间,减少碎片产生.重定位最开始会短暂StopTheWorld(时间取决于root数量,和重定位集与对象总活动集的比例),用来重定义集合中的root对象并发重定位
与并发标记
类似.
考察点
-
深入理解JVM内存模型、JMM
-
了解类加载过程,双亲委派机制
-
了解内存可见性,JMM保证的几个机制
-
了解常用的GC算法特点、执行过程和适用场景
eg:G1对最大延迟有要求的场合,ZGC 64位系统的大内存服务中
-
能够根据业务场景选择合适JVM参数和GC算法
eg:垃圾回收的并发数,偏向锁的设置
加分项
-
编译器优化
利用栈上分配,降低GC压力
编写适合内联优化的代码
-
问题排查经验与思路
解决过线上经FULL GC 的问题
排查过内存泄露的问题
-
JVM调优经验和调优思路
高并发低延迟的场景,如何调整GC参数,降低停顿时间
针对队列处理机,如何尽可能提高吞吐力
-
了解最新的技术趋势(ZGC高效的实现原理和Graalvm实现特点)
真题汇总
-
简单描述一下JVM的内存模型
-
什么时候会触发FullGC?
年轻带晋升时,老年代空间不足
永久代空间不足
-
Java类加载器有几种,关系怎样的?
-
双请问欧派机制的加载流程是谮言的,有什么好处?
-
1.8为首么用Metaspace替换掉PermGen?Meatspace保存在哪?
-
编译器会对指令做哪些优化?(简答描述编译器的指令重排)
-
简单描述一下volatile可以解决什么问题?如何做到的?
强制主内存读写同步,防止指令重排序
-
简单描述一下GC的分代回收?
-
G1与CMS的区别?
-
对象引用有哪几种,有什么特点?
强引用,不会被GC
软引用,内存空间不足时GC
弱引用,每次GC都回收
虚引用,和引用队列联合使用,跟踪一个对象被垃圾回收的过程
-
使用过哪些JVM调试工具,主要分析哪些内容?
GMC飞行计数器、堆分析工具MAT、线程分析工具JStack、获取堆信息JMap
五、并发与多线程
- 知识点汇总
- 知识点详解
- 线程的状态转换
- CAS与ABA问题
- Synchronized实现原理
- AQS与Lock
- 线程池
- 线程池参数介绍
- 考察点
- 加分项
- 真题汇总
知识点汇总
知识点详解
线程的状态转换
[外链图片转存失败(img-IFmDuGv2-1565101632762)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555645391502.png)]
六个状态对应ThreadState的枚举
CAS与ABA问题
**CAS:**一种乐观锁的实现,轻量级锁,JUC很多工具类基于CAS
[外链图片转存失败(img-j3JGycmH-1565101632763)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555646955807.png)]
线程在读取数据时不进行加锁,准备写回数据时,比较原值是否修改,若未被其它线程修改则写回,若已被修改则重新执行读取流程。
乐观策略,认为并发操作并不总会发生。比较并写回采用操作系统中的原语,保证不会被中断。
**ABA问题:**不一定会影响结果,但还是需要防范:增加额外的标位或者时间戳,JUC中有。
[外链图片转存失败(img-CddBv4tA-1565101632763)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1554780070499.png)]
Synchronized实现原理
[外链图片转存失败(img-YyPAZ022-1565101632764)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555647304472.png)]
保证同一时刻只有一个线程进入临界区:
对对象进行加锁,对象在内存中分为三块区域(对象头、实例数据、对其填充),对象头中,保存了锁标志位和指向Monitor对象的起始地址。Monitor被某个线程占用后,就会处于锁定状态,Owner指向持有Moniator对象的线程,两个队列,存放进入以及等待获取锁的线程。
锁优化
先使用偏向锁,优先同一线程再次获取锁。锁优化会将锁由轻量级升级为重量级
AQS与Lock
[外链图片转存失败(img-s0hGoVgM-1565101632764)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555647844234.png)]
AQS队列同步器,实现Lock的基础。state标志位,1有线程占用,其他需要进入同步队列等待。同步队列是一个双向链表,当获得锁的线程需要等待某个条件时,需要进入等待队列。可以有多个,当条件满足时,可以重进入同步队列,进行获取锁的竞争。
Re entrant Lock:基于AQS。有公平锁,非公平锁,差别在于新来的线程有没有可能比已经等待的更早获得锁。独占锁。Semaphore,共享锁。
线程池
复用线程,避免线程频繁的创建与销毁。
- NewFixedThreadPool 固定大小线城池,固定线程数,无界队列.适用于任务数量不均匀的场景,对内存压力不敏感,但系统负载敏感的场景.
- NewCachedThreadPool cached线程池,无限线程数,适用于要求低延迟的短期任务场景.
- newSingleThreadPool 单个线程的固定线程池,适用于保证异步执行顺序的场景.
- newScheduledThreadPool Scheduled线城池,适用于定期执行任务场景,支持固定频率和固定延迟.
- newWorkStealingPool 工作窃取线程池,使用ForkJoinPool,多任务队列的固定并行度,适合任务执行时长不均匀的场景.
线程池参数介绍
线程池构造方法:除newWorkStealingPool
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepaAliveTime,TimeUnit timeUnit,BlockQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExceptionHandler rejectedHandler) //ThreadPoolExecutor构造方法
corePoolSize
核心线程数,也可理解为最小线程数
maximumPoolSize
最大线程数
keepaAliveTime
非核心线程非活跃存活时间长度,线程闲置超过空闲时间时,被销毁
timeUnit
存活时间单位,枚举等
可以通过allowedCoreThreadTimeout方法允许核心线程被回收
workQueue
缓冲队列,
ArrayBlockingQueue(capacity):有界队列,队列有最大限制
LinkedBlockingQueue:无界队列,队列不限制容量
SynchronousQueue:同步队列,内部没有缓冲区
threadFactory
设置线程池工厂方法,可用来对线程的一些属性定制,一般使用默认即可,线程名,优先级等
rejectedHandler
线程池满时拒绝策略,
Abort:默认,满时,提交新任务会抛出异常
Discard:提交失败时,对任务直接丢弃
CallerRuns:提交失败时,由提交任务的线程直接执行提交任务
DiscardOldest:丢弃最早提交的任务
每种线程具体创建方法
- NewFixedThreadPool 固定大小线城池,核心、最大线程数指定的,无界队列LinkedBlockingQueue
- NewCachedThreadPool cached线程池,核心线程数0,最大整数Int的最大值,SynchronousQueue,只要没有空闲的线程,就会新建。
- newSingleThreadPool 单个线程的固定线程池,线程数设置为1
- newScheduledThreadPool Scheduled线城池,DelayedQueue按延迟时间获取任务的优先级队列
线程池任务执行流程
提交任务execute,submit(可以返回一个对象,了解任务的执行情况 ,可以取消任务的执行,获取执行结果,执行异常,最终也是通过execute执行的)
[外链图片转存失败(img-9QI1gaTg-1565101632764)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555649924146.png)]
先判断最大线程数
JUC常用工具
第一格,基本数据类型的原子类。
unsafe类:底层工具类,提供了类似C的指针操作,提供CAS功能,所有方法都是native
Semaphore:允许多个线程共享资源,适用限制使用共享资源,100个车,20个车位,最多20个有车位
写饥饿:多线程读写时,读线程访问非常频繁,导致总是有读线程占用资源,写线程很难加上写锁。
CompletableFuture:可以同时执行两个异步任务,然后对执行结果进行合并处理
ForkJoinPool:分治思想+工作窃取(有效平衡任务执行时间长短不一的场景)
考察点
-
理解线程的同步与互斥原理
临界资源与临界区的概念 重量级锁,轻量级锁,自旋锁,偏向锁,读写锁,重入锁的概念
-
掌握线程安全相关机制
CAS,synchronized,lock同步方式的实现原理 ThreadLocal是线程独享的局部变量,使用弱引用的ThreadLocalMap保存ThreadLocal变量
-
了解JUC工具的使用场景与实现原理
ReentrantLock,ConcurrentHash,LongAdder的实现方式
-
熟悉线程池的原理,使用场景,常用配置
大量短期的任务,适合使用Cached;系统资源紧张,固定线程池; 慎用无界队列,可能会有OOM的风险
-
理解线程的同步与异步,阻塞与非阻塞
同步异步:任务是否在同一个线程中执行 阻塞非阻塞:异步执行任务时,线程是否会阻塞等待结果,还是会继续执行后面的逻辑
加分项
-
结合实际项目经验或实际案例介绍原理
eg:项目中有一个需要高吞吐量的场景,使用了Cache的线程池
-
解决多线程问题的排查思路与经验
-
熟悉常用的线程分析工具与方法
如Jstack分析线程的运行状态,查找锁对象的持有状况
-
了解Java8对JUC的增强
用LongAdder替换AtomicLong,更适合并发度高的场景
-
了解Reactive异步编程思想,被压的概念与应用场景
真题汇总
-
如何实现生产者消费者模型?
可利用锁,信号量,线程通信,阻塞队列等方法实现
-
如何理解线程的同步与异步,阻塞与非阻塞?
-
线程池处理任务的流程?
-
wait与sleep有什么不同?
wait是Object方法,sleep是Thread方法 wait会释放锁,sleep不会 wait要在同步块中使用,sleep在任何地方使用 wait不需要捕获异常,sleep需要
-
Synchronized与ReentrantLock有什么不同,各适用什么场景?
-
读写锁适用与什么场景,ReentrantReadWriteLock是如何实现的?
读写锁:适合读并发多,写并发少的场景,另外一个可以的是CopyOnWrite
-
线程之间如何通信?
wait/notify机制 共享变量的synchronize&lock同步机制
-
保证线程安全的方法有哪些?
CAS,synchronized,lock,ThreadLocal
-
如何尽可能提高多线程并发性能?
减少临界区范围 使用ThreadLocal 减少线程切换 使用读写锁或CopyOnWrite
-
ThreadLocal用来解决什么问题,ThreadLocal是如何实现的?
不是用来解决多线程共享变量问题,而是用来解决线程数据隔离问题
-
死锁的产生条件,如何分析线程是否有死锁?
-
在实际工作中遇到过什么样的并发问题,如何发现排查并解决的?
六、数据结构与算法
- 知识点汇总
- 知识点详解
- 数据结构
- 树
- 二叉搜索树
- 平衡二叉树
- 红黑树
- B树
- B+树
- 算法
- 字符串匹配问题
- TopK问题
- 找出N个数中最小的k个数(N非常大)
- 从N有序队列中找到最小的K个值
- 常用算法介绍
- 面试考察点
- 加分项
- 真题汇总
知识点汇总
知识点详解
数据结构
树
二叉搜索树
每个节点都包含一个值,每个节点至多有两棵子树,左孩子小于自己,右孩子大于自己,时间复杂度是O(log(n)),随着不断插入节点,二叉树树高变大,当只有左(右)孩子时,时间复杂度变为O(n).
平衡二叉树
保证每个节点左右子树高度差绝对值不超过1.
比如,AVL树在插入和删除数据是经常需要旋转以保持平衡.适合插入删除少场景.
红黑树
非严格平衡二叉树,更关注局部平衡,而非总体平衡,没有一条路径比其他路径长出两倍,接近平衡,减少了许多不必要的旋转操作,更加实用.
特点:
- 每个节点不是红就是黑
- 根节点是黑色
- 每个叶子都是黑色空节点
- 红色节点的子节点都是黑的
- 任意节点到其叶节点的每条路径上存在的黑色节点数量相同.
B树
适用于文件索引,优先减少磁盘IO次数,最大子节点称为B树的阶
关键字分布在整棵树中,一个关键字只出现在一个节点中,搜索可能在非叶节点停止
m阶b树特点:
- 非叶子节点最多有m棵子树
- 根节点最少有两棵子树
- 非根非叶节点最少有m/2棵子树
- 非子叶节点保存的关键字个数,为该节点子树个数减一,有三个子树,必定包含两个关键字
- 非叶子节点的关键字大小有序,eg 37 51
- 关键字的左孩子都小于该关键字,右孩子都大于关键字
- 所有叶节点都在同一层
- 采用二分查找法
B+树
定义与b树基本相同,
区别:
- 节点有多少关键字,有多少子树
- 关键字对应子树的节点都大于等于关键字,子树中包括关键字自身
- 所有关键字都出现在叶节点中
- 所有叶节点都有指向下一个叶节点的指针
- 搜索时只会命中叶节点,叶子节点相当于数据存储层,保存关键字对应的数据,非叶节点只保存关键字与指向叶节点的指针,非叶节点B+树小很多(只保存了指针)
B+树比B树更适合做索引:
- 叶节点之间有指针相连,B+树跟适合范围检索
- 由于非叶节点只保留关键字和指针,B+树可以容纳更多的关键字,降低树高,磁盘IO代价更低
- B+树查询过程稳定,必须由根节点到叶节点,所有关键字查询路径相同,效率相当.Mysql数据的索引就提供了B+树的实现
B*树
在B+树的非叶节点上增加了指向同一层下一个非叶节点的指针
算法
字符串匹配问题
先于面试官交流,询问是否有其他要求
Example:判断给定字符串中的符号是否匹配
解题思路:
1. 使用栈
2. 遇到左括号入栈
3. 与右括号出栈,判断出栈括号是否成对
private static fianl Map<Character,Character> brackets = new HashMap<>();
static{
brackets.put(')','(');
brackets.put(']','[');
brackets.put('}','{');
}
public static boolean isMatch(String str){
if(str==null){
return false;
}
Stack<Character> stack = new stack<>();
for(char ch : str.toCharArray()){
if(barckets.containsValue(ch)){
stack.put(che);
} else if (brackets.contiansKey(ch)){
if(stack.empty() || stack.pop() != bracjets.get(ch)){
return false;
}
}
}
return stack.empty();
}
解题技巧
认真审题:
- 单模匹配还是多模匹配
- 时间复杂度空间复杂度是否有要求
- 明确期望的返回值,如,多匹配结果的处理
解题思路
- 单模匹配:BM,KMP算法
- 多模匹配:Tire树
- 前缀或后缀匹配
- 可以借助栈,树等数据结构
TopK问题
找出N个数中最小的k个数(N非常大)
解法:
- 用前K个数创建大小为K的大根堆
- 剩余的N-K个数与堆顶进行比较,小于堆顶,则替换。
时间复杂度:O(N*log(K))
优点:不用在内存中读入所有元素,适用于非常大的数据集
从N有序队列中找到最小的K个值
解法:
- 用N个队列的最小值组成大小为K的小根堆
- 取堆顶值
- 将堆顶值所在队列的下个值加入堆(与堆中最大值比较,若该值大于最大值则可停止循环)
- 重复步骤2,直到K次
时间复杂度:O((N+K-1)*log(K))
常用算法介绍
分治:快排,归并排序
面试考察点
- 了解基本数据结构及特点
- 如,有哪些二叉树,各有什么特点
- 表/栈/队列/数需要熟练掌握,深刻理解使用场景
- 红黑树适合用搜索,B+数适合做索引
- 了解常用的搜索/排序算法,以及复杂度和稳定性
- 特别是快速排序和堆排序
- 了解常用的字符串处理算法
- 如,BM使用后缀匹配进行字符串匹配
- 能够分析算法实现的复杂度
- 特别是时间复杂度
- 了解常用算法分类,解决问题的实录和解决哪类问题
加分项
- 能够将数据结构与实际使用场景结合
- 如,介绍红黑树时,结合TreeMap的实现,介绍B+数时,结合Mysql中的索引实现
- 不同算法在业务场景中的应用
- 如,TopK算法在热门排序中的应用
- 面对模糊的题目能够后沟通确认条件和边界
- 书写算法代码前,先讲一下解题思路
- 能够发现解答的一些问题,给出改进思路
真题汇总
- 各种排序算法的实现和复杂度,稳定性
- 二叉树的前中后序遍历
- 翻转句子中单词的顺序
- 用栈模拟队列(或用队列模拟栈)
- 对10亿个数进行排序,限制内存为1G
- 采用分治的思路
- 去掉(或找出)两个数组中重复的数
- 排序和hash两种思路
- 将一颗二叉树转换成其镜像
- 确定一个字符串中的括号是否匹配
- 给定一个开始词,一个结束词,一个字典,如何找到从开始词到结束词的最短单词接龙
- 考虑使用深度优先算法
- 如何查找两个二叉树的最近公共祖先
- 递归与非递归皆可实现
七、常用工具集
- 知识点汇总
- 知识点详解
- JMC(Java Mission Control)
- btrace
- 其他常用工具
- Git
- 常用Linux分析工具
- 考察点
- 加分项
- 真题汇总
知识点汇总
知识点详解
JMC(Java Mission Control)
1.7提供的图形化JVM分析与监控工具
[外链图片转存失败(img-hI3EamWI-1565101632766)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555666380171.png)]
-
JVM浏览器
- 可列出正在运行的Java程序JVM,每个JVM实例叫做一个JVM连接,使用JDP(Java Discover Protocol),可以连接到本地和远程运行的JVM
-
JMX(Java Management Extensions)
- 可以管理并监控JVM,通过对MBean的管理可以实时收集JVM信息,例如,类使用信息,堆使用情况,CPU负载,线程信息等,以及其他可以通过MBean管理的运行时属性
-
JFR(Java Flight Recorder)
- 提供了能够深入JVM内部,能看到运行时状态的能力,是个非常强大的性能profile工具,适合对程序进行调优和问题排查.主要对运行事件进行采集,可以通过指定采集的事件和频率,收集非常全面的的数据信息
- GC:不同阶段及耗时情况,停顿时间,分代大小
b-trace
JVM实时监控工具,基于动态字节码修改技术,实现对运行中的Java程序跟踪和替换,可在不重启JVM的情况下,监控系统运行情况,获取JVM运行时的数据信息,如,方法参数,返回值,全局变量,堆栈信息等
[外链图片转存失败(img-G5DrxP45-1565101632766)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555666734520.png)]
注意事项:
- 不恰当的使用会导致JVM崩溃
- btrace操作会持续JVM运行期间
- 通过JVM参数,取消btrace安全限制
其他常用工具
类 | 作用与特点 |
---|---|
jps | 查看Java进程信息:进程id,主类名称,主类全路径 |
jmap | 查看JVM中对象的统计信息:内存占用,实例个数,对象类型,可以堆分析 |
jstat | 实时监控JVM的资源和性能:类加载情况,内存容量、使用量,GC次数、时间 |
jstack | 查看JVM线程栈信息:线程名称、序号、优先级、线程状态、锁状态 |
jinfo | 动态查看,调整JVM参数 |
jcmd | 1.7提供的综合工具:向JVM发送诊断命令,包含jmap、jstat、jstack |
jconsole,jprofiler,jvisualvm | 监控与性能分析.建议使用JMC代替 |
实际应用场景
- 希望打印GC详细日志,发现未开启时,可通过jinfo开启print_gc_details,动态生效
- 分析内存泄漏风险时,使用jmap或jcmd定期获取堆对象的统计信息,发现定期增长的可疑对象
- 发现所有服务都存在耗时较高的情况,可以使用jstat检查gc回收状况,看看是不是gc停顿耗时过高
- 遇到某个服务卡死或停止处理时,可用jstack查看线程栈,是否存在多个线程为block状态,产生了死锁
- 当服务上线后没有达到预期,可用jmc分析JVM运行信息,看看哪些热点方法可以优化,哪些线程竞争可以避免
Git
Git常用工作流
常用Linux分析工具
类 | 作用与特点 |
---|---|
vmstat | 进程,虚拟内存,页面交换,IO读写,CPU活动 |
instat&iotop | 系统IO状态信息 |
ifstat&iftop | 实时网络流量监控:能看到那个ip在霸占网络流量 |
netstat | 查看网络相关信息,各种网络协议套接字状态 |
dstat | 全能型实时系统信息统计:CPU、内存、网络、负载、系统磁盘信息 |
strace | 诊断,调试程序的系统调用:JVM执行native方法时进行调试 |
GDB | 程序调试,JVM因未知原因崩溃,coredump分析 |
lsof | 查看系统当前打开的文件信息 |
tcpdump | 网络抓包工具:服务之间的调用 |
traceroute | 网络路由分析工具:本地和目标计算机之间的所有路由,经过公网的服务之间网络问题排查 |
考察点
- 了解常用的JVM分析工具
- 分析线程死锁可用jstack
- 内存溢出可用jmap:堆中占用最大的对象类型
- 分析程序性能可用jmc中的jfr
- 掌握Git的常用操作与工作流
- merge命令(提交commit来合并修改)与rebase命令(修改提交历史记录)的区别
- 各种工作流的优缺点
- 了解Linux系统下常用的分析工具
- 磁盘写入用时较高,可用iostat分析磁盘io情况
- 不能确定问题,可用strace对文件写入的系统调用进行分析
- 定位CPU负载较高的原因,可用top与jstack结合分析
加分项
- 能够主动出击体现知识广度
- 能够体现使实战能力
实战重点说明
询问线上问题
遇到过单机请求耗时较高的问题,通过JMC的飞行记录器采样分析,发现写log日志时,线程竞争非常激烈,很多线程在等待写锁时耗时非常大。
进一步通过iostate排查发现,util利用率比较高,最后定位是磁盘出现了问题。解决方法,一方面更换磁盘来解决问题,另一方面对写竞争比较激烈的日志文件,使用了异步log机制。
介绍自己开发的项目:
1.上线前使用JMC做了性能profile,发现并优化了某些问题
2.对两个不同方案使用JMH测试,验证了两个方案的性能
真题汇总
- 排查JVM问题有哪些常用工具?(你曾遇到过什么问题,如何排查,如何解决的)
- Git合并代码由哪些方法?有什么区别?
- Git与SVN有哪些差异?
- 你所在的吐纳对项目开发使用什么样的工作流?有什么优点?
JMC,TCPdump,Strace
八、必会框架1️⃣一Spring全家桶
- 知识点汇总
- 知识点详解
- Spring
- Spring中的基本概念
- Spring框架
- Spring机制与实现
- Spring应用
- Spring Context初始化流程
- Spring中Bean的生命周期
- Spring扩展接口
- SpringBoot
知识点汇总
知识点详解
Spring
Spring中的基本概念
[外链图片转存失败(img-TAawpDbs-1565101632767)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555670082098.png)]
- IOC/DI
- 对象的属性由自己创建,为正向流程,而由Spring创建,为控制反转.
- DI(依赖注入)为实现IOC的一种方式,通过配置文件或注解包含的依赖关系创建与注入对象.
- 正向流程导致了对象与对象之间的高耦合,IOC可以解决对象耦合的问题,有利于功能的复用
例如,招聘中,公司按岗位要求安排人选为正向流程,反之,由第三方猎头匹配岗位和候选人,并向公司推荐,则为控制反转
- Context&Bean
- 所有由Spring创建,管理,用于依赖注入的对象,称为Bean
- 所有Bean创建并完成依赖注入后,都会放入Context上下文中进行管理
- AOP(Aspect Oriented Programming 面向切面编程)
- 以功能进行划分,对服务顺序执行流程中的位置进行横切,完成各服务共同需要实现的功能
Spring框架
[外链图片转存失败(img-oh1hG9gQ-1565101632768)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555670118767.png)]
重点了解一下几点
- Core
- Spring组件的核心
- Beans和Context
- 实现IOC/DI的基础
- Web
- 包括SpringMVC是Web服务的控制层实现
- AOP
- 面向切面编程
Spring机制与实现
Spring应用
-
@Component和@Bean的区别
Component在类上使用,表明其是组件类,需要Spring为这个类创建bean
Bean使用在方法上,告诉Spring这个方法返回一个bean对象,需把返回的对象注册到Spring应用的上下文中
-
设置类,autowried、qualilfier 以及bytype、byname不同的自动装配机 制
-
Web类知道就行
Spring Context初始化流程
三种:xml配置的、Springboot的、web的ApplicationContext
[外链图片转存失败(img-91cSprf7-1565101632769)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555677689877.png)]
[外链图片转存失败(img-H3C7CbEB-1565101632770)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555677702922.png)]
-
prepareRefresh();
对刷新进行准备,包括设置开始时间,设置激活状态,初始化Context中的占位符,子类根据其需求执行具体准备工作,而后再由父类验证必要参数 -
obtianFreshBeanFactory();
,刷新并获取内部的BeanFactory对象 -
prepareBeanFactory(beanFactory);
,对BeanFactory进行准备工作,包括设置类加载器和后置处理器,配置不能自动装配的类型,注册默认的环境Bean -
postProcessBeanFactory(beanFactory);
为Context的子类提供后置处理BeanFactory的扩展能力,如想在bean定义加载完成后,开始初始化上下文之前进行逻辑操作,可重写这个方法 -
invokeBeanFactoryPostProcessors(beanFactory);
,执行Context中注册的BeanFactory后置处理器,有两张处理器,一种是可以注册Bean的后置处理器,一种的针对BeanFactory的后置处理器,执行顺序是先按优先级执行注册Bean的后置处理器,而后再按优先级执行针对BeanFactory的后置处理器SpringBoot中会进行注解Bean的解析,由ConfigurationClassPostProcessor触发,由ClassPathDefinitionScanner解析,并注册到BeanFactory
-
registerBeanFactoryProcessor(beanFactory();
,按优先级顺序在BeanFactory中注册Bean的后置处理器,Bean处理器可在Bean的初始化前后处理 -
initMessageSource();
初始化消息源,消息源用于支持消息的国际化 -
initApplicationEventMuticaster();
初始化应用事件广播器,用于向ApplicationListener通知各种应用产生的事件,标准的观察者模型 -
onRefresh();
,用于子类的扩展步骤,用于特定的Context子类初始化其他的Bean -
registerListeners();
,把实现了ApplicationListener的类注册到广播器,并对广播其中早期没有广播的事件进行通知 -
finishBeanFactoryInitialization(beanFactory);
,冻结所有Bean描述信息的修改,实例化非延迟加载的单例Bean -
finishRefresh();
,完成上下文的刷新工作,调用LifecycleProcessor.onRefresh(),以及发布
ContextRefreshedEvent事件 -
resetCommonCaches();
在finally中执行该步骤,重置公共的缓存,如ReflectionUtils中的缓存,
AnnotationUtils等
Spring中Bean的生命周期
[外链图片转存失败(img-9XhQo5cX-1565101632770)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555677947778.png)]
Spring扩展接口
扩展接口 | 作用 |
---|---|
BeanFactoryPostProcessor | 处理Bean前,对BeanFactory进行预处理,描述信息加载完未初始化 |
BeanDefinitionRegistryPostProcessor | 可添加自定义的Bean,根据scope创建新的代理bean |
BeanPostProcessor | 支持Bean初始化前后的处理 |
ApplicationContextAware | 可以获得ApplicationContext及其中的Bean,动态获取bean |
InitializingBean | 在Bean创建完,所有属性注入后执行,对自动装配的属性验证 |
DisposableBean | 在Bean销毁前执行,回收工作 |
ApplicationListener | 用于监听产生的应用事件 |
前三个可以通过实现ordered或者priordered接口指定执行顺序,priorityordered先于ordered
SpringBoot
九、必会框架2️⃣Netty与RPC与ORM
- 知识点汇总
- 知识点详解
- Netty
- Netty线程模型
- RPC
- 开源RPC框架介绍
- Mybatis
- Mybatis处理流程
- 面试考察点
- 加分项
- 真题汇总
知识点汇总
无
知识点详解
Netty
Netty线程模型
[外链图片转存失败(img-r6S1Rete-1565101632771)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555678637956.png)]
其中ChannelPiepline的设计模型采用的是Handler组成的责任链模型
更详细介绍请看这可能是目前最透彻的Netty原理架构解析
添加~~~
RPC
Remote Procedure Call(远程过程调用))
[外链图片转存失败(img-1KD2N1IR-1565101632771)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555678719460.png)]
开源RPC框架介绍
Dubbo 打包(double) | Motan | gRPC |
---|---|---|
服务治理型框架 多种负载均衡策略 自动服务注册治理 可视化服务治理 基于TCP私有协议,Netty | 轻量级服务治理框架 支持多语言 支持ServiceMesh方案 拓展能力强大 基于TCP私有协议,Netty | 支持多语言交互 提高服务治理拓展 支持流式调用 支持服务端推送 基于HTTP2.0 |
Mybatis
Mybatis处理流程
[外链图片转存失败(img-3pfgDxvK-1565101632772)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555679091809.png)]
面试考察点
- 掌握Spring的IOC,AOP的概念与实现
- 掌握Spring的Context创建流程和Bean的生命周期
- 了解Spring常见注解的作用与使用方法
- 了解SpringBoot的相关知识点
- 掌握Netty的线程处理模型
- 知道常用RPC框架的特点
- 了解Mybatis和Hibernate的实现原理
加分项
- 阅读过源码,了解实现细节和思路,结合断点调试的方法
- 不仅会应用,还能够理解设计理念,设计思想
- 了解最新实现或方向
- 有实际优化经验,例如netty调优,尽量减少io线程占用,把可以后置的处理放到业务线程池中
真题汇总
- SSH与SSM框架组合的区别
- SpringMVC与Struct的区别,Mybatis与Hibernate的区别
- 描述一下SpringContext的初始化流程
- 简单介绍一下Bean的生命周期与作用域
- Spring配置中的placeholder占位符是如何替换的,有什么办法实现自定义的配置替换
- 通过BeanFactoryPostProcessor处理,
- 自定义处理可以扩展PropertyPlaceholderConfigurer或PropertySourcesPlaceholderConfigurer
- SpringMVC工作流程
- 从HandlerMapping查找handler,执行handler,执行完成返回ModelAndView,由视图解析返回视图,再由渲染器进行渲染
- Spring如何解决循环依赖
- 构造器循环依赖和setter循环依赖两部分解答,构造器通过使用创建Bean中的标识池判断是否产生了循环创建,setter通过引入ObjectFactory解决
- Bean构造方法,@PostConstuct注解,InitiatingBean,init-method的执行顺序
- Netty中有哪些重要的对象,它们之间的关系是什么
- Channel,Socket,NioEventLoop,ChannelPipeline等
- RPC与HTTP的区别,以及相对应的使用场景
- 使用方式:HTTP使用C/S(client)方式调用,RPC使用动态代理方式调用
- 请求模型:HTTP经过dns解析,4/7层代理等中间环节,rpc点对点直连
- 服务治理:rpc丰富的服务治理功能,熔断,负载均衡
- 语言友好:HTTP对跨语言之间的更加友好
- RPC的交互流程是怎样的
- 介绍一下Mybatis的缓存机制
- Mybatis如何配置动态Sql,有哪些动态标签
十、缓存(Redis与Memcache)
- 知识点汇总
- 知识点详解
- MC的内存结构
- Redis
- 功能
- 持久化
- 淘汰策略
- Redis数据结构
- 缓存常见问题
- 面试考察点
- 加分项
- 真题汇总
知识点汇总
缓存是高并发场景下,提升热点数据访问性能的手段
知识点详解
MC的内存结构
[外链图片转存失败(img-YpKQLgqg-1565101632773)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555679749069.png)]
添加~~~
Redis
功能
bitmap
支持按位存取信息,可用于实现bloomfilter
hyperLogLog
提供不精确的去重统计功能,适合用作大规模数据的去重统计
geospatial
可用于保存地理位置,并作位置距离计算或根据半径计算位置等
Sub/Pub
订阅发布功能,可用于简单的消息队列
pipeline
可批量执行一组指令,一次性返回全部结果,另一种方式是使用脚本
事务功能是串行执行,但失败不会回滚
持久化
- RDB
- 将数据集以快照形式写入磁盘,通过fork子进程执行,采用二进制压缩存储
- redis数据保存在单一文件中,适合用作灾害备份,
- 缺点:快照写入磁盘之前宕机会丢失数据,保存快照时会短时间服务停顿
- AOF
- 以文本日志的形式,记录redis的每一个操作
- 追加模式,灵活同步策略以保持同步(每秒,每次操作,不同步)
- 缺点:磁盘文件与RDB方式比大,效率低于RDB
高可用
三级能哨兵监视redis主服务器状态,主挂掉,选出新主
master选举
- slave的priority越低,优先级越高
- 同等情况,slave复制的数据越多
- id越小,容易被选中
集群中sentinel也会多实例部署,之间通过rift协议保证自身的高可用
redis-claster使用分片机制,16384(2^10)个slat,每个负责一部分,通过slave节点保障数据冗余
淘汰策略
voltile-
对设置的生存时间的key进行lru,最小生存时间,随机剔除
allkeys-
则是对所有key
no-eviction
则是不进行剔除,读取正常,写入则会报异常
Redis数据结构
[外链图片转存失败(img-lfHZnttW-1565101632773)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555680619319.png)]
使用字典存储不同类型的数据,如图中的dict HT,字典由一组dictEntry组成(指向K-V的指针,及指向下一个dictEntry的指针)。所有对象都被封装为redisObject(包括了对象的类型与具体对象的存储方式)
-
sting类型,最常使用的,通过SDS(Simple Dynamic String)实现
SDS类似ArrayList可以通过预分配冗余空间,减少内存频繁分配
-
list由ziplist压缩链表和linkedlist双链表实现
ziplist
存储在连续位置上,存储效率高,不利于修改操作,适用于数据较少的情况linkedlist
再插入节点上复杂度低,但内存开销大,节点地址不连续,容易产生内存碎片- 3.2后增加了
quicklist
,其本身是双向无环链表,每个节点是ziplist
-
hash由ziplist和hashtable实现
- 当
hash
中的K/V字符串长度小于64B且hash长度小于512时使用ziplist
,超过时使用hashtable
- 当
-
set由hashtable和intset
- 当set中的值都为数值且set长度小于512时使用
intset
,否则使用hashtable
- 当set中的值都为数值且set长度小于512时使用
-
sorted set有序集合(zset)由ziplist和skiplist实现
- 当sorted set中元素长度小于64B且
zset
长度小于128时使用ziplist
,超过时会使用skiplist
- 当sorted set中元素长度小于64B且
redis内存分配采用jemalloc,将内存划分为small,large,huge三个范围,并在其中划分了不同大小的内存块,存储数据时选择大小合适的内存块进行存储,有利于减小内存碎片
缓存常见问题
缓存问题 | 产生原因 | 解决方案 |
---|---|---|
缓存更新方式 | 数据变更,缓存时效性 | 同步更新,失效更新,异步更新,定时更新 |
缓存不一致 | 同步更新失败,异步更新 | 增加重试,异步补偿任务,最终一致 |
缓存穿透 | 恶意攻击 | 空对象缓存,bloomfilter过滤器 |
缓存击穿 | 热点key失效 | 互斥更新,随机退避,差异失效时间 |
缓存雪崩 | 缓存宕机 | 快速失败熔断,主从模式,集群模式 |
-
失效时继续使用数据,由异步更新数据,避免了失效瞬间的空窗期。纯异步:定时更新
-
缓存穿透,一直用不存在的用户id频繁请求接口,查询缓存不命中,穿透db查询依然不命中,大量db查询
不存在的用户,缓存中保存空对象进行标记,可能会导致大量无用数据
bloomfilter,存在性检测,不存在则数据一定不存在;存在则实际可有可无
-
缓存击穿,某个热点数据失效时,大量针对这个数据的请求会针对到数据源
互斥锁更新,同一个进程,针对同一个数据不会并发请求db,减小db的压力
随机退避,失效时随机sleep一个很短的时间,再次查询如果失败,才执行更新
差异失效时间,针对多个热点,避免同一时刻失效
面试考察点
- 了解缓存的使用场景,不同类型缓存的使用方式
- 对db热点数据进行缓存能减轻db压力,对热点服务进行缓存能提高服务并发性能
- 单纯的K/V缓存场景可以使用MC,需要缓存特殊数据结构时可以使用Redis
- 如,缓存视频播放列表可以使用redis的list缓存,计算排行榜数据时可以使用zset
- 掌握MC和Redis的常用命令
- 了解MC和Redis在内存中的存储结构
- 了解MC和Redis得数据失效方式和提出策略
- 如主动触发的定期删除,被动触发的延期删除
- 了解Redis的持久化,主从同步与cluster部署的原理
- 如RDB与AOF的实现方式与区别
加分项
- 结合实际应用场景来介绍缓存的使用
- 如调用后端服务接口获取信息时,可使用本地+远程的多级缓存
- 动态排行榜,使用zset
- 有过分布式缓存设计和应用经验
- 什么场景使用了redis,使用了什么样的数据结构,解决了那类的问题
- 使用MC时,根据预估值的大小,调整MC slave的分配参数
- 了解缓存使用中可能出现的问题
- redis 单线程处理,避免耗时较高的单个请求任务,防止相互影响
- 避免和其他CPU密集型的进程部署在同一台机器
- 禁用内存交换,防止redis的缓存数据交互在硬盘上,影响性能
- 知道Redis的典型应用场景
- 实现分布式锁,
- 使用bit-map实现bloom filter
- 使用 进行uv统计
- 知道Redis的新特新
- 5.0stream相较Sub/Pub功能可将未消费的信息进行缓存类似(kafka)
真题汇总
- Redis和Memcache有什么区别,该如何选择?
- 你用到那些Redis的数据结构,在什么场景下?
- Redis有哪些持久化方式,有什么区别?
- Redis的失效机制是怎样的,Redis有哪些淘汰策略?
- 如何保证Redi的高并发和高可用?
- 高并发:主从读写分离,多从库,多端口实例以及cluster集群部署
- 高可用:sentinel保证主库宕机时,重新选住并完成从库的变更
- 如何使用Redis实现延时队列,如何使用Redis实现分布式锁?
- 可使用sortedset实现延迟队列,使用时间戳做score,消费方使用zrange by score命令获取指定延迟时间之前的数据.
- 可是使用setnx设置key,返回1则获取锁成功,返回0则获取锁失败,需要同时使用px参数设置超时时间,防止获取锁的实例宕机后产生死锁,严格场景下使用red log方案,单比较复杂
十一、消息队列与数据库
- 知识点汇总
- 消息队列
- RabbitMQ
- ActiveMQ
- RocketMQ
- kafka
- 数据库
- 关系型数据库
- NoSQL(Not Only SQL)
- NewSQL
- 数据库范式
- 知识详解
- Kafka架构
- Kafka消息生产/生产流程
- 数据库事务
- 事务特性
- 事务并发问题与隔离级别
- 事务分类
- MySQL
- 索引
- MySQL调优
- 考察点
- 加分项
- 真题汇总
知识点汇总
消息队列
RabbitMQ
Erlang开发的开源消息队列,通过Erlang的Actor模型,实现了数据的稳定可靠传输.支持AMQP,XMPP,SMPP等多种协议,因此也比较重量级,由于采用broker代理架构,发送给客户端时,先在中间队列进行排队.RabbitMQ单机吞吐量在万级不算很高
ActiveMQ
可部署于代理模式和P2P模式,同样支持多种协议,单机吞吐量在万级.但是不够轻巧,对于队列较多的时候支持不是很好,并且有较低概率丢失消息
RocketMQ
阿里开源的消息中间件,单机支持十万级的吞吐量,使用Java开发具有高吞吐量,高可用性的特点,适合在大规模分布式系统中使用
kafka
有Scala开发的跨语言高性能分布式消息队列,单机吞吐量在十万级,消息延迟在毫秒级.完全的分布式系统,blocker,producer,consumer都是原生自动支持分布式,依赖ZooKeeper做分布式协调.支持一写多读,可被多个消费者消费.消息皆不会丢失,但可能重复
数据库
关系型数据库
- Oracle
- 功能强大,缺点贵
- MySQL
- 互联网行业中最流行的数据库,业务逻辑简单数据可靠性要求低
- MariaDB
- MySQL的分支,由开源社区维护
- PostgreSQL
- 类似于Oracle的多进程模型,可支持高并发的应用场景,几乎支持所有SQL标准,适合严格的企业应用场景
NoSQL(Not Only SQL)
- Redis
- 适用于数据变化快,数据大小可预测的场景
- MongoDB
- 基于分布式文件存储的数据库
- 将数据存储为一个文档,数据结构由键值对组成
- 适用于表结构不明确,数据结构不断发生变化的场景
- 不适合有事务和复杂查询的场景
- Hbase
- 是在hdfs(Hadoop Distributed File System hadoop分布式文件系统)中分布式面向列的数据库,类似于Google的Bigtable
- 可提供快速随机访问海量结构化数据,在表中由行排序,一个表中有多个列族,每个列族有任意数量的列
- 依赖于hdfs,可以实现海量数据的可靠存储,适用于数据量大,写多读少,不需要复杂查询的场景
- Cassandra
- 高可靠大规模分布式存储系统
- 支持分布是的结构化K-V存储
- 以高可用为主要目标
- 适合写多场景,简单查询,不适合数据统计
- Pika
- 提供大容量类Redis的存储服务
- 兼容Redis的五种数据结构的大部分命令
- 使用磁盘存储,解决Redis存储成本问题
NewSQL
- TiDB
- 开源分布式关系型数据库
- 几乎完全兼容MySQL
- 支持水平弹性扩展,ACID事务,标准SQL,MySQL语法和MySQL协议
- 具有数据强一致性的高可用性
- 既适合在线事务处理,也适合在线分析处理
- OceanBase
- 蚂蚁金服所有,满足金融级数据可靠性以及数据一致性要求的数据库系统
- 已商业化不再开源
数据库范式
范式级别越高,对数据表要求的越严格
- 第一范式(最低)
- 要求表中的字段不可再拆分
- 第二范式
- 在满足第一范式的基础上,要求每条记录由主键唯一区分,记录中的所有属性都依赖与主键
- 第三范式
- 在满足第二范式的基础上,要求所有属性直接依赖于主键,不允许间接依赖
- 巴斯-科德范式(一般满足至此即可)
- 在满足第三范式的基础上,要求联合主键的各字段之间互不依赖
- 第四范式
- 第五范式
知识详解
Kafka架构
[外链图片转存失败(img-gu6Ns5tB-1565101632774)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555736863349.png)]
- Kafka集群有多个server组成,每个server称为一个Broker,为消息代理
- Kafka中消息是按topic进行划分的,一个topic就是一个queue,实际应用中不同数据可设置为不同topic
- 一个topic可以有多个consumer,当producer发送数据到topic中时,订阅了该topic的consumer都能接收到消息
- 为提高并行能力,维护了多个portion分区,每个portion保证id唯一且有序,新消息会储存在队尾,
- portion持久化时会分段,保证对较小的文件进行写操作,以提高性能
- 每个topic会被分为多个portion,存于多个broker上,以保证容灾
Kafka消息生产/生产流程
[外链图片转存失败(img-iT7kuUlk-1565101632774)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555737083837.png)]
- 对consumer进行分组管理,以支持消息的一写多读
- producer有多种方式选择portion,轮循(默认),指定,根据key值得hash选择portion
- 消息得发送有三种
- 同步(默认):producer发送消息时,同步获得反馈
- 异步:producer以batch的方式push消息,可以极大地提高性能,也增加消息丢失风险
- oneway:只发送消息,不返回结果
- Kafka确保每个group中只能有一个consumer消费
- 通过group coordinator管理哪个consumer负责消费哪个portion.默认支持range和轮循分配
- 在zookeeper中保存了每个topic的每个portion的消费偏移量offset.通过更新offset,以保证每条消息都被消费
ps.每个consumer线程相当于一个consumer实例,当consumer group中的consumer数量大于portion时,有的consumer会读取不到数据
数据库事务
事务特性
原子性(操作要么全成功,要么失败回滚)、一致性、隔离性(多个事务之间相互隔离)、持久性
事务并发问题与隔离级别
脏读:事务处理过程中,读取了另一个事务中未提交的数据
不可重复读:多次查询,返回不同的数据值(因为中间可能被其他事务更改数据了)
幻读:第二次查询,结果集不同,记录的增加或删除导致
[外链图片转存失败(img-ttVPxzM5-1565101632775)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1555737420868.png)]
事务分类
-
扁平事务:所有操作都在同一层次(日常使用最多).缺点:不能提交事物的某一部分
-
带保存点的扁平事务:在事务中插入保存点,失败回滚时,可回滚至任意保存点,而不是回滚整个事务
-
链事务:可看作上一事务的变种,事务提交时会将上下文隐式传递给下一个事务,事务失败时,回滚至最近的事务
只能是最近的一个保存点
-
嵌套事务:由上层事务和子事务组成,类似树形结构.顶层事务负责逻辑处理,子事务负责具体操作.子事务提交后需等待上层事务提交才算完成,若上层事务回滚,则所有子事务回滚
-
分布式事务:分布式环境中的扁平化事务
- XA规范:保证强一致性的刚性事务方案
- 两段式提交 实际中使用多
- 需要事务协调者保证,事务参与者都完成第一阶段的事务准备阶段.当都准备完成则通知事务参与者进行下一阶段事务.(类似于Java中的countdownlatch和cyclicbarruer)
- 在一个进程发生故障时,会有较长时间的阻塞
- 三段式提交
- 增加PreCommit环节,减少两段式提交中的阻塞时间
- 两段式提交 实际中使用多
- TCC:满足最终一致性的柔性事务方案
- 对每个操作都注册确认和补偿操作
- try阶段:检测业务系统,预留资源
- confirm阶段:确认提交
- cancel阶段:业务执行错误时执行回滚,释放预留资源
- 消息事务:消息一致性方案
- 将本地操作与消息发送封装在一个事务中,保证本地操作与消息发送要么都成功,要么都失败
- 下游应用收到收到消息执行对应操作
- GTS/Fescar(视频中有)
- XA规范:保证强一致性的刚性事务方案
MySQL
以下是曾经收集的SQL笔记:
索引
可大幅增加数据库的查询性能,适合读多写少的场景
代价:需要额外空间保存索引,插入更新删除时,由于更新索引增加额外的开销
- 索引类型
- 唯一索引
- 索引列中的值唯一,允许出现空值
- 主键索引
- 特殊的唯一索引不允许出现空值
- 普通索引
- 索引列中的值不唯一,成绩什么的
- 联合索引
- 多个列按顺序组成索引,相同列不同顺序为不同索引,最左原则,从左到右匹配
- 全文索引
- 只能在char varchar text等类型使用
- 唯一索引
- 索引实现
- B-Tree
- 最常用,大于或者小于的范围查询
- R-Tree
- 用于处理多维数据的数据结构,可对地理数据进行空间索引
- Hash
- 效率比B-Tree高,不支持范围查找,排序等功能
- FullText
- 适用于全文索引
- B-Tree
MySQL调优
-
表结构与索引
- 分库分表,读写分离
- 为字段选择合适的数据类型
- 将字段多的表分拣成多个表,增加中间表
- 混合范式与反范式,适当冗余
- 为查询创建必要索引,但避免滥用
- 尽可能地是以哦那个NOT NULL
-
SQL语句优化
-
寻找最需要优化的语句:分析慢查询日志
- 使用频繁或效率最低的
-
利用查询工具:explain,profile
explain:分析语句的执行计划,是否使用索引,使用了哪个索引,扫描了多少记录是否使用了文件排序
profile:每个语句执行过程中的各分部耗时
-
避免使用SELECT *, 只取需要的列
避免查询出不需要使用的字段,避免查询列字段的源信息
-
尽可能使用prepared statements
性能更好,防止SQL注入
-
使用索引扫描来排序
在有索引的字段上进行排序操作
-
-
MySQL参数优化
-
硬件及系统配置
从1到4优化成本增加,优化效果降低
考察点
-
了解消息队列,数据库的基本原理和常用队列,数据库的特点
- 消息队列适用于异步队列,削峰填谷
-
了解Kafka的架构和消息处理流程
- 如何通过portion保证并发能力与冗余灾备
- consumer group如何保证每个consumer不会回去重复的消息
-
理解数据库事务的ACID特性和隔离级别
-
掌握常用的MySQL语句和常用函数
where、order by、join、sum、count
-
了解MySQL数据库不同引擎多的特点以及不同类型的索引实现
加分项
-
了解新特性
MySQL8.0窗口函数,支持新的查询方式;支持通用表表达式,复杂查询中的嵌入表语句更加清晰
-
知道数据可表设计原则,有设计经验
如何对容量进行评估,适当分库分表保证未来服务的可扩展性
-
有过数据可调优经验
明明建立了索引语句,但是查询效率还很慢,后来通过explain分析,发现表中有多个索引,MySQL优化器选用了错误的索引导致查询效率偏低,通过SQL语句中使用use index 指定索引来解决
-
消息队列使用经验,不同场景下的取舍
日志推送场景,对小概率消息丢失可以容忍可以设置为异步发送消息
金融类业务,需要设置同步发送消息,并且设置最高的消息可靠性,把request required参数设置为-1
真题汇总
-
使用过消息队列吗,在什么场景使用,用来解决什么问题
-
使用队列是如何保证可靠性
消息的发送者保证投递到消息队列,消息队列自身的高可用,消费方处理完后修改offset
可以结合kafka的消息发送同步异步,消息的可靠性配置
-
MQ有可能发生重复消费吗,如何解决
1.通过对消息处理实现密等,消除消息重复的影响2.使用redis 消息去重,避免重复消息的处理
-
数据库查询语句很慢,如何优化
创建索引,减少关联查询,优化SQL查询条件
-
数据库事务有哪些特性,事务隔离级别有哪几种
-
如何随SQL语句进行优化
十二、架构演进与容器技术
- 系统架构演进
- 单体架构
- 微服务架构
- 分布式体统的CAP原则和BASE理论
- 云原生服务
- 云原生的12要素
- 下一代架构Service Mesh
- 微服务与Service Mesh的区别与联系
- 容器
- Docker
- Docker原理
- Kubernetes
- Kubernetes架构
- 考察点
- 加分项
- 面试技巧
- 提示
系统架构演进
单体架构
一个项目中的多个服务混合部署在一个进程内,服务之间的交互都是通过进程内调用完成的
优点:快速开发部署服务,服务之间调用的性能最好
缺点:随着业务增长项目越来越臃肿,服务之间由于jar包引用导致频繁的依赖冲突,服务资源变更困难,一个服务可能被不同业务引用,升级资源需要多个业务方同时升级.业务方可直连业务资源,存在明显的数据安全风险.修改代码后回归困难,架构难以调整等
以上问题都是由于服务之间的强耦合所导致
微服务架构
起源是为了解决企业应用问题,特点高内聚低耦合,不同的服务单独开发单独测试单独部署,服务之间通过RPC或HTTP进行远程交互,微服务架构解决了单体架构的耦合问题,但也带来了新的问题.由于不同服务部署在不同进程或主机中,要是用前需要先找到服务,即服务发现
一般微服务采用两种发现方式
- RPC方式,通过注册中心完成服务发现.由服务调用端获得服务全部可用节点,再由client进行负载均衡调用服务
- 通过http调用服务端提供的restful接口,通过nginx反向代理完成负载均衡
不论哪种方式都从进程内通信变成了远程通信,使得性能下降,可靠性降低
分布式体统的CAP原则和BASE理论
Consistency 一致性:所有节点在同一时间的数据完全一致
Availability 可用性:任意时间总能执行读写任务
Partition tolerance 分区容差:同出现节点异常时,仍然能提供满足需求的服务
三者只可能同时满足两个
只选择CA相当于单机架构
只选择CP,则允许在极端情况下出现短时的服务不可用,如zookeeper,不适合做服务注册中心
只选择AP,则允许出现短时间不一致,如eureka
Basically Available(基本可用),Soft state(软状态),Eventually consistent(最终一致性)
是对CAP中一致性权衡的结果,即使无法做到强一致性,也可以根据系统的特点采用适当的方法得到最终一致性
云原生服务
云原生架构由微服务组成,是一种能够快速持续可靠规模化的交付业务服务的模式
一般为两种,私有云和公有云
- 容器化的微服务:云原生的主体
- Devops:对微服务的动态管理
- 持续交付:云原生的目的
IaaS提供计算资源
PaaS平台提供运行环境
微服务的解耦会导致道德业务拆分成小的服务,每个服务的部署都需要考虑单点问题,需要多机房多节点部署,会造成系统资源的浪费,服务扩容是需重新整理服务依赖的环境
容器化技术把服务的运行环境进行打包管理,解决了扩缩容时对运行环境的管理问题和服务器的利用率问题
随着容器技术的逐渐成熟,微服务架构也快速普及
云原生的12要素
- 基准代码:代码由版本管理工具管理,一个应用只有一份基准代码,运行时有多个部署实例
- 依赖:在应用中显式的声明依赖
- 配置:环境中存储配置,说明配置与代码要分开管理
- 后端服务:将依赖的后端服务当作统一资源来对待
- 构建,发布,运行:需要严格区分构建,发布,运行三个步骤,并且要按顺序进行
- 进程:以一个或多个进程运行,要保证进程的无状态性
- 端口绑定:应用启动后,相应的端口可持续提供服务直至应用关闭
- 并发:应用进程之间可以并发处理,英雌可以通过对进程方式进行水平扩展
- 易处理:应该容易被管理,可以通过优雅停机和快速启动构建最健壮的服务
- 开发/生产等价:指在开发生产环境中的应用尽可能一致
- 日志:要合理记录应用的运行日志,要把日志当作事件流来对待
- 管理进程:把后台管理任务当作一次性进程来运行
下一代架构Service Mesh
service mesh在微服务的基础上引入了sidecar边车的概念,每个服务都伴生有一个sidecar,服务的交互不再由服务自身完成,服务所有出入的请求都交由sidecar处理,在管理层面对sidecar进行统一管理,由sidecar实现服务发现,负载均衡,流量调度等
微服务与Service Mesh的区别与联系
微服务要解决的是多个服务之间的耦合问题,如上图绿色竖线,将ServiceA,B,C进行解耦,单独部署单独管理,使得每个服务都要实现服务发现,服务间远程交互,负载均衡,高可用策略,服务熔断等一系列的功能
service mesh是将与业务逻辑无关的功能进行解耦,如图中红色的线,把与服务交互的功能从服务中剥离出来,统一交由sidecar实现,让服务更聚焦于业务逻辑,提高研发效率.sidecar更专注于服务的交互与治理,追求极致的功能与性能
因此service mesh并不能称为一项新的技术,而应当是微服务的演进
由于sidecar是独立进程,所以天然适合为不同语言的服务提供统一的治理能力,因此跨语言治理也是service mesh的一个重要特点
由于引入了额外的sidecar,service mesh也产生新的性能与可靠性问题,这也是service mesh架构需要解决的问题
只是让问题转移,方便对问题集中整治和处理,让服务更聚焦于业务研发,不同的功能交给专门的组件处理
通过架构演进,虽然没有消灭复杂度,但让问题变得透明化,业务无感知,提升服务整体开发效率扩展能力
容器
Docker
微服务架构的基础
- 作用:
- 构建,部署,运行服务
- 服务版本管理
- 屏蔽环境差异
- 隔离服务
- 提高资源利用率
- 特点:
- 开源容器技术
- 基于LXC,高效虚拟化
- 适合大规模构建
- 灵活可拓展
- 管理简单
- 概念:
- 镜像(Images):服务代码与运行环境的封装
- 容器(Container):基于镜像的服务运行状态,可以基于一个镜像运行多个容器
- 守护进程(Daemon):运行在宿主机上的管理进程,用户通过client与其进行交互
- 客户端(Client):和守护进程交互的命令行工具
- 镜像仓库(Repository):
Docker原理
docker通过对不同运行进程进行隔离实现虚拟化
docker运用三种方式以实现进程的隔离:
- Namespace
- 进程:docker运用三种方式以实现进程的隔离利用Linux的Namespace隔离进程之间的可见性,不同的服务进程属于不同的Namespace,互相无法感知对方的存在.
- 网络:docker运用三种方式以实现进程的隔离实现了host,container,null和bridge(默认)四种网络模式.每个容器创建时都会创建一对虚拟网卡,一个在容器中一个在docker0的网桥中,组成了数据的通道.docker0的网桥通过iptables中的配置与宿主机的网卡相连,所有符合条件的请求都会通过iptables转发到docker0,再有网桥分发给相应的容器网卡.
- 挂载点(文件目录):为防止容器进程修改宿主机的文件目录,docker通过修改进程访问文件目录的根节点结合namespace来隔离不同容器进程可以访问的文件目录
- Control Groups:资源限制
- UnionFS
- docker的镜像是分层结构,存在操作系统层,技术环境层,web容器层,服务代码层,层与层相互依赖通过UnionFS把Image的不同分层作为只读目录
- Container是在Image的只读目录上创建的可读可写的目录
docker有AUFS, Btrfs, overlay, Devicemapper, zfs等多种不同的存储驱动实现
Kubernetes(K8s)
容器集群管理系统,不是PaaS平台
- 作用:
- 容器集群管理
- 自动化部署
- 自动扩缩容
- 应用管理
- 特点:
- 可移植
- 可扩展
- 自动化
- 概念:
- Master:管理节点,负责协调集群中所有节点的行为与活动(例,应用的运行,修改,更新等)
- Node:运行容器,可有多个Pod
- Pod:Kubernetes可创建部署的基本单位,可运行多个Container
- Container:为运行中的服务镜像,共享所属Pod的网络存储
- Service:为Pod添加标签,将其划分为不同的Service
- Deployment:表示对Kubernetes集群的一次操作(例,创建,更新,滚动升级等)
Kubernetes架构
- Master
- api server:用户资源操作的唯一入口
- 创建应用部署
- 管理部署状态
- 认证授权
- 访问控制
- api注册和发现
- controller manager:维护集群状态,包含多个controller(例,node controller,route controller,service controller)
- 故障检测
- 自动扩展
- 滚动更新
- scheduler:资源调度
- api server:用户资源操作的唯一入口
- etcd:保存集群状态
- kubectl:运行命令的管理工具,与Master中的api server进行交互,通过api server下达指令
- Node
- 容器运行时(container runtime):可以不是docker
- Pod:可看作虚拟服务器,可运行多个Container
- kubelet:负责人与Master通信,周期性访问api server,进行检查和报告,执行容器的操作,维护容器的生命周期,也负责volume和网络的管理
- kube-proxy:处理网络代理和容器的负载均衡,通过改变iptables规则,控制容器上的tcp和udp包
- 容器运行时(container runtime):可以不是docker
Kubernetes把所有被管理的资源看作对象,使得对资源的管理变成对对象属性的设置,配置文件使用yaml格式
对象可大致分为四类:
- 资源对象
- 配置对象
- 存储对象
- 策略对象
考察点
- 表达沟通
- 分布式架构的理解
- 系统可用性,扩展性
- 故障的应对方法
- 熔断,容灾,流量迁移
- 架构设计中的解耦
- 了解系统优化的常用方法
- 并行,异步,水平扩展,垂直扩展,预处理,缓存,分区
- 对工作的熟悉程度
- 自己项目的规模,调用量级
- 解决问题能力
加分项
- 关注业界最新趋势
- 能提供方案对比选型
面试技巧
- 交代背景:
- STAR法则(情境(situation)、任务(task)、行动(action)、结果(result))
- 描述架构:架构图或交互流程图
- 做了什么:突出重点,最重要的突出工作,实现能力和亮点
- 结果如何:用实力作证
- 注意量化相关性能数据
- 如何改进:存在的问题与解决方法,问题的进一步思考,总结反思
提示
- 提前思考,提前准备
- 项目在精不在多
- 我了解的,就是我的
- 体现对架构的理解,对设计的理解
职场成长建议
-
有策略的努力
1-2年,学习新技术,知识的广度,技术的好奇心
3+,主动思考,学习能力,团队协作,跨团队沟通,项目设计能力
5+,自己的技术品牌
-
打造自己的技术品牌
工作中责任心,自己的任务一定要做好
协助同事排查解决技术难题
做有技术深度或者技术排查案例的分享
后续的职场人脉建立于此,对今后发展很有帮助
-
总结与反思
某项工作或阶段性任务完成之后,及时总结。有利于发现改进空间,后续准备晋升素材
- 获得了哪些收益
- 开发中遇到了哪些问题
- 哪些问题在设计初期就能避免
- 哪些问题要及早解决
- 开发中自己哪些地方做的不好,后续如何改建
完成项目重构
- 旧项目的问题
- 重构时哪些地方收益最明显