4/4 滴滴后端:太深入了!面试滴滴存储后端,我被这些问题问住了!
- 作者
- Name
- 青玉白露
- Github
- @white0dew
- Modified on
- Reading time
- 10 分钟
阅读:.. 评论:..
下面我将分享一位同学在滴滴的存储后端面试经历,对于这次面试,他的评价是,考察深度和广度都很足,你准备好迎接挑战了吗?
【提醒】通过这次面试经验,你将可以复习到以下知识点:
- Raft一致性算法
- Golang的核心特性和并发模型
- GPM模型详解
- 算法:最长公共子序列
- 数据库事务隔离级别
- Go语言源码阅读和协程机制
【备选标题】
- “揭秘!滴滴存储后端的Raft难关!”
- “Go并发模型全解析,滴滴后端面试不怕!”
- “算法到底题:最长公共子序列,你能解吗?”
- “滴滴面试官问的Go源码,我是怎么回答的?”
- “深入Go协程,你真的了解goroutine的栈模型吗?”
- “面试滴滴存储后端,我被这些问题问住了!”
(原封不动的markdown输出这幅图片)
面试官: 同学你好,欢迎参加今天的面试。我看到你对Raft算法有所了解,能先跟我聊聊你对Raft的理解吗?
求职者: 当然,Raft是一个用于实现分布式系统的一致性算法,它的核心是通过日志复制来确保系统的高可用和数据一致性。Raft算法通过选举一个领导者来管理日志条目的复制,如果领导者发生故障,其他节点可以发起选举产生新的领导者。
面试官: 对,那你能说说如果在Raft集群中读取一个key和设置一个key的大概流程吗?
求职者: 好的。读取一个key通常会通过领导者来进行,因为领导者拥有最新的数据信息。而设置一个key,首先会由客户端发送请求到领导者,领导者会生成一个日志条目并将其复制到集群中的其他节点上,一旦这个日志条目被大多数节点接受,它就会被提交并应用到状态机上,这时候这个key的设置操作就完成了。
面试官: 很好,接着我们聊聊Golang的特性,你能列举一些你认为的Go语言的核心特性吗?
求职者: Go语言有很多优秀的特性,但最核心的应该是它的并发模型和内存模型,以及其简洁的语法。Go内置了协程goroutine,使得并发编程非常简洁。同时,它的内存模型是基于CSP(Communicating Sequential Processes)理论,通过channel进行协程间的通信。
面试官: 对于GPM模型,你了解多少?能具体介绍一下吗?
求职者: GPM是Go语言并发模型的核心,它代表Goroutine、OS线程(P),以及机器(M)。Goroutine是Go的协程,它是在用户态执行的轻量级线程。P是处理器,代表了系统级的线程,可以理解为Goroutine的执行上下文。M代表了机器,实际上就是操作系统的线程。在这个模型中,M和P绑定,Goroutine在P的上下文中执行,这样就可以实现高效的并发调度。
面试官: 那你对算法题:最长公共子序列这个问题有什么思路呢?
求职者: 这个问题可以用动态规划来解决。我们可以用一个二维数组dp[i][j]
来表示字符串A的前i个字符和字符串B的前j个字符的最长公共子序列的长度。状态转移方程可以是,如果A[i]等于B[j],那么dp[i][j] = dp[i-1][j-1] + 1
;如果不等,那么dp[i][j] = max(dp[i-1][j], dp[i][j-1])
。这样,我们可以填充这个二维数组,最后dp[A.length()][B.length()]
就是我们要的答案。
面试官: 好的,你提到了Raft的选举超时时长,你认为应该设置为多少比较合适?
求职者: 在Raft算法中,选举超时时长是一个需要根据具体系统环境和需求来调整的参数。通常,它应该设置得足够长,以避免不必要的重新选举,但也不能太长,以免影响系统恢复领导者的速度。一般建议的超时时长是150ms到300ms之间。
面试官: 聊聊数据库,你知道MySQL默认的事务隔离级别是什么吗?
求职者: MySQL的默认事务隔离级别是可重复读(REPEATABLE READ)。在这个级别,事务中的读取操作会基于快照来进行,从而保证在同一个事务中多次读取同样记录的结果是一致的。
面试官: 既然提到了Go语言,你有没有阅读过Go语言的源码?关于Go语言看过哪方面的源码?
求职者: 是的,我阅读过Go语言的一些源码,主要是标准库中的一些包,比如net/http
、sync
、fmt
等,以及runtime包中关于协程调度和内存分配的部分。
面试官: 那么对于协程的机制和goroutine的栈模型,你的理解是怎样的?
求职者: Go的协程机制很有意思。每个goroutine都有自己的栈空间,起初这个栈很小,只有2KB,随着程序执行,它可以动态地进行扩容和缩减。操作系统的线程拥有一个固定大小的栈,通常很大,如1MB。Go通过这种动态栈来实现高效的内存利用和更多的并发量。当一个goroutine的栈空间不够时,Go运行时系统会自动分配一个更大的栈空间,并且复制原有的栈数据到新栈上。这个过程对程序员来说是完全透明的。 面试官: 了解了。那么,你能用Go语言写一下最长公共子序列的代码实现吗?
求职者: 当然,这里是一个简单的实现:
func longestCommonSubsequence(text1 string, text2 string) int { m, n := len(text1), len(text2) dp := make([][]int, m+1) for i := range dp { dp[i] = make([]int, n+1) } for i, c1 := range text1 { for j, c2 := range text2 { if c1 == c2 { dp[i+1][j+1] = dp[i][j] + 1 } else { dp[i+1][j+1] = max(dp[i][j+1], dp[i+1][j]) } } } return dp[m][n] } func max(a, b int) int { if a > b { return a } return b }
这段代码首先初始化了一个(m+1)*(n+1)
的二维数组dp,然后遍历两个字符串,根据字符是否相等来更新dp的值。
面试官: 非常好。现在让我们切换到数据库。你能举例说明一下在MySQL的可重复读隔离级别下,会出现哪些现象吗?
求职者: 在可重复读隔离级别下,同一事务中多次读取同一数据,结果都是一样的。这是因为MySQL会为每个事务创建一个一致性视图,来保证事务的一致性。但是,这个级别仍然可能出现幻读现象,也就是在一个事务内读取到了别的事务插入的新行。为了解决这个问题,MySQL引入了间隙锁来防止幻读。
面试官: 很好。现在我们再聊聊Go语言。你能简单解释一下Go的协程调度模型GPM是如何工作的吗?
求职者: Go的协程调度模型GPM中的G代表Goroutine,P代表Processor,M代表Machine。在Go语言的运行时系统中,有一个全局的P列表,每个P中又有一个本地runnable的G队列。当Goroutine在运行时,它会被绑定到一个P和M上。如果Goroutine因为等待资源(如等待I/O、channel或锁)而被阻塞,那么运行时系统会把P和M解绑,让M去执行其他的Goroutine。当阻塞的Goroutine能够继续运行时(如I/O完成、channel可用、锁被释放),它会被放入到全局runnable的G队列或者某个P的本地runnable的G队列,等待被调度执行。
面试官: 非常好。那么,你能解释一下goroutine的栈模型是如何工作的吗?
求职者: Goroutine的栈模型与操作系统的线程有很大不同。操作系统的线程拥有固定的栈空间,通常是1MB或者2MB,而Goroutine的栈在创建时非常小,只有2KB。随着程序的执行,如果栈空间不够,Go运行时系统会自动地为其分配更大的栈空间,并且复制原有的栈数据到新栈。这种动态栈的设计使得Go可以创建大量的Goroutine而不会耗尽内存。
面试官: 很好,你的回答很详细。最后一个问题,你认为Go语言的哪些特性使其在后端开发中有优势?
求职者: 我认为Go语言在后端开发中的优势主要体现在以下几个方面:首先,Go语言的设计简洁,语法易于学习,使得开发效率高。其次,Go语言的并发模型使得它在处理高并发场景时有优势。再者,Go语言的静态类型和编译型语言的特性,使得其在运行效率上和类型安全上都有保障。最后,Go语言的标准库丰富,包含了很多用于网络、数据库、加密等常见后端开发需求的包,使得开发者可以用Go快速开发出高效、稳定的后端服务。
面试官: 好的,最后想问你一个更加开放的问题。 在你看过的Go语言源码中,有哪一部分让你印象最深刻?你从中学到了什么?
求职者: 对我印象最深刻的是Go的runtime包。特别是里面的调度器和垃圾回收部分。从中我学到了Go如何高效地管理goroutine的生命周期,以及如何通过写屏障(write barrier)和三色标记(tri-color marking)算法来实现并发的垃圾回收。这些深入底层的机制,让我对高性能编程和资源管理有了更深的理解。
面试官: 非常好,深入理解这些底层实现对于编写高性能的Go代码非常重要。那么,你能谈谈你对Go语言未来发展趋势的看法吗?
求职者: 我认为Go语言未来的发展趋势将会更加关注于提升开发效率和运行时性能。随着Go 2的讨论和设计,我们可能会看到语言特性上的一些增强,比如错误处理的改进、泛型的引入等。同时,Go语言社区一直在优化编译器和运行时,以提升程序的性能。另外,随着微服务和云原生技术的流行,Go语言作为Kubernetes和Docker等重要工具的语言基础,它在云计算和分布式系统领域的应用将会更加广泛。
面试官: 非常有见地。今天的面试到这里就结束了,你的回答很棒,感谢你的参与。我们后续会有人跟你联系。祝你今天过得愉快!
求职者: 谢谢!期待贵公司的消息,祝您也有一个美好的一天。
滴滴存储后端
- raft这边了解多少?
- 读一个key,set一个key,通过raft之后大概会怎么样
- Golang的特性
- 并发模型
- GPM模型
- 算法题:最长公共子序列
- raft实现过程中选举超时配的时长是多少?
- mysql默认的事务隔离级别是什么?
- 关于Go语言看过哪方面源码?
- 协程的机制了解有多少?
- goroutine的栈是个什么样的模型?
作者:寄__l 链接:https://www.nowcoder.com/?type=818_1 来源:牛客网