4/2 腾讯PCG一:问麻了!腾讯一面究竟问了什么?从HTTP到算法····
- 作者
- Name
- 青玉白露
- Github
- @white0dew
- Modified on
- Reading time
- 15 分钟
阅读:.. 评论:..
下面我将分享一位同学在腾讯PCG的trpc一面的面试经历,对于这次面试,他的评价是,既全面又深入,涵盖了从网络基础到算法的多个领域,你试试呢?
【提醒】通过这次面试经验,你将可以复习到以下知识点:
- 浏览器到服务器的请求流程
- HTTPS与HTTP的差异
- JWT Token的原理和优势
- TCP连接的建立和断开流程
- epoll的工作机制
- Linux下内存的监控方法
- GMP调度模型
- Context的设计理念
- LevelDB的数据插入过程
- 数据库缓存一致性问题
- 查找两个字符串的最大公共子串算法
面试官: 同学你好,欢迎参加今天的面试。我想首先问一下,当你通过chrome浏览器输入一个地址到最终页面内容显示,中间发生了哪些过程?
求职者: 好的,这个过程大致可以分为以下几个步骤:
- 浏览器检查缓存,看请求的资源是否已被缓存并且还有效,如果有效直接使用缓存资源。
- DNS解析,浏览器将域名解析为服务器的IP地址。
- 浏览器与服务器建立TCP连接,这包括了三次握手的过程。
- 浏览器发送HTTP请求,请求方法可能是GET、POST等。
- 服务器处理请求并返回HTTP响应,响应包含状态码和请求的资源。
- 浏览器解析HTTP响应,并根据响应内容如HTML、CSS、JavaScript等构建页面内容。
- 浏览器渲染页面,显示给用户。
面试官: 那你能解释一下HTTPS和HTTP之间的区别是什么吗?
求职者: 当然。HTTPS其实是HTTP的安全版本,它通过在HTTP下加入SSL/TLS协议层来增强安全性。主要区别在于:
- 加密传输:HTTPS利用SSL/TLS进行数据加密,确保数据传输过程中的安全;
- 身份验证:HTTPS提供了身份验证机制,可以验证访问的网站是否为服务器上的合法网站;
- 数据完整性:防止传输的内容被中间人篡改。
面试官: 好,那你知道HTTP1.1和HTTP2的区别吗?
求职者: 是的,我了解。HTTP/1.1和HTTP/2的主要区别包括:
- 多路复用:HTTP/2可以在一个TCP连接中并行处理多个请求,而HTTP/1.1则需要为每个请求/响应建立一个连接或使用队头阻塞;
- 服务器推送:HTTP/2可以服务器端可以未经请求提前发送资源,提高加载效率;
- 头部压缩:HTTP/2采用HPACK压缩格式减小了头部大小,减少了延迟;
- 二进制格式:HTTP/2传输的是二进制格式,而非HTTP/1.1的文本格式,使得解析更加高效。
面试官: 那基本的HTTP加密算法原理,你能解释一下对称加密和非对称加密吗?
求职者: 当然可以。在加密算法中,对称加密使用相同的密钥进行加密和解密,它速度快,适合大量数据的加密,如AES算法。但对称加密的缺点在于密钥的分发,因为如果密钥被泄露,加密信息就不安全了。
非对称加密使用一对密钥,即公钥和私钥。公钥可以公开分享,用于加密数据,而私钥保密,用于解密。非对称加密如RSA算法,更安全,适合少量数据加密,经常用于加密对称加密的密钥,或数字签名。
面试官: 既然提到了安全,你可以讲一下JWT Token是怎么做的吗?
求职者: JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。一个JWT通常由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
- 头部通常包括了令牌的类型,即JWT,以及使用的签名算法,如HMAC SHA256或RSA。
- 载荷包含了声明(Claim),声明是关于实体(通常是用户)和其他数据的陈述。
- 签名用于验证消息的发送者是谁,以及消息没有被更改过。
JWT通常用于身份验证和信息交换,因为它可以确保在传输过程中的安全性。
面试官: 那JWT的Token相对于普通的Token有什么优势?
求职者: JWT的主要优势在于:
- 自包含:JWT包含了所有用户需要的信息,避免了多次数据库查询;
- 跨语言:由于是JSON格式,所以可以被任何支持JSON的语言读取;
- 安全性:通过签名保证了Token的真实性和完整性;
- 易于传输:可以通过URL、POST参数或者在HTTP header中传输;
- 性能:由于不需要查询数据库,所以在验证Token时可以提高性能。
面试官: 那么,refresh Token和access Token之间的关系是什么?
求职者: access Token是用来访问API的短期凭证,而refresh Token通常用来获取新的access Token。由于access Token具有较短的有效期,一旦过期,客户端可以使用refresh Token请求新的access Token,这样可以避免用户频繁地重新认证。这个机制可以提高安全性,因为即使access Token被泄露,它很快就会过期。而refresh Token通常更加安全,存储在应用服务器上,不会经常传输。
面试官: 好的,接下来让我们讨论一下TCP连接的建立和断开。建立和断开TCP连接的流程一般是什么样子的?
求职者: TCP连接的建立使用的是三次握手过程,具体如下:
- 客户端发送一个SYN包(synchronize序号)到服务器,并进入SYN_SENT状态。
- 服务器接收到SYN包后,回复一个SYN+ACK包(确认加同步),然后服务器进入SYN_RCVD状态。
- 客户端收到服务器的SYN+ACK包后,发送一个ACK包(确认)到服务器,然后进入ESTABLISHED状态,这时候连接建立成功。
断开连接则使用四次挥手过程,具体如下:
- 当一方完成数据传输后,发送FIN包(结束)以关闭连接的一半。
- 另一方接收到FIN后,发送ACK包(确认),确认序列号为接收到的序列号+1。
- 另一方如果数据也发送完毕,也发送一个FIN包。
- 最初发送FIN的一方接收到FIN后,发送ACK包。这时候,双方都可以关闭连接了。
面试官: Close Wait状态是什么意思,Fin Wait和Close Wait之间的区别是什么?
求职者: Close Wait状态是指TCP连接的一方在收到对方的FIN包,发送ACK包后进入的状态。在这个状态下,等待本端的应用程序关闭连接。而Fin Wait状态是指发送FIN包的一方,在等待对方的ACK包和对方的FIN包。
其实,Fin Wait状态主要是发起连接关闭的一方所处的状态,而Close Wait状态是响应连接关闭的另一方所处的状态。
面试官: 如果TCP连接建立好以后往其中写数据,写得太快了会怎么样?
求职者: 如果发送方发送数据太快,而接收方来不及处理,就会造成接收方的缓冲区满了。TCP提供了流量控制机制,通过窗口大小(Window size)来控制发送方的发送速度,防止接收方的缓冲区溢出。
如果接收方的窗口为0,发送方就会停止发送数据,并开始发送窗口探测包。等到接收方处理了一些数据,有空闲的缓冲区后,它会更新窗口的大小并通知发送方,发送方再根据新的窗口大小发送数据。
面试官: 你了解epoll吗,它和FD是什么关系?
求职者: 是的,epoll是Linux下多路复用IO接口之一,它可以监控多个文件描述符(File Descriptor,简称FD)上的IO事件。与select和poll不同,epoll使用一种更有效的方式来处理大量的文件描述符。在epoll使用中,我们需要使用epoll_create创建一个epoll对象,然后通过epoll_ctl将感兴趣的文件描述符添加到这个epoll对象中。当IO事件发生时,可以通过epoll_wait获取这些事件。
面试官: 那你知道边缘触发(Edge Trigger)和条件触发(Level Trigger)的区别是什么吗?
求职者: 边缘触发(Edge Trigger,ET)和条件触发(Level Trigger,LT)是epoll事件的两种触发模式。
- 条件触发,即Level Trigger,是默认的工作模式。在这种模式下,只要FD上有可读写的数据,epoll_wait就会返回该FD。这意味着,如果不处理,它会不断地通知。
- 边缘触发,即Edge Trigger,只有数据状态发生变化时,epoll_wait才会返回FD。比如说,只有当从无数据到有数据,或者从不可写到可写时,才会通知一次。
边缘触发通常效率更高,但需要更仔细地控制读写,避免数据丢失。
面试官: Linux进程占用的内存空间怎么查看?
求职者: 在Linux中,我们可以通过top命令来查看进程占用的内存空间。当运行top命令时,它会显示系统的整体资源使用情况,包括CPU、内存等,并列出占用资源最多的进程。
面试官: TOP命令中有三个和内存相关的列,分别是什么意思?
求职者: 在top命令的输出中,与内存相关的三个列通常是:
- VIRT:虚拟内存的使用量,包括进程使用的所有内存空间,含有进程未直接使用的库文件等。
- RES:常驻内存的大小,即实际使用物理内存的大小。
- SHR:共享内存的大小,表示多个进程共享的内存部分。
面试官: 那你对操作系统的虚拟地址空间了解吗?
求职者: 是的,虚拟地址空间是操作系统提供给进程的一种抽象概念,它允许每个进程认为自己是在独占地使用物理内存。实际上,操作系统会通过内存管理单元(MMU)将虚拟地址映射到物理地址上。这样做的好处是,每个进程都有一个统一的地址开始方式,简化了内存访问,并且可以通过分页或分段机制提供内存保护,防止进程间相互干扰。
面试官: Golang的Slice的Size和Cap有什么区别?
求职者: 在Go语言中,Slice是一个引用类型,它的结构包含指向数组的指针、长度(len)和容量(cap)。
- **Size(长度)**指的是Slice中实际包含的元素个数。
- **Cap(容量)**则是指Slice底层数组中从开始元素到数组末尾元素的个数。
一个Slice可以在不超过其容量的前提下动态增长,这通常通过append函数实现。当超过容量时,Slice会自动扩容,这时通常会分配一个新的底层数组,并将原有元素复制到新数组中。
面试官: 那Slice扩容后在原Slice上修改数据,新Slice会发生变化吗?
求职者: 扩容后,如果新的Slice是基于原有Slice创建的,修改原Slice上的数据不会影响新Slice,因为新Slice已经指向了一个新的底层数组。但如果没有发生扩容,新Slice和原Slice共享同一个底层数组,这时在原Slice上的任何修改都会反映到新Slice上。
面试官: 如果在C++ std中执行类似操作,比如对vector取引用然后扩容,会怎么样?
求职者: 在C++中,如果对一个vector取了引用,然后对这个vector进行扩容(比如push_back新元素导致容量不足时),那么原来的引用可能会变得无效,因为vector在扩容时可能会分配一块新的内存空间来存储元素,并将旧元素复制到新的内存空间中,这会改变元素的地址。
面试官: Go语言中关闭Channel有哪些需要注意的事项,怎样判断channel是否已经关闭了呢?
求职者: 在Go语言中,关闭Channel需要注意以下几点:
- 只有发送方应该关闭channel,接收方不应该关闭,否则会导致panic。
- 关闭一个已经关闭的channel也会导致panic。
- 关闭channel后,再往channel发送数据会导致panic。
要判断channel是否已经关闭,可以在接收时使用两个值的接收操作,如果第二个值返回false,那么表示channel已经关闭。例如:
v, ok := <-ch if !ok { // channel已经关闭 }
面试官: Go的interface和Java的interface有什么区别,继承有什么区别?
求职者: Go的interface和Java的interface的主要区别在于:
- Go的interface是隐式实现的,只要一个类型实现了interface中所有的方法,那么这个类型就实现了该interface,不需要显式声明。
- Java的interface需要显式实现,一个类必须使用implements关键字来指明它实现了哪个interface。
面试官: 好的,现在我们来做一个算法题。给定两个字符串,你能写出一个函数来找到它们的最大公共子串吗?
求职者: 当然,我们可以使用动态规划的方法来解决这个问题。这里是一个可能的解决方案:func longestCommonSubstring(s1, s2 string) string { dp := make([][]int, len(s1)+1) for i := range dp { dp[i] = make([]int, len(s2)+1) } maxLength := 0 endIndex := 0 for i := 1; i <= len(s1); i++ { for j := 1; j <= len(s2); j++ { if s1[i-1] == s2[j-1] { dp[i][j] = dp[i-1][j-1] + 1 if dp[i][j] > maxLength { maxLength = dp[i][j] endIndex = i } } else { dp[i][j] = 0 } } } return s1[endIndex-maxLength : endIndex] }
这个函数首先初始化了一个二维切片dp
,用于存储最大公共子串的长度信息。然后遍历两个字符串中的每个字符,如果字符相同,就在dp
中相应位置累加长度。同时,我们用maxLength
变量来记录出现过的最大长度,以及用endIndex
来记录当前最大公共子串的结束位置。最终,根据maxLength
和endIndex
,我们可以获取到最大公共子串。
面试官: 好的,你的方法很不错。那你能解释一下这个算法的时间复杂度和空间复杂度吗?
求职者: 这个算法的时间复杂度是O(n_m),其中n和m分别是输入的两个字符串的长度。因为我们需要对这两个字符串的每个字符进行比较。空间复杂度是O(n_m),因为我们需要一个二维数组来存储中间结果。不过在某些情况下,我们可以对空间进行优化,比如使用滚动数组来减少空间复杂度到O(min(n, m))。
面试官: 非常详尽的解答,感谢你今天的参与,面试到此结束。我们会尽快给你反馈。祝你好运!
求职者: 非常感谢这次面试的机会,期待您的回复。再见!
腾讯pcg trpc一面
- 讲一下当通过chrome浏览器输入地址直到返回内容中间经历了什么样的过程?
- 说一下了解的HTTP方法和它们之间的区别
- GET方法可以携带body吗?
- HTTP的返回码有哪些?
- HTTPS和HTTP之间的区别是什么?
- HTTP1.1和HTTP2的区别是什么?
- HTTP加密算法的基本原理,对称加密和非对称加密?
- 可以讲一下JWT Token是怎么做的吗?
- JWT的Token相对于普通的Token的优势在哪里?
- refresh Token和access Token之间的关系是什么?
- TCP连接建立和断开的流程一般是什么样子?
- Close Wait状态是什么意思,Fin Wait和Close Wait之间的区别是什么?
- TCP连接建立好以后往其中写数据,写的太快了会怎么样?
- epoll有了解吗,FD?
- 边缘触发(Edge Trigger)和条件触发(Level Trigger) 你知道吗?
- Linux进程占得内存空间怎么看?
- TOP命令中有三个和内存相关的列,分别是什么意思?
- 操作系统的虚拟地址空间了解吗?
- Golang Slice的Size和Cap有什么区别?
- Slice扩容后在原Slice上修改数据新Slice会发生变化吗?
- C++ std里执行类似操作会怎么样(vector取引用然后扩容)?
- Go关闭Channel时有哪些需要注意的事情,怎么判断channel是否已经关闭呢?
- Go的interface和Java的interface有什么区别,继承有什么区别?
- Go程序影响性能的因素有哪些,有做过一下性能优化吗,怎么优化GC?
- GMP调度模型有看过吗?
- Context源码设计理念?
- DLV有用过吗?
- LevelDB插入一条数据会发生什么事情?
- SSTable是排好序的吗?
- Level写数据会不会出现,Write返回成功了这时候进程挂了,会不会数据没落盘?
- 数据和缓存的一致性,你是怎么理解和解决这个数据库缓存一致性的问题的?
- 算法题:找到两个字符串的最大公共子串
作者:寄__l 链接:https://www.nowcoder.com/?type=818_1 来源:牛客网