• 正文
  • 相关推荐
申请入驻 产业图谱

阿里巴巴今年要招 7000人,开冲!

08/10 20:00
609
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是小林。

等了很久,刚看到阿里巴巴集团 26 届校招也正式启动了,这下感觉互联网一线大厂比如腾讯、字节、百度、美团、京东等等都已经全面进入秋招了。

这次阿里计划招 7000+ 人,感觉规模也是很庞大的,其中 AI 岗位占比超 6 成,而且部份业务占比还会更高,足以见得,阿里有很多想基于 AI 去做的新业务,所以加大了招聘规模。

之前有训练营同学去了阿里,面试问的是Java技术栈,然后进去是做 agent 平台的开发,这个就属于AI相关岗位了,这种岗位通常就是Java+AI技术,也就是基于大模型的接口或者框架来做后台相关的业务,Web服务这些还是Java后端这一套逻辑。

阿里巴巴的集团有点多,但是各个集团的薪资大差不差,所以这里以淘天 25届校招的薪资,作为例子供大家参考:

阿里巴巴除了房补之外,还有一些额外的小福利,比如交通费 800元/月,搬家费 6k(一次性),而且如果是入职杭州的阿里巴巴,还享受杭州市人才补贴等等。

这次就来看看阿里巴巴的Java面经,这是电话一面,全程都是电话沟通,所以都是问技术问题,算法的话就没有考察,技术方面主要考虑了MySQL、MongoDB、Java、MQ方面的内容。

阿里巴巴(电话一面)

1. mysql的索引数据结构是怎样的?

MySQL InnoDB 引擎是用了B+树作为了索引的数据结构。

B+Tree 是一种多叉树,叶子节点才存放数据,非叶子节点只存放索引,而且每个节点里的数据是按主键顺序存放的。每一层父节点的索引值都会出现在下层子节点的索引值中,因此在叶子节点中,包括了所有的索引值信息,并且每一个叶子节点都有两个指针,分别指向下一个叶子节点和上一个叶子节点,形成一个双向链表。

主键索引的 B+Tree 如图所示:

比如,我们执行了下面这条查询语句:

select?*?from?product?where?id=?5;

这条语句使用了主键索引查询 id 号为 5 的商品。查询过程是这样的,B+Tree 会自顶向下逐层进行查找:

    将 5 与根节点的索引数据 (1,10,20) 比较,5 在 1 和 10 之间,所以根据 B+Tree的搜索逻辑,找到第二层的索引数据 (1,4,7);在第二层的索引数据 (1,4,7)中进行查找,因为 5 在 4 和 7 之间,所以找到第三层的索引数据(4,5,6);在叶子节点的索引数据(4,5,6)中进行查找,然后我们找到了索引值为 5 的行数据。

数据库的索引和数据都是存储在硬盘的,我们可以把读取一个节点当作一次磁盘 I/O 操作。那么上面的整个查询过程一共经历了 3 个节点,也就是进行了 3 次 I/O 操作。

B+Tree 存储千万级的数据只需要 3-4 层高度就可以满足,这意味着从千万级的表查询目标数据最多需要 3-4 次磁盘 I/O,所以B+Tree 相比于 B 树和二叉树来说,最大的优势在于查询效率很高,因为即使在数据量很大的情况,查询一个数据的磁盘 I/O 依然维持在 3-4次。

2. mysql B树和B+树比较和区别是什么?

B 树和 B+ 都是通过多叉树的方式,会将树的高度变矮,所以这两个数据结构非常适合检索存于磁盘中的数据。

但是 MySQL 默认的存储引擎 InnoDB 采用的是 B+ 作为索引的数据结构,原因有:

    B+ 树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存索引又存记录的 B 树,B+树的非叶子节点可以存放更多的索引,因此 B+ 树可以比 B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。B+ 树有大量的冗余节点(所有非叶子节点都是冗余索引),这些冗余索引让 B+ 树在插入、删除的效率都更高,比如删除根节点的时候,不会像 B 树那样会发生复杂的树的变化;B+ 树叶子节点之间用链表连接了起来,有利于范围查询,而 B 树要实现范围查询,因此只能通过树的遍历来完成范围查询,这会涉及多个节点的磁盘 I/O 操作,范围查询效率不如 B+ 树。

3. mysql ?like索引失效场景是哪种情况?

当查询条件为?LIKE '%xxx'?或?LIKE '%xxx%'?时,索引通常会失效。例如:SELECT * FROM table WHERE name LIKE '%张三'

原因是索引的匹配是从左到右进行的,开头的?%?会导致无法利用索引的有序性快速定位。

4. mongoDb和mysql的区别是什么?

MongoDB 和 MySQL 的核心区别体现在数据模型和适用场景上。

    MySQL 是关系型数据库,采用固定表结构,数据按行列存储,表间通过外键关联,适合结构化数据和强事务需求,比如金融交易系统。它使用 SQL 查询,支持复杂的多表关联操作,事务 ACID 特性完善,但水平扩展相对复杂。MongoDB 属于文档型 NoSQL 数据库,用 BSON 格式存储文档,结构灵活无需预定义,适合非结构化或半结构化数据,比如社交平台的用户动态。它通过类 JSON 语法查询,支持嵌套文档和数组,原生支持分片集群,水平扩展能力强,不过事务支持虽在提升,但复杂场景下仍不如 MySQL 成熟

