【面经】字节跳动后端开发Java方向25届实习生二面

一 MQ消息堆积问题

        MQ(消息队列)消息堆积问题是指生产者发送的消息无法被消费者及时消费,导致消息在Broker端大量积累的现象。该问题不仅影响业务功能的正常使用,还可能对系统性能和稳定性造成严重影响。  

        消息堆积的主要原因是生产者发送消息的速度超过了消费者的处理能力。这可能是因为消费者实例出现故障、网络问题,或者短时间内生产者推送大量消息而消费者消费能力不足。此外,新上线的消费者功能存在BUG也可能导致消息无法正常消费。

        针对这些情况,可以采取以下措施:

  1. 增加消费者数量:通过增加消费者线程或实例来提高并行处理能力。例如,在RabbitMQ中,可以通过配置多个并发消费者来实现负载均衡,减轻单一消费者的压力。
  2. 设置预取计数(QoS):控制每个消费者一次从MQ拉取的消息数量,避免消费者一次性拉取过多消息导致处理不过来。这有助于平衡消息拉取速度和处理速度。
  3. 使用死信队列(DLQ):对于无法立即处理或处理失败的消息,可以将其转发到死信队列中单独处理,避免阻塞正常的消息流。这既能保证主流程的顺畅,又能对异常消息进行集中管理。
  4. 优化消费者性能:分析消费者代码,找出瓶颈并进行优化,提升单个消费者处理消息的速度。例如,减少不必要的数据库操作、优化算法和使用更高效的数据结构等方式,提高消费者的处理速度。
  5. 惰性队列(Lazy Queues):对于不在活跃节点上的消息,启用惰性队列,在消费者请求时才加载消息到内存中,从而减轻内存压力。这种机制尤其适用于高并发场景,能够有效避免内存溢出。
  6. 监控与报警:建立有效的监控和报警机制,当消息堆积超过阈值时,触发报警通知运维人员及时介入处理。这有助于及时发现并解决问题,确保系统的稳定运行。

二 项目上线之后要考虑的问题

        在项目上线后,确保系统的性能、稳定性和响应速度是至关重要的。通常是从每秒查询率、系统响应速度、系统稳定性等角度考虑优化。

(一)QPS(每秒查询率)

1. 优化后端服务:

  • 代码级优化:审查代码以识别性能瓶颈,使用更高效的数据结构和算法来减少时间复杂度。
  • 数据库优化:优化索引,减少不必要的表锁定,使用存储过程和触发器减少数据库交互次数。
  • 缓存策略:实现分布式缓存(如Redis),缓存热点数据以减少对数据库的访问。

2. 负载均衡:

  • 使用负载均衡器(如Nginx、LVS)分散请求到多个服务器,提高系统的处理能力。
  • 配置适当的负载均衡策略(如轮询、最少连接、IP哈希),根据服务器性能动态调整权重。

3. 异步处理与队列:

  • 引入消息队列(如RabbitMQ、Kafka),执行异步操作,减轻主流程的压力。
  • 处理长时间或非关键任务时,使用后台任务和延迟处理,从而不阻塞主线程。

(二)响应速度

1. 前端优化:

  • 压缩和合并资源文件:减少HTTP请求次数及传输大小。
  • 使用CDN:存放静态资源,加速全球访问速度。
  • 缓存策略:合理设置浏览器缓存和使用Service Worker缓存。

2. 网络优化:

  • 确保使用HTTP/2或HTTP/3,支持多路复用和头部压缩。
  • 优化TCP连接配置,如调整SO_KEEPALIVE参数。

3. 应用层优化:

  • 减少数据库交互:通过查询优化和索引减少查询时间。
  • API响应优化:使用分页、过滤不必要的数据字段,减少API响应体大小。

(三)稳定性

1. 熔断与限流:

  • 实施熔断机制(如Hystrix),在下游服务不可用时快速失败,避免级联故障。
  • 使用限流算法(如令牌桶、漏桶)控制访问速率,防止资源过载。

2. 监控与告警:

  • 建立完善的监控系统(如Prometheus + Grafana),实时监测系统状态。
  • 配置告警规则,当指标异常时(如CPU使用率过高)立即通知运维团队。

