公司岗位题库

阿里巴巴 后端开发面经

141 道题 76 个标签 143 条出现记录

后端开发工程师相关题目

netty有哪些组件?

Netty 的组件可以按启动配置、连接抽象、线程模型、事件流转、数据缓冲、编解码、业务处理、异步通知来理解。回答时不应只罗列类名,而要把 ServerBootstrap 启动服务端、EventLoopGroup 分配线程、Channel 承载连接、Pipeline 串联 Handler、ByteBuf 承载数据、Future 返回异步结果这条链路讲清楚。

常见 JVM 垃圾收集器分别适合什么场景?

垃圾回收器适用场景不能只背名称,而要围绕吞吐量、停顿时间、堆大小、对象生命周期、CPU 余量和运行时版本来选择。Serial 适合小堆和低资源环境,Parallel 适合吞吐优先任务,CMS 是旧版本低停顿方案但有碎片和并发失败风险,G1 是较新主流服务端的平衡型选择,ZGC 与 Shenandoah 面向更严苛的低停顿和大堆场景,Epsilon 只适合测试、压测和短生命周期实验。

什么情况服务器会有大量的TIME_WAIT连接?

服务器出现大量 TIME_WAIT,本质上说明这台机器在大量 TCP 连接中充当了主动关闭方,并且连接关闭后需要保留 2MSL 时间以保证最后一个 ACK 可重传、旧报文不会污染后续连接。常见诱因包括短连接比例高、高并发请求快速结束、服务端主动断开 HTTP 连接、未开启或未复用 keep-alive、反向代理到后端使用短连接、客户端或上游连接池配置不合理,以及瞬时流量尖峰。大量 TIME_WAIT 本身不一定是故障,但如果伴随本地端口耗尽、连接建立失败、CPU 软中断升高或 accept/connect 异常,就需要结合业务关闭方向、连接复用、系统参数和网络路径做定位。

进程通信方式分别适合什么场景?

这道题考察的不是背诵 IPC 名词,而是能否根据进程关系、通信方向、数据量、时延、可靠性、同步需求和部署范围选择合适方案。回答时应先按场景分类:父子进程简单字节流用管道,本机无亲缘进程可用 FIFO、消息队列或本地 Socket,高吞吐大块数据用共享内存配合同步原语,事件通知用信号,跨主机通信用网络 Socket,文件或 mmap 适合持久化、低频共享和大文件映射。

JVM 堆内存通常如何分区?

JVM 堆可以从两条线理解:按对象生命周期分为年轻代和老年代,年轻代内部又分 Eden 和两个 Survivor;按具体垃圾收集器实现,传统分代收集器更强调连续代空间,G1、ZGC、Shenandoah 等更强调 region 或分区化管理。回答时要特别说明:元空间和线程栈不属于堆,TLAB 是 Eden 中给线程预分配的私有分配缓冲区,大对象可能直接进入老年代或被特殊 region 管理。

堆上的元素满了会发生什么?

JVM 堆满通常指堆内存中可用于对象分配的空间不足。对象分配失败后,虚拟机会先尝试触发 Young GC 或 Full GC 回收空间;如果回收后仍无法满足分配,或者老年代晋升失败、连续 GC 效率过低,就可能抛出 OutOfMemoryError。回答时要围绕对象分配、GC 尝试、晋升失败、OOM 类型、排查与预防展开,不要误讲成优先队列里的堆元素满了。

数组和链表有什么区别?

数组和链表都是线性表,但底层组织方式不同:数组用连续内存存放元素,链表用离散节点通过引用连接。这个差异决定了数组随机访问快、缓存友好,但插入删除和扩容成本可能高;链表插入删除在已定位节点时很快,但查找慢、缓存局部性差、额外指针开销大。工程上不能只背复杂度,要说明复杂度成立的前提,并结合 Java 的 ArrayList 和 LinkedList 对照。

同题还出现在 1 个公司岗位

红黑树和平衡二叉树的区别?

红黑树和平衡二叉树都是为了避免普通二叉搜索树退化成链表而设计的自平衡二叉搜索树,核心区别在于平衡标准和维护成本。面试中说的平衡二叉树通常特指 AVL 树:它要求每个节点左右子树高度差最多为 1,平衡非常严格,所以查询路径更短;红黑树用颜色规则约束黑色节点数量和红色节点相邻关系,允许一定程度的不完全平衡,因此插入、删除时旋转和调整更少,更适合频繁更新的工程场景。

cpp的虚函数以及实现原理?

