自学内容网 自学内容网

场景面试题——第二篇

1. 假设有一个1G大的HashMap,此时用户请求过来刚好触发他的扩容,会怎样以及如何优化

HashMap的底层是基于数组+链表来实现的,一旦发生扩容,就需要新增一个比之前大2倍的数组,然后将元素搬运到新的数组上。
因为1G的HashMap足够大,所以,扩容需要一定的时间,而扩容使用的线程是当前线程,所以 用户此时会被阻塞,等待扩容完毕。
可以使用 渐进式rehash 进行优化。
简单来说不要一次性扩容完毕,而是慢慢搬运数据。
一个hash可以配置两个数组,比如数组1和数组2.
正常情况下,只使用一个数组,当发生扩容时,将另一个数组设置为当前的两倍大,此时用户线程就可以反悔了,后面扩容结束前同时使用当前两个数组。
在后续对这个hashmap的增删改查过程中或者定时任务中,一点点的把老数组的数据搬运到新数组中。
查询的时候,先从老的数组中找,找不到再去新的数组中找。
这样一步步操作下来,直到老数组的数据为空,此时扩容结束。
其实,就是 空间换时间。

2. 从网关到后台服务,如何设置RPC的超时时间,要考虑哪些问题

如果包含网关,那么简单的调用链路如下
在这里插入图片描述
可以看到,网页到网关是HTTP协议,网关到后端的几个服务都是RPC调用。因此,我们可以确认网页到网关的HTTP超时时间一定需要大于网关调用后端服务的综合时间。

首先我们需要考虑网关调用几个服务的方式,是串行还是并行,按图所示,三个服务是并行调用和串行调用,超时时间完全不一样。

还需要考虑每个服务TP99的耗时以及对应的超时重试次数,所谓TP99指的是百分之九十九的调用所需的最低耗时,比如我调用一个方法,1小时调用了10w次,监控显示的tp99是200ms,说明百分之九十九的调用都在200ms返回。

同时,远程调用还会有重试的情况,比如重试2次,那么实际上最多会有三次调用,最长的耗时就是超时时间*3,所以重试的时间也需要计算在总的超时时间之内。

3. 如果没有内存限制,如何快速、安全的将1000亿条数据插入到HashMap中

  1. 首先,HashMap的插入过程,会先判定HashMap的空间是否足够,如果不够的话则会扩容,每次扩容都需要将元素迁移,很浪费时间。HashMap的默认初始容量是16,如果插入到1000亿那得扩容多少次?所以,为了尽量减少这个操作,我们可以在HashMap创建的时候指定初始容量稍微超过1000亿,避免动态扩容。
  2. 负载因子可配置为1,元素量还未达到初始容量就扩容了。
  3. 采用多线程的方式,因为HashMap线程不安全的特性,其多线程插入的时候大概率会出现数据覆盖的情况,即线程不安全的情况,针对这种情况,可以使用ConcurrentHashMap解决并发安全问题。

4. 线上连接池爆满问题排查

连接池满,一般会有两种情况

  1. 很多长事务,执行的慢,导致长时间占用连接,然后别的请求都hang住了
  2. 很多短事务,执行的快,但是并发太高,即使时间短,但是量过大。

5. JDK序列化问题排查

现象
在这里插入图片描述
复现错误

  1. 定义类
    在这里插入图片描述
  2. 创建对象,set到redis中在这里插入图片描述
  3. 增加字段,再从redis里面取出打印
    在这里插入图片描述
    4.出现序列化错误
    在这里插入图片描述

1. 问题原因:
因为用的是JDK序列化,虽然class实现了Serializable接口,但没显示定义serialVersionUid,这样一来。序列化时会根据当前类信息计算得到一个serialVersionUID。
在序列化存入redis后,再把代码里的class结构变更,这时候,从redis获取之前的值反序列化,由于当前的class还是没有serialVersionUid,于是会再次根据当前类计算得到serialVersionUID,而由于结构变了,类信息肯定变了,所以计算出来的serialVersionUID不一致。因此,序列化失败
2. 解决方式
显示指定serialVersionUID,这样就不需要动态计算了。

6. 线上CPU飙高如何排查

  1. 首先确认哪个进程占用CPU过高,登陆服务器利用top命令查看
  2. 确认CPU利用率很高的进程的PID,假设为1234确实是Java进程,则通过top -Hp 1234 查看具体的线程。
  3. 假设得到的线程ID是5678,再将线程转换为16进制 printf “%x\n” 5678
  4. 得到16进制的tid为162e,此时,利用jstack 1234|grep 162e -A 100 查看具体的栈信息。jstack命令用于生成虚拟机当前时刻的线程快照,线程快照是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。
  5. 根据堆栈信息就可以定位到具体是哪行代码导致了CPU飙高。

