面试官您好,是的,作为一名开发人员,我在日常的工作、部署和问题排查中,会频繁地使用到Linux命令。我熟悉并常用的命令,可以大致分为以下几个类别:
1. 文件与目录操作 (最常用)
这是最基础、每天都会用到的命令。
- 导航与查看:
ls: 列出目录内容。我常用的参数有-l(显示详细信息)、-a(显示隐藏文件)、-h(人性化显示文件大小)、-t(按修改时间排序)。cd: 切换目录。pwd: 显示当前工作目录的路径。
- 创建与删除:
mkdir: 创建目录。-p参数可以递归创建多级目录,非常实用。touch: 创建空文件,或者更新文件的时间戳。rm: 删除文件或目录。-r用于递归删除目录,-f用于强制删除不提示。这是一个需要非常小心的命令。
- 复制与移动:
cp: 复制文件或目录。-r参数用于复制目录。mv: 移动文件或目录,也可以用来重命名。
- 内容查看与编辑:
cat: 查看文件全部内容。more/less: 分页查看文件内容,less功能更强大,可以前后翻页。head/tail: 查看文件的头部或尾部内容。tail -f是我排查实时日志的神器,可以动态跟踪文件的新增内容。vim: 强大的文本编辑器,用于修改配置文件等。
2. 进程管理 (排查性能问题必备)
当线上服务出现性能问题或异常时,这类命令是排查的起点。
ps: 查看当前系统的进程状态。我最常用的组合是ps -ef | grep [service_name],用来查找特定服务的进程ID(PID)。top: 实时动态地显示系统资源占用情况和进程信息。可以按CPU、内存等进行排序,是定位高资源消耗进程的首选。kill: 向进程发送信号,常用来终止进程。kill -9 [PID]是强制杀死进程。netstat: 查看网络连接、路由表、接口统计等信息。netstat -anp | grep [port]是我用来查看某个端口是否被占用的常用命令。
3. 文本处理与搜索 (日志分析利器)
在处理大量日志文件时,这几个命令组合起来威力巨大。
grep: 强大的文本搜索工具。可以在文件或管道中,根据正则表达式查找匹配的行。find: 在文件系统中查找文件。比如find / -name "filename"。awk/sed: 强大的流式文本处理工具。awk擅长按列处理文本,sed擅长对文本进行增删改查。|(管道符): 将一个命令的输出,作为另一个命令的输入。比如,cat app.log | grep "ERROR" | wc -l就可以快速统计日志中的错误数量。
4. 系统与网络信息
- 网络相关:
ifconfig/ip addr: 查看和配置网络接口信息。ping: 测试与目标主机的网络连通性。telnet/nc: 测试某个远程主机的特定端口是否开放。curl: 强大的URL传输工具,常用来测试HTTP接口。
- 系统信息:
df: 查看磁盘空间使用情况。-h参数可以人性化显示。free: 查看内存使用情况。uname -a: 显示系统内核和操作系统信息。
5. 权限管理
chmod: 修改文件或目录的访问权限(读、写、执行)。chown: 修改文件或目录的所有者和所属组。useradd/groupadd: 创建新用户和用户组。
6. 压缩与归档
tar: 打包和解包文件。常用的参数有-c(创建)、-x(解压)、-v(显示过程)、-f(指定文件名)、-z(使用gzip压缩/解压)。gzip/zip: 用于文件的压缩和解压缩。
这些命令是我在日常开发、部署、运维和故障排查过程中,使用频率最高、也认为最重要的一些。熟练掌握它们,能极大地提升工作效率。
面试官您好,ps 命令是我在线上排查问题时,使用频率最高的命令之一。它主要用来查看当前系统上进程的快照信息。
1. ps 命令能展示哪些东西?
ps 命令可以展示非常丰富的进程信息,其中最关键、我最常关注的列包括:
PID(Process ID):进程的唯一标识符。这是我们对进程进行操作(如kill)时最重要的信息。PPID(Parent Process ID):父进程的ID。通过它可以了解进程间的父子关系。USER或UID: 启动该进程的用户。%CPU: 进程在上一个更新周期内所占用的CPU时间的百分比。%MEM: 进程所占用的物理内存的百分比。VSZ(Virtual Memory Size):进程占用的虚拟内存大小(单位KB)。RSS(Resident Set Size):进程当前占用的、驻留在物理内存中的大小(单位KB)。这个值比VSZ更有参考意义,能真实反映进程的内存消耗。STAT(State):进程的当前状态。常见的状态有:R(Running or Runnable): 正在运行或在运行队列中等待。S(Interruptible Sleep): 可中断的睡眠状态(等待某个事件完成)。D(Uninterruptible Sleep): 不可中断的睡眠状态(通常在等待I/O)。T(Stopped): 已停止的进程。Z(Zombie): 僵尸进程。
START: 进程启动的时间。TIME: 进程自启动以来,累计占用的CPU总时间。COMMAND: 启动该进程的命令和参数。通过这个可以清晰地看到进程的启动脚本和配置。
2. 我最常用的 ps 命令选项组合
ps 命令的选项非常多,可以分为几种不同的风格(如BSD风格、Unix风格、GNU风格)。在日常工作中,我几乎不会单独使用 ps,而是使用几个固定的、功能强大的选项组合。
a. ps -ef (Unix风格,我最常用的组合)
这是我排查问题的第一步,用来查看系统上所有进程的完整信息。
-e: 显示所有(every) 进程,等同于-A。-f: 全格式(full-format) 显示。它会展示出UID,PID,PPID,C(CPU使用率的近似值),STIME(启动时间),TTY,TIME,CMD(命令)等列。
我通常会配合 grep 来使用,比如:
ps -ef | grep java —— 快速找出所有Java进程。
ps -ef | grep tomcat —— 找到Tomcat进程,获取其PID。
b. ps aux (BSD风格,功能与-ef类似,但信息侧重点不同)
这个组合也非常流行,提供了另一种视角的信息。
a: 显示所有终端上的进程,包括其他用户的。u: 以用户为中心的格式显示。它会展示出USER,PID,%CPU,%MEM,VSZ,RSS等非常实用的性能指标。x: 显示没有控制终端的进程(比如后台运行的守护进程)。
ps aux 的输出对于快速定位资源消耗大户非常有用。我通常会配合 sort 来排序查看:
ps aux | sort -rnk 3 | head -n 5 —— 按第3列(%CPU)降序排序,找出CPU占用最高的5个进程。
ps aux | sort -rnk 4 | head -n 5 —— 按第4列(%MEM)降序排序,找出内存占用最高的5个进程。
c. ps -T -p [PID] (查看线程信息)
-T: 显示指定进程下的所有线程。-p: 指定进程ID。
这个组合在我需要排查某个Java进程内部是哪个线程导致CPU飙升时非常有用。它会显示出每个线程的SPID(线程ID),然后我可以将这个线程ID转换成十六进制,再用 jstack 去进程的线程堆栈中查找,从而定位到具体的代码问题。
总结
ps -efgrep查找特定进程ps auxsort排序定位性能瓶颈ps -T -p [PID]虽然top命令可以动态地展示这些信息,但ps的优势在于它是一个静态快照,非常适合在脚本中或与其他命令(如grep, awk, sort)通过管道结合使用,进行自动化的分析和处理。
面试官您好,top命令是我在线上排查系统性能问题时,首选的、最重要的实时监控工具。它提供了一个动态的、全局的系统健康状况视图,能让我快速地了解当前系统的负载、资源瓶颈以及是哪些进程在消耗资源。
top命令的输出界面,可以清晰地分为上下两个部分:上半部分是系统总体统计信息,下半部分是进程列表。
1. 上半部分:系统总体统计信息
这部分信息通常有5行,每一行都揭示了系统某一方面的宏观状态。
-
第一行:任务队列与系统负载信息
top - 10:30:00 up 5 days, 2:15, 2 users, load average: 0.05, 0.10, 0.15up 5 days, 2:15: 系统已运行时间。2 users: 当前登录的用户数。load average: 0.05, 0.10, 0.15: 这是最关键的指标之一,分别代表系统在过去1分钟、5分钟、15分钟的平均负载。它表示的是当前正在运行(R状态)和不可中断等待(D状态)的进程总数。- 解读:如果这个值除以逻辑CPU核心数,结果持续大于1,就说明系统可能已经过载,CPU资源不足。
-
第二行:进程统计信息
Tasks: 200 total, 1 running, 199 sleeping, 0 stopped, 0 zombietotal: 总进程数。running: 正在运行的进程数。sleeping: 处于睡眠状态的进程数。stopped: 已停止的进程数。zombie: 僵尸进程数。如果这个值不为0,需要特别关注,可能意味着有父进程没有正确处理子进程的退出。
-
第三行:CPU使用情况
%Cpu(s): 1.5 us, 0.5 sy, 0.0 ni, 98.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 stus(user): 用户空间程序占用的CPU百分比。如果这个值很高,说明是应用程序在消耗CPU。sy(system): 内核空间占用的CPU百分比。如果这个值很高,说明可能是系统调用或内核线程在消耗CPU。ni(nice): 被调整过优先级的进程占用的CPU。id(idle): CPU空闲时间的百分比。这个值越低,说明CPU越繁忙。wa(I/O wait): CPU等待I/O操作完成的时间百分比。如果这个值很高,说明系统可能存在磁盘I/O瓶颈。hi/si: 处理硬件/软件中断的CPU时间。
-
第四行:物理内存使用情况 (KiB Mem)
total,free,used,buff/cache: 分别显示总物理内存、空闲内存、已用内存和用作缓冲区/页缓存的内存。- 注意:在Linux中,
free值很小是正常的,因为系统会尽可能地利用空闲内存作为cache来提升I/O性能。评估真实可用内存,通常看available列(按m键切换单位后可见)或者free + buff/cache。
-
第五行:交换空间使用情况 (KiB Swap)
total,free,used: 显示Swap分区的总量、空闲量和使用量。- 如果
used值很高,并且在持续变化,说明物理内存严重不足,系统正在频繁地使用Swap空间,这会导致性能急剧下降。
2. 下半部分:进程列表
这部分实时地列出了当前系统中各个进程的资源占用情况,默认按CPU使用率降序排列。
PID: 进程ID。USER: 进程所有者。PR/NI: 进程的优先级(Priority)和nice值。VIRT: 进程使用的虚拟内存大小。RES: 进程使用的、未被换出的物理内存大小(Resident Memory)。这是衡量一个进程真实内存占用的重要指标。SHR: 共享内存大小。S: 进程状态(与上面第二行的状态对应)。%CPU: 进程占用的CPU百分比。这是我排查CPU问题时首先关注的列。%MEM: 进程占用的物理内存百分比。TIME+: 进程自启动以来,累计占用的CPU总时间,精确到百分之一秒。COMMAND: 启动进程的命令。
常用交互式操作
在使用top时,我还会用一些快捷键来辅助分析:
1: 切换显示,可以展开/折叠所有CPU核心的详细使用情况。P(大写): 按 CPU 使用率降序排列。M(大写): 按 内存使用率降序排列。c: 切换COMMAND列,显示完整的命令路径和参数。q: 退出top。
通过对top命令输出的这些信息的综合分析,我能够快速地对一个系统的健康状况和性能瓶颈,形成一个全面而准确的判断。
面试官您好,当我知道一个进程名,要杀掉这个进程时,我会根据不同的情况,采用以下几种方法。核心思路都是先定位到进程的PID,然后再发送信号来终止它。
方法一:标准的两步法 (ps + kill)
这是最基础、最通用的方法。
-
第一步:查找进程ID (PID)
- 我会使用
ps命令配合grep来查找。最常用的命令是:ps -ef | grep [进程名]例如,要找
tomcat进程:ps -ef | grep tomcat - 这个命令会列出所有包含 “tomcat” 关键字的进程信息。我需要从输出中找到对应的那一行,并记下第二列的PID。需要注意的是,
grep命令本身也会产生一个进程,需要排除掉它。
- 我会使用
-
第二步:终止进程
- 拿到PID后,使用
kill命令来终止它。kill [PID]例如:
kill 12345 - 这个命令默认发送的是
SIGTERM(信号15),这是一个“优雅关闭”的信号。它会通知进程:“请你准备一下,然后自己退出”。应用程序可以捕获这个信号,并执行一些清理工作(如保存数据、关闭连接)。 - 如果
kill命令无法终止进程(比如进程已经卡死,无法响应信号),我就会使用“最后的手段”:kill -9 [PID] -9发送的是SIGKILL信号,这是一个强制杀死的信号,操作系统会直接剥夺该进程的资源,进程无法捕获也无法忽略。这是一种比较粗暴的方式,可能会导致数据丢失或文件损坏,所以只在必要时使用。
- 拿到PID后,使用
方法二:更高效的 pgrep + pkill 组合
在很多现代Linux发行版中,都提供了更方便的 pgrep 和 pkill 命令,它们可以直接根据进程名进行操作,省去了手动 grep 和提取PID的步骤。
-
pgrep [进程名]: 直接根据进程名查找并返回PID。- 例如:
pgrep tomcat会直接输出Tomcat进程的PID,如12345。
- 例如:
-
pkill [进程名]: 直接根据进程名查找并杀死匹配的进程。- 它和
kill命令一样,默认发送SIGTERM(15) 信号。 - 例如:
pkill tomcat - 如果需要强制杀死,同样可以使用
-9选项:pkill -9 tomcat
- 它和
优点:这个组合命令更简洁、更高效,并且能避免误杀 grep 进程。
方法三:killall 命令 (按名称批量杀死)
killall 命令可以直接根据进程的准确名称来杀死所有匹配的进程。
- 用法:
killall [进程名]例如:
killall firefox会杀死所有名为 “firefox” 的进程。 - 注意:这个命令需要精确匹配进程名,而不是关键字。比如,如果进程的命令是
java -jar my-app.jar,那么它的进程名是java,你应该使用killall java。 - 风险:这个命令的威力很大,如果系统中有多个同名但用途不同的进程,可能会导致误杀。比如,
killall java会杀死系统上所有的Java进程。因此使用时需要特别小心。
总结我的选择
grep的输出在日常工作中,如果系统支持,我首选 pkill 命令,因为它最直接、最安全。如果环境不确定,我就会退回到最经典的 ps -ef | grep ... 和 kill 的组合。
面试官您好,在Linux中查看进程状态,是我日常排查问题和监控系统健康状况时,最常进行的操作之一。根据需求的不同——是想看某个时间点的静态快照,还是想实时动态地监控——我会选择不同的命令。
主要有以下几种方法:
1. ps 命令:查看进程的“静态快照”
ps (Process Status) 命令用来显示当前时刻的进程信息,它像给系统拍了一张照片。它非常适合与管道符 | 结合,进行过滤和分析。
-
最常用的命令组合:
ps -ef # 或者 ps auxps -ef:以Unix标准格式,显示系统上所有进程的完整信息。我通常用它来配合grep查找特定进程,比如ps -ef | grep java。ps aux:以BSD风格,显示所有进程的资源占用情况。这个命令对于快速定位哪个进程占用了高CPU或高内存非常有用。
-
如何查看状态:
- 在这两种命令的输出中,都有一列叫做
STAT或S,这就是进程的状态列。 - 常见的状态码有:
R(Running/Runnable): 运行或就绪态。表示进程正在CPU上运行,或者在运行队列中等待CPU。S(Interruptible Sleep): 可中断的睡眠态。这是最常见的状态,表示进程正在等待某个事件的发生(比如等待用户输入、网络数据)。D(Uninterruptible Sleep): 不可中断的睡眠态。通常表示进程正在等待I/O操作完成(如磁盘读写)。处于D状态的进程不能被kill,如果一个进程长时间处于D状态,可能意味着系统I/O存在问题。T(Stopped): 已停止。进程被暂停,比如通过Ctrl+Z或收到了SIGSTOP信号。Z(Zombie): 僵尸态。进程已经终止,但其父进程尚未回收其资源(如进程描述符)。如果系统中有大量僵尸进程,说明有父进程代码存在缺陷。
- 状态码后面可能还会跟一些附加符号,比如
+表示这是一个前台进程组的进程。
- 在这两种命令的输出中,都有一列叫做
2. top 命令:实时动态监控
top 命令是一个动态的、交互式的进程查看器。它会周期性地刷新(默认3秒),实时地展示系统的总体资源使用情况和各个进程的动态变化。
- 启动与查看:
- 直接在终端输入
top即可启动。
- 直接在终端输入
- 如何查看状态:
- 在
top命令的下半部分——进程列表中,同样有一列S,其含义与ps命令中的STAT列完全相同。 top的优势在于,它默认就按CPU使用率降序排列,让我能一眼就看到当前最消耗CPU的进程及其状态。
- 在
- 交互式操作:
- 在
top界面,我可以按P键按CPU排序,按M键按内存排序,这对于动态定位性能瓶颈非常方便。
- 在
3. /proc 文件系统:深入底层查看
对于更深入的分析,可以直接查看 /proc 这个虚拟文件系统。Linux内核会把所有进程的详细信息,都以文件的形式暴露在 /proc/[PID]/ 目录下。
- 查看特定进程的状态:
cat /proc/[PID]/status例如:
cat /proc/12345/status - 输出内容:这个文件会提供比
ps更详细的状态信息,包括进程名、状态(State字段)、PID、PPID、UIDs、GIDs、内存使用详情、线程数等等。其中State字段的含义与ps命令中的一致。
总结
pstop/proc在日常工作中,我的排查流程通常是:
- 先用
top看一下系统的总体负载和当前最活跃的进程。 - 如果定位到某个可疑进程,再用
ps -ef | grep [PID]查看它的详细启动命令和参数。 - 如果需要进一步分析,可能会进入
/proc/[PID]目录,或者使用jstack、strace等更专业的工具。
面试官您好,在Linux中,线程通常被内核看作一种轻量级进程(Light-Weight Process, LWP)。因此,我们查看线程状态的方法,与查看进程状态的方法一脉相承,主要是通过对ps和top命令添加特定参数来实现。
1. ps 命令:查看线程的“静态快照”
要使用ps命令查看线程,最关键的参数是 -T。
-
常用命令组合:
ps -T -p [PID] # 或者 ps -eLf | grep [PID]ps -T -p [PID]: 这是我最常用的方式。-T选项会显示指定进程(-p [PID])下的所有线程。ps -eLf: 这个组合命令会列出系统上所有进程的所有线程的详细信息。-L选项就是用来显示线程的,-e显示所有进程,-f提供完整格式。通常我会配合grep来过滤出我关心的那个进程的线程。
-
输出解读:
- 当使用了线程查看选项后,
ps的输出会增加几列,最重要的是:PID: 进程ID。同一进程下的所有线程,它们的PID都是相同的。LWP或SPID: 线程ID (Light-Weight Process ID)。这是内核中线程的唯一标识符。这个ID非常重要,因为在进行性能剖析时(比如用jstack),我们通常需要用这个ID来定位问题线程。
- 其他列如
STAT,%CPU,%MEM等,此时显示的就是每个独立线程的状态和资源占用情况。
- 当使用了线程查看选项后,
2. top 命令:实时动态监控线程
top命令默认显示的是进程级别的汇总信息。要切换到线程视图,最关键的快捷键是 H,或者在启动时使用 -H 参数。
-
交互式切换:
- 先运行
top。 - 在
top的交互界面中,直接按下大写的H键。 - 此时,进程列表就会从显示进程,切换为显示所有线程。每一行都代表一个独立的线程。再次按下
H,则会切换回进程视图。
- 先运行
-
启动时指定:
top -H -p [PID]这个命令会直接启动
top,并只显示指定PID进程下的所有线程的实时动态。 -
输出解读:
- 切换到线程视图后,
PID列显示的仍然是进程ID,但通常会增加一列线程ID(通常也叫PID或LWP)。 %CPU、%MEM等列,现在都精确地表示单个线程的资源消耗。这对于快速定位是哪个线程导致了CPU飙升,非常直观和有效。
- 切换到线程视图后,
3. 实际应用场景:定位高CPU消耗的Java线程
这是一个非常经典的线上问题排查流程,完美地结合了top和ps的线程查看功能:
-
第一步:找到最耗CPU的进程
- 执行
top,按P键,找到CPU占用率最高的那个Java进程,记下它的PID。
- 执行
-
第二步:找到该进程下最耗CPU的线程
- 执行
top -H -p [PID],进入该进程的线程视图。 - 同样按
P键,找到CPU占用率最高的那个线程,记下它的线程ID(LWP/SPID)。
- 执行
-
第三步:转换线程ID格式
- 将这个十进制的线程ID,转换为十六进制。
printf "%x " [线程ID]
- 将这个十进制的线程ID,转换为十六进制。
-
第四步:打印线程堆栈
- 使用
jstack工具,打印该Java进程的线程堆栈,并用grep筛选出我们刚刚找到的那个线程。jstack [PID] | grep -A 20 [十六进制线程ID]-A 20表示显示匹配行及其后的20行,方便我们看到完整的堆栈信息。
- 使用
-
第五步:分析代码
- 通过分析打印出的线程堆栈,我们就能精确地定位到是哪一段Java代码(哪个方法、哪一行)正在消耗大量的CPU资源,从而找到问题的根源。
通过这套流程,我们就能从宏观的系统监控,一步步深入到微观的代码层面,高效地解决线上性能问题。
面试官您好,查看系统的网络连接情况,是我在线上排查网络问题、端口占用、以及分析服务通信状态时,非常频繁进行的操作。我会根据需要查看的信息的侧重点,主要使用 netstat 和更现代化的 ss 这两个命令。
1. netstat 命令 (经典的网络统计工具)
netstat (Network Statistics) 是一个功能非常强大的老牌工具。我最常用的就是您提到的那个组合,以及它的一些变体。
-
最常用的命令组合:
netstat -anp-a(all): 显示所有正在监听(LISTEN)和非监听(ESTABLISHED, TIME_WAIT等)的套接字(sockets)。-n(numeric): 直接以数字形式显示IP地址和端口号,而不是尝试去解析成主机名或服务名。这可以大大加快命令的执行速度,并且结果更清晰。-p(program): 显示该套接字所属的进程ID(PID)和进程名。这个参数在排查“哪个进程占用了某个端口”时,至关重要(需要root权限才能看到所有进程信息)。
-
我通常会配合
grep来使用:-
查找特定端口的监听情况:
netstat -anp | grep LISTEN | grep :8080这可以快速确认我的Tomcat或Java应用是否在8080端口上成功启动并处于监听状态。
-
查看特定服务的连接:
netstat -anp | grep :3306这可以查看所有与MySQL(默认端口3306)相关的网络连接,帮助我分析数据库的连接数和状态。
-
统计连接状态:
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'这个组合命令可以统计当前系统中所有TCP连接的状态(如
ESTABLISHED,TIME_WAIT,CLOSE_WAIT)及其数量,对于分析高并发下的连接瓶颈非常有用。
-
2. ss 命令 (更现代、更快速的替代品)
ss (Socket Statistics) 是 netstat 的继任者,它被设计用来在处理大量连接时,比netstat更快、更高效。它的选项和netstat非常相似,但性能更好。
-
为什么
ss更快?ss直接从内核空间中的tcp_diag模块获取信息,而netstat需要遍历/proc文件系统下的多个文件,效率较低。
-
与
netstat的常用命令对比:-
netstat -anp的等效ss命令是:ss -anp它们的输出格式和含义几乎一样。
-
ss提供了更强大的过滤功能:- 按状态过滤:
# 只显示处于 ESTABLISHED 状态的连接 ss -ant state established # 显示所有 TIME-WAIT 状态的连接 ss -ant state time-wait - 按端口过滤:
# 显示所有源端口或目标端口是80的连接 ss -ant '( sport = :80 or dport = :80 )'
- 按状态过滤:
-
总结对比
netstatss在我的日常工作中,如果我能确认系统是比较现代的Linux发行版,我首选使用 ss 命令,因为它更快、功能更强。如果是在一个不熟悉的老旧系统或嵌入式环境中,我才会回退到使用兼容性最好的 netstat。但它们的常用参数和分析思路是高度一致的。
面试官您好,当我在部署服务时遇到“端口已被占用”(Address already in use)的错误,或者需要确认某个端口的归属时,我会通过以下几种方法来快速定位占用该端口的进程。
方法一:使用 netstat 命令 (经典方法)
这是最传统、最通用的方法。它的思路是先找到使用该端口的连接,再通过连接信息找到对应的进程。
-
命令:
netstat -anp | grep :[端口号]例如,要查找占用8080端口的进程:
netstat -anp | grep :8080 -
参数详解:
-a(all): 显示所有监听和非监听的连接。-n(numeric): 直接以数字形式显示端口号,避免服务名解析,速度更快。-p(program): 这是最关键的参数,它会显示该连接所属的进程ID(PID)和进程名。(注意:在非root用户下,可能无法看到所有进程的信息)。
-
输出解读:
- 执行命令后,通常会看到一行或多行信息。如果某个进程正在监听该端口,它的状态(State)列会是
LISTEN。 - 在最后一列,会显示出类似
12345/java这样的信息,其中12345就是我们需要的PID,java则是进程名。
- 执行命令后,通常会看到一行或多行信息。如果某个进程正在监听该端口,它的状态(State)列会是
-
后续操作:
- 拿到PID后,我可以用
ps -ef | grep 12345来查看这个进程的完整启动命令,进一步确认它是什么服务。 - 如果需要,可以用
kill 12345来终止它。
- 拿到PID后,我可以用
方法二:使用 lsof 命令 (更直接、更强大的方法)
lsof (List Open Files) 是一个功能极其强大的工具,它可以列出系统中所有被进程打开的文件。在Linux中,“一切皆文件”,所以网络连接(socket)也被看作是一种文件。
-
命令:
lsof -i :[端口号] -
参数详解:
-i: 表示列出与网络连接相关的文件。:[端口号]: 指定要查询的端口号。
-
输出解读:
- 这个命令会直接、清晰地列出所有正在使用该端口的进程信息,包括
COMMAND(进程名),PID(进程ID),USER(用户)等。 - 相比
netstat,lsof的输出通常更直接明了,就是为了解决“什么进程用了什么资源”这类问题而生的。
- 这个命令会直接、清晰地列出所有正在使用该端口的进程信息,包括
-
优点:
- 语义清晰:
lsof -i :port这个命令的意图非常明确。 - 功能强大:
lsof不仅能查端口,还能查哪个进程打开了某个文件等等。
- 语义清晰:
方法三:使用 ss 命令 (netstat的现代替代品)
ss 命令是 netstat 的继任者,在现代Linux系统中,它的性能更好。其用法和 netstat 非常相似。
-
命令:
ss -lntp | grep :[端口号]例如,查找8080端口:
ss -lntp | grep :8080 -
参数详解:
-l(listening): 只显示正在监听的socket。-n(numeric): 显示数字形式的端口。-t(tcp): 只显示TCP连接。-p(processes): 显示使用该socket的进程。
总结与我的选择
lsofnetstatgrep,输出信息稍显杂乱ssnetstat的现代替代品netstat类似,需要配合grep在我的日常工作中,如果我要快速地解决“哪个进程占用了某个端口”这个问题,我首选 lsof -i :[端口号],因为它最直观、最简单。
如果是在一个不确定是否安装了 lsof 的环境,或者我需要查看更详细的网络连接状态(而不仅仅是端口占用),我就会使用 netstat -anp 或 ss -lntp。
面试官您好,当我在部署或排查分布式服务时,经常需要确认一台服务器到另一台服务器的某个特定端口是否开放和可达。为了测试端口的连通性,我主要会使用 telnet 和 nc (netcat) 这两个命令。
方法一:telnet 命令 (经典、直观)
telnet 是一个非常古老的远程登录协议工具,但因为它简单直观,所以常被“借用”来做端口连通性测试。
-
命令格式:
telnet [目标IP地址] [端口号]例如,要测试是否能连接到
192.168.1.100这台机器上的Redis服务(端口6379):telnet 192.168.1.100 6379 -
结果判断:
- 通 (Connected):如果端口是开放的,并且网络可达,屏幕会立即清空,或者显示类似
Connected to 192.168.1.100.的提示,并且光标停留在左上角闪烁,等待你输入。这表明TCP的三次握手已经成功建立。此时可以按Ctrl + ],然后输入quit来退出。 - 不通 (Connection Refused):如果目标服务器的防火墙拒绝了这个连接,或者该端口上根本没有服务在监听,通常会立即返回
Connection refused的错误。 - 不通 (Timeout):如果请求在网络中因为防火墙、路由问题被丢弃了,或者目标主机不存在,
telnet命令会一直等待,直到最终超时,返回connect: Connection timed out。
- 通 (Connected):如果端口是开放的,并且网络可达,屏幕会立即清空,或者显示类似
-
优点:
- 非常直观,结果容易判断。
- 在很多系统中都是预装的。
-
缺点:
- 在一些新的、极简的Linux发行版(如很多Docker基础镜像)中,可能没有预装
telnet客户端。
- 在一些新的、极简的Linux发行版(如很多Docker基础镜像)中,可能没有预装
方法二:nc / netcat 命令 (网络工具中的“瑞士军刀”)
nc (netcat) 是一个功能极其强大的网络工具,测试端口连通性只是它的一个小功能。我更推荐使用它,因为它功能更强,反馈信息也更明确。
-
命令格式:
nc -zv [目标IP地址] [端口号]例如,测试同样的目标:
nc -zv 192.168.1.100 6379 -
参数详解:
-z: 表示零I/O模式 (Zero-I/O mode)。它让nc在建立连接后,不进行任何数据交换,立即关闭连接。我们只是用它来“扫描”端口,而不是真的要通信。-v: 表示详细输出 (Verbose)。它会给出更清晰的连接状态反馈。
-
结果判断:
- 通 (Succeeded):如果端口通,会明确地输出
Connection to 192.168.1.100 6379 port [tcp/*] succeeded!。 - 不通 (Refused / Timeout):如果端口不通,也会明确地返回
Connection refused或No route to host等错误信息。
- 通 (Succeeded):如果端口通,会明确地输出
-
优点:
- 反馈清晰:
-v参数让结果一目了然。 - 功能强大:除了TCP,
nc还可以用来测试UDP端口(加-u参数),甚至可以用来传输文件、开启一个临时的聊天服务等。 - 可设置超时:可以用
-w参数指定一个超时时间,避免长时间等待。例如nc -zvw 3 192.168.1.100 6379表示最多等待3秒。
- 反馈清晰:
总结与我的选择
telnetnc在我的日常工作中,我首选使用 nc -zv,因为它更专业、更灵活,反馈也更明确。如果发现当前系统上没有nc命令,我才会回退到使用telnet作为替代方案。这两个工具基本能满足所有端口连通性的测试需求。
面试官您好,要通过top命令查看系统有多少个CPU核心,最简单直接的方法就是:
在 top 命令运行的交互界面中,直接按下键盘上的数字 1 键。
按下 1 之前和之后的变化
-
默认状态 (按下
1之前):top命令默认只显示一行CPU的总体使用情况。这一行展示的是所有CPU核心平均下来的各项指标。- 例如:
%Cpu(s): 1.5 us, 0.5 sy, 0.0 ni, 98.0 id, 0.0 wa, ...这里的
%Cpu(s)后面的(s)表示这是所有核心(CPUs)的平均值。
-
切换后状态 (按下
1之后):- 按下数字
1键后,CPU信息区域会展开,为每一个独立的CPU核心(或超线程)都显示一行详细的使用情况。 - 例如,如果一个系统有4个逻辑核心,它会显示:
%Cpu0 : 2.0 us, 1.0 sy, 0.0 ni, 97.0 id, 0.0 wa, ... %Cpu1 : 1.0 us, 0.0 sy, 0.0 ni, 99.0 id, 0.0 wa, ... %Cpu2 : 1.5 us, 0.5 sy, 0.0 ni, 98.0 id, 0.0 wa, ... %Cpu3 : 1.5 us, 0.5 sy, 0.0 ni, 98.0 id, 0.0 wa, ... - 通过数一下这里有多少行
%CpuX,我们就能直接确定系统拥有多少个逻辑CPU核心。再次按下1,则会切换回合并显示的模式。
- 按下数字
为什么这个功能很重要?
这个切换功能在排查性能问题时非常有用:
- 判断CPU瓶颈:如果总体的CPU使用率很高,通过展开核心视图,我们可以看到是所有核心都在均匀地繁忙,还是只有一两个核心被打满了。
- 定位单线程性能问题:如果发现只有一个核心(比如
Cpu0)的使用率接近100%,而其他核心都很空闲,这通常意味着系统中有一个单线程的、计算密集型的程序正在运行,它无法利用多核优势,成为了性能瓶颈。
其他补充方法
除了top命令,我还会使用其他几个命令来更直接地获取CPU核心数信息:
lscpu: 这是最推荐的、专门用来查看CPU架构信息的命令。它会清晰地列出CPU(s)(逻辑核心数)、Core(s) per socket(每个CPU插槽的核心数)、Socket(s)(CPU插槽数) 等详细信息。cat /proc/cpuinfo: 这个文件包含了CPU的详细硬件信息。我们可以通过统计processor字段的数量来确定逻辑核心数:cat /proc/cpuinfo | grep "processor" | wc -lnproc: 一个非常简单的命令,直接输出可用的CPU处理单元数量。
总结:虽然有多种方法可以查看CPU核心数,但在已经打开 top 进行实时监控的场景下,直接按 1 键无疑是最方便、最高效的方式。
面试官您好,修改文件或目录的权限,我主要使用 chmod (change mode) 命令。这个命令非常强大,它提供了两种主要的方式来设定权限:符号模式(Symbolic Mode)和八进制数字模式(Octal Mode)。
1. 基础知识:理解Linux文件权限
在修改之前,我们需要先理解Linux的权限位。使用 ls -l 命令可以看到类似 -rwxr-xr-- 这样的权限字符串。
- 它分为4部分:
文件类型|所有者权限|所属组权限|其他用户权限 - 每一组权限都由三个字符组成:
r(read): 读权限w(write): 写权限x(execute): 执行权限(对于目录,是进入目录的权限)
2. 符号模式 (Symbolic Mode):更直观、易于理解
这种方式通过 + (增加权限), - (移除权限), = (精确设置权限) 这三个操作符来修改。它非常适合进行增量的权限调整。
-
指定用户:
u(user): 文件所有者g(group): 文件所属组o(others): 其他用户a(all): 所有用户(u,g,o的合集)
-
常用示例:
-
为所有者增加执行权限:
chmod u+x filename.sh这个命令常用于给一个脚本文件赋予执行能力。
-
为所属组和其他用户移除写权限:
chmod go-w filename这可以防止同组或其他用户修改文件。
-
为所有人增加读权限:
chmod a+r filename # 或者简写为 chmod +r filename -
精确设置权限:
chmod u=rwx,g=rx,o=r filename这个命令会将文件的权限精确地设置为
rwxr-xr--。
-
3. 八进制数字模式 (Octal Mode):更快捷、更常用
这是在脚本和运维中更常用、更高效的方式。它用一个三位的八进制数字来代表整个权限设置。
-
数字与权限的对应关系:
r(读) = 4w(写) = 2x(执行) = 1
-
权限组合:将需要的权限对应的数字相加,即可得到权限组合的数字。
---= 0--x= 1-w-= 2-wx= 3r--= 4r-x= 5rw-= 6rwx= 7
-
三位八进制数:这三位数字,从左到右,分别代表 所有者(u)、所属组(g)、其他用户(o) 的权限。
-
常用示例:
-
chmod 755 directory:7(rwx): 所有者有读、写、执行权限。5(r-x): 所属组有读、执行权限。5(r-x): 其他用户有读、执行权限。- 这通常是目录的常用权限。
-
chmod 644 file.txt:6(rw-): 所有者有读、写权限。4(r–): 所属组只有读权限。4(r–): 其他用户只有读权限。- 这通常是普通文本文件的常用权限。
-
chmod 700 private_key:7(rwx): 只有所有者有所有权限。0(—): 所属组和其他用户没有任何权限。- 这通常用于设置私钥等高度敏感的文件,确保只有自己能访问。
-
4. 递归修改权限
如果要修改一个目录及其下所有文件和子目录的权限,需要加上 -R (Recursive) 参数。
- 示例:
chmod -R 755 /path/to/directory
总结我的选择
在日常工作中,我绝大多数时间会使用八进制数字模式,因为它更快捷、更标准。只有在偶尔需要对现有权限做一个微小的、增量式的修改时,我才会使用符号模式。
面试官您好,free命令和top命令确实都可以用来查看系统的内存使用情况,但它们的设计目标、信息粒度和使用场景是完全不同的。
简单来说,它们的区别是:
free是一个静态的、专注的“内存快照”工具。top是一个动态的、综合的“系统性能仪表盘”。
1. free 命令:内存的“CT扫描报告”
free命令的唯一职责,就是提供一个关于当前时刻系统内存使用情况的详细、静态的报告。
-
核心功能:
- 它清晰地将内存划分为物理内存(
Mem) 和交换空间(Swap) 两大块。 - 在物理内存部分,它提供了所有关键指标:
total: 总物理内存。used: 已使用内存。free: 真正的、完全未使用的空闲内存。shared: 共享内存。buff/cache: 这是理解Linux内存的关键。它表示被内核用作缓冲区(Buffer) 和页缓存(Page Cache) 的内存。Linux会尽可能地利用空闲内存来缓存磁盘I/O数据,以提升性能。available: 这是我们评估系统“还剩多少可用内存”时,应该关注的最重要指标。它估算出了在不进行交换(Swapping)的情况下,能够立即分配给应用程序的内存大小。它的值约等于free + (大部分的buff/cache)。
- 它清晰地将内存划分为物理内存(
-
使用场景:
- 当我想快速、清晰地了解系统总体的内存分配情况时,我会使用
free。 - 它非常适合在脚本中被调用,用于自动化的内存监控和告警。
- 常用的参数是
-h(human-readable,以GB/MB为单位显示) 和-s [秒数](例如free -h -s 5,每5秒刷新一次)。
- 当我想快速、清晰地了解系统总体的内存分配情况时,我会使用
2. top 命令:系统的“实时心电图”
top命令提供的是一个动态的、综合的系统性能视图,内存信息只是其中的一部分。
-
核心功能:
- 内存信息:
top命令的第四、五行(KiB Mem和KiB Swap)所展示的内存信息,其内容和free命令的输出是完全一致的。 - 超越内存:
top的强大之处在于,它不仅仅显示内存。它还同时展示了:- 系统负载 (Load Average)
- CPU使用率 (分用户、系统、等待等)
- 进程列表:这是最关键的部分,它会列出每一个进程的资源占用情况,包括
%CPU和%MEM。
- 内存信息:
-
使用场景:
- 当我发现系统内存使用率很高,需要进一步定位 “是哪个或哪些进程导致了高内存占用” 时,我必须使用
top。 - 在
top界面,我可以按M键,让进程列表按内存使用率(%MEM)降序排列,这样就能一眼找出内存消耗的“罪魁祸首”。 top是一个交互式的、用于实时诊断的工具。
- 当我发现系统内存使用率很高,需要进一步定位 “是哪个或哪些进程导致了高内存占用” 时,我必须使用
总结对比
free 命令top 命令我的使用习惯是:
- 用
free -h快速看一眼系统总体的内存健康状况,特别是available列。 - 如果发现
available内存过低,或者Swap有大量使用,再立即用top并按M键,去追查是哪个进程导致的内存问题。
面试官您好,要在Linux中用shell命令替换文件中的字符串,我首选的工具就是强大的流编辑器——sed (Stream Editor)。
1. 核心方案:sed 命令
sed 命令专门用于对文本进行流式(逐行)的处理,而字符串替换是它最核心的功能之一。
-
基本命令格式:
sed -i 's/要被替换的旧字符串/替换成的新字符串/g' 文件名 -
命令详解:
sed: 命令本身。-i: 这是最关键的参数,意为 “in-place”,即直接修改原始文件。如果不加这个参数,sed只会将修改后的结果打印到标准输出(屏幕上),而不会改变原文件。- 安全操作(带备份):为了防止误操作,我通常会先做一个备份。
sed的-i参数本身就支持一个非常方便的备份功能:sed -i.bak 's/旧字符串/新字符串/g' 文件名这样,在修改原文件之前,会自动创建一个名为
文件名.bak的备份文件。
- 安全操作(带备份):为了防止误操作,我通常会先做一个备份。
's/old/new/g': 这是sed的替换表达式,被单引号包围。s: 代表替换(substitute) 操作。/: 是分隔符,也可以用其他字符,如#或@,当字符串中包含/时特别有用。旧字符串: 要查找和替换的内容,支持正则表达式。新字符串: 用来替换旧字符串的内容。g: 全局替换(global) 标志。如果没有这个g,sed默认只替换每一行中第一次出现的匹配项。加上g,则会替换每一行中所有匹配到的项。
-
实际示例:
- 假设我要将一个
config.properties文件中的数据库地址,从192.168.1.100修改为db.prod.com。sed -i.bak 's/192.168.1.100/db.prod.com/g' config.properties
- 假设我要将一个
2. 其他替代方案
虽然sed是最佳选择,但在某些特定场景下,其他工具也能完成类似的工作。
-
awk命令:awk更擅长按列处理文本,但也可以用它的gsub函数来做全局替换。awk '{gsub("旧字符串", "新字符串"); print}' 文件名 > 新文件名- 注意:
awk本身不直接修改原文件,需要通过重定向>来生成一个新文件,然后再用mv命令覆盖回去,相对繁琐。
-
perl命令:- Perl提供了非常强大的文本处理能力,其语法与
sed非常相似。perl -pi.bak -e 's/旧字符串/新字符串/g' 文件名 - 这里的
-p表示循环处理文件每一行并打印,-i的作用和sed中完全一样。对于熟悉Perl的人来说,这也是一个很好的选择。
- Perl提供了非常强大的文本处理能力,其语法与
总结与我的选择
sedawkperl在日常工作和脚本编写中,只要涉及到文件内容的字符串替换,我99%的情况下都会选择 sed 命令。它已经成为了Linux下进行此类操作的“事实标准”,也是所有运维和开发人员都应该熟练掌握的工具。
面试官您好,sed和awk都是Linux下极其强大的文本处理工具,它们通常被并称为“文本三剑客”之二(另一个是grep)。虽然它们都能处理文本,但它们的设计哲学和擅长的领域是完全不同的。
简单来说,我的理解是:
sed(Stream Editor):是一个面向“行”的、非交互式的“编辑器”。它擅长对文本进行整行的增、删、改、查。awk(Aho, Weinberger, Kernighan):是一个面向“列”(或字段)的、“报告生成器”。它擅长将文本按列切分,然后对这些列进行复杂的计算、判断和格式化输出。
核心区别对比
sed (流编辑器)awk (报告生成器)s)、删除(d)、插入(i)、追加(a)$ 代表最后一行$0 (整行), $1 (第一列), NF (总列数), NR (当前行号)举例说明差异
假设我们有一个日志文件 access.log,内容如下:
192.168.1.100 GET /index.html 200 1024
192.168.1.101 POST /api/user 404 128
192.168.1.100 GET /static/logo.png 200 2048
sed 的用武之地:
-
场景1:将所有
GET替换为HTTP-GETsed 's/GET/HTTP-GET/g' access.logsed非常擅长这种基于行的字符串替换。 -
场景2:删除所有包含
404的行sed '/404/d' access.logsed也很擅长对整行进行删除。
awk 的用武之地:
-
场景1:只打印出访问IP和返回的状态码(第一列和第四列)
awk '{print $1, $4}' access.logawk默认按空格切分列,并用$1,$2…来引用,这对于提取数据非常方便。 -
场景2:计算所有返回
200状态的请求的总流量(第五列)awk '$4 == 200 {sum += $5} END {print "Total traffic for 200 OK: " sum " bytes"}' access.log这个例子完美地体现了
awk的编程能力:$4 == 200: 这是条件判断。sum += $5: 这是变量和数学运算。END { ... }: 这是在处理完所有行后,执行的收尾工作,非常适合用来输出最终的统计结果。
总结
- 如果你的需求是 “找到某一行,然后对它进行替换或删除”,那么
sed是你的首选,它更简单、更直接。 - 如果你的需求是 “把每一行按规则切分开,然后对切分后的部分进行计算、统计、或者按新的格式重新组合”,那么
awk是无与伦比的强大工具。
在实际工作中,我经常将grep, sed, awk通过管道符 | 串联起来使用,形成强大的文本处理流水线,以应对各种复杂的日志分析和数据处理任务。
面试官您好,您这个问题“查找日志中某个字符的长度”,我可以理解为以下两种可能的含义:
- 需求一:统计日志文件中,包含某个“字符串”的那些行的长度是多少?
- 需求二:统计日志文件中,某个“字符”总共出现了多少次?
我会针对这两种不同的需求,给出不同的解决方案。
需求一:统计包含特定“字符串”的那些行的长度
这个需求的目标是,先筛选出符合条件的行,然后计算这些行自身的长度。
-
核心思路:先用
grep筛选,再用awk或wc计算长度。 -
我的实现方案:
方案A:使用
grep+awk(最灵活)grep "ERROR" my_app.log | awk '{ print "Line " NR ": " length($0) " characters" }'grep "ERROR" my_app.log: 首先,从my_app.log中筛选出所有包含 “ERROR” 的行。|: 通过管道,将筛选出的结果,一行一行地传给awk。awk '{ print ... }':awk对每一行输入执行操作。length($0):awk的内置函数,计算当前整行($0) 的长度。NR:awk的内置变量,表示当前处理的是第几行(输入给awk的第几行)。
- 优点:
awk非常灵活,可以方便地进行格式化输出。
方案B:使用
grep+wc -L(更简洁)如果只是想找到最长的那一行的长度,
wc命令有一个不那么常用但非常有用的参数-L。grep "ERROR" my_app.log | wc -Lwc -L: 直接输出输入内容中,最长的那一行的长度。- 优点:命令非常简洁。
需求二:统计特定“字符”在文件中出现的总次数
这个需求的目标是,计算一个字符(比如字符a)在整个文件中总共出现了多少次。
-
核心思路:去掉换行符,然后用
grep -o或tr来处理。 -
我的实现方案:
方案A:使用
grep -o+wc -l(最推荐)grep -o "a" my_app.log | wc -lgrep -o "a" my_app.log: 这是最关键的一步。-o选项告诉grep只输出匹配到的部分,而不是整行,并且每个匹配项都单独占一行。- 例如,如果一行是
java,grep -o "a"会输出两行,每行一个a。
- 例如,如果一行是
| wc -l: 然后,我们只需要用wc -l来统计总共有多少行,这个行数就精确地等于字符a出现的总次数。- 优点:语义清晰,效率高。
方案B:使用
tr+grep+wctr -d -c 'a' < my_app.log | wc -ctr -d -c 'a' < my_app.log: 这是一个比较巧妙的方法。tr是字符转换/删除工具。-d表示删除。-c 'a'表示对字符a取补集(complement),即除了a之外的所有字符。- 所以,这条命令的意思是,从文件中删除所有不是
a的字符,只留下a。
| wc -c: 然后用wc -c来统计剩下的总字节数(因为a是单字节字符,字节数就等于个数)。- 优点:对于单字节字符非常高效。
总结
- 要查找包含特定字符串的行的长度,我推荐使用
grep ... | awk '{print length}'。 - 要统计特定字符在文件中的总出现次数,我推荐使用
grep -o 'char' ... | wc -l。
这两个场景的需求非常不同,需要用不同的命令组合来精确地解决。
面试官您好,当线上服务器出现CPU 100%告警时,这是一个非常紧急的情况,我会立即按照一套清晰的、从宏观到微观的思路进行排查和定位。
我的排查流程主要分为以下四步:
第一步:定位到具体“进程” (Find the Process)
首先,我需要找出是哪个进程在“作恶”。我会立刻登录到服务器,使用top命令。
- 执行
top命令:top会实时地显示系统中各个进程的资源占用情况,并且默认就是按CPU使用率降序排列的。
- 观察
%CPU列:- 我会立即关注
%CPU这一列,排在最上面的那个进程,通常就是导致CPU飙升的“罪魁祸首”。 - 我会记下这个进程的PID和USER(进程所有者),并初步判断它是什么应用(比如,是一个Java应用、Nginx还是MySQL)。
- 我会立即关注
第二步:定位到具体“线程” (Find the Thread)
一个进程通常包含多个线程。CPU 100%往往不是整个进程的所有线程都在均匀消耗,而是由其中一个或少数几个线程的异常行为(如死循环)导致的。所以,下一步就是找出是哪个线程在捣乱。
- 执行
top -H -p [PID]:- 使用
top的-H参数,可以展开指定进程(-p [PID])下的所有线程。 - 同样,在这个线程视图中,我再按一下大写的
P键,让它按CPU使用率排序。
- 使用
- 找到最耗CPU的线程ID:
- 此时,排在最前面的那个线程,就是我们要找的目标。我会记下它的线程ID(在
top中通常显示为PID或LWP列)。
- 此时,排在最前面的那个线程,就是我们要找的目标。我会记下它的线程ID(在
第三步:打印线程堆栈 (Dump the Thread Stack)
现在,我们已经有了“元凶”线程的ID,接下来就是要看看它到底在干什么。对于Java应用来说,jstack是我们的终极武器。
-
转换线程ID格式:
jstack工具需要的线程ID是十六进制格式的,而我们从top命令中得到的是十进制的。所以,需要先进行转换。printf "%x " [十进制线程ID]- 我会记下这个转换后的十六进制ID。
-
执行
jstack命令:- 使用
jstack命令打印出该Java进程的完整线程堆栈,并用grep来筛选出我们关心的那个线程。jstack [进程PID] | grep -A 20 [十六进制线程ID] grep -A 20: 这个参数非常有用,它会显示匹配到的那一行(nid=0x...)以及它后面(After)的20行,这样我们通常就能看到一个完整的、有意义的堆栈信息。
- 使用
第四步:分析堆栈,定位代码 (Analyze the Code)
现在,我们拿到了最关键的证据——问题线程的实时堆栈快照。
-
分析堆栈信息:我会仔细阅读打印出的
stack trace。- 寻找死循环:如果堆栈信息显示线程反复地在同一个或少数几个方法调用之间循环,特别是一些循环逻辑(如
while(true))或者不当的递归,那么基本可以断定是死循环导致的CPU飙升。 - 寻找复杂计算:也可能是某个线程正在执行一个极其耗时的、计算密集型的任务,比如复杂的算法、大规模的数据处理等。
- 寻找GC问题:如果发现大量的线程都阻塞在GC相关的堆栈上,或者线程名是
VM Thread,这可能表明系统正在进行频繁的Full GC,这也会导致CPU 100%。此时,我需要结合jstat -gcutil等工具进一步分析。
- 寻找死循环:如果堆栈信息显示线程反复地在同一个或少数几个方法调用之间循环,特别是一些循环逻辑(如
-
定位到代码:堆栈信息会精确地告诉我们问题出在哪个类的哪个方法的哪一行。根据这个线索,我就可以回到项目的源代码中,审查相关代码的逻辑,找到并修复问题。
总结我的排查路径
top (找到进程PID) -> top -H -p [PID] (找到线程LWP) -> printf (转换格式) -> jstack (打印堆栈) -> 分析代码
这是一套非常标准、高效且行之有效的线上CPU问题排查流程,能够帮助我快速、精准地从系统表象,层层深入,最终定位到代码根源。
面试官您好,在Linux服务器中查看负载情况,是我进行系统健康检查和性能瓶颈分析时的首要步骤。我主要通过 top、uptime、w 这几个核心命令来查看,而其中最重要的衡量指标,就是系统平均负载(Load Average)。
1. 使用什么命令查看?
a. top 命令 (最常用、最全面的工具)
这是我首选的命令。执行top后,在输出界面的第一行,就能清晰地看到系统负载信息。
- 示例输出:
top - 11:30:00 up 6 days, 3:15, 1 user, load average: 0.15, 0.20, 0.25 - 优点:
top不仅能看到负载,还能同时看到CPU使用率、内存使用情况、以及各个进程的实时资源消耗,提供了一个全面的、动态的系统视图。
b. uptime 命令 (最专注、最简洁的工具)
如果我只关心系统负载和运行时间,uptime命令是最简洁的选择。
- 示例输出:
11:30:00 up 6 days, 3:15, 1 user, load average: 0.15, 0.20, 0.25 - 它的输出内容,就是
top命令的第一行。
c. w 命令
w命令主要用来查看当前登录的用户信息,但它的第一行输出也和uptime完全一样,包含了系统负载信息。
2. 通过什么指标进行查看?—— 解读 Load Average
无论用哪个命令,最核心的负载指标都是 load average。这三个数字,分别代表系统在过去1分钟、5分钟、15分钟的平均负载。
a. Load Average 到底是什么?
它衡量的是在特定时间段内,系统中处于“可运行状态(Running/Runnable)”和“不可中断睡眠状态(Uninterruptible Sleep)”的平均进程数。
- 可运行状态 (R):进程正在CPU上运行,或者在运行队列中等待被CPU调度。这个值高,通常意味着CPU密集型的任务很多。
- 不可中断睡眠状态 (D):进程正在等待某个I/O操作完成(比如等待磁盘读写、网络响应)。这个状态下的进程虽然不消耗CPU,但它占用了资源并且无法被中断,同样反映了系统的“负载”。这个值高,通常意味着系统存在I/O瓶颈。
简单来说,Load Average 就是系统当前“有多忙”的一个量化指标。
b. 如何判断负载是否过高?
判断负载是否过高,不能只看这三个数字的绝对值,而必须将它与系统的逻辑CPU核心数进行比较。
-
获取CPU核心数:可以通过
lscpu命令,或者cat /proc/cpuinfo | grep "processor" | wc -l来获取。 -
判断标准:
- Load / Cores < 1.0: 如果平均负载除以CPU核心数,结果小于1.0,说明系统负载很低,CPU资源非常充裕。这是理想状态。
- Load / Cores = 1.0: 说明CPU资源刚好被用满,没有空闲也没有积压。系统处于满负荷状态,需要保持关注。
- Load / Cores > 1.0: 说明系统已经过载了。有超出CPU处理能力的进程正在排队等待。比如,一个4核的系统,如果load average达到8,就意味着平均有4个进程在运行,另外还有4个进程在排队。
-
分析趋势:
- 1分钟负载 > 5分钟负载 > 15分钟负载:说明系统负载在最近呈上升趋势,需要警惕。
- 1分钟负载 < 5分钟负载 < 15分钟负载:说明系统负载在最近呈下降趋势,问题可能正在缓解。
- 如果15分钟负载也持续很高,说明系统已经长时间处于高负载状态,问题比较严重,需要立即排查。
3. 排查思路
当我发现load average过高时,我会进一步使用top命令:
- 看CPU使用率 (
쒌ode>,:如果很高,说明是CPU密集型问题,我会按%sy)P键找出最耗CPU的进程。 - 看I/O等待 (
%wa):如果很高,说明是I/O瓶颈问题,我会使用iostat、iotop等工具,去定位是哪个进程或哪个磁盘的I/O出了问题。
通过这套组合拳,我就能从宏观的负载情况,一步步深入,定位到具体的性能瓶颈。
面试官您好,判断服务器内存是否够用,以及性能瓶颈是否出在内存上,是一个需要综合多个指标来判断的系统性工作。我不会只看单一的free命令输出,而是会结合多个工具,从宏观的资源使用情况和微观的系统行为两个层面来进行分析。
我的排查思路主要分为三步:看总量、看交换、看进程。
1. 第一步:看总量与可用量 (宏观检查)
这是最快速的、初步的健康检查,我主要使用free命令。
-
命令:
free -h-h(human-readable) 参数让输出更易读(以GB/MB为单位)。
-
关注的核心指标:
available列:这是我首先关注的最重要指标。它估算出在不发生交换(Swapping)的情况下,系统能够立即分配给新进程的内存大小。如果这个值过低(比如只剩下几百MB甚至几十MB),就是一个非常危险的信号,表明系统内存非常紧张。used和total列:通过used / total的比例,可以对内存使用率有一个直观的感受。但要记住,在Linux中,高used率不一定代表内存不足,因为大量的内存可能被用作了高效的buff/cache。
-
初步判断:如果
available内存持续处于一个很低的水平,我就会初步判定,内存资源可能存在压力。
2. 第二步:看交换活动 (判断瓶颈的关键证据)
如果物理内存真的不够用了,操作系统会启用Swap(交换空间),将内存中不常用的数据临时写入到磁盘上,以腾出物理内存。Swap的频繁使用,是判断内存成为性能瓶颈的最有力证据。
-
查看Swap使用情况:
free -h:Swap行的used列,如果这个值不为0,甚至很高,说明系统曾经或正在使用Swap。vmstat [间隔秒数]: 这是一个动态监控的利器。比如执行vmstat 1。- 我会重点关注
si(swap in) 和so(swap out) 这两列。 - 如果
si和so的值持续地、频繁地不为0,特别是在系统响应缓慢的时候,这就几乎可以断定,系统正在进行大量的内存交换。因为磁盘I/O比内存慢几个数量级,这种频繁的“换入换出”会导致系统性能急剧下降。
- 我会重点关注
-
结论:持续的、非零的
si/so值,是内存成为性能瓶颈的最强信号。
3. 第三步:看具体进程 (定位“元凶”)
当我们确认内存存在瓶颈后,下一步就是要找出是哪个或哪些进程消耗了大量的内存。
-
使用
top命令:- 执行
top。 - 在
top的交互界面中,按下大写的M键。这会让进程列表按照%MEM(物理内存使用率) 进行降序排列。 - 此时,排在最前面的几个进程,就是当前系统中的“内存消耗大户”。
- 执行
-
进一步分析:
- 我会关注这些进程的
RES(Resident Memory) 列,它表示该进程实际占用的物理内存大小。 - 根据进程名(
COMMAND列)和用户(USER列),判断这个进程是什么应用(比如是一个Java应用、MySQL还是Redis)。 - 如果是我们自己的Java应用,我就会怀疑可能存在内存泄漏(Memory Leak),或者JVM堆内存(
-Xmx)设置得过大。
- 我会关注这些进程的
总结我的判断流程
- 快速检查:执行
free -h,关注available是否过低。 - 瓶颈确认:执行
vmstat 1,观察si和so列是否持续有非零值。如果有,则确认内存是性能瓶颈。 - 定位元凶:执行
top,按M键,找出**%MEM和RES最高**的进程。 - 深入分析:针对找到的进程,进行专门的分析。
- 如果是Java应用,就使用
jmap,jstat等JVM工具去分析堆内存的使用情况,排查内存泄漏。 - 如果是数据库或缓存,就检查其配置是否合理,是否有大查询或大Key导致内存异常。
- 如果是Java应用,就使用
通过这样一套从宏观到微观的组合分析,我就能准确地判断出服务器的内存是否够用,以及性能瓶颈是否由内存问题所引起。
面试官您好,判断操作系统是否正在进行内存页面的换入换出(Swapping),以及评估其频率,是排查系统性能问题,特别是I/O瓶颈和内存压力的关键一步。
我会主要通过 vmstat 和 sar 这两个命令来观测。
1. vmstat 命令:最直观、最常用的实时监控工具
vmstat (Virtual Memory Statistics) 是我首选的、用于实时监控内存交换活动的工具。
-
命令:
vmstat [间隔秒数]例如,执行
vmstat 1,它会每秒刷新一次系统的各项统计信息。 -
关注的核心指标:
- 在
vmstat的输出中,有两列是专门用来显示内存交换情况的,它们位于swap区域:si(Swap In): 每秒从磁盘交换区换入到物理内存的页面数量(单位是KB/s)。so(Swap Out): 每秒从物理内存换出到磁盘交换区的页面数量(单位是KB/s)。
- 在
-
如何判断:
- 正常情况:在一个内存健康的系统中,
si和so的值应该长期保持为 0。 - 发生交换:如果我观察到
si和so的值持续地、频繁地不为0,这就明确无误地表明,操作系统因为物理内存不足,正在进行大量的页面换入换出操作。 - 频率评估:这两个值的大小,就直接反映了内存交换的频率和强度。数值越大,说明交换越频繁,对系统性能的影响也越严重,因为每一次交换都伴随着缓慢的磁盘I/O。
- 正常情况:在一个内存健康的系统中,
结论:持续的、非零的 si/so 值,是判断系统正在进行内存交换的最直接、最有力的证据。
2. sar 命令:更详细、可追溯历史的分析工具
sar (System Activity Reporter) 是一个功能更强大的系统活动报告工具,它可以提供更细粒度的分页统计信息,并且可以查看历史数据。
-
命令:
sar -B [间隔秒数]例如,执行
sar -B 1,它会每秒输出一次分页统计(Paging statistics)。 -
关注的核心指标:
sar -B的输出中,与内存回收和交换直接相关的关键指标有:pgpgin/s: 每秒从磁盘换入的千字节数(与vmstat的si类似)。pgpgout/s: 每秒换出到磁盘的千字节数(与vmstat的so类似)。pgscank/s: 这是后台内存回收线程(kswapd) 每秒扫描的页面数量。这个值不为0是正常的,表明系统在进行常规的、预防性的内存回收。pgscand/s: 这是应用程序在申请内存时,因内存不足而触发的“直接内存回收”(Direct Reclaim) 所扫描的页面数量。
-
如何判断:
- 健康状态:
pgscank/s可能有值,但pgscand/s应该基本为0。 - 性能瓶颈的信号:如果我发现
pgscand/s的值非常高,并且与系统响应变慢(抖动)的时间点相吻合,这就强烈地暗示,系统性能瓶颈在于直接内存回收。- 直接内存回收是一个同步的、阻塞的过程。当它发生时,申请内存的那个进程会被阻塞,直到内核回收了足够的内存为止。这个过程会导致明显的应用卡顿。
pgsteal/s:这个值是pgscank/s和pgscand/s回收成果的总和,可以用来评估整体的内存回收效率。
- 健康状态:
总结与我的排查思路
vmstatsi, sosar -Bpgscand/s我的排查流程通常是:
- 首先用
vmstat 1进行快速的实时诊断。如果si和so持续为0,基本可以排除内存交换是当前性能问题的直接原因。 - 如果
si和so很高,或者我想分析更深层次的内存回收行为(比如,系统为什么会卡顿),我就会使用sar -B 1,重点关注pgscand/s的值,以确认是否是“直接内存回收”在作祟。
通过这两个工具的结合使用,我就能非常精确地判断出系统是否存在内存交换,并评估其对系统性能的影响程度。
参考小林 coding