虚函数是 C++ 实现运行时多态的核心机制。它允许通过基类指针或引用调用派生类重写后的函数,把调用哪个函数的决定从编译期推迟到运行期。主流编译器通常通过虚函数表和对象中的虚表指针实现:多态类有虚表,对象保存指向虚表的指针,虚调用时先取虚表指针,再按固定槽位找到函数地址并间接调用。

C++多态怎么实现?

C++ 多态本质上是同一接口在不同类型上表现出不同行为。它分为编译期多态和运行期多态:编译期多态由函数重载、运算符重载、模板等在编译阶段完成选择;运行期多态依赖 virtual 虚函数、继承、重写以及基类指针或引用,在程序运行时根据对象真实类型进行动态绑定。回答不能只停留在虚函数表四个字,还要讲清楚触发条件、对象内存模型、构造析构规则、虚析构必要性、对象切片和多继承下的边界问题。

Redis的List底层实现原理?

Redis List 的底层实现经历过从 ziplist 与 linkedlist 的组合,到 quicklist 统一承载的演进。核心目标不是单纯追求某一种操作最快,而是在两端插入删除、内存占用、缓存友好性和中间位置修改之间做平衡。回答时要讲清:List 是有序、可重复、按插入顺序组织的线性结构,适合队列、栈、简单消息流等场景,但索引访问和中间元素定位不是它的强项。

为什么要用redis?

Redis 的核心价值不是更快的数据库,而是把高频、低延迟、可短期容忍一致性差异的数据放到内存侧处理,从而缩短读写链路、削峰填谷、降低关系型数据库压力,并利用丰富数据结构、原子命令、过期机制和高可用能力支撑缓存、计数、排行榜、限流、会话、队列等典型场景。

Redis 缓存淘汰策略有哪些?

这题要先区分两个概念:过期删除是针对设置了 TTL 的键,缓存淘汰是 Redis 在内存达到 maxmemory 限制后,为了腾出空间而选择删除哪些键。回答时不能只背策略名称,还要说明 allkeys 与 volatile 的区别、LRU/LFU/TTL/random/noeviction 的选择逻辑,以及这些策略在读多写多、冷热数据明显、TTL 管理严格等场景下的取舍。

Redis 为什么高可用?

Redis 的高可用不是单一能力,而是复制、故障检测、自动切换、分片容灾、持久化、客户端重连和监控治理共同组成的体系。主从复制提升读扩展和副本冗余,哨兵负责发现主节点故障并自动完成主从切换,Cluster 通过分片和多主多从避免单机容量与单点问题,AOF/RDB 持久化降低进程或机器故障后的数据损失。真正回答这道题时,要同时说明 Redis 能恢复服务、能减少数据丢失,但不能承诺在所有极端场景下零丢失,尤其要讲清复制延迟、脑裂和一致性取舍。

为什么Redis的速度这么快?

Redis 快不是单一原因,而是数据结构、内存访问、事件模型、网络处理和工程取舍共同作用的结果。面试回答时不能只说“因为它是内存数据库”或“因为单线程”,更关键的是说明:绝大多数请求走内存,核心命令复杂度低;单线程事件循环减少锁竞争和上下文切换;I/O 多路复用提升并发连接处理能力;协议和数据结构实现轻量;同时 Redis 也通过持久化、复制、集群等机制在速度与可靠性之间做取舍。

集群环境怎么更新本地缓存?

集群环境更新本地缓存的核心是把进程内缓存视为性能优化层,而不是共享事实源。常见方案是数据库作为最终事实源,Redis 作为跨节点共享缓存,本地缓存作为单机热点加速层;数据变更后通过可靠事件广播删除各实例本地缓存,并用 TTL、版本号和补偿机制兜底。

缓存的 key 是什么?

缓存的 key 不是随手拼接的字符串,而是后端系统把业务对象、查询条件、租户环境、版本语义和一致性边界映射到缓存空间的唯一标识。一个好的缓存 key 需要同时解决可定位、可隔离、可失效、可观测、可扩展和可治理的问题,否则很容易出现串数据、删不准、热点集中、基数爆炸和线上排查困难。

热点数据怎么保证redis和db中的一致?

热点数据的 Redis 与数据库一致性,核心不是追求所有场景下绝对强一致,而是先明确业务可接受的一致性等级,再选择缓存模式、写入顺序、失效策略和补偿机制。高频面试答案应围绕 Cache Aside、先更新数据库再删除缓存、删除失败补偿、TTL 兜底、版本号防乱序、binlog/CDC 异步修复、热点保护与强一致场景降级到串行化读写展开。

redis的gossip机制?

Redis Cluster 的 Gossip 机制是集群节点之间交换状态信息的一套去中心化通信机制。每个节点不依赖中心协调者,而是通过定期向其他节点发送 PING、PONG、MEET 等消息,携带自己已知的节点元数据、槽位信息、配置纪元和故障判断结果,使整个集群逐步达成状态收敛,并用于节点发现、拓扑维护、故障疑似与故障确认。

