从复旦春招会的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,备注:sf面试群。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。