实际应用中,常根据数据特性结合使用两者。

5. ThreadLocal的结构是怎样的?

ThreadLocal 是 Java 中用于线程本地存储的工具类,其结构设计围绕 “线程私有” 特性展开。

从整体看,ThreadLocal 本身不存储数据,而是作为访问线程内部数据的桥梁。每个 Thread 类内部有一个 ThreadLocalMap 类型的成员变量 threadLocals,这是真正存储线程本地数据的容器。

ThreadLocalMap 是 ThreadLocal 的静态内部类,采用数组实现哈希表结构,数组元素为 Entry 对象。Entry 继承自 WeakReference<ThreadLocal<?>>,以 ThreadLocal 实例为键(弱引用),以线程私有数据为值,这样设计可避免 ThreadLocal 实例长期未使用时的内存泄漏

当通过 ThreadLocal 的 get () 方法获取数据时,会先获取当前线程,再得到线程的 ThreadLocalMap,最后以当前 ThreadLocal 实例为键从 map 中获取对应值;set () 方法则是将数据存入当前线程的 ThreadLocalMap 中。这种结构确保每个线程只能访问自己的本地数据,实现线程隔离。

6. HashMap结构是什么?

在 JDK 1.7 版本之前, HashMap 数据结构是数组和链表,HashMap通过哈希算法将元素的键(Key)映射到数组中的槽位(Bucket)。如果多个键映射到同一个槽位,它们会以链表的形式存储在同一个槽位上,因为链表的查询时间是O(n),所以冲突很严重,一个索引上的链表非常长,效率就很低了。所以在?JDK 1.8?版本的时候做了优化,当一个链表的长度超过8的时候就转换数据结构,不再使用链表存储,而是使用红黑树,查找时使用红黑树,时间复杂度O(log n),可以提高查询性能,但是在数量较少时,即数量小于6时,会将红黑树转换回链表。

7. MQ如何保证不重复消费?

MQ 保证不重复消费的核心是实现幂等性消费,即确保同一条消息被多次消费时,结果与消费一次完全一致。主要通过以下机制实现:

首先是生产端去重,通过消息唯一标识(如业务 ID + 时间戳),结合 MQ 的消息去重机制(如 Kafka 的 Producer ID + 序列号,RabbitMQ 的消息 ID),避免重复发送。

消费端是关键,需为每条消息生成唯一 ID(如消息 ID 或业务唯一键),消费前先查询存储系统(如 Redis、数据库)判断是否已处理:若未处理,执行业务逻辑并记录 ID;若已处理,直接返回成功。

此外,MQ 自身可通过确认机制(如 RabbitMQ 的 ACK、Kafka 的 offset 提交)确保消息被正确处理后再标记为已消费,避免因消费端异常导致的重复投递。结合业务场景设计幂等逻辑(如数据库唯一约束、乐观锁),可彻底解决重复消费问题。

8. MQ的ACK确认机制工作原理是什么?

MQ 的 ACK制是保障消息可靠传递的核心机制,其核心原理是:消费端处理完消息后,向 MQ 服务器发送 “确认信号”,MQ 收到信号后才将消息标记为 “已消费” 并移除,否则会重新投递消息,避免因消费端异常(如崩溃、网络中断)导致消息丢失。

不同 MQ 的 ACK 机制实现细节略有差异,但核心逻辑一致:

消息投递与暂存

    • :MQ 服务器将消息投递给消费端后,不会立即删除消息,而是暂存在队列中(标记为 “未确认” 状态),等待消费端的 ACK 信号。此时消息仍会被监控,若长时间未收到 ACK,会触发重试逻辑。

消费端处理与确认

    • :消费端接收到消息后,根据配置的 ACK 模式(自动 / 手动)处理:

自动 ACK

    • :消费端接收到消息即自动发送 ACK(如 RabbitMQ 的 autoAck=true),适用于无需复杂处理的场景,但可能因 “未实际处理完成就确认” 导致消息丢失。

手动 ACK

    • :消费端处理完业务逻辑(如数据库操作成功、缓存更新完成)后,主动调用 API 发送 ACK(如 RabbitMQ 的 channel.basicAck ()、Kafka 的 commitSync ()),确保业务处理成功后再确认,更安全但需手动控制。

未确认消息的重试

    :若消费端未发送 ACK(如崩溃、网络中断),MQ 服务器会在超时后将消息重新放入队列,再次投递给其他消费端(或原消费端恢复后),直到收到 ACK 或达到最大重试次数(可配置,超过后可能进入死信队列)。

以 RabbitMQ 为例,其 ACK 机制通过 channel传递:消费端注册消费者时指定 autoAck 参数,手动模式下需调用 basicAck,其中 deliveryTag 是消息唯一标识,multiple 表示是否确认该标识之前的所有消息;若处理失败,可调用 basicNack () 拒绝并指定是否重新投递。

Kafka 则通过 offset 实现类似逻辑:消费端处理完消息后提交 offset,MQ 记录最新 offset,下次从该位置开始消费;若未提交,重启后会从上次提交的 offset 重新消费,本质是通过 offset 提交实现 “确认已消费” 的标记。

相关推荐