您的当前位置:首页正文

后端开发工程师 面试题大杂烩

2024-11-07 来源:个人技术集锦

以下题目来自于牛客网的面经真题,希望能对大伙有帮助。

  • 7层网络模型
    物数网传会表应
    应用层:针对特定应用的协议,为应用程序提供服务并规定应用程序中通信相关的细节。包括文件传输、电子邮件、远程登录等协议。
    
    表示层:将来自下一层的数据转换为上层能够处理的格式。负责数据转换、格式化、文本压缩等。
    
    会话层:负责建立和断开通信连接(数据流动的逻辑通路),以及数据的分割等数据传输相关的管理。
    
    传输层:管理两个节点之间的数据传输。
    
    网络层:地址管理和路由选择。
    
    数据链路层:互联设备之间传送和识别帧。
    
    物理层:以二进制形式在在物理媒体上传输数据。

  •  应用层协议了解哪些 传输层协议了解哪些 
    应用层常见协议:Http、Telnet、POP、DNS、FTP
    
    传输层协议:TCP、UDP

  • TCP/UDP区别 
    TCP 面向连接(如打电话要先拨号建立连接)提供可靠的服务,UDP 是无连接的,即发送数据之前不需要建立连接,UDP 尽最大努力交付,即不保证可靠交付。
    
    UDP 具有较好的实时性,工作效率比 TCP 高,适用于对高速传输和实时性有较高的通信或广播通信。
    
    每一条 TCP 连接只能是一对一的,UDP 支持一对一,一对多,多对一和多对多的交互通信。
    
    UDP 分组首部开销小,TCP 首部开销 20 字节,UDP 的首部开销小,只有 8 个字节。
    
    TCP 面向字节流,实际上是 TCP 把数据看成一连串无结构的字节流,UDP 是面向报文的一次交付一个完整的报文,报文不可分割,报文是 UDP 数据报处理的最小单位。
    
    UDP 适合一次性传输较小数据的网络应用,如 DNS,SNMP 等。

  • TCP如何使传输可靠
    校验和:TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
    
    序列号:TCP 传输时将每个字节的数据都进行了编号,这就是序列号。(为了应对延时抵达和排序混乱)。每个连接都会选择一个初始序列号,初始序列号(视为一个 32 位计数器),会随时间而改变(每 4 微秒加 1)。因此,每一个连接都拥有不同的序列号。序列号的作用不仅仅是应答的作用,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据。这也是 TCP 传输可靠性的保证之一。
    
    确认应答:TCP 传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送 ACK 报文。这个 ACK 报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发。
    
    超时重传:超时重传机制。简单理解就是发送方在发送完数据后等待一个时间,时间到达没有接收到 ACK 报文,那么对刚才发送的数据进行重新发送。如果是刚才第一个原因,接收方收到二次重发的数据后,便进行 ACK 应答。如果是第二个原因,接收方发现接收的数据已存在(判断存在的根据就是序列号,所以上面说序列号还有去除重复数据的作用),那么直接丢弃,仍旧发送 ACK 应答。那么发送方发送完毕后等待的时间是多少呢?如果这个等待的时间过长,那么会影响 TCP 传输的整体效率,如果等待时间过短,又会导致频繁的发送重复的包。如何权衡?由于 TCP 传输时保证能够在任何环境下都有一个高性能的通信,因此这个最大超时时间(也就是等待的时间)是动态计算的。
    
    连接管理:说白了就是三次握手四次挥手。
    
    流量控制:当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。
    
    拥塞控制:拥塞控制是 TCP 在传输时尽可能快的将数据传输,并且避免拥塞造成的一系列问题。是可靠性的保证,同时也是维护了传输的高效性。

  • 如何实现多路复用IO
    1) select
    fd_set 使用数组实现
    1 fd_size 有限制 1024 bitmap,fd[i] = accept()
    2 fdset不可重用,新的fd进来,重新创建
    3 用户态和内核态拷贝产生开销
    4 O(n)时间复杂度的轮询
    结果:成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0
    返回:具有超时时间
    
    2) poll
    基于结构体存储fd
    struct pollfd{
    int fd;
    short events;
    short revents; //可重用
    }
    解决了select的1,2两点缺点
    
    3) epoll
    解决select的1,2,3,4;
    不需要轮询,时间复杂度为O(1);
    epoll_create 创建一个白板 存放fd_events;
    epoll_ctl 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上;
    epoll_wait 通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符;
    
    两种触发模式:
    LT:水平触发
    当 epoll_wait() 检测到描述符事件到达时,将此事件通知进程,进程可以不立即处理该事件,下次调用 epoll_wait() 会再次通知进程。是默认的一种模式,并且同时支持 Blocking 和 No-Blocking。
    
    ET:边缘触发
    和 LT 模式不同的是,通知之后进程必须立即处理事件。
    下次再调用 epoll_wait() 时不会再得到事件到达的通知。很大程度上减少了 epoll 事件被重复触发的次数,
    因此效率要比 LT 模式高。只支持 No-Blocking,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。
    ————————————————
    版权声明:本文为CSDN博主「相偎」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https:///u013932564/article/details/127227091
  • 让你实现一个RPC框架,应该要考虑哪些点
    1、通过网络,要发送哪些数据,比如至少得发送类名或者接口名,要调用的方法名、调用方法时传入的参数等。
    
    2、方法参数如果是对象,那么如果要考虑网络发送对象的问题,就需要考虑序列化和反序列化的问题了,使用何种序列化机制,也是要考虑的问题。
    
    3、确定好了要发送的数据后,那通过什么方式发出去呢,是直接通过Socket发送,或者是http发送呢。
    
    4、如果利用http来发,那就是用http1.1,或者是http2呢,请求头放什么数据,请求体放什么数据,都是问题。
    
    5、如何直接通过socket来发,那就需要自己设计一个数据格式了,类似于htp协议,不然服务器接收到字节流之后无法解析字节流。
    
    6、确定好数据格式和网络传输方式之后,就需要考虑是否支持异步功能了,是否支持回调功能。
    
    7、另外想负载均衡、服务容错、服务路由、服务重试等功能也要逐一考虑。
    ————————————————
    版权声明:本文为CSDN博主「一只傻阿Z」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https:///qq_34069570/article/details/128111786

  •  三次握手为什么是三次  四次挥手为什么是四次
    三次握手:
    1、刚开始客户端和服务端都是处于关闭的状态,而且服务器 B 端一直处于监听的状态,时刻监听是否有建立连接的请求;
    2、当有客户端需要建立连接的时候就会发送一个确定连接的报文,此报文是同步报文SYN = 1,并且会生成一个随机的序号 seq = x,这是第一次握手;
    3、当服务端接收到请求连接报文的时候,会发送一个同步报文确认报文,此报文 SYN = 1,并且 ACK = 1,同时服务端也会随机生成一个 seq = y,并将 ack 设置成 x + 1,回传给客户端,这是第二次握手;
    4、当客户端接收到服务端的 ACK 报文后,会回复一个 ACK 确认报文,用于确认确认报文已经收到,此报文 ACK = 1,seq = x + 1, ack = y + 1,这是第三次握手;
    这里有个点说明一下:大写的 ACK 表示报文的类型是确认报文,小写的 ack 是报文里面的确认号,这个确认号是上一次握手对方的 seq 值加 1 得到。
    
    第一次握手:第一次握手是客户端发送同步报文到服务端,这个时候客户端是知道自己具备发送数据的能力的,但是不知道服务端是否有接收和发送数据的能力;
    
    第二次握手:当服务端接收到同步报文后,回复确认同步报文,此时服务端是知道客户端具有发送报文的能力,并且知道自己具有接收和发送数据的能力,但是并不知道客户端是否有接收数据的能力;
    
    第三次握手:当客户端收到服务端的确认报文后,知道服务端具备接收和发送数据的能力,但是此时服务端并不知道自己具有接收的能力,所以还需要发送一个确认报文,告知服务端自己是具有接收能力的。
    
    四次挥手:
    1、客户端发起 FIN 断开连接的报文,携带随机生成的 seq 值 u,发送给服务端,并且自己处于 FIN-WSIT 状态,这是第一次挥手;
    2、服务端接收到 FIN 报文后,回复一个确认报文,其中 ACK = 1,随机生成一个 seq,以及 ack = u + 1,这是第二次挥手;
    3、当服务端数据发送完了过后,再发送一个 FIN 报文给客户端,通知客户端,服务端准备关闭连接了,此报文 FIN = 1,ACK = 1,ack = u + 1,seq = w,这是第三次挥手;
    4、当客户端收到 FIN 确认报文时再发送一个FIN 的确认报文,其中 ACK = 1,seq = u + 1,ack = w + 1,并进入 TIME-WAIT 状态,当等待 2MSL 后关闭连接,这是第四次挥手。
    
    第一次挥手客户端发起关闭连接的请求给服务端;
    
    第二次挥手:服务端收到关闭请求的时候可能这个时候数据还没发送完,所以服务端会先回复一个确认报文,表示自己知道客户端想要关闭连接了,但是因为数据还没传输完,所以还需要等待;
    
    第三次挥手:当数据传输完了,服务端会主动发送一个 FIN 报文,告诉客户端,表示数据已经发送完了,服务端这边准备关闭连接了。
    
    第四次挥手:当客户端收到服务端的 FIN 报文过后,会回复一个 ACK 报文,告诉服务端自己知道了,再等待一会就关闭连接。

  • https加密过程(详细)
    1、首先呢,客户端先向服务端发送加密通信(https)请求,这次请求中包括:
    SSL/TSL版本号
    加密套件,也就是客户端支持的加密算法列表
    产生一个随机数,我们叫他为第1随机数
    有一个Client Hello字符串
    2、服务器收到请求后,向客户端发出响应:
    确认SSL/TSL版本号,如果客户端不支持,那么就关闭通信
    确认的加密算法列表
    生成一个随机数,我们叫第2随机数
    3、服务器再向客户端发送数字证书,这里敲重点了。服务器会把自己的公钥注册到CA(第三方证书机构),然后CA拿自己的私钥对服务器的公钥进行处理并颁发数字证书。
    4、服务器将公钥发送给客户端
    5、服务器发送Hello Done,表示发送完毕
    6、客户端收到服务端一系列响应后,确认数字证书和公钥,没有问题后向服务端发送:
    生成一个随机数,我们叫第3随机数或者预主密钥,此预主密钥会通过公钥进行加密
    客户端握手结束通知,表示客户端的握手结束
    7、服务端收到客户端数据后,使用私钥对加密后的预主密钥进行解密,没有其他人知道预主密钥,因为它加密了,除非服务器私钥泄漏。然后服务端通过第一、二、预主密钥计算出会话密钥。客户端也计算出了会话密钥。
    8、服务端向客户端发送:
    加密通信算法改变通知,以后通过会话密钥通信
    服务端握手结束
    到此为止,SSL/TSL握手结束,在此之后都会通过会话密钥来进行加密和解密,也就是对称加密。
    ————————————————
    版权声明:本文为CSDN博主「兴涛」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https:///m0_46672151/article/details/123744429

  • 浏览器寻址url过程?
    首先,在浏览器地址栏中输入url
    浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若 没有,则跳到第三步操作。
    在发送http请求前,需要域名解析(DNS解析),解析获取相应的IP地址。
    浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。
    握手成功后,浏览器向服务器发送http请求,请求数据包。
    服务器处理收到的请求,将数据返回至浏览器
    关闭TCP连接(四次挥手)
    浏览器收到响应结果解析html代码并请求资源(js、css、图片等)
    浏览器进行页面布局渲染
    ————————————————
    版权声明:本文为CSDN博主「小栗子~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https:///weixin_52793430/article/details/124488142

  • git冲突怎么处理、merge和rebase的区别
    git解决冲突有两种办法:
    rebase
    merge
    先说结论,解决冲突时尽量使用rebase。原因是因为rebase可以使得提交历史更加清晰,代码更加健壮。
    rebase与merge的区别:
    rebase:重定义起点,相当于将冲突分支整体“迁移”至另一分支上。
    merge:聚合分支,将冲突分支和另一分支“聚合”合并至新节点上。
    
    区别:
    1、不同于 git rebase的是,git merge 在不是 fast-forward(快速合并)的情况下,会产生一条额外的合并记录,类似Merge branch 'xxx' into 'xxx'的一条提交信息。
    2、另外,在解决冲突的时候,用 merge 只需要解决一次冲突即可,简单粗暴,而用 rebase 的时候 ,需要一次又一次的解决冲突。
    
    

  • 如何发现Redis 已过期key
    TTL 接口定义:TTL key    
    接口描述:获取key的过期时间。如果key存在过期时间,返回剩余生存时间(秒);如果key是永久的,返回-1;如果key不存在或者已过期,返回-2。 
    
    PTTL 接口定义:PTTL key    
    接口描述:获取key的过期时间。如果key存在过期时间,返回剩余生存时间(毫秒);如果key是永久的,返回-1;如果key不存在或者已过期,返回-2。
    
    作者:啊强啊
    链接:https://www.zhihu.com/question/452104902/answer/1809457553
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 为什么redis里用跳表不用搜索平衡树
    从内存占用上来比较,跳表比平衡树更灵活一些。平衡树每个节点包含 2 个指针(分别指向左右子树),而跳表每个节点包含的指针数目平均为 1/(1-p),具体取决于参数 p 的大小。如果像 Redis里的实现一样,取 p=1/4,那么平均每个节点包含 1.33 个指针,比平衡树更有优势。
    
    在做范围查找的时候,跳表比平衡树操作要简单。在平衡树上,我们找到指定范围的小值之后,还需要以中序遍历的顺序继续寻找其它不超过大值的节点。如果不对平衡树进行一定的改造,这里的中序遍历并不容易实现。而在跳表上进行范围查找就非常简单,只需要在找到小值之后,对第 1 层链表进行若干步的遍历就可以实现。
    
    从算法实现难度上来比较,跳表比平衡树要简单得多。平衡树的插入和删除操作可能引发子树的调整,逻辑复杂,而跳表的插入和删除只需要修改相邻节点的指针,操作简单又快速。

  • redis数据怎么设置过期时间,原理是什么,让你来设计过期机制你会怎么设计
    虽然有多种不同单位和不同形式的设置命令,但实际上 EXPIRE、PEXPIRE、EXPIREAT 三个命令都是使用PEXPIREAT 命令来实现的:无论客户端执行的是以上四个命令中的哪一个,经过转换之后,最终的执行效果都和执行 PEXPIREAT 命令一样。
    
    redisDb 结构的 expires 字典保存了数据库中所有键的过期时间,我们称这个字典为过期字典
    过期字典的键是一个指针,这个指针指向键空间中的某个键对象(也即是某个数据库键)。
    过期字典的值是一个 long long 类型的整数,这个整数保存了键所指向的数据库键的过期时间——一个毫秒精度的 UNIX 时间戳。
    
    Redis 采用的过期策略:
    懒汉式删除+定期删除
    懒汉式删除流程:
    
    1、在进行 get 或 setnx 等操作时,先检查 key 是否过期;
    2、若过期,删除 key,然后执行相应操作;
    3、若没过期,直接执行相应操作;
    4、定期删除流程(简单而言,对指定个数个库的每一个库随机删除小于等于指定个数个过期 key):
    5、遍历每个数据库(就是 redis.conf 中配置的 ”database” 数量,默认为 16)
    6、检查当前库中的指定个数个 key(默认是每个库检查 20 个 key,注意相当于该循环执行 20 次,循环体是下边的描述)
    7、如果当前库中没有一个 key 设置了过期时间,直接执行下一个库的遍历
    8、随机获取一个设置了过期时间的 key,检查该key是否过期,如果过期,删除 key
    9、判断定期删除操作是否已经达到指定时长,若已经达到,直接退出定期删除。

  • MySQL覆盖索引是什么
    覆盖索引(covering index ,或称为索引覆盖)即从非主键索引中就能查到的记录,
    而不需要查询主键索引中的记录,避免了回表的产生减少了树的搜索次数,显著提升性能。
    

  • 管道通信的原理
    管道的本质就是内核在内存中开辟了一个缓冲区,这个缓冲区与管道文件相关联,对管道文件的操作
    ,被内核转换成对这块缓冲区的操作。

  • fork()创建子进程会继承父进程哪些文件相关的内容?
    父进程经过fork()以后,父进程和子进程拥有相同内容的代码段、数据段和用户堆栈,就像父进程把自己克隆了一遍。事实上,父进程只复制了自己的PCB块。而代码段,数据段和用户堆栈内存空间并没有复制一份,而是与子进程共享。只有当子进程在运行中出现写操作时,才会产生中断,并为子进程分配内存空间。
    ————————————————
    版权声明:本文为CSDN博主「qq_42270373」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https:///qq_42270373/article/details/97264001

  • 讲一下k8s、有哪些组件和作用

    Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单高效,Kubernetes提供了应用部署、规划、更新、维护的一种机制。
    
    1、kube-apiserver是整个K8S集群中,与Etcd直接交互,控制着集群中核心资源变化,提供了K8S各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心。
    
    2、Kube-scheduler调度器是一个控制面进程,负责将 Pods 指派到节点上。 调度器基于约束和可用资源为调度队列中每个 Pod 确定其可合法放置的节点。 调度器之后对所有合法的节点进行排序,将 Pod 绑定到一个合适的节点。 
    
    3、Controller Manager作为集群内部的管理控制中心,负责集群内的Node、Pod副本、服务端点(Endpoint)、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)的管理,当某个Node意外宕机时,Controller Manager会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。
    
    4、Kubernetes网络代理运行在node 上,它反映了node 上 Kubernetes API中定义的服务,并可以通过一组后端进行简单的TCP、UDP和 SCTP流转发或者在一组后端进行循环TCP、UDP和 SCTP 转发,用户必须使用apiserver API创建一个服务来配置代理,其实就是kube-proxy通过在主机上维护网络规则并执行连接转发来实现Kubernetes服务访问。
    
    5、Kubelet 是 kubernetes 工作节点上的一个代理组件,运行在每个节点上,监视已经分配给节点的Pod
    
    6、kubectl 是 Kubernetes 的命令行工具(CLI),是 Kubernetes 用户和管理员必备的管理工具。
    
    7、Dashboard是基于网页的Kubernetes用户界面,可以使用Dashboard获取运行在集群中的应用的概览信息,也可以创建或者修改Kubernetes资源(如Deployment, Job,DaemonSet 等等),也可以对Deployment实现弹性伸缩、发起滚动升级、重启 Pod或者使用向导创建新的应用。

  • Redis如何解决大key的问题

    Redis使用者应该都遇到过大key相关的场景,比如:
    
    1、热门话题下评论、答案排序场景。
    
    2、大V的粉丝列表。
    
    3、使用不恰当,或者对业务预估不准确、不及时进行处理垃圾数据等。
    
    本质上指的是这个大key的value值过大
    
    
    对大key进行拆分处理
    我们可以将大key的键值对拆分,首先将value按照一定的规则拆分开来,按照key-value的方式存储起来,然后在将这些key按照一定的规则替换掉我们大key中的value,这样其实就是变相的将大key拆分了,我们存储的只是多个key。
    
    这样,拿到了大key的值后,在遍历获取对应的value即可。
    
    对大key的value值进行压缩处理
    我们可以使用序列化技术对我们的value进行压缩处理,这样便可缩小value的空间,使其达到合理的范围标准。这样也就完成了处理!
    
    对大key做有效时间的优化
    对我们大key做有效时间的控制,使其在超过了自己的失效,自动释放,来减少大key的危害。当我们发现做完压缩处理之后,数据依旧无法达到我们的标准,这时候,我们可以采用第一种方法继续处理,对其进行拆分,以达到我们的标准。
    
    监控Redis的使用情况
    可以用系统自带的功能,或者我们自己开发一套监控系统,来定时监控Redis的使用率,内存占用情况!如发现内存占用较多,或者短时间内内存增长过快,我们就要及时干预!
    
    以上方法中,前三种都是针对大key的本质来处理,减少value的过载,第四种就是我们运用一些辅助手段来完成监控及干预!
    ————————————————
    版权声明:本文为CSDN博主「ybb_ymm」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https:///ybb_ymm/article/details/128451485

Top