沙漏哟:2021年Java面试真题

2021.03.01 饿了么一面

1.1 使用dubbo遇到过的问题

1)dubbo序列化的问题

(1)序列化和反序列化

任何一个对象从一个JVM传输到另一个JVM,都要经过序列化为二进制数据(或者字符串等其他格式,比如JSON),然后在反序列化为Java对象,这最后都是通过二进制的数据在不同的JVM之间传输(一般是通过Socket和二进制的数据传输),本文定义一个比较符合工作中。

dubbo是采用Hessian(比jdk自带反序列化高效)进行反序列化的,该反序列化创建对象时,会取参数最少的构造方法来创建对象,构造方法参数设置默认值,基本类型设置为相应基本类型的默认值,不是基本类型设置为null(就是这点,才导致我上面的构造方法出现空指针,进而导致该对象无法实例化)

dubbo在进行反序列化时,如果找不到对象,会被反序列化成HashMap,给出类找不到的warn,具体的实现可研究com.alibaba.com.caucho.hessian.io.SerializerFactory类。

(2)无法获取到父类名称相同的属性

最近工作中遇见了一个小问题,在此记录一下,大致是这样的,有一父类,有一个属性traceId,主要是记录日志号,这样可以把所有日志串起来,利于排查问题,所有的pojo对象继承于此,但是其中一同事在子类pojo中也增加了这一个属性,在消费者端给traceId设置了值,但经过序列化解析后,提供者端这个traceId时,值为空,解决问题很简单啊,把子类中的traceId属性去掉搞定。

这个类的构造方法里调用了这样的方法getFieldMap,把里面本类和父类的所有方法放到一个fieldMap里,因为是HashMap,为了保证方法名不覆盖,这个方法里做了一个操作就是fieldMap.get(field.getName()) != null,有的话就继续循环下去不覆盖,这样的话如果有同名的方法,那只有子类的方法在里面。还有这个类Hessian2Input要说下,其中的方法readObjectInstance,它会取到本类和父类的所有方法放到一个数组fieldNames下,这些说完了说到这里面反序列化的方法JavaSerializer的readObject,是按fieldNames数组循环取值,在流里面挨个取出来,一直赋给本类的set方法,先是有值的,到父类时,取到的为空,就把本类的值覆盖了。到这里原因就清楚了。

(3)泛型的

对于泛型的ComplexModel,Hessian是可以正确的序列化和反序列化的,这让我纳闷了,既然泛型是编译时的行为,为什么序列化和反序列化能够成功?

我的理解:对于JVM而言,运行时没有泛型信息,也就是说不管是否使用泛型,它的字节码是完全一样的,当把一个没有泛型信息的对象序列化为二进制数据,然后再把它反序列回来,它的数据就是反序列化前的样子。

因此ComplexModel的List如果是Point类型的元素,那么反序列化后也是Point类型,这属于字节码级别的序列化和反序列化。

反序化时为什么能够知道List元素的类型呢?原因是在序列化时,List中的每个元素的类型都会作为序列化的数据的一部分,这部分类型信息就是反序列化到正确类型的依据

2)传输报文最大限制

1. dubbo接口限制, 针对的是单个参数, 还是整体参数的大小呢?

  • 1. 经过测试,大小限制针对整体参数大小.

2. 如何解决?

  • 1. dubbo默认参数大小限制为8388608(8M).
  • 2. 可以通过配置修改
  • 3. 配置payload属性:dubbo.protocol.dubbo.payload=10485760

3. 另外一种方式:绕过dubbo的限制

  • 大文件,都统一用第三方文件系统存储,dubbo接口调用中,只传递url地址.

3)重试次数,2次

4)其他参数

背景:如果不设置dubbo解救超时时间,默认是1s,重试次数是2次,在调用dubbo接口时,会存在超过1s的接口响应时间,这时,就会重新发送请求,而在dubbo提供方逻辑还没有走完,就会由于接口响应时间问题而造成bug,在这次事故中是对数据库的操作几乎同时操作造成了SqlMapClient operation; SQL []这个错误。
dubbo默认值:

