logo

4/2 腾讯PCG一:问麻了!腾讯一面究竟问了什么?从HTTP到算法····

作者
Modified on
Reading time
15 分钟阅读:..评论:..

下面我将分享一位同学在腾讯PCG的trpc一面的面试经历,对于这次面试,他的评价是,既全面又深入,涵盖了从网络基础到算法的多个领域,你试试呢?

【提醒】通过这次面试经验,你将可以复习到以下知识点:

  • 浏览器到服务器的请求流程
  • HTTPS与HTTP的差异
  • JWT Token的原理和优势
  • TCP连接的建立和断开流程
  • epoll的工作机制
  • Linux下内存的监控方法
  • GMP调度模型
  • Context的设计理念
  • LevelDB的数据插入过程
  • 数据库缓存一致性问题
  • 查找两个字符串的最大公共子串算法

面试官: 同学你好,欢迎参加今天的面试。我想首先问一下,当你通过chrome浏览器输入一个地址到最终页面内容显示,中间发生了哪些过程?

求职者: 好的,这个过程大致可以分为以下几个步骤:

  1. 浏览器检查缓存,看请求的资源是否已被缓存并且还有效,如果有效直接使用缓存资源。
  2. DNS解析,浏览器将域名解析为服务器的IP地址。
  3. 浏览器与服务器建立TCP连接,这包括了三次握手的过程。
  4. 浏览器发送HTTP请求,请求方法可能是GET、POST等。
  5. 服务器处理请求并返回HTTP响应,响应包含状态码和请求的资源。
  6. 浏览器解析HTTP响应,并根据响应内容如HTML、CSS、JavaScript等构建页面内容。
  7. 浏览器渲染页面,显示给用户。

面试官: 那你能解释一下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连接的建立使用的是三次握手过程,具体如下:

  1. 客户端发送一个SYN包(synchronize序号)到服务器,并进入SYN_SENT状态。
  2. 服务器接收到SYN包后,回复一个SYN+ACK包(确认加同步),然后服务器进入SYN_RCVD状态。
  3. 客户端收到服务器的SYN+ACK包后,发送一个ACK包(确认)到服务器,然后进入ESTABLISHED状态,这时候连接建立成功。

断开连接则使用四次挥手过程,具体如下:

  1. 当一方完成数据传输后,发送FIN包(结束)以关闭连接的一半。
  2. 另一方接收到FIN后,发送ACK包(确认),确认序列号为接收到的序列号+1。
  3. 另一方如果数据也发送完毕,也发送一个FIN包
  4. 最初发送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来记录当前最大公共子串的结束位置。最终,根据maxLengthendIndex,我们可以获取到最大公共子串。

面试官: 好的,你的方法很不错。那你能解释一下这个算法的时间复杂度和空间复杂度吗?

求职者: 这个算法的时间复杂度是O(n_m),其中n和m分别是输入的两个字符串的长度。因为我们需要对这两个字符串的每个字符进行比较。空间复杂度是O(n_m),因为我们需要一个二维数组来存储中间结果。不过在某些情况下,我们可以对空间进行优化,比如使用滚动数组来减少空间复杂度到O(min(n, m))。

面试官: 非常详尽的解答,感谢你今天的参与,面试到此结束。我们会尽快给你反馈。祝你好运!

求职者: 非常感谢这次面试的机会,期待您的回复。再见!

腾讯pcg trpc一面

  1. 讲一下当通过chrome浏览器输入地址直到返回内容中间经历了什么样的过程?
  2. 说一下了解的HTTP方法和它们之间的区别
  3. GET方法可以携带body吗?
  4. HTTP的返回码有哪些?
  5. HTTPS和HTTP之间的区别是什么?
  6. HTTP1.1和HTTP2的区别是什么?
  7. HTTP加密算法的基本原理,对称加密和非对称加密?
  8. 可以讲一下JWT Token是怎么做的吗?
  9. JWT的Token相对于普通的Token的优势在哪里?
  10. refresh Token和access Token之间的关系是什么?
  11. TCP连接建立和断开的流程一般是什么样子?
  12. Close Wait状态是什么意思,Fin Wait和Close Wait之间的区别是什么?
  13. TCP连接建立好以后往其中写数据,写的太快了会怎么样?
  14. epoll有了解吗,FD?
  15. 边缘触发(Edge Trigger)和条件触发(Level Trigger) 你知道吗?
  16. Linux进程占得内存空间怎么看?
  17. TOP命令中有三个和内存相关的列,分别是什么意思?
  18. 操作系统的虚拟地址空间了解吗?
  19. Golang Slice的Size和Cap有什么区别?
  20. Slice扩容后在原Slice上修改数据新Slice会发生变化吗?
  21. C++ std里执行类似操作会怎么样(vector取引用然后扩容)?
  22. Go关闭Channel时有哪些需要注意的事情,怎么判断channel是否已经关闭呢?
  23. Go的interface和Java的interface有什么区别,继承有什么区别?
  24. Go程序影响性能的因素有哪些,有做过一下性能优化吗,怎么优化GC?
  25. GMP调度模型有看过吗?
  26. Context源码设计理念?
  27. DLV有用过吗?
  28. LevelDB插入一条数据会发生什么事情?
  29. SSTable是排好序的吗?
  30. Level写数据会不会出现,Write返回成功了这时候进程挂了,会不会数据没落盘?
  31. 数据和缓存的一致性,你是怎么理解和解决这个数据库缓存一致性的问题的?
  32. 算法题:找到两个字符串的最大公共子串

作者:寄__l 链接:https://www.nowcoder.com/?type=818_1 来源:牛客网