面试总结
2022-06-02 16:15:26 0 举报
AI智能生成
中高级Java面试笔记总结
作者其他创作
大纲/内容
OSI七层体系
TCP/IP五层
网络分层模型
面向连接、可靠、基于字节流、传输层通信协议
三次握手
四次挥手
数据传输过程
TCP
面向连接、不保证可靠、基于报文、无阻塞的传输层协议
UDP
无状态、无连接、数据格式灵活、简单快速、应用层的超文本传输协议
报文格式:报文首部(请求行、多个请求体/状态行、多个响应头)、空行、报文主体
请求类型:GET/POST/HEAD/PUT/DELETE/TRACE/OPTIONS/CONNECT
请求处理中
1xx
请求成功处理
2xx
301:Moved Permanently 永久重定向
302:Found 临时重定向
重定向
3xx
400 Bad Request 请求语法错误
401 Unauthorized 未经授权
403 Forbidden 拒绝提供服务
404 Not Found 资源不存在
客户端错误,请求不合法
4xx
500 Internal Server Error 不可预期错误
503 Server Unavailable 服务不能处理请求不可用
服务端错误
5xx
状态码及含义
支持B/S、C/S架构
Session由服务端生成,可存放于文件、数据库、内存
cookies在客户端,客户端请求服务端会生成对应sessionid,并返回客户端,通过setCookies将其放入,后续请求发送cookie可查验sessionid保证其状态
Cookies与Session
1、DNS域名解析
2、建立socket连接,发起TCP三次握手
3、客户端给服务端发送请求命令(请求头和数据)
4、服务端返回响应头与数据
5、关闭socket连接,TCP四次挥手
6、客户端根据返回渲染数据
完整的http请求过程
HTTP
HTTP+加密+认证+完整性保护=HTTPS
在TCP与HTTP之间加入SSL/TLS为上层安全保驾护航
单向认证
双向认证
DOS攻击、SQL注入、中间人攻击、OS命令等
WEB攻击
HTTPS
网络协议
程序计数器
虚拟机栈
本地方法栈
Java堆
方法区
运行时常量池
直接内存
内存模型
对象分配与创建过程
OOM、内存溢出与内存泄漏常见场景
jps -l:查询虚拟机进程
jstat -gc/-gcutil:监控虚拟机运行状态
jinfo -flag xxx:实时查看虚拟机参数
-XX:+HeapDumpOnOutOfMemoryError/-XX:+HeapDumpOnCtrlBreak:在对应条件下生成堆转储快照
jhat:堆转储快照分析工具
jstack -l PID:堆栈跟踪工具
虚拟机性能监控、故障处理工具
引用计数法
GCRoots对象:1、虚拟机栈中引用的对象,被调用方法的参数、局部变量、临时变量等2、方法区的类静态属性引用的对象3、方法区中的常量引用的对象4、本地方法栈JNI引用的对象
可达性分析
对象死亡判断
内存碎片、导致内存不连续、使用率不高导致无法分配触发GC
效率随对象数量增长而降低
标记-清除
只使用一半内存,不过没有内存碎片
复制在存活对象较多时复制效率低
标记-复制
没有内存 碎片
标记整理效率不高
标记--整理
垃圾回收算法
初始标记与重新标记会STW
ParNew+CMS
G1
ZGC
垃圾回收器
Xms=Xmx、PermSize=MaxPermSize,避免内存扩展
子主题
常用的调优命令
加载-验证-准备-解析-初始化-使用-卸载
类加载过程
类加载过程中选择类加载器过程源码判断
JavaSPI与Dubbo 增强SPI6以前的Thead Context Classloader和之后的ServiceLoader,父类加载器请求子类加载器加载类
OSGi模块化热部署
破坏双亲委派机制
避免重复加载,父类加载后,子类无需加载
安全性,避免用户自定义类替换掉Java核心类
为什么优先父类加载?
双亲委派机制
JVM
31是个不大不小的质数,是优选乘数
31可被jvm优化为31*i=(i<<5)-i
质数太小,hash区分度不够,容易冲突质数太大,hash结果太大,int类型表示不了
String为何选用31做hashcode方法的乘数?
-128~127位缓存数据,超出该范围才会new Integer
Integer缓存
父类静态变量-父类静态代码块-子类静态变量-子类静态代码块-父类非静态变量-父类构造方法-子类非静态变量-子类构造方法
类实例化顺序
size>>!+size 1.5倍扩容
初始值为10,最大值为integer最大值
ArrayList扩容
因为get()通过hash&(n-1)来获取
扩容获取比当前容量大的第一个2的指数
通过低位使得hash更加分散,保留高位信息
hash函数:key.hashcode()^(h>>>16)
理想情况,负载因为为0.75,链表个数出现概率服从泊松分布,长度为8概率为0.00000006,不足千万分之一
链表树化 Treeify_Threshold=8,元素最少64
以8、7为退化阈值,会因为树化阈值为8,而反复在临界附近树化退化影响性能
红黑树退化为链表 UnTreeify_Threshold=6
HashMap
HashMap与HashTable
Java基础
给线程、线程池命名,方便问题追踪
最小化同步范围
优先使用volatile,而不是synchronized
尽量使用更高层次并发工具,而非notify-wait实现线程通信
优先使用并发容器
考虑使用线程池
多线程开发良好实践
将可能冲突代码往后放,提高并发能力
减少锁持有时间,降低锁冲突可能
ConcurrentHashMap
减小锁粒度,分割数据结构分段加锁
功能点分割
读写锁替换独占锁
插入数据和取出数据分离,阻塞队列
锁分离
多个锁统一资源,一个整个锁
锁粗化
提高锁性能
之前获取锁的线程再次获取锁,无需任何同步操作
锁偏向
轻量级锁
偏向锁-失败-获取轻量级锁-失败-膨胀为重量级锁-自旋-失败-线程挂起
自旋锁
去除不可能存在竞争的锁,逃逸分析
锁消除
JVM对锁优化
JMM内存模型
只保证可见性,不保证原子性
避免指令重排序
volatile
rt.jar的sun.misc.Unsafe
CAS与wait应使用while做条件判断,避免虚假唤醒
CAS
AtomicInteger
AtomicReference
AtomicStampedReference
Atomic类
业务完成后finally块中手动threadLocal.remove(),防止内存泄漏
inheritaleThreadLocal可访问父线程变量,在thread中也维护对应的map
ThreadLocal
写时复制COW
增删改使用独占锁,复制array副本,在副本做操作,完成后赋值给array
获取与遍历取得为快照,存在弱一致性
CopyOnWriteArrayList
LockSupport
等待达到对应数量要求后进行后续逻辑,可重复使用
acquire、release
Semapore
火箭发射,一次性使用,主线程等待所有检查完成
countDown、await
ContDownLatch
await
CyclicBarrier
限流漏桶算法令牌桶算法
Guava的RateLimiter
exclusiveOwnerThread:锁持有线程
head tail:Node双端队列,AQS队列
newCondition(),返回conditionObject对象,维护条件队列
tryAcquire与tryRelease需要子类实现,修改对应state状态并返回
lock方法拿不到锁,进入AQS队列等待;trylock拿不到直接返回false
xxxShared:共享锁实现
xxxInteruptibly:对中断进行响应,中断后抛出InterrupterException
AQS AbstractQueuedSynchronizer
state:可重入次数
实现newCondition()
实现AQS要求的各种方法
内部有Sync的子类FairSync与NonFairSync,构造方法有是否公平参数
ReentrantLock
state:高16位为读锁状态,低16位为写锁状态
读读不阻塞,其余都阻塞
ReadLock不支持condition
ReentrantReadWriteLock
单链表+volatile+CAS
无界非阻塞队列
ConcurrentLinkedQueue
单链表+reentrantlock
有界阻塞队列
LinkedBlockingQueue
数组+独占锁
ArrayBlockingQueue
最小堆实现有序
优先级无界阻塞队列
PriorityBlockingQueue
无界阻塞延时队列
DelayQueue
队列
BlockingQueue
ConcurrentSkipListMap
Vector
JDK并发容器
高三位表示线程池状态,低29位表示线程数
构造器各参数含义
N+1CPU使用率高,开启过多线程,产生上下文切换开销
CPU密集型
2N+1CPU使用率不高,在IO等待时处理别的任务
IO密集型
分别使用各自线程池
(线程等待时间/线程CPU时间+1)*CPU期望使用率*CPU核数
混合型
线程池大小设置
1s内任务数*单线程单个任务时间*80%(八二原则)
过期时间
1s线程可处理任务数
队列大小
自定义threadFactory的name前缀,方便问题追踪
AbortPolicy(抛出异常)
CallerRunsPolicy(调用线程执行任务)
DiscardPolicy(丢弃,不抛异常)
DiscardOldestPolicy(丢弃最老任务,执行当前任务)
拒绝策略
1、任务为空,抛出NPE
2、当前线程数是否小于核心线程数如小于开启新线程运行
3、否则判断线程池状态是否为Running,如果是添加任务到阻塞队列再次判断如果不是Running,从阻塞队列中删除,并执行拒绝策略否则如果线程池为空,新建线程执行
4、如果队列满,则新增线程执行,新增失败执行拒绝策略
线程池任务提交过程
线程池选择
RecursiveTask
RecusiveAction
Fork-Join框架
生产者-消费者模式
CompletableFuture
Java并发
连接器:管理连接,权限校验
分析器:词法语法分析
优化器:执行计划生成,索引选择等
执行器:操作引擎,返回结果
缓存:8.0之后删除
Server层
支持事务
有crash-safe能力(redo log)
支持并发行锁
InnoDb
不支持事务
只支持表锁
MyISAM
Memory等
引擎层
架构
Mysql执行过程中使用的内存都是在连接对象中的,断开连接后才会释放连接累积会导致内存占用严重,OOM,Mysql异常重启
定期断开长连接
5.7之后,执行mysql_reset_connection重新初始化连接,过程中不需要鉴权或重连
长链接内存耗用严重
属于InnDB,通过它保证crash-safe能力
内存结构类似于RingBuffer,环形链表大小固定,满了会将头部记录刷入库后擦除
是物理日志,记录在某个数据页中做了什么修改
redo log
属于Server层,所有引擎都可用
文件记录,可追加写入不会覆盖
记录逻辑操作,分为statement、row、mix等格式
binlog
redo log写入会分为prepare和commit阶段
更新操作到内存后,写入redo log此时为prepare状态写入binlog成功后,redo log为commit状态,提交事务
如果没有两阶段提交,redo log与binlog任何一个写入失败,binlog与redolog数据都不一致,会导致从库同步或者异常恢复导致数据不一致
两阶段提交
日志模块
原子性、一致性、隔离性、持久性
脏读:未提交变更其他事务可见
读未提交
不可重复读:提交变更其他事务可见
读提交
幻读:前后读取数量不一致
可重复读
以上问题都解决,但并发性能差
串行化
一致性视图及MVCC、undolog
ACID及隔离级别
只有等值查询场景,没有范围查询,Nosql引擎使用
Hash表
不适合更新,只适用静态存储引擎
有序数组
即可等值查询,也可范围查询
搜索树(N叉树)
常见索引实现方式
主键索引叶子节点存储整行数据,非主键索引存储的主键(回表,到主键索引查询整行数据)
叶子节点会存储链指针,实现快速区间查询
B+树为N叉树,一般去N为1200左右,树高为4时已到十亿级别,减少IO次数
B+树
主键索引(聚簇索引)
唯一索引
联合索引
普通索引(非聚簇索引)
分类
InnoDB实现
调整顺序可减少索引,便优先考虑这个顺序
高频查询选择交换顺序,争取占用内存最小
最左前缀原则
联合索引创建原则
索引覆盖了查询需求,减少回表,提升性能
覆盖索引
索引遍历过程中,对索引包含字段先做判断,过滤不满足条件的
索引下推
普通索引会查询到第一个不满足条件的记录为止
查询到满足条件记录即停止
查询过程
普通索引查询到对应记录,更新,执行结束
唯一索引查询到对应记录,判断唯一性(需要回表查询整行),更新,执行结束
如果记录数据页在内存中
普通索引将更新记录在changebuffer中,执行结束
唯一索引将数据页读入内存,判断没有冲突,更新,执行结束
如果记录数据页不在内存中
更新过程
只适用于普通索引
适用于读少写多的场景,页面写完后马上被访问的概率小
减少磁盘访问
唯一索引更新操作需要判断唯一性,读取数据页到内存,无法使用changebuffer
changebuffer
redo log 主要节省随机写磁盘的IO操作,转为一定数量的顺序写
changebuffer主要节省随机读磁盘的IO消耗
changebuffer与redolog
1、从磁盘读入数据页到内存
2、从changebuffer中找出该数据页的记录,一次应用,得到新版数据页(脏页)
3、写redo log 该redo log包含数据变更和changebuffer变更
changebuffer merge过程
普通索引与唯一索引
索引
flush tables with read lock 全库做逻辑备份
全局锁
lock tables ... read/write
表级锁
两阶段锁协议行锁是在需要的时候加上,并不是不需要立即释放,等事务结束才会释放
行锁
行锁+间隙锁(可重复读条件下生效)实现
解决幻读
原则1:加锁基本单位next-key lock,前开后闭
原则2:查找过程中访问到的都加锁
优化1:索引上的等值查询,给唯一索引加锁时,next-key lock退化为行锁
优化2:索引上的等值查询。向右遍历且最后一值不满足条件,next-key lock退化为间隙锁
一个bug:唯一索引上范围查询会访问到第一个不满足条件的值为止
加锁规则
next-key lock
锁
遍历哪个索引树结果都一样,会找最小的索引树遍历
InnDB不记录表中记录数,需读出计数
count(字段)<count(主键id)<count(1)约等于count(*)
count(*)
对索引字段做函数操作,可能破坏索引值得有序性,优化器决定放弃索引
select count(*) from tablea where month(t_modified) = 7;
条件字段函数操作
select * from tablea where tradeid = 110717=select * from tablea where CAST(tradeid as signed int) = 110717Mysql是将字符串转数字
隐式类型转换
两表字符集不同为utf-8和utf-8m64,两表字段做表关联,utf-8表做主表,关联条件变为CONVERT(tradeid USING utf-8m64)
隐式字符编码转换
SQL逻辑相同性能差距巨大
配置慢sql条件收集慢sql
使用explain分析索引使用情况,是否排序、临时表等
分析索引创建是否合理且足够
查询infomation-schema.optimize_trace,看优化器索引选择情况
排除执行期间,是否有MDL、flush操作、大量循环执行sql等情况
慢sql分析
专库专用,单表拆分主子平行表
垂直拆分
hash取模
某字段范围(id、时间戳等)
水平拆分
方式
维护查询字段与分区键的映射关系
查询非分区键子弹,需要携带分区键查询
跨库join有分页数据不会太多,业务代码中处理
count使用redis或count表存储
跨库join与count
group-range
问题
停机部署
双写部署,基于业务
双写部署,基于binlog
迁移
UUID
1bit-41bit-10bit-12bit保留-时间戳-workerID(进程、机房id)-序列号(如超过4096序列号,sleep(1s)获取下一秒的)
SnowFlake
ID算法
sharding-sphere
分库分表
MySql
数据结构与算法
Mybatis
连接点:join point
execution
within
bean
@annotation
表达式组合
execution匹配表达式
切点:point cut
before advice
after returning advice
after throwing advice
after finally advice
around advice
增强:advice
JDK动态代理
为一个未实现任何接口的类进行代理
Cglib动态代理
一个类被AOP织入advice,生成包含原类和增强逻辑的代理类
AOP proxy
定义
创建切面,获取request.cookie,进行鉴权处理
1、HTTP接口鉴权
before after returnning throwing advice打印对应日志
2、方法调用日志
around advice 记录proceedingJoinPoint.proceed前后时间差
3、方法耗时统计
@ControllerAdvice+@ExceptionHandler
4、统一异常处理
使用场景
编译器织入
类装载期织入
动态代理织入
AOP织入方式
采用编译器织入和类装载期织入,Spring采用动态代理
还支持属性级别增强,Spring仅支持方法级增强
@EnableAspectJAutoProxy
<aop:aspectj-autoproxy/>
使用方式
AspectJ
Spring AOP
声明式事务
手动控制事务相关操作,开启提交回滚等
编程式事务
1、Spring事务通过platformTransactionManager进行管理
2、PlatformTransactionManager的抽象子类AbstractPlatformTransactionManager有多种实现:JDBC、DatasourceTransactionManager
Spring如何与多种数据持久层做集成
常用Required、Required-New
传播级别:propagation
超时:timeout
只读:readonly
回滚:rollbackfor
隔离属性:isolation
事务的相爱难相关属性
@EnableTransactionManagement
注解
<tx:annotation-driven><bean id = \"transactionManager\" class = \"xxx.DatasourceTransactionManager\"> <property name = \"dataSource\" ref = \"xxxDataSource\"></bean>
<tx:advice = \"mainTxAdvice\" transaction-manager=\"transactionManager\" <tx:attributes> <tx:method name = \"query*\" propagation=\"REQUIRED\" rollback-for=\"java.lang.Throwable\"/> </tx:attributes></tx:advice><aop:config> <aop:pointcut id = \"businessServiceMethods\" expression = \"execution(* com.xxx.xxx.*.*(..))\"/> <aop:advisor advice-ref=\"mainTxAdvice\" pointcut-ref = \"businessServiceMethods\"/></aop:config>
xml
使用
Spring Transaction
工厂模式+反射
实现机制
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)加载对应资源类并注册beanDefination到容器(添加到beanDefinationMap与beanDefinationNames属性中)
如何解决循环依赖
两级缓存就可以解决循环依赖为什么设置三级缓存
三级缓存
beanFactory获取从缓存中获取bean
根据是否是单例、是否允许循环依赖、是否在创建中等条件判断是否放入三级缓存
进行属性填充,处理循环依赖
按对应scope进行bean实例化
调用对应aware接口的setxxx方法
调用org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
调用初始化方法,init-method/afterPropertiesSet
AOP在这里获取工厂生产的代理类
调用org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
初始化
新创建的bean放入一级缓存并清除二三级缓存,调用org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton
注册到IOC
容器关闭调用destory-method/afterPropertiesSet
销毁
SpringBean生命周期
Spring IOC
加锁startupShutdownMonitor
prepareRefresh() 时间参数等属性的初始化
obtainFreshBeanFactory() 旧BeanFactory销毁,创建新BeanFactory并加载beanDefination
prepareBeanFactory(beanFactory)
postProcessBeanFactory(beanFactory) 允许子类实现对应BeanFactoryPostProcessor增强逻辑
invokeBeanFactoryPostProcessors(beanFactory) 激活beanFactoryPostProcessor
registerBeanPostProcessors(beanFactory) 激活BeanPostProcessors
initMessageSource() 初始化上下文资源文件,如国际化
initApplicationEventMulticaster() 初始化广播器
onRefresh() 子类扩展初始化其他bean
registerListeners() 注册监听器,并发布前期事件
finishBeanFactoryInitialization(beanFactory) 初始化剩余单例bean
finishRefresh() 完成刷新并发布对应事件
AbstractApplicationContext.refresh(),刷新Spring应用上下文
Spring
构造在Spring之上的Boot启动器
编码、配置、部署、监控变简单,未提供注册中心、微服务相关的解决方案
继承spring-boot-starter-parent项目
导入spring-boot-dependencies项目依赖<type>pom</type><scope>import</scope>
统一引用版本
spring.profiles.active=xxx/ymal文件中spring.profiles:xxx+---分隔符
spring.profiles.active=xxx+application-{profiles}.propertites
使用配置中心
maven profiles标签
不同环境部署
命令行参数
命令行spring.application.json=xxx
JNDI参数
java系统变量
操作系统环境变量
外部带profile的application配置 application-{profile}.propertites/yaml
内部带profile的application配置application-{profile}.propertites/yaml
外部不带profile的application配置application.propertites/yaml
内部不带profile的application配置application.propertites/yaml
自定义@Configuration中的@PropertySource
配置加载顺序
Java Config
配置方式
@EnableAutoConfiguration@Import(AutoConfigurationImportSelector.class)org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports
获取@EnableAutoConfiguration注解元信息
移除重复的实现类
通过注解的exclude、excluedename、spring.autoconfiguration.exclude获取需要排除的实现类集合
检查排除类的合法性
移除排除类
触发自动装配事件,AutoConfigurationImportEvent
自动装配
@Value
@ConfigurationPropertites(prefix=\"xxx\")
@PropertySource(value=\"config/db-config.propertites\")+@Value
@PropertySource(value=\"config/db-config.propertites\")+@CondigurationPropertites
@Autowiredprivate Enviroment env
读取配置方式
实现ApplicationRunner/CommandLineRunner接口,并注册bean
启动时运行代码
命名规则:{module-name}-spring-boot-starter
1、添加spring-boot-starter基础依赖
2、创建对应配置类xxxAutoconfiguration,并添加@Configuration
3、将其全类名添加到META-INF/spring.factories文件的EnableAutoConfiguration下的实现类
4、打包构建,项目添加xxx-spring-boot-starter依赖,可以正常获取自动加载相关bean
自定义Starter
SpringBoot
有丰富的数据类型
支持数据持久化
支持实施恢复
支持集群cluster
使用单线程的IO多路复用
支持发布订阅、lua脚本、事务等
删除策略同时使用惰性删除和定期删除
优点
内存访问速度快
高性能
单机redis支持QPS远高于mysql
高并发
为什么使用redis实现缓存
String 动态字符串,可保存文本、二进制、int等,常用于计数器
list 链表/压缩列表,双向链表实现
hash hashtable/压缩列表,适合存储档案信息
set intset/hashtable 存储不可重复对象,支持并集、交集、差集计算,常用于统计共同关注共同喜欢等
zset ziplist/skiplist 有序排列,常用于排行榜、在线用户、弹幕等
bitmap bit表示某元素状态,常用于用户签到、活跃用户、行为统计等
常用数据结构
基于Reactor模式开发的文件事件处理器,通过IO多路复用监听客户端的大量连接
大量socket-IO多路复用-任务队列-文件事件分排气-分发给连接应答处理器、命令请求处理器、命令回复处理器
单线程模型
类似binlog,save 60 1000 60s1000个key发生变化触发BGSAVE生成快照
快照持久化RDB
类似redolog,只追加文件,appendonly yes appendonly everysec 每秒同步一次
AOF
RDB以一定频率进行,两次之间使用AOF记录增量记录
aof-use-rdb-permble
混合持久化
压缩aof文件
后台子线程bgwriteof完成,避免阻塞主线程
fork线程子线程是需要拷贝处理大量数据,未完成前是阻塞的
fork操作本身也是阻塞主线程的
AOF重写
RDB是二进制,AOF是命令,磁盘IORDB效率高,从库恢复,RDB效率高于AOF
持久化机制
MULTI EXEC DISCARD WATCH
EXEC之前,会将所有命令放入队列,一起执行
Redis不满足回滚即原子性和持久性
redis事务
热点数据缓存失效
对于频繁访问的任店数据。不设置过期时间
缓存穿透
大量请求key不存在,直接访问数据库
缓存物料key,避免数据库压力过大
多个hash函数,结果存于二进制位上,后续字符串进行相同多个hash,如返回结果位数据都为1,则存在
不存在一定不存在,存在不一定存在
布隆过滤器
缓存击穿
同一时间缓存大面积失效,请求直接访问数据库
采用redis集群,避免单机流量过大不可用
限流,非核心业务返回降级信息,核心业务查询数据库
设置不同的失效时间,加随机数
缓存永不失效
缓存雪崩
先更新DB,删除缓存
如缓存删除失败,添加对应的重试机制,重试后仍不可用存入队列,待服务可用时删除
旁路缓存模式
先删缓存,更新DB,sleep线程读取数据写入缓存的最大时间后再删除缓存
延时双删
保证缓存与数据库数据一致
建议使用主从从结构,将生成RDB的压力分散到一级从库上
主从同步
周期性给所有主从发送ping命令,看是否在线,如未返回,则认为主观下线
超过quorum值哨兵认为主观下线,则标记为客观下线
监控
一定的筛选条件和规则打分,得分最高的为主库
筛选条件:主库的运行状态,及以往的网络连接状态,如从库多次与主库断联超过一定阈值则排除
规则:1、优先级高的从库得分高,slave_priority 2、和旧主库同步程度最接近的得分高 3、id小的得分高
选主
主库上\"__sentinel__:info\"频道
基于Pub/Sub机制建立哨兵集群
基于INFO命令返回从库列表,哨兵建立与所有从库连接
基于Pub/Sub实现客户端与哨兵、哨兵与哨兵、哨兵与从库的连接
超过quorum并超过半数才能当选,不满足永远选不出
哨兵通过leader选举出一个哨兵执行主从切换
通知
哨兵服务配置应保持一致
哨兵机制
CRC32%1024获取slot编号
RedisCluster
CRC16%16384获取槽编号
Codis
集群与数据切片
GEO
list实现
streams实现
实现消息队列
要求:瞬时并发访问量高,读多写少
商品详情页静态化资源缓存
活动前
保证原子性,在redis处理避免请求压力大,更新不及时导致超售
库存查验、库存扣减
数据库处理,真正下单请求压力小,添加重试机制保证成功
订单处理
活动开始
请求压力小,订单追踪等
结束
阶段
请求拦截流控,恶意攻击黑名单、流控等
库存信息过期时间处理,防止缓存击穿不设置过期时间
订单异常处理,添加重试机制
建议:秒杀商品存量信息、分布式锁信息单独实例保存,与日常业务区分,避免相互影响
关键环节
单个redis保存商品信息hash,lua脚本实现库存查验和扣减
分布式锁
原子操作实现
库存查验、库存扣减原子性保证
Redis秒杀场景
redis多个命令实现为一个操作:Incr/Decr
多个命令写入Lua脚本,原子性方式执行(避免不需要并发的操作写入,通过参数传递)
加锁使用set key value NX PX/EX expiretime
解锁通过Lua命令获取唯一id并判断相等后释放锁
实现分布式锁
基于多节点实现:RedLock
无锁的原子性操作
Redis
Consumer/Provider/Registry/Monitor
Service/Config/Proxy/Registry/Cluster/Monitor/Protcol等
分层架构
架构图
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(DubboProtocol.NAME);Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension()动态编译生成对应的适配器类,并根据@SPI选择对应的实现类
增强SPI
Root-Service-Type-URLDubbo-com.xxx.xxx.xxxService-Providers-127.0.0.1:20881
zk目录结构
临时顺序节点
zk实现分布式锁
各属性的含义及使用
Dubbo
Eureka
Zuul
Hystrix
Ribbon
Feign
Config
Bus
SpringCloud
sagas
tcc
其它
分布式事务
Netty
面试总结
0 条评论
回复 删除
下一页