Linux

Linux 系统启动流程是怎样的?
  1. BIOS/UEFI 加电自检,检查 CPU、内存、硬盘、网卡等硬件是否正常;
  2. 加载 Bootloader(GRUB),包含内核镜像(vmlinuz)和 initramfs(临时根文件系统);
  3. 内核初始化,内核解压缩并加载到内存、初始化硬件驱动(存储、网络、文件系统等)、启动第一个用户空间进程(systemd);
  4. 根据 /etc/fstab 挂载磁盘分区;
  5. 启动系统服务(syslog、network、sshd)和用户空间服务(nginx、docker…);
  6. 最后进入 ssh 登录界面。

如何排查一台 Linux 服务器的负载过高问题?
  1. 首先可以通过监控面板,或登录宿主机使用 w、uptime 等命令查看 1 分钟、5 分钟、15 分钟的平均负载(load average),如果 1 分钟的平均负载偏高,有可能是瞬时的,可以继续观察,如果如果 15 分钟的平均负载也高,则需要继续排查;
    • 平均负载 > CPU核心数 = 高(CPU 和 IO 的排队时间)
  2. 使用 top、ps、iotop、nethogs 等命令获取占用 CPU 或 IO 高的进程;
  3. 最后通过查看服务日志、系统日志、内核日志等方式排查是否有报错。
    • 系统日志:/var/log/syslog(Ubuntu)、/var/log/messages(CentOS)。
    • 内核日志可以使用 dmesg 查看(重点关注 I/O error、OOM killer)。

请解释 top 命令输出中 load average 的含义。
  • top 的 load average 表示在过去 1、5、15 分钟内,系统中处于运行态(R,正在运行或等待 CPU)和不可中断睡眠态(D,等待 I/O)的进程的平均数量;
  • 是否算高要结合 CPU 核心数来看,正常应该 load < CPU 核数,超过太多说明有性能瓶颈。

如何查看和分析内存使用情况?
  • free -h 查看内存和SWAP的总体使用情况,还可以使用 top 命令 + M 按内存使用率排序。