7.如果发现Redis内存溢出了,怎么做

遇到线上问题,第一时间是止损,如果发现Redis内存溢出,即应该立即扩容,增加Redis实例的内存。

然后在排查内存溢出的可能原因:

  • 数据过多:Redis中存储的数据量过大,超过了可用内存。
  • 数据过期策略失效:大量的key没有设置过期时间,导致内存不断增长。
  • 大对象或者大数据结构:某些key关联的数据结构过于庞大,占用了大量内存。
  • 持久化机制:RDB采用写时复制,极端情况下会占用正常两倍的内存。

常见的优化方案

  • 调整内存淘汰策略:根据业务需求选择合适的淘汰策略,如allkeys-lru或者volatile-lru。
  • 设置数据过期时间
  • 优化数据结构
  • 垂直扩展:升级单台Redis配置
  • 水平扩展:将数据分片到多个Redis实例,使用集群缓解单实例内存压力。

8. 两百万个生产者发送消息,仅一个消费者,如何高效设计锁

  • 使用无锁数据结构:如Java的ConcurrentLinkedQueue,采用了非阻塞算法,避免了加锁的开销,这样,多个生产者可以并发的将消息添加到队列中,而消费者可以从队列中安全的读取消息。
  • 批量操作:生产者可以批量发送消息,减少锁竞争的频率,例如,一个生产者可以先在本地缓存一批消息,然后一次性将这些消息推送到队列中,减少了多次加锁解锁的开销。

ConcurrentLinkedQueue原理
ConcurrentLinkedQueue是一种无锁并发队列,能实现线程安全的无阻塞操作。通过CAS操作实现线程安全,而不是依赖传统的锁机制,避免了锁的开销,降低了线程争用带来的性能损耗。

入队操作

  1. 创建新节点:首先为要插入的元素创建一个新的节点
  2. 定位尾节点:通过尾指针找到当前的尾节点
  3. CAS操作更新尾节点:通过CAS操作将新节点链接到当前尾节点的next引用上,然后更新尾指针,使其指向新的尾节点。

出队操作

  1. 定位头节点:通过头指针找到当前的头节点
  2. 获取下一个节点:检查头节点的next引用,找到下一个节点
  3. CAS操作更新头节点:通过CAS操作将头指针更新为下一个节点,旧的节点被垃圾回收器回收。

9. Java写入文件到磁盘会经历哪些过程

  1. 应用层(Java代码执行)
  • 文件对象的创建:首先,Java程序通过File对象指定要写入的文件路径,可以使用FileOutputStream、BufferedWriter等类来实现数据的写入操作。
  • 写入操作:调用写入方法,将数据从内存写入到文件流或者缓冲区。
  1. Java I/O流与缓冲区
  • 缓冲区管理:Java中的IO类通常使用缓冲区来减少实际磁盘IO操作的频率,例如BufferedWriter会将数据写入内存缓冲区,等到缓冲区满或者手动调用flush()时,才会将数据写入到操作系统。
  • 数据刷入:调用flush或者close方法时,强制将缓冲区的数据刷入到底层的文件系统缓冲区。
  1. 操作系统层:系统调用
  • 系统调用:当Java程序调用flush或者close时,底层会触发相应的系统调用,将数据从用户态传递到内核态。
  • 内核缓冲区:操作系统接收到系统调用后,会将数据写入内核缓冲区,此时,数据还在内存中。
  1. 文件系统
  • 文件系统的组织:操作系统会根据文件系统类型(EXT4、NTFS)管理文件的元数据,如文件名、权限、文件内容的块位置等。
  • 分配磁盘块:操作系统根据文件的大小和位置,分配磁盘块存储数据。
  1. 磁盘调度和写入
  • IO调度:操作系统中的IO调度器决定实际的写入顺序,以优化性能。常用的调度算法包括电梯算法、最短寻道时间优先。
  • 硬件缓冲区:数据从内核缓冲区通过DMA或者中断机制传递到磁盘控制器的硬件缓冲区。
  • 磁盘写入:磁盘控制器最终将数据写入到磁盘的物理扇区中。
  1. 数据持久化
  • 缓存刷盘:操作系统可能延迟将数据从内核缓冲区写入磁盘,以提高写入效率,这时可以通过fsync()系统调用强制刷新缓冲区,确保数据持久化。
  • 日志与恢复机制:许多文件系统使用日志机制,在写入数据前记录操作日志,以便在系统崩溃后能够恢复数据一致性。

原文地址:https://blog.csdn.net/weixin_42824596/article/details/142781243

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!