继续分享最新的面经,前面发的两篇大家也可以看看:
今天分享的是golang开发岗面经,要求是3年以上golang开发经验,薪资为15~30K,整体面下来的感受就是,面的比较广,细节拷打不多,来看看难度如何:
面试题详解
1. GMP调度
GMP调度模型是Go语言运行时的核心调度机制,用于实现高效的并发执行。G代表Goroutine(协程),M代表Machine(操作系统线程),P代表Processor(处理器)。
- Goroutine 是用户态的轻量级线程,由Go运行时管理,创建和销毁成本低。
- Machine 是操作系统线程,负责真正执行代码,每个M可以绑定一个或多个G。
- Processor 是逻辑处理器,用于分配任务给M,并维护本地队列中的G。
调度过程:
- 每个P维护一个本地队列,存放待执行的G。如果本地队列为空,会从全局队列或其他P的队列中偷取任务(Work Stealing)。
- 当一个G阻塞时(如I/O操作),M会释放当前P并寻找其他可执行的G,从而避免浪费资源。
- 如果所有M都在忙,而有新的G需要执行,运行时会动态创建新的M来满足需求。
这种调度方式的优点是高效利用多核CPU,减少了上下文切换的开销,同时支持大量并发任务。
2. 协作式调度和抢占式调度有什么区别
协作式调度 和 抢占式调度 是两种不同的任务调度方式,主要区别在于任务的执行控制权归属:
协作式调度:
- 任务主动让出CPU,只有当前任务完成或显式调用让出函数时,调度器才能切换到其他任务。
- 缺点是如果某个任务长时间占用CPU而不让出,会导致其他任务“饿死”。
- 优点是实现简单,上下文切换开销小,适合任务间信任度高的场景。
抢占式调度:
- 调度器通过定时器中断等方式强制剥夺当前任务的CPU使用权,确保公平性。
- 优点是可以防止某个任务独占CPU,保证系统的响应性和公平性。
- 缺点是上下文切换频繁可能导致性能开销增大。
在现代操作系统中,抢占式调度更为常见,因为它能更好地应对复杂任务环境。而协作式调度更多用于嵌入式系统或特定领域。
3. 垃圾回收讲一下,三色标记和混合写屏障
垃圾回收(GC)是一种自动内存管理机制,用于回收不再使用的对象,避免内存泄漏。常见的GC算法包括引用计数、标记清除、分代回收等。
三色标记 是一种经典的GC算法,其核心思想是将对象分为三种状态:
- 白色:尚未被访问的对象,表示可能需要回收。
- 灰色:已被访问但其引用的对象尚未完全扫描,表示正在处理中。
- 黑色:已被访问且其引用的对象也已扫描完毕,表示安全存活。
GC过程:
- 初始时,所有对象为白色。
- 从根对象(如全局变量、栈变量)开始,将可达对象标记为灰色。
- 不断从灰色对象集合中取出对象,将其引用的对象标记为灰色,自身标记为黑色。
- 当灰色集合为空时,剩余的白色对象即为不可达对象,可被回收。
混合写屏障 是一种优化技术,用于解决三色标记中的并发问题。当GC与程序并发运行时,可能会出现新引用导致对象状态不一致的情况。混合写屏障通过记录修改过的引用,确保GC能够正确识别对象状态,从而提高效率和安全性。
4. 事务执行中,mysql如果宕机了,重新恢复会发生什么?
MySQL使用事务日志(Redo Log和Undo Log)来保证数据一致性。如果在事务执行过程中发生宕机,重启后会通过以下步骤恢复:
- 检查Redo Log:Redo Log记录了事务对数据页的物理修改,即使事务未提交,修改也会先写入日志。重启后,MySQL会重放Redo Log,将未持久化的修改应用到数据页上。
- 检查Undo Log:Undo Log记录了事务的回滚信息。对于未提交的事务,MySQL会使用Undo Log撤销已完成的部分操作,确保事务原子性。
- 崩溃恢复:MySQL的InnoDB引擎会在启动时执行崩溃恢复流程,将未完成的事务标记为回滚状态,并清理相关的日志文件。
通过这种方式,MySQL能够在宕机后恢复到一致状态,保证事务的ACID特性。
5. 讲一下两阶段提交的过程,两阶段提交解决什么问题?
两阶段提交(2PC, Two-Phase Commit)是一种分布式事务协议,用于协调多个节点之间的事务提交,确保分布式系统中的一致性。
过程:
准备阶段:
- 协调者向所有参与者发送Prepare请求,询问是否可以提交事务。
- 参与者执行事务操作,并将结果写入日志,然后回复Yes或No。
提交阶段:
- 如果所有参与者都回复Yes,协调者发送Commit请求,参与者正式提交事务。
- 如果有任何参与者回复No,协调者发送Abort请求,参与者回滚事务。
解决的问题:
- 2PC解决了分布式系统中事务的原子性问题,即要么所有节点都提交事务,要么全部回滚。
- 它适用于强一致性要求的场景,但存在单点故障(协调者故障)和性能瓶颈等问题。
6. 讲一下MVCC,它解决了幻读问题吗?
MVCC(多版本并发控制)是一种数据库并发控制机制,通过保存数据的多个版本来实现高并发读写。
原理:
- 每次更新数据时,都会生成一个新的版本,旧版本保留供读取。
- 读操作只访问符合当前事务隔离级别的版本,避免了读写冲突。
解决的问题:
- MVCC有效解决了读写冲突问题,提高了并发性能。
- 在可重复读(Repeatable Read)隔离级别下,MVCC通过版本控制避免了不可重复读问题。
- 对于幻读问题,MVCC在某些情况下可以通过间隙锁(Gap Lock)结合版本控制部分解决,但在串行化(Serializable)级别下,仍需依赖锁机制来完全避免幻读。
7. redis的跳表了解吗?
跳表(Skip List)是一种基于链表的数据结构,通过多层索引加速查找操作,时间复杂度接近O(log n)。
Redis中的跳表主要用于实现有序集合(Sorted Set)。
- 跳表的每一层是一个有序链表,越高层的链表包含的节点越少。
- 查找时从最高层开始,快速缩小范围,然后逐层向下定位目标节点。
- 插入和删除操作也通过多层索引进行维护,保证整体效率。
跳表的优点是实现简单,性能稳定,适合Redis这种高性能场景。
8. Redis大key会有什么问题?怎么解决?
问题:
- 大key指的是存储大量数据的单个键,可能导致Redis性能下降。
- 内存占用过高,增加GC压力,甚至引发OOM(内存溢出)。
- 操作大key可能导致阻塞,影响其他请求的响应时间。
解决方案:
- 拆分大key:将大key拆分为多个小key,分散存储。
- 使用合适的数据结构:例如,将Hash、List等结构改为分片存储。
- 渐进式删除:通过脚本逐步删除大key,避免一次性操作引发阻塞。
- 监控和优化:定期分析Redis内存使用情况,及时发现和处理大key。
9. kafka如何解决消息有序问题?
Kafka通过分区(Partition)机制保证消息的有序性。
- 每个分区内的消息是严格有序的,按照写入顺序存储和消费。
- 生产者可以指定消息的分区键(Key),相同Key的消息会被路由到同一分区,从而保证局部有序。
消费者组内的消费者按分区消费,每个分区只能被一个消费者消费,进一步确保顺序性。
需要注意的是,跨分区的消息无法保证全局有序,若需要全局有序,需将所有消息写入同一个分区。
10. 如何保障kafka消息不丢失?
保障Kafka消息不丢失需要从生产者、Broker和消费者三个层面入手:
生产者:
- 设置acks=all,确保消息写入所有副本后才返回成功。
- 启用重试机制,处理网络异常等情况。
Broker:
- 配置副本数大于1,启用ISR(同步副本集)机制,确保数据冗余。
- 定期备份数据,防止磁盘损坏导致丢失。
消费者:
- 手动提交偏移量,在业务逻辑处理完成后提交,避免重复消费或丢失。
- 设置合理的消费超时时间,防止消费者挂起导致消息堆积。
通过以上措施,可以在绝大多数情况下保障消息不丢失。
11. 链上操作了解吗?
链上操作通常指区块链上的交易或智能合约执行。
- 交易:用户发起的操作,如转账、调用智能合约等,需要经过共识机制验证后写入区块链。
- 智能合约:部署在链上的代码,通过交易触发执行,具有自动化和不可篡改的特性。
链上操作的特点:
- 透明性:所有操作记录公开可查。
- 不可篡改:一旦写入区块链,无法修改。
- 去中心化:无需信任第三方,由共识机制保证安全。
链上操作的挑战包括性能瓶颈、Gas费用高昂等问题,因此在实际应用中需权衡成本与效率。
欢迎关注 ❤
我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。
没准能让你能刷到自己意向公司的最新面试题呢。
感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:面试群。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。