数据结构与集合
集合
- HashMap数据结构【🔺】
- https://blog.csdn.net/mbshqqb/article/details/79799009
- 散列实现,是数组和链表的结合,通过hash函数获取key的hashcode,然后将键值对和next指针的Entry存放在数组的对应位置
- 如果哪里已经有Entry,并且key的equals返回false,新entry的next=老的entry,新entry把老的顶出去,如果链表长度超过8,会把链表转换成红黑树,提高查询性能
- 查找的时候先通过hashcode找到数组里面对应的桶的位置,然后遍历链表并调用key.equals方法找到Entry
- 如果Entry的个数超过默认容量16*默认扩容因子0.75的时候,HashMap会增大1倍,并且重新进行rehashing算法进行位置分配,这么做主要是为了减少碰撞的发生使得HashMap性能更高。
- 容量是16主要是选择了一个2的次幂来保证HashMap的位运算hash算法能够尽可能的平均分配。
- HashMap的key必须重写hashcode和equels方法,最好是一个不可变对象,比如String,这样能保证获取的hashcode的一致性
- HashMap,Hashtable,ConcurrnetHashMap的区别
- HashMap是非线程安全的,其他两个是线程安全的
- Hashtable对整个对象进行加锁,ConcurrnetHashMap做了优化,对部分加锁,所有ConcurrnetHashMap性能更好,相对的,使用起来也要更注意,一些复合操作需要使用者自己加锁
JVM原理
JVM原理
-
对JVM的理解【⭐】
- JVM的内存模型和对操作系统的封装使java能够一次编译到处运行
- JVM的主要工作包括自动内存管理,对象生命周期管理,类的加载,垃圾回收等
-
内存区域
- 主要是堆和栈,堆里存放对象,方法区属于堆,方法区里存放加载的类信息,常量和静态变量
- new:old=1:2,Eden:Suvirve=8:1:1
- 栈里存放对象的引用和基本数据类型,还有线程的局部变量
- 本地方法栈存放Native方法服务
- 计数器存放字节码行号指示器,控制程序的需要执行的指令,线程的恢复等
- 主要是堆和栈,堆里存放对象,方法区属于堆,方法区里存放加载的类信息,常量和静态变量
-
垃圾回收
- 可达性算法:从GC Root开始寻找没有引用的对象,能作为GC Root的包括栈里的引用对象,常量,静态变量的引用的对象,还有Native方法引用的对象
-
内存模型
- 内存模型是用来保证多线程下主内存和线程的工作内存的内存共享的原子性,可见性和有序性的规范
- 内存模型分主内存和工作内存
-
类加载机制
- java的运行期动态加载特性,让一个成勋能在运行期间加载远程的一个二进制流作为程序的一部分
- 类的加载分5步,加载,验证,准备,解析,初始化
- 加载通过双亲委派模型找它的父加载器,一层一层往上找
JVM调优
-
JVM调优的经验【⭐⭐】
- 对直接和用户交互的应用使用CMS并发收集器,来提高响应速度。
- 在使用多线程后:使用并发缓解Scooby调用的网络传输时间,垃圾回收速度跟不上,通过增加GC线程和增大MaxGCPareaMill来增加允许GC的时间来改善。
- 通过jmap的hinalizerinfo发现Finalizer线程的队列里面有大量的Scooby对象,发现是写了finalizer方法来释放Scooby的handle,造成对象垃圾回收对象不及时,这是由于Finalizer线程的优先级太低。临时解决方案是通过高优先级的线程调用Finalizer线程的run方法来提高释放handle的速度。下一个Release立马废弃了Finalizer方法
- 还遇到过Direct Memory OOM,报的错误是OOM happend out of the JVM heap in native code。通过jstack查看native内存发现问题。调用Scooby代码造成大量Native Object,造成Native OOM,默认的直接内存大小和XMX一样大,解决方案是减小xmx并且调高MaxDirectMemorySize。因为Direct Memory的回收是在full gc的时候顺便进行的
-
JVM调优工具和参数【⭐】
- jps -l
- jstat -gc: 监控java堆内存状态和垃圾回收情况
- jmap : 显示dump文件,对象数量,堆信息等
- jstack: 显示线程堆栈情况,包括锁,native内存等
- JConsole/VisualVM可视化工具
- 参数
- -XX:printGC
- -XX:printGCDetail
Java源码,原理与特性
多线程
- 面试总结: https://blog.csdn.net/ll666634/article/details/78615505
- Synchronized的实现原理【⭐】
- 如何保证java并发的原子性【⭐】
- 使用synchronized代码块
- 使用ReentrantLock锁
- 使用concurrent包的原子类,比如AtomicInteger
- 在符合volatile场景的时候使用volatile
- 多线程的实现方式
- Thread常用方法
- start和run的区别:start启动一个线程,执行run方法体,run只是普通方法调用,不启动新的线程,run可以多次调用但是start一个正在运行的线程会报错
- sleep和wait的区别: sleep不释放锁,wait释放锁
- join:是两个线程按顺序执行,由wait实现
- yield: 让出CPU执行时间,立马参与竞争,不释放锁
- interrupt:
编程思想与设计模式
设计模式
- 生产者与消费者的三种实现方式【⭐】
- https://blog.csdn.net/u010983881/article/details/78554671
- 好处是生产与消费的隔离性带来的好处,还有性能的提高
- 在我们DS进程中使用了这种模式,启动N个生产者线程和1-3个消费者线程,调节N来使得生产速度在5秒以内
- 使用LinkedBlockingQuere的put/take方法实现
- 使用synchronized和wait/notifyAll
- 使用ReentrentLock的lock/unlock和Condition的await/signalAll
语言
-
java与scala的区别【⭐】
- 语法上吸取java的长处,补充java的不足,使得语法风格更简洁
- 更现代的语言,原生支持单例模式,map键值对语法,支持类型推断,将函数做为一等公民
- 开发速度比java快,java发展时间久,体系更成熟,生态更完善
-
Scala的函数式编程【⭐】
- 函数的结果不依赖上下文,也不修改上下文,与状态无关,这种独立性使得函数天生线程安全,也更适合分布式系统
- Scala里函数是一等公民,可以赋值给变量,也可以作为参数传递或者返回值
数据库
概念与原理
- 索引的原理,什么情况不适合使用索引
- 大部分索引是由二叉树实现,通过二叉树能大幅度提高查询效率,但是对其他操作有一定反作用,因为需要增删操作需要重新维护二叉树,带来一定开销
- 数据量小,更新频繁,数据重复性大的列不适合使用索引
SQL/数据库优化
- oracle sql如何优化【⭐】
- 主要是对索引的处理,live数据表数据量比较小,更新十分频繁,基本不会去建索引
- historical数据表里面price/yield这些列上边建立索引,因为这些列一般会出现在where查询中,或者是order by中,在country,currency,assest type等列上面建立位图索引,这些列的重复性非常高
- 在like模糊查询中,将最前面没用的%去除,这是在性能优化过程中做的
- 还有就是调整语句中表的顺序,小的表写在FROM最后面,将过滤性强的条件写在后面等
- 在与页面交互的服务中,我们使用全量Cache作为Live数据的获取,来减少Orcale访问,并且使用不过期的Cache,通过Cache consumer来订阅Kafka中的live数据来主动刷新Cache
框架
spring
- spring mvc的加载机制【⭐】
- spring 初始化方法【⭐】
- spring AOP的原理【⭐】
- springAOP的使用情景【⭐】
Spring Cloud
- 配置中心的工作原理【⭐】
- 配置中心的动态刷新机制【⭐】
Redis
- Redis数据结构【⭐】
- 如何实现Redis数据库的条件查询
Kafka
- Kafka的toipc数量【⭐】
- Kafka的分区数量【⭐】
ORM
- mybatis分页【⭐】
- RowBounds进行分页,它的原理是获取所有内容,然后根据RowBounds中提供的offset和limit值来获取最后的结
- 或者使用PageHelper插件进行分页,通过拦截器拦截请求,然后对sql进行处理
- 最原始的方法是用limit等sql语句进行分页
- java8的Stream的limit或者filter方法也是很好的分页选择
架构设计
架构
- 微服务的组件【⭐】
- 为什么选择使用spring cloud做微服务【⭐】
- eureka集群怎么搭建【⭐】
- 集群与非集群开发的注意事项【⭐】
- 分布式系统Cache同步问题
- 负载均衡问题,包括区域亲和的考虑
- 数据一致性问题,CAP定理
- Session同步问题
- 分布式定时任务
- 服务器时间同步问题
- 集群服务发现治理问题
- 集群环境的session共享
- 服务器Session共享
- 使用Redis或者数据库存储Session
- 客户请求黏贴
开放式
项目
-
技术选型的过程【⭐】
-
项目技术架构【🔺】
-
项目业务描述【🔺】
- Rates是为国债、外汇、信贷、股票等金融产品提供交易分析,到期利率预估服务的平台。主要通过金融算法计算,对金融衍生品进行计算分析,产生有价值的数据或者报表,图表等给终端用户。
- 通过后台进程轮询的方式从数据源获取最新的基础数据,经过花旗金融分析师提供的金融算法进行计算后得到用户感兴趣的实时数据或者历史数据图表。用户通过订阅数据获取实时数据推送来监控行情。
-
线上遇到的问题【⭐】
- 数据源提供错误数据造成结果偏差极大或者实时数据丢失等问题。应对这种问题,我们在重要页面都做了数据报警系统。并且在处理过程中开启降级功能,提供close数据代替live数据,等到数据源修复后关闭降级。
- 金融算法缺陷造成数据偏差,通过紧急上线修复
- DS进程OOM,或者由于数据源不可预见的错误造成宕机。添加loop机制监控进程。后改称高可用DS机制
- Liberator服务器宕机造车实时推送失败。Support team添加liberator进程和服务器的监控机制
其他
- 平时关注的技术【⭐】
- API规范【⭐】
- 实时股票信息通知到所有客户的解决方案【⭐】
- 可以使用邮件/短信群发系统
- 如果是通知到web应用,可以使用订阅推送模式,比如WebScoket+Kafka,Liberator,以前可以使用ajax长连接的框架实现
算法
编程题
写当前项目业务场景的代码
-
数据库隔离级别?
- Read uncommitted : 会产生脏读,幻读,不可重复读
- Read committed :
- 提交了才能读取到,解决脏读,不解决幻读,不可重复读
- 解决脏读的方法可以加锁,但是效率低
- 更好的方式是快照读,commit时给数据拍一个快照,叫恢复段,commit之后的快照叫做回滚段,如果发现数据来自回滚段,读取操作会去恢复段拿数据
- Read committed是Oracle默认的隔离级别,Oracle使用快照读
- Repeatable Read :事物提交后才允许其它事物修改,解决不可重复读,不解决幻读, MySQl默认的隔离级别
- Serializable : 事物提交后才允许其它事物操作,能解决所有问题,性能最低
- 脏读,不可重复读,幻读
- 脏读 :读到了没提交的事物的数据
- 不可重复读 :事物两次提读取得到了不一样的数值
- 幻读 :事物在两次读取得到不一样的纪录数
-
加密方式
-
分布式事务
- ACID特性
- Paxos算法/Raft算法
- 最终一致性/MVCC
-
遇到的问题
- 随机port 0的问题
- 在服务启动完成服务注册之前调用其它服务,比如在@PostConstruct里调用,会造成随机端口注册失败,注册port变成0
- Kafka自动shutdown,报Zookeeper session time out
- 尚未找到问题
- AOP无法拦截interface方法上的注解
- https://blog.csdn.net/xybz1993/article/details/80627432
- 直接在实现类上加注解就行了
- 随机port 0的问题