硬盘空间满了你会如何排查?
  1. 先使用 df -h 查看是哪块磁盘满了,以及对应的挂载点;
  2. 然后使用 du -sh /挂载点/*,逐级定位是哪个目录或者文件占用空间大,也可以使用find / -xdev -type f -size +1G 搜索大于指定大小的文件;
  3. 解决方案:如果是日志等无用的文件,可以先使用>文件名立即释放磁盘空间,持久解决方案可以选择使用逻辑卷扩展。其他的优化手段,比如减少程序的日志写入量等;
  4. 还可使用 lsof | grep 文件名 来定位文件对应的进程。

*磁盘空间还有,但数据无法写入是什么原因?
  • inode 用尽,可以使用 df -i 检查;
  • 文件系统只读,可以使用 mount | grep 挂载点 检查,ro 表示只读,rw 读写;
  • 用户没有写权限。

删除文件后,磁盘空间并未释放,为什么?
  • 是因为这个文件的 inode 仍然被其他进程持有,可以使用 lsof | grep 文件名 定位到进程后重启进程。

你如何查看某个进程打开了哪些文件?
  • 可以使用 lsof -p <PID> 查看进程打开的所有文件。

软链接和硬链接的区别?
  • 软连接相当于Windows下的快捷键方式,而硬链接本质上是同一个文件;
  • 软连接与源文件的 inode 不同,而硬链接与源文件的 inode 是相同的;
  • 软链接可跨分区,硬链接不可以;
  • 源文件删除,软链接不可访问,硬链接可以;
  • 软链接可以对文件、目录创建,而硬链接只能针对文件。

你如何限制某个用户的资源使用(CPU、内存等)?
  • 可以用 ulimit 限制用户的 CPU 时间、内存、进程数和打开文件数;更精细的可以用 cgroups 限制 CPU、内存、IO;如果是 systemd 管理的服务,也可以在 service 文件里配置 CPUQuota 和 MemoryMax。

什么是文件描述符?如何查看和调整目前文件描述符的限制量?
  • 文件描述符是一个非负整数,用于标识进程打开的文件或 I/O 资源(包括普通文件、目录、设备、管道、socket 等)。
  • 查看进程打开的文件描述符,有两种方案,一种是 ls -l /proc/<pid>/fd,另一种是 lsof -p <pid>。在较新的系统中,比如 Ubuntu 2404,还可以使用 lsfd 命令查看。
  • 如果程序打开文件过多导致 “too many open files” 错误,可以通过 ulimit 临时调整上限,或编辑 /etc/security/limits.conf 永久修改。
    • 临时查看进程能打开的文件描述符上限:ulimit -n
    • /etc/security/limits.conf 中的软/硬限制含义:硬限制(hard)表示最高能开多高,软限制(soft)当前用户可调整的数量,但不能超过硬限制。

Linux 系统级优化你做过哪些?

内核参数级优化(通过 sysctl 或 /etc/sysctl.conf 配置,然后通过 sysctl -p 生效。):

net.ipv4.tcp_max_tw_buckets = 65536  # 减少TIME_WAIT连接
net.ipv4.tcp_tw_reuse = 1  # 复用TIME_WAIT连接
net.ipv4.tcp_fin_timeout = 30  # 缩短FIN等待时间
net.core.somaxconn = 65535  # 监听队列最大值

其他系统资源/环境级优化(配置文件、资源限制、包管理等):

  • apt/yum 源指向内部仓库或国内镜像站。
  • 修改打开文件描述符的最大数量(通常软硬限制都设置为 65535)。
  • 时间同步,ntp源指向内部或国内NTP服务器。
  • 服务器多 CPU 场景下,调整 NUMA node ,让 CPU 优先访问本地内存,以避免跨 NUMA 节点的远程内存访问带来的延迟损耗。
    • 一般通过 BIOS/UEFI 配置调整。
    • 假设服务器 2 个 CPU,每个 8 核,512 GB 内存。CPU 0-7 属于 node 0,CPU 8-15 属于 node 1,给每个 NUMA 节点 256 GB 内存。
    • 可以用 numactl -Hnumastat -mlscpu 查看目前 NUMA 分配情况。
  • 关闭 Swap、SELinux

SQL

练习表
  • 在数据库中执行该sql语句,创建练习表
-- 创建部门表
CREATE TABLE departments (
    department_id INT PRIMARY KEY,
    department_name VARCHAR(100) NOT NULL
);

-- 插入部门数据
INSERT INTO departments VALUES
(1, 'Engineering'),
(2, 'Human Resources'),
(3, 'Marketing'),
(4, 'Finance');

-- 创建员工表
CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    gender CHAR(1),
    hire_date DATE,
    department_id INT,
    FOREIGN KEY (department_id) REFERENCES departments(department_id)
);

-- 插入员工数据
INSERT INTO employees VALUES
(101, 'Alice', 'Smith', 'F', '2015-03-01', 1),
(102, 'Bob', 'Johnson', 'M', '2017-07-15', 1),
(103, 'Carol', 'Williams', 'F', '2019-01-10', 2),
(104, 'David', 'Brown', 'M', '2018-11-23', 3),
(105, 'Eve', 'Davis', 'F', '2020-06-17', 4);

-- 创建薪资表
CREATE TABLE salaries (
    salary_id INT PRIMARY KEY,
    employee_id INT,
    salary DECIMAL(10,2),
    from_date DATE,
    to_date DATE,
    FOREIGN KEY (employee_id) REFERENCES employees(employee_id)
);

-- 插入薪资数据
INSERT INTO salaries VALUES
(1, 101, 80000, '2020-01-01', '2021-12-31'),
(2, 101, 85000, '2022-01-01', '9999-12-31'),
(3, 102, 75000, '2019-01-01', '9999-12-31'),
(4, 103, 60000, '2019-01-10', '9999-12-31'),
(5, 104, 72000, '2018-11-23', '9999-12-31'),
(6, 105, 68000, '2020-06-17', '9999-12-31');

-- 创建项目表
CREATE TABLE projects (
    project_id INT PRIMARY KEY,
    project_name VARCHAR(100),
    start_date DATE,
    end_date DATE
);

-- 插入项目数据
INSERT INTO projects VALUES
(1, 'Project Apollo', '2021-01-01', '2021-12-31'),
(2, 'Project Zephyr', '2022-03-01', NULL),
(3, 'Project Orion', '2020-06-01', '2021-06-30');

-- 创建员工-项目关系表(多对多)
CREATE TABLE employee_projects (
    employee_id INT,
    project_id INT,
    role VARCHAR(50),
    PRIMARY KEY (employee_id, project_id),
    FOREIGN KEY (employee_id) REFERENCES employees(employee_id),
    FOREIGN KEY (project_id) REFERENCES projects(project_id)
);

-- 插入员工项目关系数据
INSERT INTO employee_projects VALUES
(101, 1, 'Developer'),
(101, 2, 'Lead Developer'),
(102, 1, 'Tester'),
(103, 2, 'HR Manager'),
(104, 3, 'Marketing Lead'),
(105, 2, 'Accountant');

练习题 1:查询所有员工的姓名及其所在部门名称
  • 查询每位员工的 first_name、last_name 和其对应的 department_name。
SELECT e.first_name, e.last_name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id;

练习题 2:查询当前薪资最高的员工信息
  • 找出当前薪资(to_date = ‘9999-12-31’)最高的员工的姓名和薪资。
SELECT e.first_name, e.last_name, s.salary
FROM salaries s
JOIN employees e ON s.employee_id = e.employee_id
WHERE s.to_date = '9999-12-31'
ORDER BY s.salary DESC
LIMIT 1;

练习题 3:查询每个部门的平均薪资
  • 统计每个部门当前员工的平均薪资。
SELECT d.department_name, AVG(s.salary) AS average_salary
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN salaries s ON e.employee_id = s.employee_id
WHERE s.to_date = '9999-12-31'
GROUP BY d.department_name;

练习题 4:查询参与了“Project Zephyr”的员工及其角色
  • 列出参与了名为“Project Zephyr”的员工的姓名和他们的角色。
SELECT e.first_name, e.last_name, ep.role
FROM employee_projects ep
JOIN employees e ON ep.employee_id = e.employee_id
JOIN projects p ON ep.project_id = p.project_id
WHERE p.project_name = 'Project Zephyr';

练习题 5:查询至少参与了两个项目的员工
  • 列出参与两个或以上项目的员工的姓名和项目数量。
SELECT e.first_name, e.last_name, COUNT(ep.project_id) AS project_count
FROM employee_projects ep
JOIN employees e ON ep.employee_id = e.employee_id
GROUP BY e.employee_id
HAVING COUNT(ep.project_id) >= 2;

练习题 6:查询“Engineering”部门的所有员工当前薪资
  • 显示 Engineering 部门所有员工的姓名及其当前薪资。
SELECT e.first_name, e.last_name, s.salary
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN salaries s ON e.employee_id = s.employee_id
WHERE d.department_name = 'Engineering'
  AND s.to_date = '9999-12-31';

练习题 7:查询所有项目的负责人(Lead Developer 或 Manager)
  • 列出所有项目的名称、员工姓名及他们担任的领导角色(如包含“Lead”或“Manager”的角色)。
SELECT p.project_name, e.first_name, e.last_name, ep.role
FROM employee_projects ep
JOIN employees e ON ep.employee_id = e.employee_id
JOIN projects p ON ep.project_id = p.project_id
WHERE ep.role LIKE '%Lead%' OR ep.role LIKE '%Manager%';

练习题 8:查询未参与任何项目的员工
  • 列出没有参与任何项目的员工。
SELECT e.first_name, e.last_name
FROM employees e
LEFT JOIN employee_projects ep ON e.employee_id = ep.employee_id
WHERE ep.project_id IS NULL;

网络

主机网络不通,如何排查?
  1. 首先可以查看IP、子网掩码、网关、路由配置是否正确,相关的排查命令有ip、ping、traceroute;
  2. 然后还可以看防火墙策略是否对其限制,并结合tcpdump抓包测试;
  3. 最后可以看网卡、网线、路由器、交换机等硬件设备是否工作正常。

*访问一个网站背后的过程?
  1. 首先通过DNS解析,将域名解析为对应的IP地址,解析顺序依次为 “浏览器缓存” → “本地 hosts 文件” → “递归查询(本地 DNS)” → “迭代查询(根→顶级→权威)”;
  2. 获取到IP地址后,进行TCP三次握手建立连接;
  3. 如果请求的域名是HTTPS的,客户端和服务器还会通过 TLS 握手 建立加密通道,握手过程包括证书验证、密钥协商等;之后所有 HTTP 报文将通过 TLS 进行加密传输。
  4. 之后向服务端发送HTTP请求报文,请求报文中包含方法(GET/POST/PUT/DELETE等)、路径、HTTP版本号、首部字段(一组键值对,如 Host、User-Agent、Accept 等 )、请求体(可选,例如在 POST 请求中携带 JSON 数据);
  5. 服务端收到后,返回HTTP响应报文,其中包含版本号、状态码、短语、首部字段(Content-Type、Server等)、空行、数据实体;

DNS解析流程?
  • 将域名解析为对应的IP地址,解析顺序依次为 “浏览器缓存” → “本地 hosts 文件” → “递归查询(本地 DNS)” → “迭代查询(根→顶级→权威)
  • DNS相关的测试工具有 dig、nslookup

什么是递归查询?什么是迭代查询?
  • 假设宿主机的 DNS 服务器指向了 223.5.5.5(阿里云DNS),本机向这个 DNS 服务器发起的查询就是递归查询;
  • 而这个DNS服务器(223.5.5.5),如果没有命中缓存,它会向根服务器、顶级服务器、权威服务器发起的查询,就叫迭代查询。

迭代查询的细节简述?
  • 访问 www.baidu.com 时,如果本地 DNS 没有缓存,它会向根服务器查询,根服务器返回 .com 的 DNS 地址;
  • 接着去问 .com 顶级域服务器,它告诉你 baidu.com 的权威服务器地址;
  • 最后向权威服务器请求 www.baidu.com 的 IP,获取成功后返回给客户端。这个过程就是迭代查询。

*TCP三次握手的过程?
  • 第一次握手(SYN):客户端向服务器发送一个 SYN。此时,客户端进入 SYN_SENT 状态;
  • 第二次握手(SYN-ACK):服务器收到客户端的 SYN 报文后,会发送一个 SYN-ACK(同步确认)报文段作为响应。此时,服务器进入 SYN_RCVD 状态;
  • 第三次握手(ACK):客户端收到服务器的 SYN-ACK 报文后,发送一个 ACK(确认)报文段作为最终确认。此时,客户端进入 ESTABLISHED 状态。服务器收到客户端的 ACK 后也进入 ESTABLISHED 状态,连接正式建立。

*TCP和UDP的区别?
  • 连接与可靠性:TCP是面向连接的,会通过三次握手、流量和拥塞控制、重传等机制使传输更可靠 ;而UDP仅提供最基本的数据传输能力,只管发送,不管对方是否收到。
  • 传输速度:UDP要高于TCP。
  • 首部结构:
    • TCP首部最小为20字节,最大为60字节(其中包括源端口、目标端口、序列号、确认号、6个标志位、效验和、滑动窗口、紧急指针、数据实体等)
    • UDP首部为8个字节(其中包括:源端口、目标端口、长度、效验和、数据实体)
  • 通信方式:TCP 仅支持一对一通信(因为只能和一台主机建立三次握手);UDP支持一对一、一对多的方式通信。
  • 应用场景:TCP 适合下载文件等对数据传输可靠性要求高的场景;而 UDP 更多的用于在线视频、语音等对数据实时传输效率要求高的场景,像 DNS、DHCP 协议是基于 UDP 的。

OSI七层模型指的是哪几层?分别有什么协议?
  • xxx

常见服务的端口号
  • 未特别说明的,均为TCP,但有些服务,既支持UDP,又支持TCP
    PortService
    20ftp-data
    21ftp
    22ssh
    23telnet
    25smtp
    53/udpdns
    67/udpdhcp
    68/udpdhcp-client
    69/udptftp
    80http
    110pop3
    119nntp
    123/udpntp
    443https
    465smtps
    514/udpsyslog
    873rsync
    995pop3s
    1521oracle
    2049nfs
    3306mysql
    3389rdp
    5432postgresql
    5672RabbitMQ
    6379redis
    8080tomcat
    9092Kafka
    9200elasticsearch
    11211memcached

监控与告警

Prometheus 主要由哪些组件组成?
  • Prometheus Server:负责数据采集、存储和查询。
  • Exporter:指标暴露器,负责把应用/系统的监控数据转成 Prometheus 能识别的格式。
    • Node Exporter:采集主机 CPU、内存、磁盘、网络等系统指标
    • cAdvisor:采集容器运行时的资源指标
    • MySQL/Redis/Kafka Exporter:采集中间件运行指标
  • Pushgateway:用于 短生命周期任务 或 无法被主动拉取的任务。用于 短生命周期任务 或 无法被主动拉取的任务。
    • 场景:一次性批处理任务(job 运行几秒就结束,Prometheus 来不及拉取)。Job 可以把指标主动 推送(push) 给 Pushgateway,Prometheus 再去拉取 Pushgateway。
  • Alertmanager:处理告警通知。
    • 去重(避免重复通知)
    • 分组(相似告警合并)
    • 抑制(例如主机宕机时抑制其子服务告警)
    • 静默(临时屏蔽某些告警的通知)
    • 路由(邮件、Slack、钉钉、企业微信等)
  • Grafana(可选,用于可视化)

Prometheus 的数据模型是什么?

Prometheus 使用多维数据模型,每个时间序列由以下部分组成:

  • 指标名称(Metric Name):说明“监控的是什么”。(如 http_requests_total)。
  • 标签(Labels):区分相同指标的不同维度。(如 method=“GET”、status=“200”)。
  • 时间戳(Timestamp):表示采样的时间点。
  • 值(Value):表示该时间点的数值。

如何监控 K8s 集群?
  • 通常的方案是 Prometheus + Grafana + Alertmanager,Prometheus作为时序数据库采集指标数据,Grafana 基于 Prometheus 的指标进行图形展示,Alertmanager 实现告警;
  • 还可以通过 KubeSphere、Rancher 等 K8s 管理平台实现监控,这些平台都集成了监控告警功能;
  • 常见的监控指标:
    • Node:CPU、内存、磁盘使用率、磁盘IO
    • Pod/容器:CPU、内存使用情况
    • Pod 状态:Running、Pending、CrashLoopBackOff 等
    • API Server 的每秒请求数、请求延迟
    • 网络流量和带宽使用情况
    • 存储类的使用情况

如何监控应用程序?
  • Prometheus + 第三方或程序内部集成的  /metrics 端点。

如何设计一个有效的监控系统?
  • 全面覆盖:监控系统应覆盖所有关键组件,包括服务器、网络设备、数据库、应用层等。
  • 多维度监控:不仅要监控硬件资源(如CPU、内存、磁盘),还要监控应用性能(如请求延迟、错误率)和服务健康状态(如服务可用性)。
  • 实时性:监控数据应尽可能实时更新,以便及时发现问题。
  • 告警机制:设置合理的告警阈值和通知渠道(如邮件、短信、Slack等),确保问题能够被及时发现和处理。
  • 可视化:通过仪表盘展示关键指标,便于快速了解系统状态。
  • 历史数据分析:保留历史数据,便于分析趋势和排查问题。

如何设置合理的告警阈值?
  • 基于历史数据:分析历史数据,了解系统的正常运行范围,确定合适的阈值。
  • 区分紧急和非紧急告警:对于影响用户体验的关键指标(如请求失败率),设置较为严格的阈值;对于次要指标(如磁盘使用率),可以适当放宽。
  • 动态调整:随着系统负载的变化,定期调整告警阈值,确保其始终处于合理范围内。
  • 避免误报:设置合理的触发条件,避免频繁的误报。例如,可以通过多次采样确认异常后再触发告警。

CI/CD

容器

*容器与虚拟机的区别?
  • 容器使用宿主机的内核,而每个虚拟机都有自己独立的内核。
  • 容器更加轻量,迁移和部署都比虚拟机更加方便,并且启动速度也要比虚拟机快。
  • 容器的隔离性不如虚拟机,因为容器是公用宿主机的内核 + 通过内核的 namespace 实现隔离。

namespace 有哪些?
  • PID namespace:隔离进程 ID(每个 namespace 中的进程看到的 PID 是独立的)
  • Network namespace:隔离网络资源(如网卡、IP 地址、端口等)
  • Mount namespace:隔离文件系统挂载点
  • UTS namespace:隔离主机名和域名
  • User namespace:隔离用户和组 ID
  • IPC namespace:隔离进程间通信(如信号量、消息队列等)

Dockerfile 的指令有哪些?
  • FROM 指定基础镜像。
  • LABEL 给镜像打标签。
  • COPY 将宿主机文件。
  • COPY 和 ADD,都可以将宿主机的文件拷贝至容器,但 ADD 还可以将压缩包解压缩拷贝,以及从 URL 下载文件拷贝至镜像。
  • RUN 指定镜像构建时执行的shell命令,每个 RUN 指令都会在镜像中新增一层。
  • ARG 和 ENV,ARG 是 “构建时变量”,ENV 是 “运行时变量”。
  • USER 指定容器运行时的用户。
  • WORKDIR 为后续的RUN、COPY、ADD、CMD、ENTRYPOINT等指令设置工作目录”(构建和运行阶段均生效)
  • EXPOSE 声明容器运行时 “监听的端口”(仅为元数据说明,不实际映射端口)。
  • VOLUME 定义容器中的 “匿名卷”(持久化数据的目录),避免容器内的数据随容器删除而丢失。
  • ONBUILD 定义 “触发器”,当当前镜像被用作其他镜像的基础镜像时,自动执行ONBUILD后的指令。
  • STOPSIGNAL 指定容器停止时发送的系统信号(默认是SIGTERM),用于优雅关闭应用。
  • CMD 和 ENTRYPOINT,都是指定容器启动时的命令,但 ENTRYPOINT 不可变。CMD 通常作为容器启动时的参数,可以被覆盖。

Dockerfile 中的 COPY 和 ADD 有什么区别?
  • COPY 和 ADD,都可以将宿主机的文件拷贝至容器,但 ADD 还可以将压缩包解压缩拷贝,以及从 URL 下载文件拷贝至镜像。

Dockerfile 中的 CMD 和 ENTRYPOINT 有什么区别?
  • CMD 和 ENTRYPOINT,都是指定容器启动时的命令,但 ENTRYPOINT 不可变。CMD 通常作为容器启动时的参数,可以被覆盖。

使用 Dockerfile 制作镜像时,如何减少镜像的大小?
  • 使用轻量级镜像,如 alpine。
  • 清理无用的缓存文件。
  • 尽量减少 RUN 指令的使用,以减少镜像分层。
  • 使用多阶段构建,比如第一阶段使用nodejs镜像构建前端代码,第二阶段仅把前端构建结果拷贝至nginx镜像。

Overlay 与 Underlay 的区别?

Overlay 与 Underlay 的本质上都是为了解决容器跨宿主机通信的问题

  • Overlay 是在底层网络之上构建一层虚拟网络(典型代表有 Calico 的 IPIP/VxLAN 模式),来实现容器跨宿主机通信。而 Underlay 是直接使用底层网络,来实现容器跨宿主机通信( K8s 的 hostNetwork 模式)。
  • IP 方面,Overlay 网络下,容器 IP 有独立的地址段,而 Underlay 网络下,容器需要和宿主机处于同一网段。
  • 性能开销方面,Overlay 封装 / 解封装会带来少量 CPU 开销,Underlay 无封装 / 解封装过程,转发效率接近物理网络。

Docker 的网络模式有哪些?containerd呢?
  • bridge(默认),容器连接到一个虚拟网桥(docker0),容器间可互通,可通过端口映射与宿主机交互。
  • host,容器与宿主机共用网络命名空间,没有隔离,性能好但安全性低。
  • none,容器没有网络,只有 loopback。
  • container,多个容器共享同一个容器的网络命名空间。
  • overlay,用于多主机网络,常结合 Swarm 或 Kubernetes。 PS:containerd 本身不提供复杂网络模式,只负责容器运行。但它对外提供了 CNI 接口,可对接不同的网络插件。

K8s

Kubernetes 的核心组件有哪些?

Master 节点

  • API Server:提供 Kubernetes API,是集群的前端接口。
  • Controller Manager:管理各种控制器(如 Deployment、StatefulSet、DaemonSet等),确保实际状态与期望状态一致。
    • 比如:Deployment Controller 会监控实际状态,发现副本数不匹配后,会自动创建一个新的 Pod,确保实际状态与期望状态一致。
  • Scheduler:负责将 Pod 调度到合适的节点上。
  • etcd:分布式键值存储,保存集群的所有配置数据。

Worker 节点

  • Kubelet:管理节点上的 Pod,并定期向 API Server 报告 Pod 状态。
  • Kube Proxy:负责 Service 的负载均衡和流量转发,确保客户端请求的流量转发到对应的 Pod 上,有 iptables 和 IPVS 两种模式。
  • Container Runtime:运行容器的引擎(如 Docker、containerd)。

其他:

  • CoreDNS:集群内部 DNS 服务。

kubernetes 中的 Pod 是什么?
  • 在 Kubernetes 中,Pod 是最小的调度和运行单位,Pod 中可以包含一个或多个容器,这些容器共享网络和存储资源。
    • 共享网络是指 Pod 内所有容器共享同一个网络命名空间,容器之间可以通过 localhost 直接通信。
    • 共享存储是指 可以挂载同一个 Volume,多个容器可同时读写,常用于日志共享、配置共享等。

pause 容器是干嘛的??
  • 每个 Pod 启动时,都会启动一个 pause 容器,这个容器相当于是 Pod 的“底座”,为 Pod 中的其他容器提供网络、命名空间等基础环境。

Pod 运行模式?
  • 单容器应用:一个 Pod 就运行一个业务容器(最常见)。
  • Sidecar 模式:在主应用容器旁边放一个辅助容器(如日志收集、监控代理)。
  • Adapter 模式:主应用容器不变,旁边加一个数据转换容器。
  • Ambassador 模式:通过代理容器来与外部服务通信。

Pod 控制器有哪些?
  • 在 K8s 中,常见的 Pod 控制器有 Deployment、StatefulSet、DaemonSet、Job、CronJob;
  • Deployment 是 ReplicaSet 增强版,主要用于运行无状态服务。
  • StatefulSet 主要用于运行无状态服务。
  • DaemonSet 确保在集群的每个节点上都运行一个 Pod,通常用于集群级别的服务,如日志收集器、监控代理等。
  • Job 用于执行一次性任务,任务完成后 Pod 会被终止。
  • CronJob 是周期性任务,任务会定时执行。

Deployment 和 StatefulSet 有什么区别?
  • Deployment 通常用于运行无状态服务,而 StatefulSet 通常用于运行有状态服务;
  • Pod 名称方面,Deployment 是随机分配的,而 StatefulSet 有固定的名称后缀,比如-0、-1、-2;
  • 启动和删除顺序方面,Deployment 没有要求,而 StatefulSet 启动和删除都有严格的先后顺序要求;

ReplicaSet 和 Deployment 有什么区别?
  • Deployment 是 ReplicaSet 增强版,增加了滚动更新和回滚功能。

Pod 创建过程?
  1. 首先 kubectl 或其他客户端会向 kube-apiserver 发送 PodTemplate;
  2. API Server 对请求进行 认证、鉴权、准入控制;
    • 认证:你是谁?(比如通过证书验证身份)
    • 鉴权:你有没有权限做这个操作?(比如基于角色的访问控制中,Alice 是否有 “create pods” 这个权限。)
    • 准入控制:这个操作是否合法、合规?(namespace的Pod 数量、CPU、内存使用总量是否超限?PodSecurity、ResourceQuota、LimitRanger 这三种都属于准入控制器)
  3. 验证通过后,Pod 对象被转换成 json 格式存入 etcd;
  4. Controller Manager 监控到 etcd 中有新的 Pod 资源对象后,会将 Pod 状态置为 Pending;
  5. Scheduler 从 etcd 拿到 Pending 状态的 Pod 后,根据调度策略(资源量、亲和性/反亲和、污点/容忍、优先级等)选择合适的节点,把调度结果(Pod.Spec.NodeName) 通过 API Server 写回 etcd;
  6. kubelet 监听到本节点被分配了新的 Pod 后,根据 Pod 定义(PodSpec),就会开始调用 CNI 插件配置网络,CSI 插件挂载持久化存储,CRI拉镜像、启动 pause 容器和业务容器,以及启动、就绪、存活探针开始探测;
  7. 最后 kubelet 会定期向 API Server 上报 Pod 状态(Pending、Running、Succeeded、Failed…)。

Pod 删除过程?
  1. 首先 kubectl 或其他客户端向 kube-apiserver 发送 Pod 删除请求;
  2. API Server 将 Pod 标记为 Terminating 状态,并设置一个宽限期(默认30秒)。在宽限期内,kubelet 会尝试优雅地停止 Pod 中的容器;
    • 如果定义了停止前钩子(preStop Hook),会在此期间执行。
  3. 如果宽限期内容器仍未停止,kubelet 会向容器发送 9(SIGKILL) 信号,强制终止进程;
  4. 最后 kubelet 会向 API Server 报告 Pod 已终止,API Server 收到后,最终会把 Pod 对象从 etcd 中移除。

Pod 状态有哪些?
  • Pending:Pod 已创建,但还没有被调度到节点上。
  • Running:Pod 中的所有容器都已启动并运行。
  • Succeeded:在一次性任务中出现,表示任务已成功执行完毕。
  • Failed:表示 Pod 中的容器以非零状态码退出。
  • Unknown:Kubelet 无法获取 Pod 的状态。
  • Terminating:Pod 已经收到了删除请求,但还没有完全删除,正在进行资源清理和容器终止的过程。
  • CrashLoopBackOff(容器状态):表示容器启动失败并多次重启失败。

Pod 的探针有哪些?
  • Startup Probe(启动探针):检查容器是否成功启动。
  • Readiness Probe(就绪探针):检查容器是否已准备好接收流量,探测成功才会通过 Service 将流量路由到该容器。
  • Liveness Probe(存活探针):周期性检查容器是否健康。
  • PS:
    • 探测方式有三种,分别是基于命令、基于 HTTP 状态码、基于 TCP 连接。
      • 基于命令是根据命令执行的退出状态码判断是否执行成功,0表示成功,非0表示失败;
      • 基于 HTTP 状态码,2xx、3xx表示成功,否则表示失败;
      • 基于 TCP 连接,是根据能否建立 TCP 连接来判断(类似 telnet)
    • 执行顺序上,启动探针是首先执行,启动探针探测成功后,就绪和存活探针并行执行。
    • 启动探针成功后不再持续探测,存活和就绪探针会在容器运行期间进行周期性探测。

kubernetes 中的 Service 是什么?
  • kubernetes 中的 Service 是 Pod 的代理,可以为 Pod 提供一个稳定的访问入口,并且 Pod 之间还可以通过 Service 的域名进行通信;
  • Service 的代理是基于 iptables 或 ipvs 的。

Service 的类型有哪些?
  • ClusterIP(默认):提供一个仅在集群内部可访问的虚拟 IP。
  • NodePort:在每个节点上打开一个端口,通过 NodeIP:NodePort 的方式访问服务。
    • 在生成 NodePort 的同时,也会生成一个 ClusterIP。可以通过 NodeIP:NodePort 从外部访问服务;但在集群内部,依然可以通过 ClusterIP 来访问。
  • LoadBalancer:在公有云(如 AWS、GCP、Azure)中使用时,会自动创建一个云负载均衡器,将外部流量转发到 Service。常用于生产环境对外暴露服务。
    • 会生成一个 ClusterIP + NodePort,然后再由云提供商创建一个外部的负载均衡器,转发流量到 NodePort。
    • 请求流程:外部 → LoadBalancer 公网 IP → NodePort → ClusterIP → Pod。
  • ExternalName:把集群外部服务引入到集群内。

什么是 Headless Service?它与普通 Service 有什么区别?
  • Headless Service 是一种特殊的 Service 类型,它与普通的 Service 主要区别在于不分配 Cluster IP。
  • Headless Service 的核心作用在于它改变了 DNS 解析的行为。
    • 对于普通 Service:当你查询其 DNS 名称时,DNS 服务器会返回 Service 的 Cluster IP。
    • 对于 Headless Service:当你查询其 DNS 名称时,DNS 服务器会返回与该 Service 相关联的所有 Pod 的 IP 地址。
  • 说白了就是可以实现 Pod 间直接进行通信,而不使用 service 进行负载均衡,通常用于有状态服务需要通过 Pod IP 直接通信的场景。
  • 定义方式是在 Service 的 clusterIP 处定义为 None。

kubernetes 中的 Ingress 是什么?
  • “Kubernetes 中的 Ingress 是一种 API 对象,主要作用是管理集群外部到内部服务的 HTTP/HTTPS 流量路由。简单说,它就像集群的‘入口网关’,能根据域名、路径等规则,把外部请求转发到对应的内部 Service;
  • Ingress 本身只是规则的定义,必须配合 Ingress 控制器(比如 Nginx Ingress Controller)才能生效,常见的控制器有 Nginx、Traefik、Istio。

Service 和 Ingress 的区别?
  • 在 K8s 中,Service 和 Ingress 都是对外暴露流量的方式;
  • Service 是给一个或多个 Pod 提供稳定访问入口,负责四层(TCP/UDP)负载均衡,有 ClusterIP、NodePort 和 LoadBalancer 类型,适合内部访问或者简单对外暴露;
  • Ingress 是给一个或多个 Service 提供稳定访问入口,负责七层(HTTP/HTTPS)路由规则,需要依赖 Ingress Controller,比如 Nginx、Traefik、Istio,支持基于域名和路径的流量分发,还可以配置 TLS;
  • 简单来讲,Ingress 通过七层代理转发到 Service,Service 通过四层代理转发到Pod。
外部请求 → Ingress Controller → Service → Pod

kubernetes 中的 Namespace 是什么?
  • Namespace 实现了 K8s 中各种资源的逻辑隔离;
  • 默认的 Namespace 有 default、kube-system、kube-public、kube-node-lease。
    • kube-system 下默认运行了coredns、etcd、apiserver、controller-manager、kube-proxy、scheduler。

kubernetes 中的 Configmap 和 Secret 是什么?
  • Configmap:用于存储非敏感的配置数据(如环境变量、配置文件)。
  • Secret:用于存储敏感数据(如密码、密钥),内容经过 Base64 编码。

k8s 中 StorageClass、PV、PVC的关系是?
  • 这三个是 K8s 中最常用的持久化存储解决方案,可以实现静态或动态供应持久化存储资源;
  • 静态供应(Static Provisioning)
    1. 管理员手动创建好 PV;
    2. 用户创建 PVC;
    3. 系统自动将 PVC 和符合条件的 PV 绑定;
    4. StorageClass 可选。
  • 动态供应(Dynamic Provisioning)
    1. 用户创建 PVC,并指定 StorageClass;
    2. StorageClass 的 Provisioner 插件会自动创建一个 PV,并且 PVC 会自动绑定这个 PV;
    3. 这是现代集群更常用的方式。

kubernetes 中的 Volume 有哪些?
  • 临时卷:
    • emptyDir:在 Pod 被分配到节点时创建,生命周期与 Pod 一致。当 Pod 从节点移除时,emptyDir 中的数据会被永久删除。常用于 Pod 内多个容器之间共享数据。
  • 持久卷:
    • PersistentVolume(PV):由管理员配置的集群级存储资源,独立于 Pod 生命周期。
    • PersistentVolumeClaim(PVC):由用户申请的存储资源,类似 “存储需求订单”,Kubernetes 会自动匹配满足条件的 PV。
  • 本地存储卷
    • hostPath:宿主机的文件系统路径直接挂载到 Pod 中。
    • local:与 hostPath 类似,但更强调稳定性,需要显式指定节点亲和性,适用于需要高性能本地存储的场景(如数据库)。
  • 配置类卷:
    • Configmap:用于存储非敏感的配置数据(如环境变量、配置文件)。
    • Secret:用于存储敏感数据(如密码、密钥),内容经过 Base64 编码。
    • downwardAPI:将 Pod 或容器的元数据(如 Pod 名称、IP、标签等)以文件形式暴露给容器。
  • 网络存储卷
    • nfs:挂载 NFS(网络文件系统)共享目录,适用于需要多节点共享数据的场景。

K8s 如何实现滚动更新?
  • 通过 Deployment 的 strategy 字段定义滚动更新策略,并通过 maxUnavailable、maxSurge 控制速率。
    • maxUnavailable 表示升级时最多有几个 Pod 不可用。
    • maxSurge 表示升级时最多比期望副本数多出的 Pod 数量。
  • 最常见配置(高可用):maxUnavailable = 0,maxSurge = 1,先多启动一个新 Pod,确认可用后再删旧的,不会出现服务空档。

K8s 如何实现蓝绿部署?
  • 蓝绿部署是指存在A、B两套环境,平常A对外提供服务,当B升级测试完成后,把流量迁移到B环境中;
  • K8s中要实现蓝绿部署,可以基于 service 的标签选择器,切换到不同的 Pod 控制器来实现。

K8s 如何实现金丝雀发布?
  • 金丝雀发布又称灰度部署,指的是先进行小范围的升级,当运行一段时间没问题后,再进行增量或全量替换。
  • K8s中要实现灰度部署,可以通过 service 的标签选择器控制转发的后端 Pod。也可以使用服务网格(如 Istio),通过基于权重的方式实现流量控制。

K8s 如何实现金丝雀发布?
  • 金丝雀发布又称灰度部署,指的是先进行小范围的升级,当运行一段时间没问题后,再进行增量或全量替换。
  • K8s中要实现灰度部署,可以通过 service 的标签选择器控制转发的后端 Pod。也可以使用服务网格(如 Istio),通过基于权重的方式实现流量控制。

K8s 中的 CRD 和 Operator 是什么?
  • CRD 是自定义资源类型,Operator 是一个自定义的控制器,两者结合通常用于管理有状态应用。

什么是 Helm?
  • Helm 是 Kubernetes 的包管理工具,类似于 Linux 的 apt 或 yum,也像 Node.js 的 npm。
  • 它把一组 Kubernetes 资源(Deployment、Service、ConfigMap、Ingress 等)打包成一个 Chart,可以安装、升级、回滚和删除。

Helm 相关组件有哪些?
  • Chart:类似于 yum/apt 里的软件包;
  • Release:Chart 的一次部署实例,支持版本回滚;
  • Repo:Chart 的仓库;
  • Values:Chart 的配置文件;
  • Templates:通过 Go 模板机制渲染生成最终的 K8s YAML。

数据库

事务特性有哪些?
  • 原子性(Atomicity):整个事务中的所有操作要么全部成功执行,要么全部失败后回滚。
  • 一致性(Consistency):事务做完后,数据得保持前后一致(比如转账时,A少了100块,B就必须多100块)。
  • 隔离性(Isolation):事务在未提交前不可见,但有多种隔离级别:读未提交、读已提交、可重复读、串行化。
    • MySQL 的 InnoDB 存储引擎默认是可重复读。
  • 持久性(Durability):事务一旦提交,其所做的修改会永久保存于数据库中。 PS:事务还依赖于事务日志,其中包含 redo log 和 undo log,redo log保障事务的持久性,undo log保障事务的原子性。

MySQL 的锁有哪几种?
  • 全局锁、表锁、行锁,行锁又分为共享锁(读锁)和排他锁(写锁)。

数据库如何做备份?

看数据量

  • 较小:每日全量备份(每日定时任务,K8s 或系统 crontab) + 开启二进制日志(binlog),工具可以使用 mysqldump。
  • 较大:每周或每月全量备份 + 每日增量备份 + 开启二进制日志(binlog),工具可以使用 xtrabackup(XtraBackup 本身只支持增量,不支持差异备份。)。
    • 增量备份(Incremental Backup):仅备份自上次备份以来变化的数据,恢复时必须按顺序应用:全量 → 第1次增量 → 第2次增量 → …

MySQL最常用的高可用方案?
  • 8.0 以上推荐用 MGR (MySQL Group Replication)

如果数据库 CPU 飙高怎么排查?
  • SHOW PROCESSLIST 或 SHOW FULL PROCESSLIST(Info 列显示完整的 SQL 语句)
  • 检查慢查询、是否有全表扫描、索引是否失效。

消息队列

Kafka的核心组件有哪些?
  • Producer(生产者):负责将数据发布(写入)到 Kafka 的 Topic 中。
  • Consumer(消费者):订阅并消费 Kafka 中的消息。
  • Broker(代理):Kafka 集群中的每个节点称为 Broker,负责接收、存储和传输消息。
  • Topic(主题):Kafka 中消息的逻辑分类单元。
  • Partition(分区):Topic 的物理分片,可以提高并行处理和扩展性。
  • Zookeeper(可选):早期版本用于管理集群元数据,Kafka 2.8+ 开始,使用 KRaft(Kafka Raft Metadata mode) 模式,作为 Zookeeper 的替代方案。

负载均衡

四层负载均衡中,常用的负载均衡算法有哪些?
  • 轮询(Round Robin):流量均匀地分配到所有后端服务器上。
  • 最少连接(Least Connection):将流量优先分配给连接数最少的服务器。
  • 加权轮询(Weighted Round Robin):根据权重分配流量。
  • 加权最少连接(Weighted Least Connection):根据权重和连接数分配流量。
  • 基于源地址哈希(Source Hashing):根据源 IP 地址的哈希值分配流量。

七层负载均衡中,常用的负载均衡算法有哪些?

IPVS 是什么?
  • IPVS (IP Virtual Server) 是 LVS (Linux Virtual Server) 的一种实现。它是 LVS 的一个增强版。

Web 服务

配置 Nginx 作为 Web Server 时,你常用的优化配置有哪些?
  • 性能优化:
    1. 开启和 CPU 核心数相同的 worker 进程(worker_processes auto;)
    2. worker 进程与 CPU 亲缘性绑定(worker_cpu_affinity 0001 0010 0100 1000; # 假设4核CPU,绑定每个进程到特定核心)
    3. 增大 worker 进程的最大连接数(worker_connections 10240;)
    4. 使用 epoll 事件通知模型
    5. 开启 gzip 压缩
    6. 客户端频繁请求的场景下,开启 keepalive,并设置合理的 timeout
  • 安全优化:
    1. 普通用户运行 worker 进程(user www-data; # master 进程还是以 root 身份运行,因为只有 root 身份才能绑定 <1024 的特权端口)
    2. 隐藏 Nginx 版本号(server_tokens off;)
    3. 防盗链(仅允许指定域名访问图片等静态资源)
  • 反向代理:
    1. 开启缓存
    2. 开启客户端 IP 透传(proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;)
  • 其他:
    1. 日志输出改为 json 格式(便于 ELK 分析)

Python

Python 的数据类型有哪些?
  • 基本类型:int(整型), float(浮点型), complex(复数), bool(布尔型), 字符串;
  • 容器类型:list(列表), tuple(元组), set(集合), dict(字典)。

列表和元组的区别?
  • 列表可变,元组不可变;
  • 定义方式上,列表使用方括号[],元组使用圆括号()或直接用逗号分隔;

Python 中 *args 和 **kwargs 的作用?
  • *args:接收任意数量的位置参数,返回元组
  • **kwargs:接收任意数量的关键字参数,返回字典

Python 中 is 与 == 的区别?
  • is比较对象的id,即内存地址(是否是同一个对象),==比较对象的值
a = [1, 2]
b = [1, 2]
print(a == b)  # True
print(a is b)  # False