2023.3.21日面腾讯云智研发公司面经
1,先进行自我介绍
2,你是计科的,计网是必修的吗?
3,说一下两台服务器如何通信?
服务器A向服务器B进行三次握手,然后确认建立连接之后发送资源,经过四次挥手后断开连接,通信 结束。
4,刚才你提到了三次握手,那简述一下三次握手。
-
第一次握手(SYN):客户端向服务器发送一个连接请求报文,其中设置了SYN(同步)标志位,并选择一个初始序列号(Sequence Number)。这表明客户端想要建立连接,并指明自己的初始序列号。
-
第二次握手(SYN + ACK):服务器收到客户端的连接请求后,如果同意建立连接,则会发送一个确认报文作为回应。该报文中设置了SYN和ACK(确认)标志位,确认号(Acknowledgment Number)设置为客户端的初始序列号加1,并选择自己的初始序列号。这表明服务器同意建立连接,并告知客户端自己的初始序列号。
-
第三次握手(ACK):客户端收到服务器的确认报文后,会发送一个确认报文作为回应。该报文中设置了ACK标志位,确认号设置为服务器的初始序列号加1。这表明客户端确认了服务器的连接确认,并告知服务器自己收到了确认,并准备好发送数据。
5,一定要三次握手吗,两次或者四次不行吗?
三次握手实现了以下几个目标:
-
双方能够确认彼此的存在:客户端发出连接请求,服务器回应确认连接请求,然后客户端再次确认。这样双方都确认了对方的存在和可达性。
-
同步双方的初始序列号:通过在握手过程中交换序列号,双方能够确定彼此的初始序列号,从而为后续的数据传输建立正确的序列号顺序。
-
防止过早的连接请求被接受:在一个旧的连接请求仍然存在网络中的情况下,通过三次握手可以确保双方不会意外地接受一个已经过时的连接请求。
如果TCP连接建立过程只进行两次握手或者四次握手,可能会引发一些问题:
-
两次握手:
-
客户端发送连接请求(SYN)。
-
服务器接收到连接请求并发送确认(ACK)。
-
如果此时客户端并没有发送确认,而是开始发送数据,那么服务器将会认为连接已建立。然而,由于客户端并没有接收到服务器的确认,可能会导致服务器误解连接的状态,进而造成不一致的状态。这种情况下可能会有安全隐患和数据传输问题。
-
-
四次握手:
-
如果有额外的握手过程,例如客户端和服务器各发送一个确认,这可能会导致额外的延迟和资源消耗,尤其是在高负载的网络环境中。
-
6,抓包工具用过吗?
7,敲命令:抓包网卡eth1,ICMP协议,来自1.1.1.1发送的消息
tcpdump -i eth1 icmp and src host 1.1.1.1
8,https协议如何工作的?
① 证书验证阶段: 1)浏览器发起 HTTPS 请求; 2)服务端返回 HTTPS 证书; 3)客户端验证证书是否合法,如果不合法则提示告警。
② 数据传输阶段: 1)当证书验证合法后,在本地生成随机数; 2)通过公钥加密随机数,并把加密后的随机数传输到服务端; 3)服务端通过私钥对随机数进行解密; 4)服务端通过客户端传入的随机数构造对称加密算法,对返回结果内容进行加密后传输。
9,TCP和UDP有什么不同?
TCP是可靠传输,UDP是不可靠传输。 TCP面向连接,UDP无连接,即发送数据之前不需要建立连接。 TCP传输数据有序,UDP不保证数据的有序性。 TCP面向字节流,把数据看成一连串字节流,UDP是面向报文的。 TCP传输速度相对UDP较慢。 TCP有流量控制和拥塞控制,UDP没有。 TCP是重量级协议,UDP是轻量级协议。 TCP首部20字节,UDP首部8字节。 TCP连接只能是一对一的(端到端);UDP支持一对一、一对多、多对一和多对多的通信方式。
9,在网站上输入www.baidu.com,服务器是如何返回页面的?
当你在浏览器中输入 www.baidu.com 并按下回车后,浏览器会执行以下步骤来获取并显示页面:
-
DNS解析:浏览器首先会将域名 www.baidu.com 解析为相应的IP地址。通常情况下,浏览器会首先查找本地DNS缓存,如果找不到,则向本地DNS服务器发送DNS查询请求。本地DNS服务器可能会将请求转发给根域名服务器、顶级域名服务器、权威域名服务器等,直到找到与 www.baidu.com 相关联的IP地址。
-
建立TCP连接:一旦浏览器知道了 www.baidu.com 的IP地址,它将与该IP地址的服务器建立TCP连接。这通常涉及到三次握手过程,确立客户端与服务器之间的可靠连接。
-
发送HTTP请求:一旦TCP连接建立起来,浏览器将向服务器发送一个HTTP请求,请求获取网页的内容。这个请求中包含了一些信息,如请求方法、路径、请求头等。
-
服务器处理请求:服务器收到来自浏览器的HTTP请求后,会解析该请求,并根据请求的内容做出相应的处理。在这个例子中,服务器会寻找请求的资源(比如首页),生成相应的HTML页面。
-
服务器返回响应:服务器将处理后的网页内容封装在HTTP响应中,并发送回浏览器。这个响应包含了状态码(比如200表示成功)、响应头和实际的网页内容等信息。
-
浏览器渲染页面:浏览器收到来自服务器的HTTP响应后,会解析响应,根据HTML、CSS、JavaScript等内容来渲染页面。最终呈现给用户的是经过渲染后的网页内容。
-
关闭TCP连接:一旦页面渲染完成,浏览器会关闭与服务器之间的TCP连接,释放资源。
10,如何进行域名解析的?
域名解析是将人类可读的域名转换为计算机可识别的IP地址的过程。这个过程通常由域名系统(DNS)来完成。以下是进行域名解析的一般步骤:
-
本地DNS缓存查询:当你输入一个域名时,首先会检查你的操作系统是否有该域名的解析结果的缓存。如果之前已经解析过该域名,且缓存中的记录仍然有效(未过期),那么系统会直接使用缓存的结果。
-
向本地DNS服务器查询:如果本地缓存中不存在或者已经过期,操作系统会将域名查询请求发送给本地DNS服务器。通常,这个本地DNS服务器由你的网络服务提供商(如电信、移动、联通等)或者你所连接的网络环境(如公司、学校等)提供。
-
递归查询过程:如果本地DNS服务器缓存中没有该域名的解析结果,它会开始进行递归查询。它首先向根域名服务器发送查询请求,询问该域名的顶级域名服务器(如.com、.net、.org等)的IP地址。
-
迭代查询过程:一旦本地DNS服务器收到根域名服务器的响应,它就会向顶级域名服务器发送查询请求,询问域名的权威域名服务器(即负责管理该域名的服务器)的IP地址。
-
获取目标域名的IP地址:当本地DNS服务器收到权威域名服务器的响应后,它会从中获取到目标域名的IP地址,并将这个解析结果返回给操作系统。
-
缓存解析结果:本地DNS服务器会将获取到的解析结果缓存一段时间,以便下次有相同的查询时能够直接返回结果,避免重复的解析过程。
-
返回解析结果:操作系统收到来自本地DNS服务器的解析结果后,会将其返回给应用程序(如浏览器),应用程序就可以使用这个IP地址来与目标服务器建立连接。
11,Linux是必修吗?
12,了解raid吗?
13,说一下raid5是什么。
RAID 5(冗余独立磁盘阵列级别5)是一种磁盘阵列配置方案,它提供了数据冗余和性能增强的功 能。RAID 5通常由至少三块磁盘组成,其中一个磁盘用于存储奇偶校验信息。简单来说,RAID 5通过将数据和奇偶校验信息分布存储在多个磁盘上,实现了数据的冗余和性能提升。
以下是RAID 5的主要特点:
-
数据冗余:RAID 5通过分布式存储奇偶校验信息来实现数据的冗余。当其中一块磁盘发生故障时,系统可以根据剩余的数据和奇偶校验信息来恢复丢失的数据,从而保证了数据的完整性和可靠性。
-
性能提升:RAID 5通过将数据分布存储在多个磁盘上,并充分利用并行读写的能力,实现了性能的提升。在典型的RAID 5配置中,数据被分成多个块,并且每个块被写入不同的磁盘上,从而提高了并行处理能力。
-
容量利用率:RAID 5的容量利用率较高,因为只需要一个磁盘的空间用于存储奇偶校验信息,而剩下的磁盘空间都可以用于存储数据。这使得RAID 5成为了一种经济有效的数据保护和存储方案。
14,写一下shell脚本,一个文件,test.txt,每行一个数字,求这些数的累加和。
#!/bin/bash awk ' { sum += $1 } END { print "累加和为: " sum } ' test.txt
15,下来来问问三剑客吧,我看你简历上有写,查询/data下的以*.log结尾的建立时间大于5天,大小大于20M的文件并删除。
find /data -type f -name "*.log" -size +20M -ctime +5 -exec rm {} \;
16,敲命令:输出一个文件的第5000行
sed -n '5000p' test.txt
17,敲命令:求一个文件,test.txt的倒数第二行的每个数的和,并输出,以空格为分隔符。
tail -n 2 test.txt | head -n 1 | awk '{ sum=0; for(i=1;i<=NF;i++) sum+=$i; print sum }'awk '{ sum=0; for(i=1;i<=NF;i++) sum+=$i } END { print sum }' <(tail -n 2 test.txt | head -n 1)
18,敲命令:一个文件内容是
{
a bb ccc dddd a bb ccc a
}
求各个单词出现的次数,任用语言
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MAX_WORD_LEN 100 int main() {char filename[] = "input.txt"; // 输入文件名FILE *file = fopen(filename, "r"); // 打开文件 if (file == NULL) {fprintf(stderr, "无法打开文件 %s\n", filename);return 1;} char word[MAX_WORD_LEN];int count = 0;int word_count = 0;int in_word = 0; // 读取文件内容while (fscanf(file, "%s", word) != EOF) {int len = strlen(word); // 去除标点符号并转换为小写for (int i = 0; i < len; i++) {if (ispunct(word[i])) {word[i] = ' ';} else {word[i] = tolower(word[i]);}} // 根据空格判断是否是一个单词的结尾for (int i = 0; i < len; i++) {if (word[i] == ' ') {if (in_word) {word_count++;in_word = 0;}} else {in_word = 1;}} // 处理最后一个单词if (in_word) {word_count++;in_word = 0;}} // 输出结果printf("单词出现次数:%d\n", word_count); // 关闭文件fclose(file);return 0; }
19,敲命令:一个列表,例如:[1,3,2,4,5,3,2,1,6,4,2,1]。求列表中下表和为7的数的下标。任用语言
#include <stdio.h> int main() {int nums[100]; // 假设最多输入100个数int n; // 提示用户输入列表长度printf("请输入列表长度:");scanf("%d", &n); // 提示用户输入列表元素printf("请输入列表元素(用空格分隔):");for (int i = 0; i < n; i++) {scanf("%d", &nums[i]);} // 找出列表中下标和为7的数的下标printf("列表中下标和为7的数的下标为:\n");for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {if (nums[i] + nums[j] == 7) {printf("[%d, %d]\n", i, j);}}} return 0; }
20,需要在10000台机子上执行命令,你会怎么办?
最好的方式是使用配置管理工具或者批量管理工具,例如Ansible
21,如果每台机子的密码都不同,你要怎么做?
可以通过在Ansible的inventory文件中为每台主机指定用户名和密码来实现。 以下是一个示例的Ansible inventory文件,其中每台机器都指定了不同的用户名和密码:
[all] host1 ansible_user=user1 ansible_ssh_pass=password1 host2 ansible_user=user2 ansible_ssh_pass=password2 host3 ansible_user=user3 ansible_ssh_pass=password3 ...
然后,你可以使用Ansible Ad-hoc命令或者Playbook来在所有主机上执行命令,如下所示:
ansible all -i inventory_file -m shell -a "your_command_here"
22,敲命令:用Ansible,在指定机子上执行一个命令,指定为shell模块
ansible all -m shell -a "echo 123"
23,说一下你知道的Ansible的模块。
Ansible拥有丰富的模块,可以用于执行各种不同的任务。以下是一些常用的Ansible模块:
-
command模块:用于在目标主机上执行任意的命令。
-
shell模块:与command模块类似,用于在目标主机上执行Shell命令,但可以使用管道、重定向等Shell特性。
-
copy模块:用于将本地文件复制到目标主机上。
-
fetch模块:用于从目标主机上复制文件到本地。
-
template模块:用于在目标主机上渲染Jinja2模板文件。
-
file模块:用于在目标主机上创建、删除、修改文件和目录。
-
service模块:用于启动、停止、重新启动服务。
-
yum/apt模块:用于在目标主机上安装、更新、删除软件包。
-
user/group模块:用于在目标主机上创建、删除用户和用户组。
-
cron模块:用于管理定时任务。
24,我看你的项目都是有关Kubernetes的,那接下来问问k8s的吧!
25,说一下如果要创建一个pod,都要经历什么过程?
-
用户提交创建Pod的请求:用户通过kubectl或者其他Kubernetes API工具向API Server提交创建Pod的请求,请求中包含了Pod的配置信息,如名称、容器镜像、端口映射等。
-
API Server接收请求:API Server接收到用户的创建Pod请求后,会进行权限验证和请求合法性检查。
-
Scheduler选择合适的节点:API Server将合法的创建Pod请求转发给Scheduler进行调度。Scheduler根据Pod的调度需求和集群的状态,选择一个合适的节点来部署Pod。
-
分配节点资源:Scheduler选择节点后,将Pod的调度信息更新到API Server中。API Server将Pod的信息发送给选择的节点上的kubelet。
-
kubelet创建Pod:选定的节点上的kubelet接收到API Server的请求后,开始创建Pod。kubelet根据Pod配置文件中定义的容器镜像等信息,拉取镜像并创建容器。
-
更新Pod状态:Pod创建完成后,kubelet将Pod的状态报告给API Server。API Server更新Pod的状态为Running,并分配Pod的IP地址。
-
容器启动:Pod创建成功后,容器开始启动,并开始执行定义的任务。
-
监控和维护:Kubernetes的Controller Manager中的控制器会持续监控集群中的Pod状态,并根据需要进行调整和维护,确保Pod的副本数量符合用户的期望值,并处理节点故障等情况。
26,k8s中用于存储信息的是什么?
在Kubernetes中,用于存储信息的主要组件是etcd
。etcd
是一个高可用的分布式键值存储数据库,它被设计用于保存集群的配置信息、状态和元数据。
27,说一下相同node上的不同pod中的container,相同node上的相同pod中的container,不同node上的pod上的container之间是怎么通信的?
在Kubernetes中,Pod是最小的部署单元,而容器则是Pod的实际运行载体。当在同一Node上的不 同Pod中的容器需要进行通信时,它们可以通过网络相互通信,这是因为它们共享同一个Node网络命 名空间。具体来说,在同一Node上的不同Pod中的容器之间通信的过程如下:
-
共享网络命名空间:Kubernetes中的Pod中的所有容器共享相同的网络命名空间。这意味着它们拥有相同的网络接口、IP地址和端口空间,它们可以直接通过本地网络接口进行通信。
-
IP地址和端口:每个Pod都会被分配一个唯一的IP地址,并且Pod中的每个容器都可以使用这个IP地址和Pod内部的端口进行通信。
-
本地通信:当同一Node上的不同Pod中的容器需要进行通信时,它们可以直接使用Pod的IP地址和容器之间的端口来进行通信。这些通信在Node内部进行,不需要经过网络。
而当在同一Node上的相同Pod中的容器需要进行通信时,由于它们在同一个Pod中,它们可以通过 本地主机的回环接口(localhost)进行通信。这种通信是非常高效的,因为它们共享同一个进程命名 空间,可以直接通过本地主机的网络接口进行通信,而不需要经过网络。而当不同Node上的Pod中的 容器需要进行通信时,则需要通过网络进行通信。在这种情况下,Kubernetes会使用其内置的网络插 件(如Flannel、Calico等)来实现跨Node的容器网络通信。通常情况下,Kubernetes集群中的每个 Node都会有一个Pod网络,Pod中的容器可以通过这个网络互相通信,而不同Node上的Pod之间则通 过路由和网络转发来实现通信。
28,情景模拟:如果一台node出现故障,说一下这台node上的pod是如何被驱逐出这台node的?
-
节点失联检测:Kubernetes的控制平面(包括API Server和Controller Manager)会定期检测集群中各个节点的健康状态。一旦发现某个节点失联(例如,节点宕机或网络故障),控制平面会将该节点标记为不可用。
-
调度器触发Pod Eviction:调度器收到节点失联的通知后,会触发Pod Eviction机制。调度器会检查在该节点上运行的所有Pod,并确定哪些Pod需要被驱逐出该节点。
-
优雅驱逐:对于需要被驱逐的Pod,Kubernetes会向它们的容器发送终止信号(SIGTERM),通知它们进行优雅关闭。Pod中的容器在接收到SIGTERM信号后,会有一定的时间(默认为30秒)来完成正在进行的任务,并准备停止。
-
强制驱逐:如果在优雅终止期内,容器没有成功停止,或者超过了优雅终止期,Kubernetes会发送强制终止信号(SIGKILL)给容器,强制停止它们。这样可以确保Pod中的容器被完全终止,避免资源泄漏和性能问题。
-
Pod重新调度:一旦Pod中的所有容器都被成功驱逐出该节点,Pod会被标记为未调度,并重新调度到其他可用的节点上。调度器会根据Pod的调度需求和集群的状态,选择一个合适的节点来重新部署Pod,以确保应用程序的高可用性和稳定性。
29,谁监控pod的健康状态?
-
Kubelet:Kubelet是每个节点上运行的代理程序,负责管理节点上的Pod和容器。Kubelet会定期检查节点上运行的所有Pod和容器的健康状态,并将这些信息报告给API Server。如果发现Pod或容器出现故障,Kubelet会尝试自动恢复它们,例如重启容器或者重新调度Pod到其他节点。
-
Kubernetes API Server:API Server是Kubernetes集群的入口,负责接收来自用户和其他组件的请求,并将这些请求转发给其他组件进行处理。API Server会定期从各个节点的Kubelet中收集健康状态信息,并维护集群中所有Pod的状态。它还会通过调度器和控制器来管理Pod的创建、调度和维护。
-
Controller Manager:Controller Manager包含了多个控制器,负责监控集群中的各种资源状态,并根据需要进行调整和控制。其中一个重要的控制器是Replication Controller或者ReplicaSet控制器,它负责确保Pod的副本数量符合用户的期望值,当节点上的Pod出现故障时,会自动创建新的Pod来替代。
-
kube-state-metrics:kube-state-metrics是Kubernetes社区维护的一个开源项目,用于将Kubernetes集群中的各种资源状态导出为Prometheus格式的指标。通过监控这些指标,可以了解集群中Pod的健康状态、资源利用率等信息。
30,我看你简历上有写MYSQL,那就写一段SQL语句,查询一个表内第二大的ID。
SELECT MAX(id) AS second_largest_id FROM your_table WHERE id < (SELECT MAX(id) FROM your_table);
31,MYSQL如何做主从同步的?
-
确认主数据库(master)的服务器 ID。在主数据库的 MySQL 配置文件中(my.cnf 或 my.ini)设置 server-id 属性。例如,将其设置为 1。
-
确认主数据库的二进制日志文件名和位置。在主数据库的 MySQL 配置文件中设置 log-bin 属性。例如,将其设置为 mysql-bin。
-
创建用于复制的 MySQL 用户。在主数据库上执行以下命令:
CREATE USER 'repl'@'slave_ip_address' IDENTIFIED BY 'password'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'slave_ip_address';
其中,slave_ip_address 是从数据库(slave)的 IP 地址,password 是用于复制的密码。
-
在主数据库上执行 FLUSH TABLES WITH READ LOCK 命令,以停止对主数据库进行写操作。
-
获取主数据库状态,包括二进制日志文件名和位置。在主数据库上执行以下命令:
SHOW MASTER STATUS;
-
备份主数据库,并将备份文件复制到从数据库。
-
在从数据库(slave)的 MySQL 配置文件中设置以下属性:
server-id = 2 # 从数据库的服务器 ID,必须与主数据库不同relay-log = mysql-relay-binreplicate-do-db = my_db # 要复制的数据库名
-
在从数据库上执行以下命令:
CHANGE MASTER TOMASTER_HOST='master_host_name',MASTER_USER='repl',MASTER_PASSWORD='password',MASTER_LOG_FILE='mysql-bin.000001', # 主数据库的二进制日志文件名MASTER_LOG_POS=4; # 主数据库的二进制日志文件位置
其中,master_host_name 是主数据库的主机名或 IP 地址,password 是用于复制的密码,MASTER_LOG_FILE 和 MASTER_LOG_POS 是第 5 步中获取的值。
-
启动从数据库的复制进程:
START SLAVE;
-
检查从数据库的状态,以确保复制已成功启动:
SHOW SLAVE STATUS;
确认 Slave_IO_Running 和 Slave_SQL_Running 值都为 Yes。
-
配置完成后,从数据库将自动复制主数据库中的更改。