Redis解决了什么问题?

Redis 本质上解决的是把需要极低延迟、高并发访问、临时状态管理和轻量计算的数据,从慢路径中抽出来的问题。它不是关系型数据库的替代品,而是用内存读写、丰富数据结构、过期机制、原子操作、持久化和集群能力,帮助系统降低数据库压力、提升响应速度、承载热点流量,并处理计数、排行榜、会话、限流、分布式锁等高频场景。

Redis的过期策略?

Redis 的过期策略本质上是在性能、内存回收及时性和主线程延迟之间做平衡:它不会为每个带 TTL 的键单独启动定时器,而是通过 TTL 元数据记录过期时间,再结合访问时惰性删除和后台周期性主动抽样删除来清理过期键。回答时要区分过期删除与内存淘汰,并补充持久化、复制、过期风暴和热 Key 场景下的工程治理。

说一下数据库底层数据结构B+数据,为什么用,与二叉平衡树区别 Redis怎么用的?

数据库索引常用 B+ 树,核心原因不是“查找复杂度看起来是 O(log n)”,而是它非常适合磁盘和页式存储:节点扇出高,树高低,单次查询需要的页访问次数少;叶子节点按键有序并通过链表连接,范围查询、排序扫描、分页扫描都很高效。二叉平衡树如 AVL、红黑树更适合内存中的动态查找结构,节点扇出低、树高大、局部性差,如果直接用于磁盘索引会产生大量随机 I/O。

还知道哪些缓存中间件?

缓存中间件不只有 Redis。可以按部署位置和能力分为远程内存缓存、进程内本地缓存、分布式缓存、CDN/HTTP 缓存、数据库内部缓存,以及用于削峰和结果复用的消息缓存、结果缓存。回答这题的关键不是罗列产品名,而是说明 Redis、Memcached、Caffeine、Ehcache、Hazelcast、Ignite、CDN、数据库 Buffer Pool 等分别解决什么问题,以及选型时如何比较数据结构、持久化、一致性、延迟和运维复杂度。

过去经历中怎么应对高并发或高性能场景的?

高并发或高性能场景不是考单点技术名词,而是考候选人能否把真实工程问题讲成闭环:先明确业务目标和容量指标,再通过压测和可观测性找到瓶颈,随后从流量、应用、缓存、队列、数据库、线程池、连接池、锁竞争、水平扩展和稳定性预案等层面治理,最后用结果指标证明方案有效。

锁的实现原理是什么?

锁的实现原理可以概括为:用一个可被原子修改的状态表示锁是否被占用,用所有者信息判断谁持有锁,用等待队列管理竞争失败的线程,用阻塞与唤醒降低空转成本,并通过内存屏障建立临界区内外的可见性与有序性保证。理解锁不能只停留在“加锁和解锁”两个动作,而要能讲清互斥、状态变更、线程挂起、唤醒、公平性、重入、超时、中断和竞争优化之间的关系。

可重入锁的原理?

可重入锁的核心原理是:锁不仅记录有没有被占用,还记录被哪个线程占用以及同一线程重复进入了多少次。当持有锁的线程再次请求同一把锁时,不会被自己阻塞,而是把重入计数加一;退出时计数减一,只有计数归零才真正释放锁并唤醒后续等待线程。Java 中 synchronized 和 ReentrantLock 都支持可重入,但实现层次不同:synchronized 由 JVM 管理监视器和锁记录,ReentrantLock 主要基于 AQS 的 state、独占线程 owner、等待队列、CAS 和 park/unpark 实现。

分布式锁的使用场景?

分布式锁用于解决多个进程、多个实例、多个节点同时争抢同一份业务资源时的互斥问题,典型场景包括库存扣减、定时任务去重、幂等控制和资源抢占。面试回答不能只说“防止并发”,还要讲清锁的粒度、过期时间、唯一 token、续期、释放校验、可重入、公平性,以及 Redis、ZooKeeper、数据库方案在性能、一致性和故障边界上的取舍。

线程锁锁的到底是什么?

线程锁并不是把某个线程本身锁住,也不是直接把一段代码或一个变量物理锁住。更准确地说,锁是一种同步协议:它通过某个可竞争的同步状态,约束多个线程进入临界区的顺序,从而保护共享资源及其不变量。Java 中 synchronized 竞争的是对象监视器或类对象监视器,ReentrantLock 竞争的是基于 AQS 维护的同步状态;操作系统层面的 mutex、semaphore 等竞争的是内核或用户态维护的同步状态。