变量名 描述 默认值 用途
DEFAULT_IO_THREADS 默认IO线程 Math.min(Runtime.getRuntime().availableProcessors() + 1, 32) 创建NettyServer和MinaServer时
DEFAULT_PROXY 默认代理, javassist 通过生成字节码代替反射
DEFAULT_PAYLOAD 默认最大数据大小 8 * 1024 * 1024/8M 在从通道获取数据进行编码时判断大小
DEFAULT_CLUSTER 默认集群容错方案 failover
DEFAULT_DIRECTORY 默认集群目录服务 dubbo
DEFAULT_LOADBALANCE 默认负载均衡方案 random(随机)
DEFAULT_PROTOCOL 默认协议 dubbo
DEFAULT_EXCHANGER 默认信息交换方式 header
DEFAULT_TRANSPORTER 默认传输方式 netty(netty3)
DEFAULT_REMOTING_SERVER 默认远程客户端 netty(netty3)
DEFAULT_REMOTING_CODEC 默认协议编码 dubbo
DEFAULT_REMOTING_SERIALIZATION 默认远程调用序列化方案 hessian2
DEFAULT_HTTP_CLIENT protocol为hession时的默认客户端类型 jdk
DEFAULT_HTTP_SERIALIZATION http类型默认序列化方案 json
DEFAULT_CHARSET 默认字符集 UTF-8
DEFAULT_WEIGHT 服务默认权重 1000
DEFAULT_FORKS 默认并行请求数 2
DEFAULT_THREAD_NAME 默认线程名 Dubbo
DEFAULT_CORE_THREADS 默认核心线程数 0
DEFAULT_THREADS 线程池默认线程数 200
DEFAULT_QUEUES 默认队列数 0
DEFAULT_IDLE_TIMEOUT 默认空闲时间 600 * 1000(10分钟)
DEFAULT_ALIVE 连接默认存活时间 60 * 1000(1分钟)
DEFAULT_CONNECTIONS 默认连接 0
DEFAULT_ACCEPTS 默认接收 0
DEFAULT_HEARTBEAT 默认心跳时间 60 * 1000(1分钟)
DEFAULT_TIMEOUT 请求执行默认超时时间 1s
DEFAULT_CONNECT_TIMEOUT 连接默认超时时间 3s
DEFAULT_RETRIES 默认重试次数 2
DEFAULT_BUFFER_SIZE 默认缓冲区大小 8 * 1024(8K)

1.2 redis 分布式锁

A线程拿到分布式锁,但是处理时间过长,然后B线程又来拿到分布式锁,怎么处理这种情况

1.3 mysql的联合索引,a,b,c

我用a,c查询条件,可以走到a,b,c的索引吗

1.4 classloader隔离

比如rocketmq引用了slf4j,其他包也引用了slf4j,但是版本不一致怎么处理
两个不同的classloader加载相同的类,互相之间怎么通信?

不同分支加载同一个class文件会被认为是不同的class,不可直接互相访问
比方说class A 分别被两个分支上的classLoader 加载,分别生成a1,a2两个实例,
如果两个实例都持有对方的引用, 在a1 中调 a2.f();或在a2中调a1.f();都会提示class not found

但是通过接口访问没问题,比方说A implements IA ,不同classloader 加载的类可以通过IA的引用互访

其原理是,classloader加载顺序为从父类到子类顺着继承关系一级一级的加载,如果在加载的过程中没有找到改class 则到父类里面寻找,平行的 classloader是不能够互访的。

所以,实现方法是要先用一个公共接口的jar包。这个jar包放到父类里面。也就是osgi框架级别加载。

使用自定义ClassLoader解决反序列化serialVesionUID不一致问题

利用类加载器解决不兼容的Jar包共存的问题

就是rocketmq引用了一个jar包2.0版本的,调用了里面某个类,假设是com.xxx.classA里面的hello2方法,但是redis里面引用的是一个1.0版本的jar,里面的com.xxx.classA中没有hello2方法,那如果类加载过程中,先由redis的classloader加载com.xxx.classA,那么rocketmq调用hello2的时候就找不到这个方法

1.5 分布式事务的原理

XA、2PC、3PC、TCC、SAGA

Seata

1.6 rocketmq消息队列堆积问题

1.7 rocketmq的分片机制

2021.03.02 小鹅拼拼一面

