Java
Concurrency
Baeldung Java Concurrency
马士兵50道面试多线程题
Java多线程与并发系列22道高频面试题
锁机制实现方式
synchronized
volatile
ThreadLocal
ReentrantLock
Condition
java.util.concurrent
Synchronizers
Semaphores
CountDownLatch
CyclicBarrier
Phaser
Exchanger
SynchronousQueue
原子类
AtomicInteger
AtomicBoolean
Questions
线程的状态有几种?
新建(New)
运行(Runnable)
无限期等待(Waiting)
限期等待(TimedWaiting)
阻塞(Blocked)
结束(Terminated)
sleep、yield、wait、join的区别?
JVM
故障排查/性能分析
分析JVM堆转储快照文件(hprof文件)
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Domains/rcsv-fm.wd.local/server1/logs
Eclipse Memory Analyzer 分析hprof文件
77道JVM系列面试题总结
底层原理
64位虚拟机的指针压缩是什么?为什么要指针压缩?
对齐填充(Padding)
-XX:+UseCompressedOops
基础
静态变量final和不final的区别?
有final修饰的情况下,其对象值必须在声明的时候初始化且不可在编译期或运行期被修改
在类加载阶段,读取或设置一个类型的静态字段(没被final修饰)需要先触发其初始化阶段,如果是已经被final修饰的对象,其类加载初始化阶段是在虚拟机加载final字段所在类的时候触发
使用final关键字修饰变量就可以保证它是不可变的
被final修饰的类不可以被继承
被final修饰的方法不可以被重写
Java创建对象有几种方式
new
通过反射机制
采用clone机制
通过序列化机制
深拷贝 VS 浅拷贝
Java深拷贝和浅拷贝
Java如何对一个对象进行深拷贝?
How to Make a Deep Copy of an Object in Java
面向对象
特性
封装
继承
多态
将我们编程当中的业务场景都给对象化,这样子开发的软件系统相对面向过程的编程来说,更加易维护、易复用、易扩展,可以设计出低耦合的系统
基础数据
字符串
StringBuffer VS StringBuilder
他们的底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用StringBuffer和StringBuilder来进行操作。另外StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的
transient
transient是在对象序列化的时候,不参与序列化的字段
集合
ArrayList VS LinkedList
读写速度各自的优劣
一个基于数组元素,一个是基于双向链表结构实现
HashMap VS HashTable
HashTable的key和value都不能为null,HashMap的key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性;可以有多个key值对应的value为null
HashTable是相对线程安全的,HashMap非也
HashTable每个方法上都有synchronized 关键字,当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap,ConcurrentHashMap的锁粒度没有HashTable的粗,只在关键地方做必要的锁同步
微服务
50个微服务面试问题
Ribbon或者Nacos负载均衡有多少种实现机制?
轮询 (round-robin)
适用于服务器性能相近的集群情况,其中每个服务器承载相同的负载
加权轮询
加权轮询可以应用于服务器性能不等的集群中,使资源分配更加合理化
IP 哈希(IP hash)
在一定程度上解决了集群部署环境下 Session 不共享的问题
如果是多个微服务之间要实现同步锁进行某个数据的操作更新,可以借助redis进行标记上锁
某个微服务对某一唯一数据做同步操作时上锁(可以用hashmap数据结构标志上锁),其他微服务要等待锁释放
架构
垂直拆分和微服务分布式拆分的区别?
最重要的区别是垂直式拆分的各个子系统之间没有交互,都是直接与数据库交互,而微服务分布式的各个子系统时刻错终复杂地进行各种业务交互,解耦和扩展相对来说都比较便捷和清晰明了
微服务的优点
独立开发
独立部署
故障隔离
出现故障的微服务可以降级熔断
混合技术堆栈
粒度缩放
单个组件可根据需要进行缩放,无需将所有组件缩放在一起
注册中心
注册中心的作用是什么?
Eureka VS Nacos
eureka对要新注册进来的微服务感知比较慢,一个服务启动完有可能要等上几十秒才能被发现。
注册中心的实现机制
Spring
Spring系列面试题129道
Baeldung的Spring系列文章
Basic
Bean生命周期
创建bean的实例
给实例化出来的bean填充属性
初始化Bean
通过IOC容器使用我们DI到各个类的Bean
容器关闭时销毁Bean
循环依赖
N个类互相嵌套(DI)引用,形成闭环
解决方法
可以提到Mapper、Service类的单一职责原则,多个表混合的业务逻辑抽到OperateService
一级缓存、二级缓存和三级缓存
singletonObjects
第一级缓存,存放可用的完全初始化,成品的Bean
earlySingletonObjects
第二级缓存,存放半成品的Bean,半成品的Bean是已创建对象,但是未注入属性和初始化
singletonFactories
第三级缓存,存的是Bean工厂对象,用来生成半成品的Bean并放入到二级缓存中。如果Bean存在AOP的话,返回的是AOP的代理对象
Spring Transaction的事务传播行为
PROPAGATION_REQUIRED
默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景
PROPAGATION_SUPPORTS
支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行
PROPAGATION_MANDATORY
支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常
PROPAGATION_REQUIRES_NEW
创建新事务,无论当前存不存在事务,都创建新事务
PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常
PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作
SpringMVC
SpringMVC请求流程
请求的入口最先到达DispatchServlet,通过一个处理映射器(HandleMapping)找到请求路径对应的Controller,然后再将请求转到Controller里面去做具体的处理
HandlerInterceptor什么时候被触发?
通过配置请求的URL路径,可以通过通配符的方式配置,在通过URL请求到对应的Controller之前会触发拦截器
preHandle
请求处理之前进行调用
postHandle
在当前请求处理之后进行调用,也就是Controller 方法调用之后执行
afterCompletion
需要当前对应的Interceptor的preHandle方法的返回值为true 时才会执行
Mybatis
一级缓存VS二级缓存
Mybatis Plus
Springboot
SpringBoot自动装配原理
官方文档大概一遍
Spring Cloud
Springcloud用来做什么的?
Spring Cloud面试题
Spring Cloud Stream
应用的业务场景
日志处理
生产者端发送日志的原生数据
消费者端接收原生数据格式化处理之后输出,将处理过的日志存储起来
Spring Cloud Alibaba
Nacos
Sentinel
流量削峰
服务降级和熔断
Dubbo
服务调用
Seata
分布式事务
数据库
MySQL
我自己总结的博文
Mysql系列之基础知识
Mysql系列之性能优化与问题定位
阿里巴巴MySQL规范
存储引擎
MyISAM
不支持事务,但是每次查询都是原子性的,适合做报表,或者一些只有查询操作的数据库
InnoDB
Mysql默认
锁机制
行级锁
锁的类型
共享锁 (也称为 S 锁)
独占锁 (也称为 X 锁)
意向共享锁 (IS)
意向排他锁 (IX)
行锁的算法
Record Locks
该锁为索引记录上的锁,如果表中没有定义索引,InnoDB 会默认为该表创建一个隐藏的聚簇索引,并使用该索引锁定记录
Gap Locks
Next-key Locks
死锁
锁的优化建议
表级锁
页面锁
combos
怎么防止SQL注入
数据库连接池的问题
事务的四个特性
原子性 (Atomicity)
一致性 (Consistency)
隔离性 (Isolation)
持久性 (Durability)
事务隔离级别和传播性
隔离级别
Serializable(串行化隔离)
最严格的级别,事务串行执行,资源消耗最大
REPEATABLE READ(可重复读)
在同一个事务里, select 的结果是事务开始时时间点的状态,因此,同事务的 select 操作读到的结果会是一致的
READ COMMITTED(读提交)
一个事务可以读取另一个已提交的事务,多次读取会造成不一样的结果
READ UNCOMMITTED(读未提交)
该隔离级别的事务会读到其它未提交事务的数据,此现象也称之为脏读
概念
脏读
读到其它未提交事务的数据,此现象也称之为脏读
幻读
一个事务读多次,出现的结果可能存在于真实数据不一致的情况,比如某个SQL第一次读取无记录,然后其他事务此时提交了某些数据(同个SQL可以查出来的),该SQL在同个事务之下再次读取还是无记录
不可重复读
一个事务可以读取另一个已提交的事务,多次读取会造成不一样的结果,此现象称为不可重复读问题
MySQL 事务隔离级别和锁(IBM)
脏读、幻读与不可重复读
缓存
Redis
Redis的11道面试题
缓存穿透,缓存击穿,缓存雪崩原因+解决方案
缓存穿透
key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库
解决方案
如果一个查询返回的数据一直为空(不管是数据不存在,还是系统故障),我们可以把这个空结果进行缓存,但它的过期时间会很短,最长可以不超过五分钟、10分钟。
布隆过滤器
缓存击穿
key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮
解决方案
使用互斥锁(mutex key)
在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法
缓存雪崩
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力
与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key
解决方案
大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上
将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件
设置过期标志更新缓存,同时增加缓存实际过期时间
缓存标记
记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存
缓存数据
它的过期时间比缓存标记的时间延长1倍,这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存
高并发如何保证缓存与数据库的双写一致性?
Cache Aside Pattern
读的时候,先读缓存,缓存没有的话,就读数据库,读完将数据一并同步到缓存里面,同时返回响应,更新的时候,先删除缓存数据,再更新到数据库,然后事务提交成功的话就能保证双写一致性
数据更新,缓存不一致问题
先更新数据库,再删除缓存。如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据就出现了不一致。
数据更新,先删除缓存再更新数据库,也会导致数据不一致问题
删除缓存之后去更新数据库期间,有个请求进来命中了空缓存和数据库的老数据
更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个 jvm 内部队列中,也就是多个请求同时高并发对同一个数据做读取或更新要串行化
为什么是先删除缓存,而不是先更新缓存?
简单粗暴,如果取更新缓存的话可能会涉及一些关联的复杂逻辑,对于比较复杂的缓存数据计算的场景,如果更新的同时有读取同个缓存数据的高并发请求过来,这时候出现数据不一致的概率会更大,直接删除的相对来说比较快
确保数据一致,如果数据库更新失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致
Netty
消息队列
生产者
消费者
Elasticsearch
研究完明博的es代码套路
流程
Flowable
研究下邹耀天流程的代码
设计模式
创建型模式
结构型模式
行为型模式
观察者模式
网络
协议
TCP
三次握手
UDP
HTTP
短链接
无状态
应用层协议,基于传输层的TCP协议
Socket
长链接
基于对TCP/IP的封装
Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开
HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
Cybersecurity
Cross-site request forgery (CSRF)
算法
IO/NIO(Input/Output)(New IO)
内存
操作系统内核(Kernel)
GDT
保护模式
Syscall(系统调用)
暴露一系列接口操作硬件
中断
软中断(用户程序的调用)
硬中断(鼠标、键盘操作的调用)
用户程序
QQ、WeChat等
Tomcat、Java等
内核内存空间,可以与硬件直接交互
用户程序内存空间,不可与硬件直接交互
CPU
指令集
Range0~3(级别)
内核是作用在指令集Range0级别上面的
用户程序间接使用的指令集是在Range3级别
命令
strace(跟踪系统调用)
-ff 抓取所有的线程
如果某个Java程序占用资源异常的多,也可以使用该命令快速简易地查看是否发生过多线程的创建
跟踪过程
jps
cd /proc/xxxx
task目录
列出xxxx的jdk进程里面的所有的线程
fd目录
任何一个程序至少有三个IO
标准输入0
标准输出1
错误输出2
同样可以用来跟踪Nginx、Redis等
BIO
早期的IO方式,阻塞IO
弊端
每个客户端请求发生一系列系统调用
创建的线程太多,每个线程都要通过系统调用clone,系统调用太多,资源消耗太多
CPU在进程或线程之间来回切换时间成本抬高
O(n)复杂度
NIO
相较BIO的改进之处
所有请求进来的客户端只汇总发生一遍系统调用
弊端
每次要传递给n个请求的所有数据给内核,内核在其内部要一下子去循环处理n个”数据包“,数据太多
内核要主动遍历拿到所有IO请求的返回结果,再交给用户程序去同步读取
弊端的改进方法
内核开闭一个空间,用来接收传递的请求数据,减少每次传递的过程
基于网卡到内存的事件驱动,准备一个内存空间,专门存放可读可写的IO返回结果供程序统一获取去同步读写
epoll更充分发挥硬件资源,尽量不浪费CPU资源
O(m)复杂度
select(fds)
软件测试
服务请求压力测试
使用Apache的Jmeter开了多个现场循环多次去调用查单词的接口
全栈开发
前端技术
Vue以及其生态
各种UI组件、图标库、请求组件和前端好用便捷的组件
项目经验
贵州电信运维系统
系统业务模块
用户组织架构
权限管理
基础数据管理模块
字典
流水号配置
业务数据配置
策略引擎自定义流程
材料调拨分发子系统
工单流程化统一调度
通用树配置模块
平时的需求大概都是些什么?
技术栈
新版本
前端
Vue、以及Vue生态的各种组件
Element UI
一些自研的组件,用来自动去生成页面、表单和符合我们业务需求的常用工单操作
通过Web Socket通信
后端
Spring Cloud 微服务架构
注册中心
Spring Cloud Eureka
Nacos
配置中心
Spring Cloud Config
Nacos
网关(Spring Cloud Gateway)
API网关
路由
负载均衡
负载均衡(Spring Cloud Ribbon)
微服务调用(Restful)
Spring Cloud Feign
断路器
Spring Cloud Hystrix
Spring cloud turbine
调用链路跟踪
skywalking
Spring Cloud Sleuth + Zipkin
基础设施
分布式缓存
分布式数据库
Mysql
MyCat
消息中间件
RabbitMQ
Kafka
ES搜索引擎
分布式文件存储(FastDFS)
时序数据库(InfluxDB)
Docker容器化部署、jenkins自动发布
分布式任务调度(XXL-JOB)
日志处理(ELK)
系统服务访问大致路径
外部请求 → 负载均衡 → 服务网关→ 微服务 → 数据服务/消息服务
江苏/上海/新疆电信综合调度系统
公司已经打算从传统的外包过度到SaaS模式了
Kiwi词典
开发运维
Jenkins
灰度发布
CI/CD
持续集成(CONTINUOUS INTEGRATION)
持续交付(CONTINUOUS DELIVERY)
敏捷交付
Combos
COW(写时复制/Copy-on-write)
遇到问题一般都是怎么解决的?
最重要的还是先跟踪一些具体的报错信息,以前老是忽略了报错日志的细节,然后自己去想当然地跟代码排除故障,实际上应该第一时间点从错误日志切入才是最正确的做法
询问做过的系统中的QTS、TPS能达到多少的问题
可以拿我自己用Apache的Jmeter服务压力请求测试
平常经常看哪些编程的资讯、技术学习的渠道
v2ex
Spring官网
spring.io
Spring的blog
Java
How2J
Baeldung
Spring官网
spring.io
Spring的blog
javatpoint
Algorithm
leetcode
leetcode-cn
tool
alfred
web search
runoob
dockerhub
gh
jce
mvn
sof
baeldung