3. 灾难恢复规划:

  • 准备灾备方案,包括故障转移和数据备份策略。
  • 定期进行灾难恢复演练,确保在真正的故障中能够迅速恢复。

三 Redis的持久化策略

        Redis主要提供两种持久化策略:RDB(Redis DataBase)和AOF(Append Only File)。这两种策略有不同的应用场景、优势和劣势,具体选择哪种方式需要根据具体的应用需求来定。

        RDB持久化策略:RDB 持久化策略是指在一定的时间间隔内,将 Redis 内存中的数据以二进制文件的形式保存到硬盘上。这个二进制文件就是一个快照,记录了某个时刻 Redis 内存中的所有数据。可以通过配置文件或命令手动触发。配置文件中可以设置多个条件,当任意一个条件满足时,就会执行一次快照操作。例如:save 900 1表示900秒内如果有1次修改则进行持久化。其优点是RDB 文件紧凑,全量备份,非常适合用于备份和灾难恢复;生成 RDB 文件时,Redis 主进程会 fork() 一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作;RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。但是RDB 快照是一次全量备份,可能会丢失两次快照之间的数据;在生成 RDB 文件的过程中可能会占用较多的内存和 CPU 资源。

        AOF持久化策略:AOF 持久化策略是指将 Redis 服务器执行的每一条写命令都记录到一个文本文件中,即追加文件(append only file)。AOF 日志文件通过记录每次写命令进行同步。它有三种刷盘策略:no(由操作系统决定何时刷盘)、everysec(每隔一秒刷一次盘)和 always(每次写操作立即刷盘)。AOF 的特点是可以更好地保护数据不丢失,一般 AOF 会每隔1秒通过后台线程执行一次 fsync 操作,最多只丢失1秒钟的数据;此外AOF 的文件是一个文本文件,可以方便地查看和编辑,适合做灾难性误删除的紧急恢复;并且AOF 文件不容易破损,即使文件过大,重写操作也不会影响客户端的正常读写。但是AOF 文件通常比 RDB 文件大,占用更多磁盘空间,且AOF 文件恢复数据的速度比 RDB 慢,因为需要重新执行所有的命令。

        混合持久化策略:混合持久化结合了 RDB 和 AOF 的优点。该策略在同一时间里既生成 RDB 快照,又记录 AOF 日志。当 Redis 重启时,优先使用 AOF 文件进行数据恢复,这是因为 AOF 文件中的数据更加完整且实时。它结合了 RDB 快速恢复数据和 AOF 数据完整性高的优点,但需要更多的磁盘空间来存储两种格式的文件,并且恢复数据时需要先加载 RDB 再逐个执行 AOF 文件中的命令。

        综上所述,Redis 提供了多种持久化策略以满足不同的需求。RDB 适用于对数据恢复速度要求较高且可以接受一定数据丢失的场景;AOF 适用于对数据完整性有严格要求的场合;而混合持久化则兼顾了两者的优点。在选择适当的持久化策略时,需要结合实际的业务场景和需求进行权衡。

四 Redis的RDB策略如何解决边写边存

        Redis通过使用子进程和写时复制(Copy-On-Write,COW)技术来解决边写边存的问题。写时复制技术在子进程进行数据持久化操作时,父进程可以继续接收和处理客户端命令,而不会影响子进程的数据备份操作。

        在Redis中,当执行bgsave命令时,Redis会通过fork创建一个子进程。这个子进程是主进程的一个副本,继承了主进程的所有内存数据。由于操作系统的写时复制优化,这些内存数据在子进程和主进程之间是共享的,但任何一方对数据的修改都会导致一个私有的数据副本被创建。这意味着,主进程可以继续修改数据,而子进程则会安全地将数据保存到RDB文件中,两者之间不会相互干扰。