对着简历的项目经验问,我说项目经验里用到了SpringBoot + Dubbo + Redis + MySQL,然后就一个个地开始问了。

1)SpringBoot

(1)SpringMVC和SpringBoot使用起来有什么区别

回答一个是少了很多配置,一个是SpringBoot把Tomcat容器集成进去了

(2)看过SpringBoot的源码吗?他和Dubbo的类加载区别是什么?

(3)SpringBoot是怎样提前读取配置给到Tomcat的?tomcat有配置过超时时间、请求协议之类的吗?

(4)自己写过SpringBoot starter吗?

写一个AutoApplication注解

(5)你说用过Apollo,那Apollo是怎么实现热更新的?怎么热更新Tomcat的配置?

(4)Bean的生命周期

2)Dubbo

(1)Dubbo有哪些负载均衡策略?

(2)给我讲一讲Dubbo的完整调用链。

(3)Dubbo的SPI是怎么实现的?

3)Redis

(1)Redis主要用来做什么?分布式缓存和分布式锁。

(2)分布式缓存是先操作数据库还是先操作缓存?分别有什么样的问题,怎么解决?

(3)假设先操作缓存,然后服务宕机了,这个时候锁就拿不到了怎么解决?

(4)用了哪些数据类型?String、list、set、zset主要用在什么场景?

我说zset用来做排行榜。那1亿的用户数据怎么用zset做排行榜?

(5)zset底层的实现原理是什么?

字典表+跳表。字典表用来做什么?插入一个数据,插在跳表的第几层?

4)MySQL

事务隔离级别知道吧?

MySQL的MVCC在RC和RR上分别有什么样的表现?你说下两种隔离级别下的事务ID视图?(后来问了说是活跃数和快照表)

MVCC读取的快照数据在哪里?

undo log和redo log分别什么情形下写入?bin log呢?

5)网络了解过吗?

说下TCP的四次挥手。

HTTP响应码主要有哪些? 200,404,500

forward和redirect的响应码是什么?302?

你用看过HTTP请求的时候当前连接状态吗?用什么看的。我说用过netstat,主要用来看端口是否被占用了。他说他想问的不是这个。

HTTPS的连接过程是怎样的?证书是谁颁发的?怎么验证证书的?

6)我们来写一道算法题吧

刚开始是大数的一个题,我没听懂是什么。

他就说写个简单的两个大数相加吧。

2021.03.05 永辉超市一面

1)Object里有哪些方法

2)Dubbo的一次完整调用链

3)有一张门店表、一张门店商品表,一张门店商品关联表,门店商品关联表的数据量特别大,怎么提高这张表的查询速度?

4)HashMap 1.7和1.8的区别,什么时候链表转红黑树,数据后来又删除了,红黑树会变成链表吗?

2021.03.06 微盟一面

1)项目经历,这次主要讲了信贷的项目分库分表,引入到了这个项目

我说拆分成4库16表,你为什么这样分?

2)Spring是怎么解决循环依赖问题的(微盟必问,去年一面就是这个挂了)

3)数据库的MVCC是怎么实现的

4)你们是怎样解决redis和数据库的数据一致性问题的?

我说先更新数据库,再删除redis。

那么如果这个时候并发量比较高,流量都打在redis上怎么办?

5)你们分布式链路跟踪用的什么?

6)我看你有带团队,你是怎样保证团队代码质量的?

2021.03.06 百布一面

1)对象的HashCode是什么?两个Person 年龄属性值都是1,作为HashMap的key存入HashMap会保存几条记录?

2)Java里面是值传递还是引用传递?为什么你传一个Integer,然后改了外面的方法感知不到?

3)ArrayList按照1.5倍扩容,如果ArrayList容量是100万再插入时,扩容时速度会变慢吗?

4)System开头的方法代表什么?

5)MyBatis的Mapper接口没有实现类,但是却能自动注入,实现原理是什么?

6)MinoGC和FullGC的关联关系是什么?

7)Histrix的熔断策略是配置在客户端还是服务端?

2021.03.08 Soul一面

1)Redis集群情况下,主从同步失败,导致分布式锁失效怎么处理?

redis的单点故障主从切换带来的两个客户端同时执行(而不是叫同时获取锁的错误写法)的问题

解决方案

