写点什么

金三银四快过去一半了,是时候加把劲了

作者:王中阳Go
  • 2025-03-20
    北京
  • 本文字数:4313 字

    阅读完需:约 14 分钟

金三银四快过去一半了,是时候加把劲了

从复旦春招会的 15000+岗位争夺战,到 AI 算法岗年薪百万的“神仙打架”,再到游戏行业 20:1 的残酷竞争比,今年的金三银四像极了《三体》里的黑暗森林:机会看似遍地,但稍有不慎就成了别人的“背景板”


但现实真的是“投晚了就凉了”吗?数据告诉你真相:智联研究院统计显示,算法工程师、机器人算法工程师等岗位需求同比激增 44%,而中小企业的“捡漏窗口”才刚开启。


这半个月,我整理了 20+场面试实录(含小鹅通、万兴等热门公司),发现那些“面着面着就上岸”的人,早就不靠海投简历,而是用「反直觉策略」精准破局——比如把 JD 里的“精通 SpringCloud”翻译成“如何用分布式事务帮老板少赔 200 万”。


今天我就给大家分享一下我整理的小鹅通的面经,感兴趣的朋友接着往下看看吧。



1、自我解释以及问项目

2、Go 特点 怎么做到高并发

答案

Go 语言在实现高并发方面具有独特的特点和机制:


  • 轻量级协程(goroutine):goroutine 是 Go 语言实现高并发的核心。与传统线程相比,goroutine 的开销非常小,一个 goroutine 只需要几 KB 的栈空间,而线程需要几 MB。这使得在 Go 程序中可以轻松创建成千上万个 goroutine,例如在一个 Web 服务器中,可以为每个客户端请求创建一个 goroutine 来处理,而不会像传统线程那样因为资源消耗过大而导致系统崩溃。

  • 高效的调度器:Go 语言的调度器(GPM 模型)可以高效地管理和调度 goroutine。G 代表 goroutine,P 代表处理器(逻辑处理器),M 代表操作系统线程。调度器会根据系统的负载情况,将多个 goroutine 合理地分配到不同的 M 上执行,并且可以在 M 之间动态地迁移 goroutine,从而充分利用多核 CPU 的性能。

  • 通信顺序进程(CSP)模型:Go 语言提倡通过通信来共享内存,而不是通过共享内存来通信。通过 channel(通道)可以实现 goroutine 之间的安全数据传输和同步。例如,一个生产者 goroutine 可以将数据发送到 channel 中,另一个消费者 goroutine 可以从 channel 中接收数据,这种方式避免了传统多线程编程中复杂的锁机制,提高了并发编程的效率和安全性。

3、对比 go 的协程和正常线程的区别

答案

Go 的协程(goroutine)和正常线程有较大区别:


  • 内存开销:线程的栈空间通常在几 MB,而 goroutine 的栈空间初始时只需几 KB,并且可以根据需要动态增长和收缩。这使得在相同的内存资源下,Go 程序可以创建更多的 goroutine。

  • 调度方式:线程由操作系统内核调度,调度过程涉及用户态和内核态的切换,开销较大。而 goroutine 由 Go 语言的运行时(runtime)进行调度,是用户级线程,调度在用户态完成,切换速度快。

  • 创建和销毁开销:创建和销毁线程的开销较大,涉及到内核资源的分配和释放。而 goroutine 的创建和销毁由 Go 运行时管理,开销较小。

  • 并发性能:由于线程的调度开销大,在高并发场景下,大量线程会导致系统性能下降。而 goroutine 可以轻松创建成千上万个,在高并发场景下表现出色。

4、每秒产生一万条数据,每条数据处理大概要 0.1 秒,如何处理

答案

对于每秒产生一万条数据,每条数据处理约需 0.1 秒的场景,可以采用以下几种方式:


  • 多个 goroutine 并行处理:使用 Go 语言的 goroutine 可以高效地并行处理数据。可以创建多个 goroutine,每个 goroutine 负责处理一部分数据。例如,可以将一万条数据平均分配给多个 goroutine,每个 goroutine 处理一部分数据,利用多核 CPU 的性能提高处理速度。

  • 多主机分布式处理:如果单机的处理能力无法满足需求,可以使用多个主机进行分布式处理。每个主机负责处理部分数据,通过网络通信将数据分发到不同的主机上进行处理。这样可以充分利用多个主机的计算资源,提高整体处理能力。

