面试时长1小时 (太卷了 不想刷题)
1、本地缓存如何实现一致性?如何保证一致性
A)通过zookeeper watcher 机制实现本地内存一致性;java进程 通过watcher监听临时节点、一旦被监听的临时节点发生变化;Java进程重新从数据库拉取最新数据、更新到Redis、本地缓存。
B)进程异步上报心跳(本机IP) ;同时配置中心配置节点数(动态扩容要修改配置); 通过定时任务、根据配置节点数来检查节点心跳是否对其。
如果3次触发定时任务;心跳没有对其;就触发更新缓存;直到6次 没有对其;就触发报警。
2、JVM底层原理
A) JVM内存区域;
主要描述了堆栈区域、栈没深入聊;大概就说了用来存储基本类型信息、和对象引用。而我们开发人员主要关注的是堆区域、堆区域分为Eden/S0/S1区域 再就是Old区域、还有一个永久代P区域、P区域一般都存储常量信息基本不会被回收;
Eden/S0/S1区域内存比例一般是8-1-1 对象首先会进入E区域、E区域满了触发YGC会把存活的对象放入S0区域、清空Eden区域;等下次满了YGC的时候又会把E/S0区域存活的对象放入S1区域;再清空Eden/S0区域;如果S1区域存放不了就直接放到Old区域;而能够存放的并且没有满足16次GC没回收掉的对象就会一直存在S0或者S1的一个区域。如果Eden区满了触发YGC;存活的内存太大;S1存不了直接入Old区域。
新生代之所以这么设计主要为了降低内存存放老年代的次数;因为老年代(Old)满了会触发FullGC可能对业务有影响。
Old 触发Full GC 存在stop the world 就是在触发Full GC可能业务会停顿、而对于停顿时长的优化要结合业务来设置;毕竟设置大了触发频率变低了;一旦触发GC停顿RT会增加、设置小了、GC停顿RT降低了、但触发频率变高了。
B) JDK 7 JDK8 永久代的区别
永久代 JDK7 存储的信息比较少、方法、常量等;基本不会触发Full GC 、JDK 8 使用了元空间后;实际上默认共享了物理内存、也就是说物理内存有多大;就可以使用多大;充分降低了JVM 可能会造成的GC影响;但一般都会去设置元空间大小为了避免对宿主机内存造成影响;影响其他进程。
C) 项目中如何排查内存溢出问题(结合实际项目案例)
1、通过top 看高耗线程、线程ID 转换16进制 、再通过jstack 打印堆栈信息、找到16进制的代码块。
2、通过jmap gcutil 查看内存分配、内存实时运行状态 来判断。很多时候内存溢出都会触发大量的Full GC
通过gcutils 可以找到判断信息。有些情况并没有代码抛异常、就是触发Full GC 导致系统卡顿、这个时候查询JVM内存状态是非常好的手段。
3、分布式锁
A) ZK 实现分布式锁原理
通过ZK临时节点实现分布式锁、再并发的时候比如说ABC三个来竞争;那么在flie/临时节点存存三条临时路径,A001/A002/A003 同时临时节点相互监听;A002监听A001 ;A003监听A002以此类推。一旦A001获得锁直接任务结束后会删除临时节点、而A002监听了A001的状态并且也是最小的自然就获得锁。
但存在一个问题就是、如果并发量大我这个文件队列会非常长;而ZK的写 更新是存在性能问题的;因为都是在Master上执行、而他的从节点只是读。所以对于并发量非常大的场景ZK不太适合做分布式锁。
B)Redis分布式锁实现与原理
Redis 实现分布式锁 主要通过 ex px 方案、和 redisson来实现;
ex px:存在一个问题就是没办法续租;也就是说 如果我获得锁;执行业务;但业务没执行完;但锁已经过期释放了、就会导致其他进程获得锁;这个是冲突问题。
redisson: 避免了这种问题 可以设置独立一个线程来检查你的key过期时间、比如说设置锁5秒钟;如果三秒钟还没执行完;我再去续租3秒。直到你业务执行完;避免了业务没执行完释放问题。
但redis是主从异步复制;如果在Master获得锁;在没有同步到从节点;Master挂了导致主从切换;也可能其他进程获得锁。导致锁冲突问题。 所以在锁的一致性极其苛刻的场景下不太建议使用redis做分布式锁。
C) ETCD分布式锁实现
ETCD 是走的raft协议 CP模型的框架;性能也非常好;存储通过物理DB存储;也提供了可视化界面;使用交互简单、获锁方式可以通过HTTP、Grpc协议。代码侵入性低。一般部署也是集群方案。
4、分布式事物
TCC(Try Confirm Cancel)基本原理
跨行转账例子;通过中间态来实现
背景:A账户、B账户各有1000元; 比如A账户向B账户转账100元
上游:
1、当A账户Try阶段的时候;金额减去100、把这100给到中间态字段保留。
2、当A账户Cofirm阶段的时候;把中间态字段清除 (转账金额-中间态金额)。
3、当A账户Cancel阶段的时候;把中间态的金额加回账户余额并且清除。(转账金额+余额)(中间态金额-转账金额)。
下游:
1、当B账户Try阶段的时候;把转账金额100;存入中间态字段保留。
2、当B账户Cofirm阶段的时候;把转账金额加余额、把中间态金额清除(转账金额-中间态金额) 。
3、当B账户Cancel阶段的时候;把中间态金额清除(转账金额-中间态金额)。
image.png
A) saga seate
简单聊了下TCC分布式事物方案;以及saga基于状态机的命令模式、回滚也是基于提前要写好逆操作补偿接口。
B) 事物消息实现
消息分布式事物;其实通过半消息实现分布式事务的功能;达到最终一致性;对于一致性要求苛刻的不建议使用;因为他的下游如果执行失败;可能需要补偿;或者人工去处理。
上游:
1、首先发一个半消息发到消息中心
2、发送成功执行本地事物
3、本地事物执行成功; commit 消息中心;把半消息转换成完整消息
4、如果本地事物执行失败、rollback 半消息;
5、如果本地 comomit失败;消息中心通过会查接口;查询本地本地消息是否以发送;失败再次投递。
6、到这一步保证了上游的原子性。
下游:
1、拉取消息;判断幂等性;再存储消息表;
2、定时任务、检查消息表已发送的消息;获取消息执行本地事物、执行成功;修改消息状态;
3、失败记录频次;下次再执行;超过阈值就不执行人工干预处理。
网友评论