(1)业务容忍

(2)RedLock

2)Redis的内存淘汰机制有哪几种?

volatile lru ttl random lfu

allkey lru lfu

3)MySQL是先操作undolog还是redolog?

4)MySQL写磁盘前会先写到Cache里,这个原理叫什么?

checkpoint规则:checkpoint触发后,将buffer中脏数据页和脏日志页都刷到磁盘。

脏数据刷盘:buffer-pool ====> redo log

脏日志刷盘:redo log buffer ====> redo log file

redo log buffer -> os buffer -> fsync函数 -> redo log file

5)你们的分布式事务一致性是怎么做的?用的什么框架?

6)给你一个100亿的数据,你要怎样分库分表?

7)ES有用过吗?主要用来做什么?

8)dubbo配置的连接池有哪几种类型,区别是什么?

9)岗位描述,C端业务研发

技术栈:Dubbo、zookeeper、mysql、HBase、Mongo 

2021.03.10 喜马拉雅一面

第一面

1)Redis疯狂地面,所有知识点

(1)怎么发现热key?

Storm流式计算统计,判断成热点缓存。

zookeeper同步,放到本地缓存

(2)怎么解决热key?

(3)redis的过期删除策略是什么?我回答惰性+定时。

他问定期删除是怎么实现的?定期删除的时候拿所有的key?

2)JVM

(1)JVM怎么管理堆外内存

(2)强引用、软引用、弱引用的实现原理是什么?分别什么时机回收?JVM是怎么知道要去回收的?

(3)你看了软引用类的源码里的参数,有什么启发吗?

(4)怎样动态输出GC的日志?

3)RocketMQ

(1)RocketMQ的存储实现原理是什么?

(2)RocketMQ怎样延时队列的实现原理是什么?

(3)RocketMQ的事务消息实现原理是什么?

第二面

1)Redis

(1)zset的底层数据结构是什么?

HashMap + 跳表。跳表可以用红黑树代替吗?

zset的range怎么实现?查询的路径是什么?

2)MySQL

(1)MVCC的实现原理是什么?在RC和RR的事务隔离级别下分别有什么?

(2)MySQL用B+树,MongoDB用B树,为什么?

(3)给我画一下B+树升级层级的过程

3)讲一下Dubbo的client调用过程

4)Zookeeper

(1)看过Zookeeper的源码吗?

(2)Zookeeper的选举过程是怎样的?

(3)Zookeeper的ZAB算法实现原理是什么?看过ZAB的Paper吗?

2021.03.10 叮咚一面

讲了6个生产问题,问我可能的原因是什么,怎么解决?

1)A系统更新库存,通过消息通知B系统库存更新完成了,B系统过来反查但是发现库存没变化,可能原因是什么?

2)发完版本后,redis(腾讯云上的单实例)带宽占满了怎么处理?

3)发现某个应用线程数占用几万个,怎么处理?

4)修改商品库存,100个商品的库存同时修改,在一个事务里做for 循环偶尔会发生死锁,可能是什么原因?

解决方案,对商品ID排序后再操作。

5)说一下缓存和数据库的先操作哪个,分别会有什么问题,怎么解决。

6)乐观锁和悲观锁的区别是什么,分别用在什么场景?

7)A系统一个接口会调用B、C、D三个系统的查询接口,怎么提高A系统这个接口的查询速度?

8)CQRS 更新和查询分离,更新解决并发问题,查询解决一致性问题

分布式系统就是解决并发和一致性问题

2021.03.11 比心一面

1. dubbo里的线程池是用来做什么的?什么阶段用?你说有200个线程,是200个连接吗?具体是指什么?业务线程和这200个线程是同一个线程吗?如果不是,他们是怎么通信的呢?
2. 你刚刚说用了future,那future是怎么拿到线程的返回的?可以具体讲讲吗?
3. 线程池是怎么管理线程的?怎么回收的?可以具体讲讲吗?
4. 你可以手写一个阻塞队列吗?
5. 数组123456右移2位变成561234,空间复杂度O(1)

用 Spring 的 @Transactional 注解控制事务有哪些不生效的场景?

 

posted @ 2021-07-22 10:08  沙漏哟  阅读(234)  评论(2编辑  收藏  举报