5、100 个机器消费 Redis 列表数据的相关问题

答案

  • 消费 Redis 列表数据是否有问题:一般情况下,100 个机器同时消费 Redis 列表数据可能会存在一些问题。例如,多个机器同时从 Redis 列表中获取数据时,可能会出现竞争问题,导致部分数据被重复消费或丢失。可以通过 Redis 的原子操作(如 LPOP)来保证数据的一致性。

  • 处理消息时机器挂了,丢的消息怎么办:可以让发送端重发消息,但如果所有机器都挂了,这种方法就不可行。可以使用一个 Redis 的列表做辅助记录,记录已经处理和正在处理的消息。由于 Redis 具有持久化机制,即使机器重启,记录也不会丢失。

  • 怎么知道哪个消息挂了:使用一个 Redis 的列表做辅助记录,记录每个消息的处理状态。例如,可以在消息被取出处理时,将消息的 ID 记录到辅助列表中,处理完成后再从辅助列表中删除该记录。这样,在机器重启后,通过检查辅助列表就可以知道哪些消息没有处理完成。

  • 消息顺序怎么保证:可以为每个消息分配一个序号,消费者按照序号顺序处理消息。但在分布式环境下,由于网络延迟等原因,可能会出现消息乱序的情况。可以在消费者端使用一个缓冲区,将消息按照序号排序后再进行处理。

  • Redis 正在处理数据,重启后数据丢失怎么办:可以在数据库中做一个记录,记录每个消息的处理状态。在 Redis 重启后,从数据库中获取未处理的消息,重新进行处理。同时,需要根据具体的业务需求,检查对处理速度的要求。

6、对数据库了解多少

答案

数据库是用于存储、管理和检索数据的软件系统。常见的数据库类型包括关系型数据库(如 MySQL、Oracle)和非关系型数据库(如 MongoDB、Redis)。


  • 关系型数据库:基于关系模型,使用表来组织数据,表与表之间可以通过关联关系进行连接。具有严格的表结构和数据类型,支持 SQL 语言进行数据操作,适用于对数据一致性和完整性要求较高的场景。

  • 非关系型数据库:不遵循传统的关系模型,数据存储方式更加灵活,如键值对、文档、图形等。具有高可扩展性和高性能,适用于对数据读写速度要求较高、数据结构变化频繁的场景。

7、mysql 的事务怎么实现的

答案

MySQL 的事务通过一系列机制来实现其四个特性(ACID):


  • 原子性(Atomicity):通过日志(如 redo log 和 undo log)来实现。redo log 用于在事务提交后,将未写入磁盘的数据持久化到磁盘,保证事务的持久性。undo log 用于在事务回滚时,将数据恢复到事务开始前的状态,保证事务的原子性。

  • 一致性(Consistency):通过数据库的约束(如主键约束、外键约束)和事务的隔离级别来保证。事务的执行必须使数据库从一个一致的状态转换到另一个一致的状态。

  • 隔离性(Isolation):通过多版本并发控制(MVCC)和锁机制来实现。MVCC 允许事务在不同的版本上进行操作,避免了读写冲突。锁机制用于控制对数据的并发访问,保证事务之间的隔离性。

  • 持久性(Durability):通过 redo log 和磁盘的持久化存储来保证。当事务提交时,redo log 会将事务的操作记录到磁盘上,即使数据库崩溃,也可以通过 redo log 将未持久化的数据恢复到磁盘上。

8、你觉得 mysql 实现这些事务复杂吗

答案

MySQL 实现事务的机制相对复杂。从技术实现角度来看,涉及到日志系统(redo log、undo log)、多版本并发控制(MVCC)、锁机制等多个方面。这些机制相互配合,以确保事务的 ACID 特性。例如,在实现原子性时,需要通过 undo log 记录事务的反向操作,以便在事务回滚时能够恢复数据;在实现隔离性时,需要根据不同的隔离级别使用不同的锁策略和 MVCC 机制。


虽然事务机制对于保证数据的一致性和完整性是必要的,但对于开发者来说,理解和正确使用这些机制需要一定的学习成本。不过,MySQL 将这些复杂的实现细节封装起来,开发者只需要使用简单的 SQL 语句(如 BEGIN、COMMIT、ROLLBACK)就可以进行事务操作,从这个角度看,使用事务相对简单。

