@songhanshi
2021-02-24T18:08:17.000000Z
字数 11060
阅读 509
1234
jvm
mysql
redis
并发
mq
spring
源码
java基础知识
java新特性
项目亮点
2月复习完毕 简历完成
3月开始投 边面试边复习
4月离职 4月底才能走
年前jvm+redis 优先jvm看完
2月一定要把简历完善好
3月开始投边面试边复习
4月离职 4月底才能走
done
1.redis常用的数据结构
2.redis过期数据删除策略
3.了解redis事务么?为什么不支持回滚
3.怎么保证 Redis 挂掉之后再重启数据可以进行恢复
4.aof和rdb怎样使用、区别
5.redis主从复制了解么?
6.redis缓存雪崩、击穿、穿透
8.如何保证双写一致性
7.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
1.redis持久化日志(rdb和aof是什么区别)
2.Redis 挂掉之后再重启数据可以进行恢复(aof的恢复过程)
3.aof恢复异常遇到过么?(redis-check-aof --fix appendonly.aof 进行修复 )
4.AOF写入原理?(详细)
5.AOF重写触发机制
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
--当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。一般都设置为3G,64M太小了。
6.RDB主要的触发机制有哪些?
7.redis主从复制的实现原理是什么?
8.主从复制可能带来的问题
9.Redis 的线程模型有了解么?(什么是IO多路复用)
10.如何保证双写一致性https://github.com/doocs/advanced-java/blob/main/docs/high-concurrency/redis-consistence.md
11.redis在项目中保证原子性(事务、setnx、lua)
12.redis缓存击穿之类
9.Redis 的线程模型有了解么?(什么是IO多路复用)
10.如何保证双写一致性https://github.com/doocs/advanced-java/blob/main/docs/high-concurrency/redis-consistence.md
8.如何保证双写一致性
11.redis在项目中保证原子性(事务、setnx、lua)
2.redis过期数据删除策略
3.了解redis事务么?为什么不支持回滚
7.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
https://mp.weixin.qq.com/s/4BMYHgWAR2UEFAeNlS0pvg redis快的原因
9.Redis 的线程模型有了解么?(什么是IO多路复用)
10.如何保证双写一致性https://github.com/doocs/advanced-java/blob/main/docs/high-concurrency/redis-consistence.md
8.如何保证双写一致性
11.redis在项目中保证原子性(事务、setnx、lua)
2.redis过期数据删除策略
3.了解redis事务么?为什么不支持回滚
7.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
https://mp.weixin.qq.com/s/EjDeypra_d9Tfsn-WkJZdw 雪崩
https://blog.csdn.net/qq_38734403/article/details/113488687 编码
done
14.jvm回收算法
15.将一下常用的垃圾收集器
16.对象晋升老年代的条件
17.什么时候产生Full GC
18.什么时候产生minor GC
19.你们项目中jvm参数介绍一下
20.你们项目中用的什么垃圾收集器,为什么用它
21.运行时数据区
22.1.7 8 6 运行时数据区的变动
23.双亲委派模式
24.对象的创建过程
25.哪些对象可以被作为GCroot
26.对象结构
27.对象头有什么呢
28.类加过程
29.对象引用哪些类型
30.说一下虚引用
1.你们线上是怎样设置jvm参数
2.并行与并发的区别
3.jvm在什么情况下会加载一个类?
4.类加载过程
5.类的二进制字节流?
6.符号引用和直接引用
7.类加载器有什么用?
8.双亲委派机制是什么
9.双亲委派模式的优点
10.你了解双亲委派机制打破的方式
11.运行时数据区包含哪些
12.什么是NIO?
13.为什么移除永久代?
14.jvm栈帧包含哪些内容?
15.对象创建过程的并发问题?
16.对象存活判断的方法
17.哪些对象可以做为gcroot
18.对象引用类型
19.怎样判断对象已死
20.对象之间会存在跨代引用怎么办?
21.对象的分代年龄为什么是15
22.对象结构
23.什么是安全点?
24.安全点和安全区域的区别
25.如何让所有线程都停下来?stp
26.如果有线程处于没有“执行”(没有获取到CPU)的时候?怎么让这些也进入安全点?
27.垃圾回收算法有哪些?优缺点
28.进入老年代有哪些对象
29.老年代垃圾回收算法
30.方法区的内存回收触发时机
31.你了解的垃圾收集器
32.为什么新生代GC快?
33.为什么老年代GC很慢?
1.回答问题没有逻辑,没有前因后果
2.不能简单说一下名次,要说是什么
文档:JVM.md
链接:http://note.youdao.com/noteshare?id=ba00f3dbc44d1b4ab48e7c550f737845&sub=C2A75958708C4176B2B59B9B1589ABA3
https://apppukyptrl1086.pc.xiaoe-tech.com/detail/p_5d0ef9900e896_MyDfcJi8/6
看完这个基本面试没啥问题了
done
1.redolog undolog binlog
https://mp.weixin.qq.com/s/Lx4TNPLQzYaknR7D3gmOmQ
https://www.jianshu.com/p/4bcfffb27ed5
1.mysql存储引擎了解哪些?介绍一下inndb
2.聚簇索引
3.mysql行锁和表记锁
4.事务
done
1.jmm是什么
2.jmm特性
3.进程间通讯方式
4.MESI是什么?MESI一致性例子
5.线程安全性,CPU3级缓存
6.DCL问题
7.JMM如何实现3大特性
8.volatile介绍一下,围绕3大特性
9.happenbefore原则
10.synchronize
11.对象头包含什么
12.volatile和final共同点
13.分布式锁
14.死锁概念
15.java线程状态
16.死锁排查
17.线程状态及其转化
18.sleep和wait区别
19.线程实现的方法
20.thread和runnable的区别
21.callable和runnable的区别
22.Thread的run和start区别
23.lock和synchronize区别
24.AQS原理
25.AQS与synchronize重入锁区别
26.公平锁与非公平锁 非公平锁遇到的问题
27.读写锁的实现原理
30.乐观锁和悲观锁
31.信号量各种实现
一面
1.自我介绍
2.常用的数据结构有哪些?并大说了一些操作的时间复杂度
3.数组从下标最大的删与最小的删有什么区别?
4.介绍主要用到的技术(技术栈)
5.介绍一下集合类
6.list和set的区别?以及各个实现类和底层实现
7.CopyOnWriteList的特点及实现
8.创建一个线程有几种方式?项目中怎么创建的?
9.讲一下线程池
10. 你们使用的任务拒绝策略是那种?
11. 线上服务器最多可以创建多少个线程?
12. 线程的状态有哪些?(线程的生命周期)
13. 跟线程相关的方法介绍一下
14. HashSet的底层实现
15. 介绍下HashMap和CurrentHashMap
16. HashMap线程不安全会导致什么问题?
17. 为什么1.8版本中会将链表转为红黑树?
18. HashMap解决Hash冲突使用的什么方式?
19. HashMap的hash函数讲一下(如何确定槽位)
20. JVM的内存区域21. 那个区域不会发生内存溢出?
22. JVM运行时内存?
23. 新生代老年代讲讲
24. JVM为什么分新生代老年代?
25. 垃圾回收算法讲讲
26. 类加载过程讲一下
27. 双亲委派模型讲一下
28. Spring的启动流程
29. SpringBean的作用域
30. SpringBoot的特点
31. 相比于SpringMVC有什么好用的地方?
32. MySQL的事务隔离级别
33. 讲讲Java中的锁?
34. 重入锁怎么实现的?
35. Synchronized讲讲使用及原理
36. Synchronized的优缺点?
37. retryLock了解吗?
38. Java里的轻量级锁?
39. 索引了解么?balabala
40. InnoDB还能有什么索引
41. 为什么用索引?项目中怎么用的?
42. 讲一下B+树的实现
43. B+树与B树有什么区别?
44. MySQL的锁哪几种?
45. 行锁的实现?
46. 你们项目中用到Redis都是怎么用的?
47. 分布式锁你们是怎么做的?
48. 为什么不升级Redis版本?
49. Redis的内存淘汰策略 LRU?
50.讲讲项目为什么要用Hystrix?
二面
1.画项目架构图
2.分布式任务调度系统是怎么实现的?
3.ElasticSearch都用过那些查询方式
4.如何做数据同步的?(MySQL到ES)
5.如何做CodeReview的?
6.SpringCould都用了那些组件?
7.什么场景用到断路器(Hystrix)
8.你是如何理解分布式锁的?
9.Redis分布式锁你们是怎么用的?
10. Redis你都用到那些命令?
11. Synchronized讲讲
12. 说说轻量级锁,无锁的方式(CAS ABA问题?)
13. 加锁我们是为了解决什么样的问题?
14. 说说volatile关键字
15. 了解什么叫不可变类么?或者是叫不可变对象?
16. final的含义是什么?
17. 成员变量都是final修饰的话,如何进行赋值?
18. 如何关闭线程?
19. 手撕代码。牛客题霸上的原题,可以去看看:NC22合并两个有序的数组
20. 我有8件事要做,最要要同意返回处理结果,每件事要进行异步的方式去做。你怎么完成这个需求
21.我需要在项目启动时,将一些配置加载到内存中,你有什么方式能解决?
三面
1.自我介绍
2.讲讲做的项目
3.RabbitMQ优缺点讲一下?
4.分享一下你这个项目的挑战性吗?
5.项目中有遇到什么问题么?
6.讲讲SpringCould中用到的组件吧?
7.Feign为什么效率低?
8.为什么大部分服务对外不提供的接口都是HTTP的?(没太理解什么意思)
9.讲讲项目中为什么会把MySQL升级为ES?
10. CodeReview你都是怎么做的?
11. list跟Set有什么差别?
12. HashMap跟CurrentHashMap有什么区别?
13. 讲讲Redis的数据结构
14. 问了问我现在的待遇,有什么想问我的?
作者:iawuheui链接:https://www.nowcoder.com/discuss/583437?type=post&order=time&pos=&page=1&channel=-1&source_id=search_post_nctrack
21.运行时数据区
私有:程序计数器 Java虚拟机栈 本地方法栈
共享:堆 方法区
** 类加载
作用:
-加载类信息 放在 方法区
加载->连接(验证->准备->解析)->初始化
-加载:
类的全限定名->二进制字节流
字节流的静态存储结构->方法区的运行时数据结构
生成.Class对象->各种数据访问入口
-连接:
-验证:
符合要求,文件格式、元数据、字节码、符号引用
-准备:
类变量-方法区(除实例变量-堆) 分配内存与初始值
-解析
符号引用->直接引用
针对:类/接口、字段、类方法、接口方法、方法类型等(在常量池中)
-初始化
执行类构造器方法()过程
** 类加载器
模型:
启动类加载器/引导类
扩展类
应用程序/系统类
自定义
向父类委托
启动类加载
父类无法完成,子类加载
** 运行时数据区
方法区:
类信息(类加载的)
运行时常量池信息
字符串字面量和数字常量(class文件中常量池部分的内存映射)
程序计数器
程序控制流指示器,是个计数器
作用:存储下一条指令的地址
每个线程都有自己的
给字节码解释器提供下一条执行指令
唯一无oom
存储反编译后的指令地址(理解:类似于行号),对应操作指令
Java栈:
线程创建->栈创建,内部保存栈帧
一个方法对应一个栈帧的入栈和出栈
包含方法的局部变量(8基本数据类型,对象的引用地址)、部分结果
-Xss
-Xss1024k 最大256kb
方法两种返回/栈帧弹出 return和异常
栈帧->基本单位存储,存储方法执行的各种数据
-结构:
-局部变量表:
存方法参数和方法体中的局部变量
含基本数据类型、对象引用、返回值类型
方法执行时,jvm使用局部变量表->参数值到参数变量列表的传递
存储单位slot(变量槽)
32位以内的类型只占用一个slot(包括 引用类型、returnAddress类型),64位的类型(long和double)占用两个slot
构造器、实例方法中,对象引用this 都会存放在索引为0的位置
slot重复使用
-操作栈:
变量临时存储空间
后进先出,由字节码指令(pc计数器),进出数据
-动态连接(或指向运行时常量池的方法引用)
栈帧->包含指向运行时常量池中该栈帧所属方法的引用
Java源文件->编译->字节码文件,变量和方法引用->作为符号引用->存在class文件的常量池里
符号引用=>直接引用:通过静态链接|动态链接
-方法返回地址:
存 调用该方法的pc寄存器的值
-一些附加信息
如,对程序调试提供支持的信息
本地方法栈:
native
作用:管理本地方法的调用
堆:
还可以划分线程私有的缓冲区(TLAB)
存储:对象和数组
几乎所有对象实例?有一些对象在栈上分配(逃逸分析、标量替换)
-Xms10m -Xmx10m 堆内存
堆:新生区、老年区、永久区(1.8元空间)
新生-Eden、survivor
-Xms 初始 = -XX:InitialHeapSize
-Xmx 最大 = -XX:MaxHeapSize
老年/新生 占比 -XX:NewRatio = 4
Eden/survivor -XX:SurvivorRatio
Eden 满了MinorGC ,survivor大对象进入老年代
年龄:-XX:MaxTenuringThreshold=N
养老区内存不足 MajorGC 依旧 OOM
部分收集Partial GC
-新生代 MinorGC/YoungGC
-- 会发生STW
-老年代 MajorGC/OldGC -- CMS
--STW更久,最少伴随一次Minor
-混合收集 MixedGC
-- 整个新生代和部分老年代--只有G1
整堆收集FullGC 整Java堆和方法区
--触发:① System.gc() ② 老年代空间不足③ 方法区空间不足④Minor后进入老年代的avg大于年老代可用内存⑤to过小,对象进入老年代,但老年代空间不足
优化:
避免FullGC,缩短STW
分->优化GC性能
** 内存分配策略/对象提升(promotion)规则
-不同年龄对象分配原则
-优先Eden
-大对象 老年代
-长期存活 老年代
-survivor同年纪和大于survivor一半
-空间分配担保 Minor后,survivor无法容纳,进入老年代 -XX:HandlePromotionFailure 是否允许担保
** TLAB
-堆中,每个线程独占,在Eden,线程安全,提升内存分配吞吐量
-XX:TLABWasteTargetPercent 占Eden的百分比
** 逃逸分析技术
-对象逃逸方法失败,栈上分配 无需回收
-标量-无法分解的更小数据,如Java中的原始类型
-逃逸分析,对象不会被外界分配,JIT优化,将对象拆解成若干变量过程,标量替换-好处,不需要分配内存了,减少堆内存占用
-默认打开 -XX:+ElimilnateAllocations
-Hotspot 标量替换 实现 逃逸分析
** 方法区
主要是Class
Person person = new Person();
方法区 Java栈 Java堆
.class
堆的逻辑部分,独立于堆的内存空间
类只加载一次
- OOM:定义太多类,方法区溢出
eg:加载大量三方jar包|tomcat部署工程较多(30-50)|大量动态的生成反射类
- 演进:
永久代:更易导致Java程序oom(超过-XX:MaxPermsize上限)
元空间永久代区别:元空间不在虚拟机设置的内存中,使用本地内存
-大小
JDK7永久代:
-XX:Permsize 初始分配空间 mr:20.75M
-XX:MaxPermsize 最大可分配空间 32位机器64M,64位-82M
JDK8元空间:
-XX:MetaspaceSize mr:win 21M
超过 FullGC触发并卸载没用的类(这些类对应类加载器不再存活) 值重置 新界限
-XX:MaxMetaspaceSize mr:-1 无限制
查看:
jinfo -flag MetaspaceSize PID
jinfo -flag MaxMetaspaceSize PID
弊端:mr虚拟机会耗尽所有可用系统内存
- 解决oom
-通过内存映像分析工具对dump的堆转储快照进行分析
-内存中的对象是否必要?即区分内存泄漏还是内存溢出
内存泄漏:大量引用指向某些不会使用的对象,这些对象还和GCROOT关联不会被回收
- 工具查看泄漏对象到GCROOT的引用链。查看为什么不会回收,类信息,找到泄漏代码位置
内存溢出:内存中的对象还都必须存活
-检查虚拟机堆参数(-Xmx与-Xms),调整大小,检查某些对象生命周期过长?持有状态时间过长?减少程序运行期内的内存消耗
方法区内部结构:
-存储内容:
已被jvm加载的类型信息
常量
静态变量
即时编译器编译后的代码缓存等
-结构
类型信息、运行时常量池、静态变量、JIT代码缓存、域信息、方法信息
-- 类型信息:
-- 域信息
-- 方法信息
-- 运行时常量池
https://www.cnblogs.com/tiancai/p/9321338.html
方法区-运行时常量池
Class字节码文件-常量池
- 常量池:
字节码文件包含:类的版本、字段、方法、接口等描述符信息、
及常量池(各种字面量和对类型、域、方法的符号引用)
字面量:文本字符串
被声明为final的常量值
基本数据类型的值
其他
符号引用:类和结构的完全限定名
字段名称和描述符
方法名称和描述符
- 为什么用它
不使用常量池,类信息、方法信息等要记录在当前字节码文件,文件过大,需要的结构信息记录在常量池,通过引用的方式加载、调用所需结构
- 有什么?
数量值、字符串值、类引用、字段引用、方法引用
- 常量池,可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
- 运行时常量池:
方法区的一部分
常量池表-Class字节码文件的一部分,存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后放在方法区的运行时常量池中
演进:
1.7 8 6 运行时数据区的变动
1.6 永久区->方法区 静态变量
1.7 去永久区->方法区 字符串常量池、静态变量 放进了堆
1.8 元空间 ->方法区 存放类信息
字符串常量池、静态变量 还在堆
- jdk6
方法区(永久代):
类型信息、域信息、方法信息
JIT代码缓存、静态变量
运行时常量池[字符串常量池StringTable]
- jdk7:
类型信息、域信息、方法信息
JIT代码缓存
运行时常量池
堆:静态变量、StringTable
- jdk8:
无永久代,类型信息,字段,方法,常量保存在本地内存的元空间,但字符串常量池、静态变量仍然在堆中。
为什么使用元空间?
- 虚拟机融合
- 为永久代设置空间大小很难确定
动态加载类过多,OOM
- 对永久代调优困难
方法区的回收:常量池废弃的常量、不再用的类型
调优 为降低FullGC
方法区回收效果难以满意,尤其是类型的卸载、条件苛刻
为什么移动字符串常量池?
- 永久代回收效率低,FullGC触发 老年代空间不足、永久代不足
- 开发中大量字符串被创建,回收效率低,会导致永久代内存不足,放在堆里,能及时回收内存
静态变量放在哪?
-6 7 永久代 8 堆
- 静态变量对应的对象实体使用存在堆空间(只要是对象实例必然会在Java堆中分配)
方法区类回收?
总结?
MinorGC 新生区
MajorGC 老年区
FullGC 整个堆和方法区
** 对象
创建对象?
- new
- clone()
步骤?
1判断对象对应的类是否加载、连接、初始化
-new指令
-检查指令参数能否在元空间的常量池中定位到一个类的符号引用,
-检查这个符号引用代表的类是否被加载、解析、初始化 即类元数据是否存在
-未加载,双亲委派模式下,类加载器以ClassLoader+包名+类名为key查找.class文件,未找到,异常,找到,类加载
2为对象分配内存
-内存规整 -> 指针碰撞
-不规整 -> 空闲列表分配
指针碰撞:
用过的一边,空闲的一边,中间指针为分界点指示器,挪动对象大小
空闲列表:
jvm维护列表,记录哪些可用,给对象分配足够空间,更新表
-堆规整?->由采用的垃圾收集器是否带有压缩功能决定,如标记清除 会有很多内存碎片
3处理并发安全问题
-cas+重试失败、区域加锁保证更新的原子性
-每个线程预先分配TLAB -XX:+/-UseTLAB参数设置(区域加锁机制)
-Eden区给给个线程分配一块区域
4初始化分配到的空间
所有属性设置默认值,保证对象实例字段在不赋值时可以直接使用
5设置对象的对象头
-对象所属类(即类的元数据信息)、对象hashCode、对象GC信息、锁信息等数据存储在对象的对象头
6执行init方法进行初始化
对象的内存布局?
1对象头
-运行时元数据(MarkWord)
哈希值(hashcode)
GC分代年龄
锁状态标志
线程持有锁
偏向线程ID
偏向时间戳
-类型指针
指向方法区中存放的类元信息 确定该对象所属类型
对象是数组,还需记录数组长度
2实例数据
是对象真正存储的有效信息
3对齐填充
非必须 占位符作用
对象访问?
如何通过栈帧中的对象引用访问到其内部的对象实例?
-定位,通过栈上的reference访问
-句柄访问
优点:reference中存储稳定句柄地址,对象被移动(垃圾收集时移动对象很普遍)时只会改变句柄中实例数据指针即可,reference本身不需要被修改
缺点:在堆空间中开辟了一块空间作为句柄池,句柄池本身也会占用空间;通过两次指针访问才能访问到堆中的对象,效率低
-直接访问(Hotspot采用)
优点:直接指针是局部变量表中的引用,直接指向堆中的实例,在对象实例中有类型指针,指向的是方法区中的对象类型数据
缺点:对象被移动(垃圾收集时移动对象很普遍)时需要修改 reference 的值
** 垃圾回收器
HotSpot回收器?(连线可搭配)
Serial ParNew Parallel Scaveage
G1
CMS Serial Old(MSC) Parallel Old
-jdk8:mr:Parallel Scavenge、Parallel Old
Serial:
-分为Serial、SerialOld
-单线程 垃圾回收线程开始时,业务线程必须暂停
Serial-复制、SerialOld-标记压缩
ParNew:
-多线程
-多条垃圾回收线程并行工作,业务线程处于等待状态
-复制算法
ParallelScnvenge:
-多线程并行
-多条垃圾回收线程并行工作,业务线程处于等待状态
-复制算法
ParallelOld:
-ParallelScnvenge的老年代版本
-多线程 等待
-标记压缩
CMS:
-以获取最短回收停顿时间为目标的收集器
-多线程
垃圾线程和业务线程可以一起执行
-标记清除
-步骤:
初始标记-GCRoot能直接关联到的对象
并发标记-和业务并发
重新标记-修正并发标记期间的变动部分-不能和业务并发
并发清除
-并发标记问题:
1漏标-非垃圾对象后面引用消失,浮动垃圾 重新标记
2错标-垃圾对象后面又被引用
-解决:三色标记算法
漏标:CMS重新标记 A(黑)变成灰色
-CMS大bug
没有jdk版本默认CMS
并发标记漏标:remark阶段,必须从头扫描一遍
G1:
-面向服务端
-步骤:
初始标记
并发标记
最终标记
筛选回收
-优点:并行与并发、分代收集、空间整合、可预测停顿
https://www.cnblogs.com/ysocean/p/9227233.html
分布式锁:https://www.bilibili.com/video/BV1d4411y79Y?p=2&spm_id_from=pageDriver
应用场景:
1.互联网秒杀
2.抢优惠卷
客户端api:
Jedis
RedisTemplate:Springboot封装好的模板
例子:redis库存 stock-1操作
问题:
多线程并发
解决1:synchronized(this)
适合单体架构(1个tomcat示例运行)
集群:
集群、分布式(多个tomcat部署)
-每个tomcat jvm进程
synchronized 在jvm内部
-整体并发:
2个请求 ngnix 分发到2个tomcat 2个代码段同时操作
-更改端口号 启动程序 可创建多个tomcat实例
-Jmeter 模拟压测的工具
解决2:redis分布式锁-初级理解,问题很多
setnx k v:.setIfAbsent(k,v)
k不存在,设置v;k存在,v不变
完毕后删除k
问题1:
-异常:try finally,finally中删除k
-死锁:try finally中代码,在执行中服务挂了(重启或kill),k未释放,其他请求不到
问题2:死锁:
method:设置超时时间 expire
问题3:
setnx后,未expire成功
method:
原子操作:setIfAbsent()同时设置setnx、expire
高并发场景:
问题4:
-场景:线程A执行任务15',k过期时间10’,->执行过程中,10'后锁已过期;
线程B需8',获取锁,再进行5',锁被A释放;还有C、D...;
=>锁永久失效(k、v是一样的)
-method:
-删除对应k问题:生成唯一标识uuid:原v+“id”,释放前判断是否是自己的v
-程序没执行完,k过期问题:分线程执行定时器timer,k续命,设置过期时间的1/3,如过期时间10',则10/3=3,timer 3'执行一次(注:分布式锁,无论几个tomcat,多线程只有一个timer执行)
redisson框架:redisson.org
-上述思想的实现
-与Jedis类似,redis Java的一个客户端,更适合分布式
问题:redis主从结构
-主从复制时,主挂了,选举,从变成主,新主还没同步k(超高并发下)
m:redlock、zookeeper(推荐,内部也会保证一致性)
-性能优化:分段式
为什么选择redis而不是zookeeper?
-redis性能更高
-zk准确性高