五  JVM内存空间

         程序计数器:线程私有的,是一块很小的内存空间,作为当前线程的行号指示器,用于记录当前虚拟机正在执行的线程指令地址;
        虚拟机栈:线程私有的,每个方法执行的时候都会创建一个栈帧,用于存储局部变量表、操作数、动态链接和方法返回等信息,当线程请求的栈深度超过了虚拟机允许的最大深度时,就会抛出StackOverFlowError;
       本地方法栈:线程私有的,保存的是native方法的信息,当一个jvm创建的线程调用native方法后,jvm不会在虚拟机栈中为该线程创建栈帧,而是简单的动态链接并直接调用该方法;
        堆:java堆是所有线程共享的一块内存,几乎所有对象的实例和数组都要在堆上分配内存,因此该区域经常发生垃圾回收的操作;
        方法区:存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码数据。

六 垃圾回收主要针对哪一块

        JVM中的垃圾回收主要针对堆内存进行。JVM的垃圾回收机制是Java语言的一大特色,它通过自动检测和释放不再使用的对象来避免内存泄漏和提高程序执行效率。在Java虚拟机中,垃圾回收器主要工作在堆内存区域,因为这是对象实例和数组分配的主要空间。同时,JVM采用多种算法和策略来实现高效的内存管理,确保系统性能和稳定性。

七 用到了什么垃圾回收器

        Serial:单线程的收集器,收集垃圾时,必须stop the world,使用复制算法。它的最大特点是在进行垃圾回收时,需要对所有正在执行的线程暂停(stop the world),对于有些应用是难以接受的,但是如果应用的实时性要求不是那么高,只要停顿的时间控制在N毫秒之内,大多数应用还是可以接受的,是client级别的默认GC方式。

        ParNew:Serial收集器的多线程版本,也需要stop the world,复制算

        Parallel Scavenge:新生代收集器,复制算法的收集器,并发的多线程收集器,目标是达到一个可控的吞吐量,和ParNew的最大区别是GC自动调节策略;虚拟机会根据系统的运行状态收集性能监控信息,动态设置这些参数,以提供最优停顿时间和最高的吞吐量;

        erial Old:Serial收集器的老年代版本,单线程收集器,使用标记整理算法。

        Parallel Old:是Parallel Scavenge收集器的老年代版本,使用多线程,标记-整理算法。

        CMS:是一种以获得最短回收停顿时间为目标的收集器,标记清除算法,运作过程:初始标记,并发标记,重新标记,并发清除,收集结束会产生大量空间碎片;

        G1:标记整理算法实现,运作流程主要包括以下:初始标记,并发标记,最终标记,筛选回收。不会产生空间碎片,可以精确地控制停顿;G1将整个堆分为大小相等的多个Region(区域),G1跟踪每个区域的垃圾大小,在后台维护一个优先级列表,每次根据允许的收集时间,优先回收价值最大的区域,已达到在有限时间内获取尽可能高的回收效率;

八 有调过垃圾回收器的参数吗

        1.jps:JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
        2.jstat:jstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
        3.jmap:jmap(JVM Memory Map)命令用于生成heap dump文件
        4.jhat:jhat(JVM Heap Analysis Tool)命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看。在此要注意,一般不会直接在服务器上进行分析,因为jhat是一个耗时并且耗费硬件资源的过程,一般把服务器生成的dump文件复制到本地或其他机器上进行分析。
        5.jstack:jstack用于生成java虚拟机当前时刻的线程快照。jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。

九 JVM发生OOM,你会怎么排查

        1.增加两个参数 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof,当 OOM 发生时自动 dump 堆内存信息到指定目录;
        2.同时 jstat 查看监控 JVM 的内存和 GC 情况,先观察问题大概出在什么区域;
        3.使用 MAT 工具载入到 dump 文件,分析大对象的占用情况,比如 HashMap 做缓存未清理,时间长了就会内存溢出,可以把改为弱引用 。

十 CPU的load

        CPU load(中央处理单元负载)是指计算机系统中CPU在特定时间内正在处理以及等待处理的进程数之和,通常以三个数值表示1分钟、5分钟和15分钟的平均负载。CPU负载本质上反映了CPU的工作繁忙程度。理想情况下,负载值应小于或等于CPU核心数,以确保系统运行流畅。如果负载值长期高于CPU核心数,可能会导致系统响应变慢,影响性能。

  • 21
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值