9、慢 sql 遇到过吗,追问 select*为什么最好不用,和走不走索引有关系吗

答案

  • 慢 SQL:在实际开发中,慢 SQL 是比较常见的问题。慢 SQL 指的是执行时间较长的 SQL 语句,可能会影响系统的性能。常见的慢 SQL 原因包括查询语句复杂、缺少索引、数据量过大等。

  • select*为什么最好不用:使用 select 会查询表中的所有列,可能会导致不必要的数据传输和处理。例如,在一个包含大量列的表中,如果只需要部分列的数据,使用 select 会将所有列的数据都查询出来,增加了数据库的负担和网络传输的开销。

  • 与走不走索引的关系:使用 select 可能会影响索引的使用。如果查询语句中只包含索引列,数据库可以直接通过索引获取数据,而不需要访问表的数据行,这种方式称为索引覆盖。但如果使用 select,可能会导致数据库无法使用索引覆盖,需要访问表的数据行,从而降低查询性能。

10、问 explain,慢查询日志

答案

  • EXPLAIN:EXPLAIN 是 MySQL 提供的一个用于分析 SQL 语句执行计划的工具。通过在 SQL 语句前加上 EXPLAIN 关键字,可以查看数据库是如何执行该 SQL 语句的,包括使用的索引、表的连接顺序、扫描的行数等信息。例如,EXPLAIN SELECT * FROM users WHERE age > 20; 可以帮助开发者了解该查询语句的执行过程,从而优化查询性能。

  • 慢查询日志:慢查询日志是 MySQL 提供的一种日志记录机制,用于记录执行时间超过指定阈值的 SQL 语句。通过开启慢查询日志,可以找出执行时间较长的 SQL 语句,进行优化。可以通过设置long_query_time参数来指定慢查询的时间阈值,例如:SET GLOBAL long_query_time = 1; 表示将慢查询的时间阈值设置为 1 秒。

11、什么情况走索引什么情况不走

答案

  • 走索引的情况

  • 等值查询:当查询条件是等值比较(如WHERE column = value)时,数据库通常会使用索引。

  • 范围查询:在范围查询(如WHERE column BETWEEN value1 AND value2)中,如果该列上有索引,数据库也会使用索引。

  • 排序:如果查询语句中有ORDER BY子句,且排序的列上有索引,数据库可以利用索引进行排序,提高排序效率。

  • 不走索引的情况

  • 函数操作:如果查询条件中对索引列使用了函数(如WHERE UPPER(column) = 'VALUE'),数据库通常不会使用索引。

  • 模糊查询:当使用LIKE进行模糊查询,且通配符在开头(如WHERE column LIKE '%value')时,数据库可能不会使用索引。

  • 类型不匹配:如果查询条件中的数据类型与索引列的数据类型不匹配,数据库可能不会使用索引。

12、联合索引,为什么要求前缀匹配

答案

联合索引是指在多个列上创建的索引。要求前缀匹配是因为联合索引的存储结构是按照索引列的顺序进行排序的。例如,在列(A, B, C)上创建的联合索引,索引首先按照列 A 的值进行排序,在 A 值相同的情况下,再按照列 B 的值进行排序,以此类推。


当查询条件满足前缀匹配时,数据库可以利用索引的有序性快速定位到符合条件的数据。例如,对于查询WHERE A = value1 AND B = value2,数据库可以根据联合索引先找到 A 等于 value1 的所有记录,然后在这些记录中再找到 B 等于 value2 的记录。


如果查询条件不满足前缀匹配,例如WHERE B = value2,数据库无法直接利用联合索引的有序性进行快速定位,可能需要扫描整个索引,甚至全表扫描,从而降低查询性能。

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。


没准能让你能刷到自己意向公司的最新面试题呢。


感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:infoq 面试群。

发布于: 刚刚阅读数: 4
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论 (1 条评论)

发布
用户头像
需要简历优化&就业辅导的朋友,可以直接加我微信:wangzhongyang1993
刚刚 · 北京
回复
没有更多了
金三银四快过去一半了,是时候加把劲了_Go_王中阳Go_InfoQ写作社区