-
12月技术干货合集分享:1、MySQL实现双机双向热备份的详细教程—转载cid:link_62、MySQL参数innodb_force_recovery详解—转载cid:link_73、Mysql中RelayLog中继日志的使用—转载cid:link_84、MySql 预处理(Preprocessor)的使用小结—转载cid:link_95、 MySQL错误1005(errno: 150)的原因分析与解决方案—转载cid:link_06、MySQL慢查询优化从30秒到300毫秒的完整过程—转载cid:link_17、MySQL回滚binlog日志的实现示例—转载cid:link_28、MySql 游标和触发器概念及使用详解—转载cid:link_109、 nginx+lua+redis实现限流的示例代码—转载cid:link_310、Nginx 访问控制的多种方法—转载cid:link_411、Nginx服务器部署详细代码实例—转载cid:link_1112、nginx跨域访问配置的几种方法实现—转载cid:link_513、在服务器上获取Linux目录大小的三种实用方法—转载cid:link_1214、 Linux中实现文件复制与迁移的命令详解—转载https://bbs.huaweicloud.com/forum/thread-0235200649718185081-1-1.html
-
方法一:使用 du 命令查看Linux目录大小du(disk usage的缩写)命令可以告诉你目录占用了多少空间。该命令是Linux核心工具之一,适用于所有主流发行版。在终端中运行以下命令以检查当前目录的大小:1sudo du命令的输出会显示当前目录中所有文件的大小,单位为千字节(KB)。通常,这些数字可能较大且不易理解,可以使用 -h 选项来提高可读性:1sudo du -h你还可以通过传递目录的路径来查看指定目录的大小:1du -h /var如果你的账户没有访问某个文件的权限,你会看到如下错误信息而非目录列表:1du -h /var要解决这个问题,只需在 du 命令前加上 sudo 以获取目录及其内容的访问权限:1sudo du -h /var你可以使用 -c 选项来查看特定目录的总磁盘使用情况:1sudo du -c /var结合 -c 和 -h 选项以更易读的格式显示总使用情况:1sudo du -hc /var如何限制 du 命令的目录扫描深度默认情况下,du 命令会遍历整个目录。如果要处理一个多级文件夹,处理时间可能较长。可以使用 --max-depth 选项限制扫描的子目录级别。例如,使用 --max-depth=0 只扫描顶级目录:1sudo du -hc --max-depth=0 /var如果希望查看顶级目录及其下的一级子目录,可以使用以下命令:1sudo du -hc --max-depth=1 /var获取 du 命令的帮助du 命令非常灵活,可以通过各种选项获取精确的磁盘使用信息。可以使用以下命令查看这些选项的详细信息:1man du该命令不需要root权限即可运行,因为它只会显示手册文档。方法二:使用 tree 命令查看Linux目录大小tree 命令以图形化方式显示目录结构。它使用不同的颜色区分文件和文件夹,并通过线条显示子目录与文件之间的关系。可以使用以下命令以人类可读的格式查看当前目录下子目录的大小:1tree -d -h也可以通过传递目录路径来查看特定目录的结构:1tree /var获取 tree 命令的帮助可以通过以下命令获取 tree 命令的详细信息和可用选项:1man tree注意:在某些Linux发行版中,tree 命令默认不可用,可以通过系统的包管理器安装,例如在Ubuntu中运行以下命令:1sudo apt-get install tree方法三:使用 ls 命令查看Linux目录大小可以使用标准的 ls 命令列出系统中的文件和文件夹大小。不过需要注意的是,ls 命令主要用于列出目录中的文件,因此其显示的文件夹大小不够准确。建议使用 du 或 ncdu 工具来更精确地估算目录大小。运行以下命令可以列出当前工作目录中的文件和目录大小:1ls -lah仅列出输出中的文件夹如果只想列出输出中的目录而不包括文件,可以使用以下命令:1ls -d */或者将 ls 命令的输出通过管道传递给 grep 工具,以仅列出目录:1ls -F | grep "/$"结论了解如何确定Linux中的文件和文件夹大小对于保持服务器的良好运行至关重要。在本指南中,我们介绍了 du、tree、ls 这三种简单的方法来获取文件夹的大小。掌握这些方法后,你将能够更好地管理服务器,找到占用大量空间的文件夹,并做出合理的空间管理决策。
-
一、scp 命令复制文件:1scp -r /Users/test/Downloads/home/* root@39.11.11.15:/usr/share/nginx/html二、rsync 命令先创建文件夹1rsync -avz -e ssh /Users/test/Downloads/home/* root@39.11.11.15:/usr/share/nginx/html/在使用 scp 命令进行远程复制时,如果目标目录不存在,scp 命令本身不会自动创建目标目录。你需要在执行 scp 命令之前,先通过 SSH 连接到远程服务器并创建目标目录。以下是修改后的步骤:创建目标目录:首先通过 SSH 连接到远程服务器,然后创建目标目录。使用 scp 命令复制文件:在目标目录创建完成后,使用 scp 命令复制文件。以下是具体的命令:1234567891011# 1. SSH 连接到远程服务器ssh root@39.11.11.15 # 2. 在远程服务器上创建目标目录(如果不存在)mkdir -p /usr/share/nginx/html/home # 3. 退出 SSH 连接exit # 4. 使用 scp 命令复制文件scp -r /Users/test/Downloads/home/* root@39.11.11.15:/usr/share/nginx/html/home解释:ssh root@39.11.11.15:通过 SSH 连接到远程服务器。mkdir -p /usr/share/nginx/html/home:创建目标目录,-p 参数确保目录的父目录也会被创建。exit:退出 SSH 连接。scp -r /Users/test/Downloads/home/* root@39.11.11.15:/usr/share/nginx/html/home:使用 scp 命令复制文件到目标目录。如果你希望在一个命令中完成这些操作,可以使用 rsync 命令,它在复制文件之前会自动创建目标目录:1rsync -avz -e ssh /Users/test/Downloads/home/ root@39.11.11.15:/usr/share/nginx/html/home/解释:rsync:是一个更强大的文件同步工具。-avz:表示增量传输、保留文件权限、压缩数据。-e ssh:指定使用 SSH 进行传输。/Users/test/Downloads/home/:本地源目录。root@39.11.11.15:/usr/share/nginx/html/home/:远程目标目录。这样,rsync 会自动创建目标目录并复制文件。三、方法补充常用迁移文件操作如下:CP命令(常用于本机操作)cp 是 Linux 中最基本的文件复制命令,语法:cp [选项] 源文件 目标文件选项说明:-r 或 -R:递归复制目录及其内容(用于复制目录)。-i:交互模式,覆盖前提示用户确认。-v:显示详细的复制过程(verbose)。-f:强制复制,覆盖目标文件而不提示。-p:保留文件的原始属性(如权限、时间戳等)。-a:归档模式,等同于 -dpR,保留所有文件属性和递归复制目录。-u:仅当源文件比目标文件新时才复制(更新模式)。-l:创建硬链接而不是复制文件。-s:创建符号链接(软链接)而不是复制文件。12345# 将 file1.txt 复制为 file2.txtcp file1.txt file2.txt # 将 file1.txt 复制到指定目录cp file1.txt /home/user/documents/rcp命令(常用于远程操作)rcp用在远端复制文件或目录到本地。语法:rcp [-pr][源文件或目录][目标文件或目录]或 rcp [-pr][源文件或目录...][目标文件]选项说明:-r :递归处理,将指定目录下的文件与子目录一并处理(用于复制目录)。-p :保留源文件或目录的属性,包括拥有者,所属群组,权限与时间。12#复制远程文件到本地 rcp root@192.168.8.88:./test.txt test.txt SCP命令(常用于安全远程操作)scp 是加密的,更加安全的操作,rcp 是不加密的,scp 是 rcp 的升级加强版。语法:scp [选项] [源文件] [目标路径]常用选项说明:-r:递归复制整个目录。-P:指定远程主机的 SSH 端口号(默认是 22)。-p:保留文件的修改时间、访问时间和权限。-v:显示详细的调试信息,有助于排查问题。-C:启用压缩,可以加快传输速度。例如:本机文件上传到远程机器语法:scp [选项] 本地文件路径 用户名@远程主机地址:远程目录路径 使用:1scp /path/to/local/file.txt user@remotehost:/path/to/remote/directory/反之远程机器文件到本机语法:scp [选项] 用户名@远程主机地址:远程目录路径 本地文件路径使用: 1scp user@remotehost:/path/to/remote/directory/file.txt /path/to/local/如果是到当前目录可以是1scp user@remotehost:/path/to/remote/directory/file.txt .这个命令中:user@remotehost:/path/to/remote/directory/file.txt 是远程主机上的文件路径。. 表示当前目录。使用 rsync 命令是 Linux 系统中一个功能强大的文件同步工具,它能够高效地在本地或远程系统之间同步文件和目录。语法:rsync [选项] 源文件 目标文件rsync 的特点增量同步:仅传输变化的文件部分,节省带宽和时间保留属性:可以保持文件权限、时间戳等元数据压缩传输:支持数据传输时压缩,减少网络负载灵活排除:可以排除特定文件或目录远程支持:通过 SSH 安全地同步远程服务器文件还可以支持机器之间实时同步文件常用选项说明:-a(archive): 以归档模式传输文件,保持文件属性,保留符号链接、权限、时间戳等。-v(verbose): 显示详细的传输信息。-r(recursive): 递归传输文件夹及其子文件夹。-z(compress): 在传输过程中压缩文件,减少数据量。--delete: 删除目标路径中源路径不存在的文件。--exclude: 排除特定的文件或文件夹,不进行同步。--progress: 显示传输进度信息。-e: 指定远程shell连接命令,如SSH。1rsync -avz -e ssh /home/data/docker_data/db_data/ root@192.168.8.88:/home/software/docker_servers_data/db_data/1rsync -P -avz -e ssh /home/data/docker_data/db_data/ root@192.168.8.88:/home/software/docker_servers_data/db_data/以下是使用rsync进行断点续传的一些示例:从本地上传文件到服务器rsync -P -t -r -v -e [待传输文件] usr@IP:[接收目录]从服务器下载文件到本地rsync -P -t -r -v -e usr@IP:[待传输文件] [接收目录]本地文件夹同步1rsync -av /path/to/source /path/to/destination远程主机同步1rsync -azv -e ssh /path/to/source remote_host:/path/to/destination删除目标多余文件1rsync -av --delete /path/to/source /path/to/destination排除特定文件和目录1rsync -av --exclude='logs' --exclude='temp' /path/to/source /path/to/destination注意事项:在使用rsync进行断点续传时,需要注意以下几点:确保两台机器的时间同步,以避免因时间差异导致文件传输错误。使用-P参数,它是--partial和--progress的组合,可以在显示传输进度的同时支持断点续传。传输过程中,rsync会在目标目录下生成一个临时文件,可以通过ls -a命令查看。这个临时文件在下次传输时会被用来继续传输,从而实现断点续传。其他方法:使用CURL或WGET(适用于HTTP/HTTPS操作)需要通过HTTP或HTTPS协议上传文件到服务器(例如,使用某些Web服务),可以使用curl或wget。使用CURL上传文件:123curl -X POST -F "file=@/path/to/local/file.txt" http://remotehost/upload.php#或者,如果服务器支持HTTP PUT方法:curl -T /path/to/local/file.txt http://remotehost/upload.php使用WGET上传文件(通常用于下载,但可以模拟上传):1wget --method=PUT --body-file=/path/to/local/file.txt http://remotehost/upload.php还有FTP或者SFTP也都是可以实现的。至此就可以进行文件移动操作了
-
AppImage 是 Linux 系统中一种新型的软件包格式,它与 rpm、deb 这些软件包格式相比最大的不同便是:(1)无需安装,即用即删。(2)只需打包一次,便可到处运行。完美的解决了不同 Linux 发行版(Ubuntu/Debian/Fedora/CentOS)之间软件包不统一的问题。它的工作原理便是将程序运行所需的文件全部打包在一个文件中,待程序运行时再将这些文件提取在 /tmp/.mount_xxxxxxx/ 目录中,然后执行 AppRun 脚本启动程序以进行资源的调用。以下便是一个 AppImage 文件内部包含的目录树结构:AppDir/ ├── AppRun ├── 应用图标.png ├── 程序名.desktop ├── usr/ ├── bin/ ├── lib/ ├── share/它本质上就是一个 squashfs 文件系统 + runtime 执行器。特别注意:(1)要实现跨平台运行,待打包的程序最好是在 CentOS 7 系统上进行编译 ,然后再进行打包。【注:编译 C/C++ 程序所使用的系统库 glibc 在 Linux 系统上几乎肯定存在,而该库有着良好的向后兼容性,因此使用旧版本的 glibc 库编译出来的程序几乎可以完美的运行在新版本的 glibc 系统上。而在 CentOS 7 上的 glibc 版本是 2.17,该版本较旧且兼容性较好,因此在其系统上编译出来的 C 程序通常也可以在大部分的 Linux 发行版系统中使用。】(2)待打包程序依赖的 lib 文件中最好只包含其专属的库文件即可,不要包含类似 glibc 这样的系统库文件。【注:这是因为在 A 系统中的 glibc 文件通常并不可以在 B 系统中使用,因此为了避免 AppImage 程序运行错误,请勿这样去做。再者,glibc 在 Linux 系统中是肯定会存在的,因此也并不需要额外去包含这样的依赖文件。】手动打包 - appimagetool linuxdeploy是由 AppImage 官方制作的打包工具,在使用它进行打包时,必须要先分析待打包程序的动态库依赖情况,然后再完成对 AppDir 目录的装填,最后才能使用 appimagetool 完成对程序的打包。由于分析程序的依赖情况是个很复杂的问题,因此该工具在使用上体验并不太好。接下来,我将演示如何对一个简单的 C 程序完成打包过程:(1)文件准备:hello.c。// 主文件 hello.c#include <stdio.h>int main() { printf("Hello Appimage\n"); return 0;}(2)编译并打包#(1)编译及检验运行gcc -o hello hello.c./hello#(2)制作 AppDir 目录树mkdir -p AppDir/usr/bin/cp ./hello AppDir/usr/bin/wget https://github.com/boolean-world/appimage-resources/blob/master/hello-world-appimage/hello-world-icon.png -O AppDir/hello.png #任意图片文件即可nano AppDir/hello.desktop #文件内容见下方nano AppDir/AppRun #脚本内容见下方#(3)开始制作 AppImage 程序/root/appimagetool-x86_64.AppImage AppDir/附注:hello.desktop 文件如下:[Desktop Entry]Name=helloExec=helloIcon=helloType=ApplicationCategories=Utility;Terminal=trueAppRun 脚本如下:#!/bin/shAPPDIR="$(dirname "$(readlink -f "$0")")"# 添加库目录if [ -d "$APPDIR/lib64" ]; then export LD_LIBRARY_PATH="$APPDIR/lib64:$LD_LIBRARY_PATH"fiif [ -d "$APPDIR/usr/lib" ]; then export LD_LIBRARY_PATH="$APPDIR/usr/lib:$LD_LIBRARY_PATH"fi# 启动主程序 //注意:不同应用主程序路径需要修改exec "$APPDIR/usr/bin/hello" "$@"AppDir 目录树结构如下:AppDir/├── AppRun //启动程序,可以是简单的脚本,也可以是 ELF,只要保证运行该脚本主程序能被启动即可。├── hello.desktop //注意 EXEC 的值,它对应的是/usr/bin/目录中的程序,而 Icon 对应的是当前目录├── hello.png //也支持 svg 格式└── usr └── bin └── hello自动打包 - linuxdeploylinuxdeploy是一个由第三方制作的 AppImage 打包工具,与 appimagetool 不同的是,它可以对待打包程序自动进行依赖分析,并自动将所需的依赖及资源文件按照 AppDir 的目录格式给装填完毕,用户只需将模版化的 desktop 文件和 icon 文件准备好即可,使用起来简直美滋滋。【示例一】:接下来,我将演示如何对一个需要依赖的简单 C 程序完成打包过程:(1)文件准备:mylib.h、mylib.c、main.c、Makefile。// 动态库头文件 mylib.h#ifndef MYLIB_H#define MYLIB_Hint add(int a, int b);void hello();#endif// 动态库源码 mylib.c#include <stdio.h>#include "mylib.h"int add(int a, int b) { return a + b;}void hello() { printf("Hello from my dynamic library!\n");}// 主程序 main.c#include <stdio.h>#include "mylib.h"int main() { hello(); int result = add(3, 5); printf("3 + 5 = %d\n", result); return 0;}# Makefile 文件CC=gccCFLAGS=-fPIC -WallLDFLAGS=-sharedTARGET_LIB=libmylib.soTARGET_MAIN=mainall: $(TARGET_LIB) $(TARGET_MAIN)$(TARGET_LIB): mylib.o $(CC) $(LDFLAGS) -o $(TARGET_LIB) mylib.omylib.o: mylib.c mylib.h $(CC) $(CFLAGS) -c mylib.c$(TARGET_MAIN): main.o $(TARGET_LIB) $(CC) main.o -L. -lmylib -o $(TARGET_MAIN)main.o: main.c mylib.h $(CC) -c main.cclean: rm -f *.o $(TARGET_MAIN) $(TARGET_LIB)(2)编译并打包#(1)编译及检验运行cd myappmakemv libmylib.so /lib64/libmylib.so./main#(2)制作的 main.desktop 文件内容cat main.desktop[Desktop Entry]Name=mainExec=mainIcon=mainType=ApplicationCategories=Utility;Terminal=true#(3)获取一个 Icon 文件wget https://github.com/boolean-world/appimage-resources/blob/master/hello-world-appimage/hello-world-icon.png -O main.png#(4)开始制作 AppImage 程序/root/linuxdeploy-x86_64.AppImage --appdir /root/myapp --output appimage --icon-file main.png --desktop-file main.desktop -e mainls -l main*.AppImage 【示例二】:最后,我再演示如何对一个系统命令 find 完成打包过程:#(1)制作的 find.desktop 文件内容cat find.desktop[Desktop Entry]Name=findExec=findIcon=findType=ApplicationCategories=Utility;Terminal=true#(2)获取一个 Icon 文件wget https://github.com/boolean-world/appimage-resources/blob/master/hello-world-appimage/hello-world-icon.png -O find.png#(3)开始制作 AppImage 程序cd $(dirname $(which find))/root/linuxdeploy-x86_64.AppImage --appdir /root/find --output appimage --icon-file find.png --desktop-file find.desktop -e findls -l find*.AppImage 注意:(1)建议将 icon 和 desktop 文件放置在 find 命令根目录下,这样在打包的时候能够避免很多问题。(2)由于 linuxdeploy 在打包环节调用的是 appimagetool,而 appimagetool 在打包的时候会在 github 上拉取 runtime 文件,因此在使用前建议设置全局代理以确保 github 可访问。(*)全局代理设置export http_proxy=http://192.168.56.1:7890export https_proxy=http://192.168.56.1:7890export no_proxy=192.168.56.1,localhostexport HTTP_PROXY=http://192.168.56.1:7890export HTTPS_PROXY=http://192.168.56.1:7890export NO_PROXY=192.168.56.1,localhost文章来源:https://www.cnblogs.com/kqdssheng/p/19269888
-
在软件开发的演进长河中,我们始终在追求一个理想状态:一次编写,随处运行。从 Java 的“Write Once, Run Anywhere”到 .NET 的跨平台战略,再到容器化与云原生的兴起,这一目标不断被重新定义。而今天,一项名为 WebAssembly(简称 Wasm) 的技术正以惊人的速度重塑软件分发、执行与安全模型——它不仅让高性能应用在浏览器中成为可能,更正在成为操作系统之上的通用轻量级运行时,悄然开启“后容器时代”的序幕。一、什么是 WebAssembly?不只是浏览器的“加速器”WebAssembly 是一种低级的、可移植的字节码格式,设计目标是在现代 Web 浏览器中以接近原生的速度执行代码。它于 2017 年由 W3C 联合 Mozilla、Google、Microsoft 和 Apple 正式标准化,如今已被所有主流浏览器支持。但 WebAssembly 的意义远不止于此:Wasm 不是 JavaScript 的替代品,而是其高性能补充;更重要的是,它正在脱离浏览器,成为通用的沙箱化运行时。核心特性特性说明接近原生性能预编译为紧凑字节码,JIT 编译后执行效率达 C/C++ 的 90%+语言无关支持 Rust、C/C++、Go、Python(实验性)、TypeScript 等编译为 Wasm安全沙箱默认无文件/网络访问权限,能力通过“导入”显式授予快速启动毫秒级冷启动,远优于 JVM 或容器跨平台同一字节码可在 Windows、Linux、macOS、甚至嵌入式设备运行二、从浏览器到全栈:Wasm 的三大演进阶段阶段 1:浏览器中的高性能模块(2017–2020)典型应用:Figma(设计工具)、AutoCAD Web、视频编辑器价值:将计算密集型任务(如图像处理、物理引擎)从 JS 迁移至 Wasm,提升流畅度// Rust 示例:计算斐波那契数列(编译为 Wasm)#[no_mangle]pub extern "C" fn fibonacci(n: u32) -> u32 { if n <= 1 { return n; } fibonacci(n - 1) + fibonacci(n - 2)}阶段 2:服务端 Wasm(2020–2023)随着 WASI(WebAssembly System Interface) 的提出,Wasm 获得了访问文件、网络、时间等系统能力的标准接口,从而走出浏览器。代表项目:Wasmtime(Bytecode Alliance):独立 Wasm 运行时WasmEdge:面向边缘和 Serverless 优化Deno:内置 Wasm 支持的 JS/TS 运行时阶段 3:通用插件与函数运行时(2023–至今)Wasm 正成为安全、轻量、跨语言插件系统的事实标准:场景案例数据库扩展SingleStore、FerretDB 允许用 Wasm 编写 UDFAPI 网关插件Envoy Proxy 支持 Wasm 过滤器Serverless 函数Shopify Functions、Cloudflare Workers区块链智能合约CosmWasm(Cosmos 生态)CLI 工具插件HashiCorp Vault、Terraform 插件实验三、实战:用 Rust 编写一个 Wasm Serverless 函数我们将创建一个简单的 HTTP 处理函数,部署到 WasmEdge 运行时。1. 初始化项目(使用 cargo-wasi)cargo new --lib hello-wasmcd hello-wasm2. 修改 Cargo.toml[package]name = "hello-wasm"version = "0.1.0"edition = "2021"[lib]crate-type = ["cdylib"] # 编译为动态库(Wasm 模块)[dependencies]wasmedge-bindgen = "0.4"wasmedge-macro = "0.4"3. 编写函数逻辑// src/lib.rsuse wasmedge_bindgen::*;use wasmedge_macro::*;#[async_func]pub fn handle_request(request: Vec<u8>) -> Vec<u8> { let name = std::str::from_utf8(&request).unwrap_or("Guest"); format!("Hello, {}! Time: {}", name, chrono::Utc::now()).into_bytes()}4. 编译为 Wasmcargo build --target wasm32-wasi --release# 输出: target/wasm32-wasi/release/hello_wasm.wasm5. 在 WasmEdge 中运行# 安装 WasmEdgecurl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash# 启动 HTTP 服务wasmedge --http-addr=0.0.0.0:3000 hello_wasm.wasm现在访问 http://localhost:3000/Alice,将返回:Hello, Alice! Time: 2025-11-17 08:30:45 UTC优势:冷启动 < 10ms内存占用 < 5MB自动沙箱隔离,无法访问主机文件系统四、Wasm vs 容器:为何它是“后容器时代”的答案?维度Docker 容器WebAssembly启动速度秒级毫秒级内存开销100MB+1–10MB镜像大小100MB–1GB100KB–10MB安全模型基于 Linux Namespace/cgroups基于能力的安全(Capability-based)多语言支持需打包完整运行时共享统一运行时冷启动成本高(Serverless 痛点)极低趋势:在边缘计算、FaaS(Function as a Service)、微服务插件等场景,Wasm 正逐步替代轻量级容器。 结语:Wasm 不是未来,而是现在WebAssembly 已从“浏览器性能补丁”蜕变为新一代软件交付与执行的通用基座。它以极致的轻量、安全与跨平台能力,解决了云原生时代的关键痛点:如何在保障安全的前提下,实现极致的资源效率与启动速度。💡 给开发者的行动建议:前端工程师:尝试用 Wasm 优化图像/音视频处理后端工程师:评估 WasmEdge/Wasmtime 作为 FaaS 运行时系统架构师:在插件系统、边缘节点中引入 Wasm 沙箱区块链开发者:关注 CosmWasm、Substrate Wasm 智能合约正如当年 JavaScript 将浏览器变成应用平台,WebAssembly 正在将整个计算世界变成一个安全、高效、可组合的函数网络。这一次,舞台不再局限于浏览器——而是无处不在。
-
11月技术干货合集分享:1、 Linux使用waitpid回收多个子进程的方法小结 — 转载cid:link_02、 Linux获取子进程退出值和异常终止信号的完整指南 — 转载cid:link_1PostgreSQL 安装部署及配置使用教程 — 转载cid:link_34、 MongoDB分片模式集群部署方案详解 — 转载cid:link_4redis缓存神器之@Cacheable注解详解 — 转载cid:link_55、通过Redisson监听Redis集群的Key过期事件的实现指南 — 转载cid:link_66、Oracle数据库空间回收从诊断到优化实战指南详细教程 — 转载cid:link_77、MySQL EXPLAIN详细解析 — 转载cid:link_88、Linux使用wait函数回收子进程的操作指南 — 转载cid:link_99、Nginx 中的Rewrite 使用示例详解 — 转载cid:link_1010、 Linux系统日志持久化配置的完整指南 — 转载cid:link_1111、 PostgreSQL中pg_surgery的扩展使用 — 转载cid:link_1212、PostgreSQL扩展bloom的具体使用 — 转载cid:link_1313、PostgreSQL扩展UUID-OSSP的使用方法 — 转载cid:link_214、MySQL深度分页优化的常用策略 — 转载cid:link_1415、Linux使用du和sort命令查找最大文件和目录 — 转载https://bbs.huaweicloud.com/forum/thread-0250198135428299001-1-1.html
-
JFR(Java Flight Recorder)是 JDK 内置的高性能诊断工具,以极低开销记录 JVM 和应用运行时的关键事件。然而,不当配置可能导致录制开销升高、文件过大或分析困难。尤其在高并发、长时间运行的生产环境(如鲲鹏 ARM64 服务器)中,合理优化 JFR 的使用策略至关重要。本文将从 录制配置、资源控制、事件筛选、分析效率 四个维度,系统讲解如何优化 JFR 的性能表现。一、核心原则:平衡“数据完整性”与“运行开销”JFR 的默认配置(profile.jfc)已针对通用场景做了权衡,但实际业务需根据目标调整:目标推荐策略长期监控(7×24)仅启用关键事件(GC、线程、CPU 采样),降低采样频率故障复现启用详细事件(方法、异常、I/O),短时间高保真录制性能压测对比使用统一配置,确保数据可比性二、优化录制阶段的性能1. 选择合适的预设模板JDK 提供两个内置模板:default.jfc:基础事件(低开销,适合长期运行)profile.jfc:包含方法采样、锁竞争等(中等开销,适合性能分析)建议:# 长期监控用 default-XX:StartFlightRecording=settings=default,duration=1h,filename=/data/jfr/low.jfr# 深度分析用 profile-XX:StartFlightRecording=settings=profile,duration=5m,filename=/data/jfr/high.jfr 毕昇 JDK 还提供 kunpeng-optimized.jfc(如有),可进一步适配 ARM64。2. 自定义 .jfc 配置文件(推荐)复制并修改模板,关闭非必要事件:<!-- custom-low-overhead.jfc --><configuration ...> <event name="jdk.MethodSampling"> <setting name="enabled">false</setting> <!-- 关闭方法采样 --> </event> <event name="jdk.JavaMonitorEnter"> <setting name="enabled">true</setting> <setting name="threshold">10ms</setting> <!-- 仅记录 >10ms 的锁等待 --> </event> <event name="jdk.GCPhasePause"> <setting name="enabled">true</setting> </event></configuration>启动时指定:-XX:StartFlightRecording=settings=/path/to/custom-low-overhead.jfc,...3. 控制录制时长与文件大小避免无限制录制导致磁盘爆满:# 方式1:固定时长duration=10m# 方式2:循环录制(保留最近数据)maxsize=500MB,maxage=1h# 方式3:条件触发(JDK 17+ 支持)-XX:FlightRecorderOptions:repository=/tmp/jfr-cache生产建议:单文件 ≤ 1GB总录制时长 ≤ 30 分钟(除非明确需要长期趋势)4. 调整采样频率(降低 CPU 开销)关键参数:jdk.ThreadCPULoad:线程 CPU 采样间隔(默认 1s)jdk.ExecutionSample:方法栈采样间隔(默认 10ms)在自定义 .jfc 中调整:<event name="jdk.ExecutionSample"> <setting name="period">100ms</setting> <!-- 从 10ms 放宽到 100ms --></event> 注意:采样间隔越长,热点方法识别精度越低。三、减少 I/O 与内存开销1. 使用高速存储路径将 .jfr 文件写入 SSD 或内存盘:filename=/dev/shm/app.jfr # 写入 tmpfs(内存文件系统) 优势:避免磁盘 I/O 成为瓶颈 风险:重启丢失,需及时备份2. 启用压缩(JDK 17+)-XX:FlightRecorderOptions=compress=true可减少 30%~50% 文件体积。3. 避免多进程同时写同一目录每个 Java 进程应使用独立子目录,防止文件锁竞争。四、优化分析阶段的效率1. 使用命令行快速筛查(避免 GUI 开销)# 查看 GC 暂停总时间jfr print --events GCPhasePause app.jfr | grep "duration"# 统计最耗时的 10 个方法jfr summary app.jfr --category "Code" | head -n 102. 在分析机而非生产机运行 JMC将 .jfr 文件拷贝至开发机或专用分析服务器;避免在生产环境启动图形界面工具。3. 使用脚本自动化分析结合 jfr 命令 + Shell/Python 脚本,实现:自动提取关键指标生成性能报告触发告警(如 GC 暂停 > 100ms)示例脚本片段:MAX_PAUSE=$(jfr print --events GCPhasePause app.jfr | awk '/duration/ {print $2}' | sort -nr | head -1)if [ "$MAX_PAUSE" -gt 100000000 ]; then # 100ms in nanoseconds echo "ALERT: Max GC pause exceeds 100ms!"fi五、鲲鹏 ARM64 环境下的特别建议优先使用毕昇 JDK其 JFR 实现针对鲲鹏处理器的缓存、NUMA 架构优化,事件采集效率更高。关注 ARM64 特有事件如:jdk.CPULoad:ARM64 大小核调度可能影响 CPU 利用率jdk.NativeLibrary:验证 native 库是否为 ARM64 编译对比 x86 基线在相同负载下,分别录制 x86 与鲲鹏的 JFR 数据,使用 JMC 的 Compare 功能 定位架构差异点。
-
一、系统日志存储机制概述1.1 默认存储行为在红帽企业Linux 9中,系统日志默认存储在/run/log目录中。重要特性:易失性存储:系统重启后自动清除内存存储:/run文件系统仅存在于运行时内存性能优先:读写速度快,但不持久1.2 为什么需要持久化日志?默认配置的问题:系统重启后无法查看历史日志故障排查时缺少关键历史信息无法进行安全审计和历史分析二、配置持久化系统日志2.1 核心配置文件持久化配置通过/etc/systemd/journald.conf文件实现,主要修改Storage参数:12# 编辑配置文件sudo vim /etc/systemd/journald.conf2.2 Storage参数详解参数值存储位置持久性说明persistent/var/log/journal✅ 持久系统重启后保留日志volatile/run/log/journal❌ 易失默认值,重启后清除auto自动选择条件持久目录存在则持久,否则易失none无存储❌ 易失丢弃所有日志(仅转发)2.3 配置步骤详解步骤1:创建持久化目录1sudo mkdir /var/log/journal步骤2:编辑配置文件1sudo vim /etc/systemd/journald.conf在[Journal]部分添加或修改:12[Journal]Storage=persistent步骤3:重启服务生效1sudo systemctl restart systemd-journald2.4 验证配置检查目录结构:12345# 查看生成的日志目录ls /var/log/journal/ # 查看具体的日志文件ls /var/log/journal/4ec03abd2f7b40118b1b357f479b3112/预期输出:12system.journal # 系统日志user-1000.journal # 用户日志三、日志文件结构与管理3.1 日志文件特点二进制格式:结构化存储,带索引文件扩展名:.journal目录命名:长十六进制字符串(机器ID)自动分类:系统日志、用户日志分开存储3.2 日志大小管理systemd-journald具有自动的日志轮转和大小限制机制:默认限制规则:每月自动触发日志轮转日志大小不超过文件系统的10%保证文件系统可用空间不低于15%查看当前日志大小:1journalctl | grep -E 'Runtime Journal|System Journal'输出示例:12Mar 15 04:21:14 host systemd-journald[226]: Runtime Journal is 8.0M, max 113.3M, 105.3M free.Mar 15 04:21:19 host systemd-journald[719]: System Journal is 8.0M, max 4.0G, 4.0G free.四、按系统启动查看日志4.1 查看启动列表持久化日志后,可以查看历次系统启动记录:12# 列出所有系统启动事件journalctl --list-boots输出示例:1234567-6 27de... Wed 2022-04-13 20:04:32 EDT-Wed 2022-04-13 21:09:36 EDT-5 6a18... Tue 2022-04-26 08:32:22 EDT-Thu 2022-04-28 16:02:33 EDT-4 e2d7... Thu 2022-04-28 16:02:46 EDT-Fri 2022-05-06 20:59:29 EDT-3 45c3... Sat 2022-05-07 11:19:47 EDT-Sat 2022-05-07 11:53:32 EDT-2 dfae... Sat 2022-05-07 13:11:13 EDT-Sat 2022-05-07 13:27:26 EDT-1 e754... Sat 2022-05-07 13:58:08 EDT-Sat 2022-05-07 14:10:53 EDT 0 ee2c... Mon 2022-05-09 09:56:45 EDT-Mon 2022-05-09 12:57:21 EDT字段说明:左侧数字:启动序号(0=当前,-1=上一次,-2=上上次)中间ID:启动的唯一标识符右侧时间:启动的开始和结束时间4.2 按启动序号查看日志1234567891011# 查看当前启动的日志journalctl -b # 查看上一次启动的日志journalctl -b -1 # 查看上上次启动的日志journalctl -b -2 # 查看特定序号的启动日志journalctl -b 14.3 故障排查应用场景:系统崩溃分析12345678# 查看崩溃前最后一次启动的日志journalctl -b -1 # 结合时间范围筛选journalctl -b -1 --since "14:00" --until "15:00" # 只看错误信息journalctl -b -1 -p err五、高级配置选项5.1 自定义大小限制在/etc/systemd/journald.conf中可以调整大小限制:12345[Journal]SystemMaxUse=1G # 系统日志最大使用量SystemKeepFree=2G # 系统保持空闲空间RuntimeMaxUse=100M # 运行时日志最大使用量RuntimeKeepFree=200M # 运行时保持空闲空间5.2 压缩配置123[Journal]Compress=yes # 启用压缩Seal=yes # 启用密封(安全特性)六、实际应用场景6.1 生产环境配置建议服务器环境:123456[Journal]Storage=persistentSystemMaxUse=2GSystemKeepFree=4GCompress=yesMaxRetentionSec=1month开发测试环境:123[Journal]Storage=autoSystemMaxUse=500M6.2 故障排查流程1234567891011# 1. 确认系统重启情况journalctl --list-boots # 2. 查看问题发生时间段的日志journalctl -b -1 --since "2024-01-15 14:00" --until "2024-01-15 15:00" # 3. 筛选关键错误信息journalctl -b -1 -p err --no-pager # 4. 查看特定服务日志journalctl -b -1 -u nginx.service七、注意事项与最佳实践7.1 权限管理123# 确保日志目录权限正确sudo chown root:systemd-journal /var/log/journalsudo chmod 2755 /var/log/journal7.2 监控日志大小123456# 定期检查日志大小journalctl --disk-usage # 手动清理旧日志sudo journalctl --vacuum-time=30d # 保留30天sudo journalctl --vacuum-size=1G # 保留1GB7.3 备份策略12# 备份重要时间段的日志sudo journalctl --since "2024-01-01" --until "2024-01-31" > /backup/january-2024.log八、总结8.1 配置持久化日志的价值故障诊断:系统崩溃后仍可分析日志安全审计:保留完整的安全事件记录性能分析:长期跟踪系统性能趋势合规要求:满足日志保留的法规要求8.2 关键命令速查命令功能使用场景journalctl --list-boots列出系统启动记录查看重启历史journalctl -b -1查看上一次启动日志分析系统崩溃journalctl --disk-usage查看日志磁盘使用监控存储空间journalctl --vacuum-*清理旧日志释放磁盘空间
-
wait 函数的作用wait 函数的作用是阻塞父进程,直到一个子进程终止。当子进程终止时,wait 函数会返回子进程的退出状态,并回收子进程的资源。具体功能包括:阻塞父进程:父进程在调用 wait 后会进入阻塞状态,直到子进程终止。获取子进程退出状态:通过 wait 函数可以获取子进程的退出状态信息。回收子进程资源:wait 函数会清理子进程的进程控制块(PCB),释放子进程占用的资源【1†source】。创建僵尸进程的示例在深入讲解 wait 函数之前,我们先通过一个示例代码展示僵尸进程的产生。123456789101112131415161718192021222324252627#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h> int main() { pid_t pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程 printf("Child process (PID: %d) is exiting.\n", getpid()); exit(EXIT_SUCCESS); } else { // 父进程 printf("Parent process (PID: %d) is running. Child PID: %d\n", getpid(), pid); sleep(10); // 父进程继续运行,但不调用 wait() printf("Parent process exiting.\n"); exit(EXIT_SUCCESS); } return 0;}代码解释fork() :创建子进程。pid 为 0 表示子进程,正值表示父进程的 PID。子进程终止:子进程调用 exit(EXIT_SUCCESS) 终止。父进程未回收:父进程未调用 wait,导致子进程成为僵尸进程。运行上述代码后,可以使用以下命令查看僵尸进程:1ps -o pid,ppid,stat,cmd僵尸进程的 STAT 列将显示为 Z【5†source】。使用 wait 函数回收子进程为了避免僵尸进程的产生,父进程需要调用 wait 或 waitpid 函数来回收子进程。以下是使用 wait 函数的示例代码。12345678910111213141516171819202122232425262728293031323334353637#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h> int main() { pid_t pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程 printf("Child process (PID: %d) is exiting.\n", getpid()); exit(EXIT_SUCCESS); } else { // 父进程 printf("Parent process (PID: %d) is waiting for child %d.\n", getpid(), pid); // 调用 wait 回收子进程 int status; pid_t child_pid = wait(&status); if (child_pid == -1) { perror("wait"); exit(EXIT_FAILURE); } printf("Child process %d terminated with status %d.\n", child_pid, status); exit(EXIT_SUCCESS); } return 0;}代码解释fork() :创建子进程。子进程终止:子进程调用 exit(EXIT_SUCCESS)。父进程调用 wait :父进程调用 wait(&status) 阻塞,直到子进程终止。获取退出状态:status 包含子进程的退出状态信息。回收子进程资源:wait 函数回收子进程的资源,避免僵尸进程的产生。wait 函数的详细解析函数原型1pid_t wait(int *status);参数说明status :一个指向整数的指针,用于存储子进程的退出状态信息。如果 status 为 NULL,则不返回退出状态信息【6†source】。返回值成功:返回子进程的 PID。失败:返回 -1,并设置 errno 以指示错误原因。注意事项wait 函数会阻塞父进程,直到子进程终止。如果子进程已经终止,wait 函数会立即返回。如果父进程调用 wait 时没有子进程,函数会阻塞,直到有子进程终止【7†source】。处理僵尸进程的方法除了使用 wait 函数,还可以通过以下方法避免僵尸进程的产生:及时调用 wait 或 waitpid :父进程在子进程终止后立即调用 wait 或 waitpid 回收子进程。使用信号处理:设置 SIGCHLD 信号处理函数,在信号处理函数中调用 wait 或 waitpid【8†source】。忽略 SIGCHLD 信号:调用 signal(SIGCHLD, SIG_IGN);,让内核自动回收子进程【9†source】。常见问题解答1. wait 函数会阻塞父进程吗?是的,wait 函数会阻塞父进程,直到子进程终止【1†source】。2. 如何避免僵尸进程的产生?及时调用 wait 或 waitpid 回收子进程,或者设置 SIGCHLD 信号处理函数【8†source】。3. wait 和 waitpid 的区别是什么?wait 函数会阻塞父进程,直到任意一个子进程终止。waitpid 函数可以指定要等待的子进程,并支持非阻塞模式【6†source】。总结wait 函数是 Linux 进程管理中一个重要的工具,用于回收子进程并避免僵尸进程的产生。通过调用 wait 函数,父进程可以获取子进程的退出状态信息,并清理子进程的资源。在实际开发中,及时调用 wait 或 waitpid 函数是确保系统稳定性和高效性的关键。
-
子进程退出状态的基本概念在Linux/Unix系统中,子进程终止时会向父进程发送一个SIGCHLD信号,父进程可以通过特定的系统调用来获取子进程的终止状态。这个状态包含了子进程是正常退出还是被信号异常终止,以及相关的退出码或信号编号。wait()和waitpid()系统调用父进程可以使用wait()或waitpid()系统调用来等待子进程终止并获取其状态。wait()系统调用1234#include <sys/types.h>#include <sys/wait.h> pid_t wait(int *status);wait()会阻塞调用进程,直到其任意一个子进程终止。如果子进程已经终止,wait()会立即返回。终止状态会通过status指针返回给父进程。waitpid()系统调用1234#include <sys/types.h>#include <sys/wait.h> pid_t waitpid(pid_t pid, int *status, int options);waitpid()提供了更灵活的控制:pid参数可以指定要等待的特定子进程options参数可以控制等待行为(如WNOHANG使调用非阻塞)检查子进程退出状态通过status参数返回的状态值,我们可以使用一组宏来解析子进程的终止信息:检查是否正常退出123#include <sys/wait.h> WIFEXITED(status); // 如果子进程正常返回,则为非零如果子进程通过exit()或_exit()正常退出,可以使用WEXITSTATUS(status)获取退出码:1WEXITSTATUS(status); // 返回子进程的退出码(低8位)检查是否被信号终止1WIFSIGNALED(status); // 如果子进程被信号终止,则为非零如果子进程被信号终止,可以使用WTERMSIG(status)获取导致终止的信号编号:1WTERMSIG(status); // 返回导致子进程终止的信号编号完整示例代码下面是一个完整的示例,展示如何创建子进程,并在父进程中获取子进程的退出状态:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <signal.h> void child_process() { printf("子进程开始运行,PID: %d\n", getpid()); // 模拟子进程执行某些操作 sleep(2); // 正常退出 exit(42); // 使用退出码42退出} void child_process_with_signal() { printf("子进程开始运行,PID: %d\n", getpid()); // 模拟子进程执行某些操作 sleep(2); // 发送信号给自己 raise(SIGINT); // 发送SIGINT信号} int main() { pid_t pid; int status; // 示例1:正常退出的子进程 pid = fork(); if (pid == 0) { // 子进程 child_process(); } else if (pid > 0) { // 父进程 printf("父进程等待子进程 %d\n", pid); waitpid(pid, &status, 0); if (WIFEXITED(status)) { printf("子进程 %d 正常退出,退出码: %d\n", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("子进程 %d 被信号 %d 终止\n", pid, WTERMSIG(status)); } } else { perror("fork失败"); } printf("\n"); // 示例2:被信号终止的子进程 pid = fork(); if (pid == 0) { // 子进程 child_process_with_signal(); } else if (pid > 0) { // 父进程 printf("父进程等待子进程 %d\n", pid); waitpid(pid, &status, 0); if (WIFEXITED(status)) { printf("子进程 %d 正常退出,退出码: %d\n", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("子进程 %d 被信号 %d 终止\n", pid, WTERMSIG(status)); } } else { perror("fork失败"); } return 0;}高级主题:信号处理和进程状态使用WNOHANG选项waitpid()的options参数可以设置为WNOHANG,使调用非阻塞:12345678pid_t ret = waitpid(pid, &status, WNOHANG);if (ret == 0) { // 子进程仍在运行} else if (ret > 0) { // 子进程已终止,状态在status中} else { // 错误}检查子进程是否被暂停可以使用WIFSTOPPED(status)和WSTOPSIG(status)来检查子进程是否被暂停:123if (WIFSTOPPED(status)) { printf("子进程被信号 %d 暂停\n", WSTOPSIG(status));}检查子进程是否被继续执行可以使用WIFCONTINUED(status)来检查子进程是否从暂停状态继续执行:123if (WIFCONTINUED(status)) { printf("子进程从暂停状态继续执行\n");}常见问题和解决方案问题1:子进程变成僵尸进程如果父进程没有调用wait()或waitpid()来收集子进程的状态,子进程会变成僵尸进程(Zombie Process)。僵尸进程会占用系统资源,因为内核需要保留其退出状态直到父进程读取。解决方案:父进程应该始终调用wait()或waitpid()来收集子进程的状态,或者可以设置对SIGCHLD信号的忽略处理(在Linux上):1signal(SIGCHLD, SIG_IGN); // 忽略SIGCHLD信号,子进程退出时自动清理问题2:如何处理多个子进程当父进程有多个子进程时,可以使用循环和waitpid()的pid参数为-1来等待任意子进程:123while ((pid = waitpid(-1, &status, 0)) > 0) { // 处理已终止的子进程}问题3:获取子进程的core dump状态如果子进程因为信号终止并生成了core dump,可以使用WCOREDUMP(status)来检查:123if (WCOREDUMP(status)) { printf("子进程生成了core dump\n");}实际应用场景场景1:构建并行任务系统在需要并行执行多个任务的系统中,父进程需要监控每个子任务的执行状态:1234567891011121314151617181920212223242526#define MAX_CHILDREN 10 pid_t child_pids[MAX_CHILDREN];int child_status[MAX_CHILDREN]; // 创建子进程for (int i = 0; i < MAX_CHILDREN; i++) { pid_t pid = fork(); if (pid == 0) { // 子进程执行任务 execute_task(i); exit(EXIT_SUCCESS); } else { child_pids[i] = pid; }} // 等待所有子进程完成int completed = 0;while (completed < MAX_CHILDREN) { pid_t pid = waitpid(-1, NULL, 0); if (pid > 0) { completed++; // 可以在这里记录完成的子进程 }}场景2:实现超时机制在某些情况下,可能需要限制子进程的运行时间:123456789101112131415161718pid_t pid = fork();if (pid == 0) { // 子进程执行长时间任务 long_running_task(); exit(EXIT_SUCCESS);} else { // 设置定时器 alarm(10); // 10秒超时 int status; waitpid(pid, &status, 0); if (WIFEXITED(status)) { printf("任务正常完成\n"); } else { printf("任务被超时或信号终止\n"); }}总结在Linux系统编程中,正确获取子进程的退出值和异常终止信号对于编写健壮的程序至关重要。通过wait()和waitpid()系统调用,结合一系列状态检查宏,父进程可以全面了解子进程的执行状态。本文介绍了基本概念、系统调用、状态检查宏、示例代码以及常见问题和解决方案,希望能帮助开发者更好地处理子进程监控任务。在实际应用中,根据具体需求选择合适的等待方式和状态检查方法,可以有效地管理子进程的生命周期,提高程序的可靠性和稳定性。
-
什么是waitpidwaitpid是Unix/Linux系统提供的一个系统调用,用于等待子进程的状态改变并回收其资源。相比于wait函数,waitpid提供了更灵活的控制选项,可以指定等待哪个特定的子进程,以及是否阻塞等待【1†source】。123#include <sys/wait.h> pid_t waitpid(pid_t pid, int *status, int options);参数说明:pid: 要等待的子进程ID。特殊值包括:-1: 等待任意子进程0: 等待与调用进程同组的任意子进程0: 等待指定PID的子进程status: 用于存储子进程退出状态的指针options: 控制选项,最常用的是WNOHANG,表示非阻塞模式回收多个子进程的方法方法一:循环调用waitpid最简单的方法是在父进程中循环调用waitpid,直到所有子进程都被回收:123456789101112131415161718192021222324252627282930313233343536#include <stdio.h>#include <unistd.h>#include <sys/wait.h>#include <stdlib.h> int main() { pid_t pids[5]; int i; // 创建5个子进程 for (i = 0; i < 5; i++) { pids[i] = fork(); if (pids[i] == 0) { // 子进程代码 printf("Child process %d started\n", getpid()); sleep(1 + rand() % 3); // 随机休眠1-3秒 printf("Child process %d exiting\n", getpid()); exit(0); } } // 父进程回收子进程 int status; pid_t pid; for (i = 0; i < 5; i++) { pid = waitpid(pids[i], &status, 0); if (pid == -1) { perror("waitpid"); exit(1); } printf("Parent reaped child %d\n", pid); } return 0;}方法二:非阻塞方式回收子进程使用WNOHANG选项,父进程可以在不阻塞的情况下检查子进程状态:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include <stdio.h>#include <unistd.h>#include <sys/wait.h>#include <stdlib.h> int main() { pid_t pids[5]; int i; // 创建5个子进程 for (i = 0; i < 5; i++) { pids[i] = fork(); if (pids[i] == 0) { // 子进程代码 printf("Child process %d started\n", getpid()); sleep(1 + rand() % 3); // 随机休眠1-3秒 printf("Child process %d exiting\n", getpid()); exit(0); } } // 父进程非阻塞方式回收子进程 int status; pid_t pid; int children_left = 5; while (children_left > 0) { pid = waitpid(-1, &status, WNOHANG); if (pid > 0) { // 成功回收一个子进程 printf("Parent reaped child %d\n", pid); children_left--; } else if (pid == 0) { // 有子进程仍在运行 printf("Waiting for children to finish...\n"); sleep(1); } else { // 出错 perror("waitpid"); exit(1); } } printf("All children have been reaped\n"); return 0;}方法三:信号处理方式回收子进程可以通过SIGCHLD信号来通知父进程子进程已经终止,然后在信号处理函数中回收子进程:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849#include <stdio.h>#include <unistd.h>#include <sys/wait.h>#include <signal.h>#include <stdlib.h> void sigchld_handler(int sig) { int status; pid_t pid; // 回收所有已终止的子进程 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { printf("Parent reaped child %d\n", pid); }} int main() { pid_t pids[5]; int i; // 设置SIGCHLD信号处理 struct sigaction sa; sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } // 创建5个子进程 for (i = 0; i < 5; i++) { pids[i] = fork(); if (pids[i] == 0) { // 子进程代码 printf("Child process %d started\n", getpid()); sleep(1 + rand() % 3); // 随机休眠1-3秒 printf("Child process %d exiting\n", getpid()); exit(0); } } // 父进程继续执行其他任务 printf("Parent doing other work...\n"); sleep(5); printf("Parent finished\n"); return 0;}最佳实践和注意事项及时回收子进程:父进程应该及时回收子进程,避免僵尸进程的产生【2†source】。处理异常情况:在调用waitpid时,应该检查返回值,处理可能的错误情况。信号处理注意事项:使用信号处理方式回收子进程时,需要注意信号处理函数的可重入性和安全性。避免竞争条件:在多线程环境中使用waitpid时,需要注意同步问题,避免竞争条件。使用WNOHANG:对于需要同时处理多个任务的父进程,使用WNOHANG选项可以避免阻塞,提高程序的响应性【3†source】。
-
1. 服务器无法访问排查步骤:检查物理连接:确认服务器的电源、网络连接是否正常。查看显示器(如有)是否有故障信息。SSH 登录失败:使用 `ping` 命令检查服务器是否在网络上。检查是否能够访问网络的其他设备。2. 系统资源耗尽排查步骤:使用 CTRL + ALT + F1 进入控制台:登录后使用 `top` 或 `htop` 查看 CPU、内存使用情况。检查磁盘使用情况:1df -h如果根目录 (`/`) 使用率过高,应清理不必要的文件。检查进程状况:1ps aux --sort=-%mem | head # 查看内存占用最高的进程3. 服务未运行排查步骤:检查服务状态:1systemctl status <service-name>如果服务未运行,可以尝试重启:1systemctl restart <service-name>查看服务日志:1journalctl -u <service-name>4. 内核崩溃(Kernel Panic)排查步骤:重启服务器,检查引导日志:在 `GRUB` 引导菜单中,选择“编辑”引导行,查找是否有错误信息。**检查 `/var/log/kern.log` 或 `/var/log/messages`**: 这些日志文件可以提供有关崩溃的详细信息。5. 网络故障排查步骤:使用 `ping` 命令确认本机到其他IP(如路由器、外部地址)的连通性。检查网络配置:12ip address # 查看IP配置ip route # 查看路由设置检查网络服务状态:1systemctl status NetworkManager6. 文件系统损坏排查步骤:启动进入单用户模式或者使用 Live CD。使用 `fsck` 命令修复文件系统:1fsck /dev/sdXn # 替换为具体的设备7. 应用程序异常排查步骤:查看应用程序日志,通常在 `/var/log` 或应用程序的配置目录下。检查配置文件,确认没有错误的配置导致服务错误。8. 定期健康检查定期监控服务器健康状态的做法:设置监控工具: 使用工具如 Zabbix、Nagios 或 Grafana 监控服务器的 CPU、内存、磁盘和网络使用情况。实施备份方案: 定期备份数据,以便在恶性 事件后快速恢复。9. 记录与文档在每次故障排查和修复后,记录相关信息和操作步骤。
-
1.du命令概述du(Disk Usage)是 Linux 系统中的一个常用命令,用于显示指定文件和目录的磁盘空间使用情况。它可以递归地计算目录及其子目录所占的空间大小,并显示每个文件或子目录的大小。du 是非常适合用于分析磁盘空间使用情况的工具,特别是当我们需要知道哪个目录占用了大量磁盘空间时,它显得尤为重要。du命令常用选项-h:以“人类可读”的格式输出,即显示为带单位的大小(例如 K、M、G)。这对于直观查看文件大小非常有用。-s:仅显示每个目录的总大小,而不是递归列出每个文件。-a:显示每个文件的大小(而不仅仅是目录的大小)。-c:输出总计,显示所有文件和目录的总大小。例如,如果我们要查看 blog 目录下的磁盘使用情况,命令如下:1du -h blog/该命令会列出 blog 目录下所有文件和子目录的大小。2. 使用sort命令排序结果在日常工作中,我们不仅仅关心每个文件或目录的大小,还想要查看哪些文件或目录占用了最多的磁盘空间。此时,结合 sort 命令的使用可以帮助我们快速找到这些“占地最大”的文件或目录。sort 是 Linux 中用于排序文本行的命令。它支持按字母、数字、时间等多种方式进行排序。在我们的需求中,我们关心的是按数字大小来排序。为了达到这一目的,我们需要使用 sort 命令的 -h 和 -r 选项。2.1sort命令常用选项-h:按照“人类可读”的格式(即类似 1K、2M、3G 这样的单位)进行排序。-r:反向排序,即从大到小排序。当我们把这两个选项与 du 命令结合使用时,可以按从大到小的顺序列出 blog 目录下的所有文件和子目录。具体命令如下:1du -h blog/* | sort -hr2.2 命令解析du -h blog/*:这个部分会列出 blog 目录下所有文件和子目录的大小,并以人类可读的格式显示。|(管道符):表示将 du 命令的输出结果传递给 sort 命令进行处理。sort -hr:按照从大到小的顺序排序输出的结果,其中 -h 让排序考虑人类可读格式,-r 则是反向排序,从大到小。3. 示例:如何查看博客目录下最大文件假设我们有一个名为 blog 的目录,其中包含了大量的文件和子目录。如果我们想要查看哪些文件或目录占用了最多的空间,可以执行如下命令:1du -h blog/* | sort -hr3.1 命令输出示例假设命令输出如下:2.3G blog/images1.5G blog/videos512M blog/articles128M blog/styles10M blog/script.js这个输出结果告诉我们,blog 目录下占用最大空间的是 images 子目录(2.3G),其次是 videos(1.5G)。通过这种方式,我们可以清晰地知道每个文件或目录的大小,进而决定是否需要清理一些不再需要的数据。4. 进一步优化命令在某些情况下,blog/* 可能会列出大量的文件和子目录,而我们只关心其中某个子目录的磁盘使用情况。为了更加精准地定位问题,我们可以将 du 命令的路径限定为具体的文件或子目录,而不是整个目录。例如,如果我们只关心 blog/images 目录,可以执行以下命令:1du -h blog/images/* | sort -hr这样我们就可以只查看 images 子目录下的文件大小,并按从大到小的顺序进行排序,快速找到最大的文件。5. 清理不必要的文件通过使用 du 和 sort 命令,我们可以快速找到占用空间最多的文件或目录,从而进行清理。清理不必要的文件不仅能节省磁盘空间,还能提高系统的性能和响应速度。5.1 删除大文件一旦我们找到了占用空间最多的文件,我们可以使用 rm 命令删除它们。例如,如果 blog/images 目录下有一个占用 1GB 空间的文件 large_image.jpg,我们可以使用以下命令删除它:1rm blog/images/large_image.jpg5.2 清理临时文件有时,一些临时文件(如缓存文件)会占用大量磁盘空间。我们可以通过 du 命令找出这些临时文件并删除。例如,许多应用程序会在 /tmp 目录下创建临时文件,我们可以使用如下命令清理它:1du -h /tmp/* | sort -hr然后,删除那些不再需要的临时文件。
-
理解文件⽂件在磁盘⾥,磁盘是永久性存储介质,因此⽂件在磁盘上的存储是永久性的Linux 下⼀切皆⽂件(键盘、显⽰器、⽹卡、磁盘……)0KB 的空⽂件也是占⽤磁盘空间的⽂件是⽂件属性(元数据)和⽂件内容的集合(⽂件 = 属性(元数据)+ 内容)所有的⽂件操作本质是⽂件内容操作和⽂件属性操作对⽂件的操作本质是进程对⽂件的操作, 磁盘的管理者是操作系统⽂件的读写本质不是通过 C 语⾔ / C++ 的库函数来操作的(这些库函数只是为⽤⼾提供⽅便),⽽是通过⽂件相关的系统调⽤接⼝来实现的理解硬盘机械磁盘是计算机中唯⼀的⼀个机械设备磁盘是外设,特点:慢,容量⼤,价格便宜磁盘的物理结构:磁盘的存储结构:扇区是从磁盘读出和写⼊信息的最⼩单位,通常⼤⼩为 512 字节。磁头(head)数:每个盘⽚⼀般有上下两⾯,分别对应1个磁头,共2个磁头磁道(track)数:磁道是从盘⽚外圈往内圈编号0磁道,1磁道...,靠近主轴的同⼼圆⽤于停靠磁头,不存储数据柱⾯(cylinder)数:磁道构成柱⾯,数量上等同于磁道个数扇区(sector)数:每个磁道都被切分成很多扇形区域,每道的扇区数量相同圆盘(platter)数:就是盘⽚的数量磁盘容量=磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数细节:传动臂上的磁头是共进退的通过柱⾯(cylinder),磁头(head),扇区(sector),就可以定位数据了,这就是数据定位(寻址)⽅式之⼀,CHS寻址⽅式。磁盘的逻辑结构磁带逻辑结构在理解磁盘的逻辑结构之前我们先来了解一下磁带的逻辑结构: 磁带上面存取数据,当我们把磁带拉直就形成了线性结构 虽然磁盘本质上虽然是硬质的,但是逻辑上我们可以把磁盘想象成为卷在⼀起的磁带,那么磁盘的逻辑存储结构我们也可以类似于: 磁盘逻辑结构机械臂上的磁头是共进退的 柱⾯是⼀个逻辑上的概念,其实就是每⼀⾯上,相同半径的磁道逻辑上构成柱⾯。所以,磁盘物理上分了很多⾯,但是在我们看来,逻辑上,磁盘整体是由“柱⾯”卷起来的 这样看来一个柱面就是一个二维数组.整盘 故整盘就是多张二维的扇区数组表 “三维数组” .这样每⼀个扇区,就有了⼀个线性地址(其实就是数组下标),这种地址叫做 LBA.CHS && LBA地址CHS转成LBA:磁头数*每磁道扇区数 = 单个柱⾯的扇区总数LBA = 柱⾯号C*单个柱⾯的扇区总数 + 磁头号H*每磁道扇区数 + 扇区号S - 1即:LBA = 柱⾯号C*(磁头数*每磁道扇区数) + 磁头号H*每磁道扇区数 + 扇区号S - 1LBA转成CHS:柱⾯号C = LBA // (磁头数*每磁道扇区数)【就是单个柱⾯的扇区总数】磁头号H = (LBA % (磁头数*每磁道扇区数)) // 每磁道扇区数扇区号S = (LBA % 每磁道扇区数) + 1在磁盘使⽤者看来,根本就不关⼼CHS地址,⽽是直接使⽤LBA地址,磁盘内部⾃⼰转换。故磁盘是⼀个 元素为扇区 的⼀维数组,数组的下标就是每⼀个扇区的LBA地址。OS使⽤磁盘,就可以⽤⼀个数字访问磁盘扇区了。引入文件系统“块” 的概念操作系统读取硬盘数据的时候,其实是不会⼀个个扇区地读取,这样效率太低,⽽是⼀次性连续读取多个扇区,即⼀次性读取⼀个”块”(block)硬盘的每个分区是被划分为⼀个个的”块”。⼀个”块”的⼤⼩是由格式化的时候确定的,并且不可以更改,最常⻅的是4KB,即连续⼋个扇区组成⼀个 ”块”。(每个扇区512B)文件系统和存储管理中,“块(Block)” 是磁盘(或其他存储设备)进行数据读写的最小单位,也是文件系统管理存储空间的基础单元。“分区” 的概念其实磁盘是可以被分成多个分区(partition)的,以Windows观点来看,你可能会有⼀块磁盘并且将它分区成C,D,E盘。那个C,D,E就是分区。分区从实质上说就是对硬盘的⼀种格式化。但是Linux的设备都是以⽂件形式存在,那是怎么分区的呢?柱⾯是分区的最⼩单位,我们可以利⽤参考柱⾯号码的⽅式来进⾏分区,其本质就是设置每个区的起始柱⾯和结束柱⾯号码。 柱⾯⼤⼩⼀致,扇区个位⼀致,那么其实只要知道每个分区的起始和结束柱⾯号,知道每⼀个柱⾯多少个扇区,那么该分区多⼤,其实和解释LBA是多少也就清楚了. inode我们知道 ⽂件=内容+属性 ,我们使⽤ ls -l 的时候看到的除了看到⽂件名,还能看到⽂件元数据(属性)每⾏的7列分别代表:模式硬链接数⽂件所有者组⼤⼩最后修改时间⽂件名这个信息除了通过ls来读取,还有⼀个stat命令能够看到更多信息。 我们知道⽂件数据都储存在”块”中,那么很显然,我们还必须找到⼀个地⽅储存⽂件的元信息(属性信息),⽐如⽂件的创建者、⽂件的创建⽇期、⽂件的⼤⼩等等。这种储存⽂件元信息的区域就叫做inode,中⽂译名为”索引节点”。每⼀个⽂件都有对应的inode,⾥⾯包含了与该⽂件有关的⼀些信息。为了能解释清楚inode,我们需要是深⼊了解⼀下⽂件系统。注意:Linux下⽂件的存储是属性和内容分离存储的Linux下,保存⽂件属性的集合叫做inode,⼀个⽂件,⼀个inode,inode内有⼀个唯⼀的标识符,叫做inode号⽂件名属性并未纳⼊到inode数据结构内部inode的⼤⼩⼀般是128字节或者256任何⽂件的内容⼤⼩可以不同,但是属性⼤⼩⼀定是相同的ext2 ⽂件系统认识文件系统所有的准备⼯作都已经做完,是时候认识下⽂件系统了。我们想要在硬盘上储⽂件,必须先把硬盘格式化为某种格式的⽂件系统,才能存储⽂件。⽂件系统的⽬的就是组织和管理硬盘中的⽂件。在 Linux 系统中,最常⻅的是 ext2 系列的⽂件系统。其早期版本为 ext2,后来⼜发展出 ext3 和 ext4。ext3 和 ext4 虽然对 ext2 进⾏了增强,但是其核⼼设计并没有发⽣变化。ext2⽂件系统将整个分区划分成若⼲个同样⼤⼩的块组 (Block Group),如下图所⽰。只要能管理⼀个分区就能管理所有分区,也就能管理所有磁盘⽂件。上图中启动块(Boot Sector)的⼤⼩是确定的,为1KB,由PC标准规定,⽤来存储磁盘分区信息和启动信息,任何⽂件系统都不能修改启动块。启动块之后才是ext2⽂件系统的开始。Block GroupBlock Group(块组) 是文件系统管理磁盘空间的核心 “模块化单元”,每ext2⽂件系统会根据分区的⼤⼩划分为数个Block Group。⽽每个Block Group都有着相同的结构组成。每个Block Group自主管理资源,以提升效率和容错性。块组内部构成超级块(Super Block)存放⽂件系统本⾝的结构信息,描述整个分区的⽂件系统信息。记录的信息主要有:bolck 和 inode的总量,未使⽤的block和inode的数量,⼀个block和inode的⼤⼩,最近⼀次挂载的时间,最近⼀次写⼊数据的时间,最近⼀次检验磁盘的时间等其他⽂件系统的相关信息。Super Block的信息被破坏,可以说整个⽂件系统结构就被破坏了。GDT(Group Descriptor Table)块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描述符存储⼀个块组 的描述信息,如在这个块组中从哪⾥开始是inode Table,从哪⾥开始是Data Blocks,空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有⼀份拷⻉。块位图(Block Bitmap)Block Bitmap以位图的形式记录着Data Block中哪个数据块已经被占⽤,哪个数据块没有被占⽤。inode位图(Inode Bitmap)每个bit表⽰⼀个inode是否空闲可⽤。(位值为0表示可用,为1不可用)i节点表(Inode Table)存放⽂件属性 如 ⽂件⼤⼩,所有者,最近修改时间等当前分组所有Inode属性的集合inode编号以分区为单位,整体划分,不可跨分区Data Block数据区:存放⽂件内容,也就是⼀个⼀个的Block。根据不同的⽂件类型有以下⼏种情况:对于普通⽂件,⽂件的数据存储在数据块中。对于⽬录,该⽬录下的所有⽂件名和⽬录名存储在所在⽬录的数据块中,除了⽂件名外,ls -l命令看到的其它信息保存在该⽂件的inode中。Block 号按照分区划分,不可跨分区,只能在自己分区内有效不可跨分区inode和datablock映射 12 个直接块指针(直接翻到章节):直接指向存储文件数据的 “普通数据块”(小文件可通过这些指针直接找到所有数据块,因此小文件存储非常高效)。间接块索引指针一级间接块索引指针(“先查目录,再翻章节”):该指针指向了一级数据块索引表(4KB),该索引表中储存了多个普通数据块的编号(每个编号4字节),则索引表中管理了1024个数据块。则可以在直接块的基础上多管理(1024 * 4KB = 4MB)4MB的文件。二级间接块索引指针(“查目录的目录,再翻章节”):该指针指向了数据块索引表,该数据块索引表又可以指向1024个数据块索引表,每个索引块可以管理1024个数据块。则可以在前面的基础上多管理(1024 * 1024 * 4KB = 4GB)4GB的文件。三级间接块索引指针(“查目录的目录的目录,再翻章节”):以此类推,则可以在前面的基础上多管理(1024 * 1024 * 1024 * 4KB = 4TB)4TB的文件。结论:分区之后的格式化操作,就是对分区进⾏分组,在每个分组中写⼊SB、GDT、Block、Bitmap、Inode Bitmap等管理信息,这些管理信息统称: ⽂件系统只要知道⽂件的inode号,就能在指定分区中确定是哪⼀个分组,进⽽在哪⼀个分组确定是哪⼀个inode拿到inode⽂件属性和内容就全部都有了[root@localhost linux]# touch abc[root@localhost linux]# ls -i abc263466 abc 如上图可知创建⼀个新⽂件主要有以下4个操作:1. 存储属性内核先找到⼀个空闲的i节点(这⾥是263466)。内核把⽂件信息记录到其中。2. 存储数据该⽂件需要存储在三个磁盘块,内核找到了三个空闲块:300 ,500,800。将内核缓冲区的第⼀块数据复制到300,下⼀块复制到500,以此类推。3. 记录分配情况⽂件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。4. 添加⽂件名到⽬录新的⽂件名abc。linux如何在当前的⽬录中记录这个⽂件?内核将⼊⼝(263466,abc)添加到⽬录⽂件。⽂件名和inode之间的对应关系将⽂件名和⽂件的内容及属性连接起来。目录与文件名我们发现平常访问⽂件,⽤的是⽂件名,并没⽤inode号,那它是怎么访问的呢?答:目录是文件,磁盘上是没有目录这一概念的,目录的内容保存的是当前目录下的文件名和inode的映射关系。所以,访问⽂件,必须打开当前⽬录,根据⽂件名,获得对应的inode号,然后进⾏⽂件访问。所以,访问⽂件必须要知道当前⼯作⽬录,本质是必须能打开当前⼯作⽬录⽂件,查看⽬录⽂件的内容!路径解析我们知道访问文件时需要访问目录文件,可是目录我们也只知道文件名,要访问当前目录也要知道他的inode。故需要一直向上访问上级目录,类似于“递归”,需要把路径中所有的⽬录全部解析,出⼝是"/"根⽬录(根⽬录固定⽂件名,inode号,⽆需查找,系统开机之后就必须知道)。实际上,任何⽂件,都有路径,访问⽬标⽂件,⽐如: /home/whb/code/test/test/test.c 都要从根⽬录开始,依次打开每⼀个⽬录,根据⽬录名,依次访问每个⽬录下指定的⽬录,直到访问到test.c。这个过程叫做Linux路径解析。路径谁提供?你访问⽂件,都是指令/⼯具访问,本质是进程访问,进程有CWD!进程提供路径。你open⽂件,提供了路径.软硬链接创建软硬连接观察,对比它们的inode: 硬链接abc和def的链接状态完全相同,他们被称为指向⽂件的硬链接。内核记录了这个连接数,inode:68511212 的硬连接数为2。硬连接是新文件名与和目标文件inode编号的映射关系;创建硬连接,就是建立映射关系,并且把inode的链接数增加;我们在删除⽂件时⼲了两件事情:在⽬录中将对应的记录删除,将硬连接数-1,如果为0,则将对应的磁盘释放。如上图我们可以发现当前目录下的 . 和下级目录下的 .. 都连接着该目录故他的连接数是3软连接那么软连接是什么?软连接是一个独立的文件,文件内容是目标文件的路径。有点类似于快捷方式.一个目录被创建时,会产生三个连接。其中两个“目录名”和"."指向自己,还有一个".."指向上一级目录。目录可以创建软连接,但是不能创建硬连接!否则会形成环路问题,除非是系统自己建立。————————————————版权声明:本文为CSDN博主「new null」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/2301_80468112/article/details/154292952
-
一、基本框架iptables 是 Linux 系统中常用的防火墙工具,工作在用户空间,用来编写规则,基于内核的 netfilter 框架实现数据包的过滤、转换和修改。其核心框架由 “四表五链” 构成,规则的匹配和执行遵循特定顺序,同时支持自定义链以灵活管理规则。二、iptables 中的链“链” 是数据包流转过程中经过的检查点,每条链对应数据包处理的特定阶段,由内核自动创建,即内置链。对应内核中的每一个勾子函数 (INPUT,OUTPUT,FORWARD,PREROUTING,POSTROUTING)。除了内置链外,用户还可创建自定义链,用于对内置链进行扩展或补充,可实现更灵活的规则组织管理机制;只有钩子函数调用自定义链时,才会生效,即需通过内置链的规则引用自定义链。1、PREROUTING 链数据包进入本机后,路由选择之前经过的链。用于提前修改数据包(如 DNAT),或标记数据包。即主机接收到数据是否是给我们的,是否要修改(ip或port),相当于进站安检。2、INPUT 链当路由判断数据包的目标地址是本机时,经过此链。用于控制哪些外部数据包可进入本机(如允许 SSH 连接)。即接收到的数据经过路由分析,是本机处理,相当与上车。3、FORWARD 链当路由判断数据包需要经过本机转发(本机既非源也非目标)时,经过此链。用于控制转发行为(如网关服务器的转发规则)。即接收到的数据经过路由分析,不是本机处理,本机只做转发,相当于转车。4、OUTPUT 链本机产生的数据包(如应用程序发送的请求)在离开本机前经过此链。用于控制本机对外发送的数据包。即本机处理完的数据经过路由分析,直接传输出去,相当于下车。5、POSTROUTING 链数据包经过路由选择后,离开本机前的最后一条链。用于修改源地址(如 SNAT,将内网地址转换为外网地址)。即数据传输出去的时候,是否需要修改(ip或port),相当于出站安检。三、iptables 中的表iptables 的表用于分类管理不同功能的规则,每个表关联特定的链,主要包括以下四类:filter、nat、mangle、raw。优先级从高到低依次是:raw > mangle > nat > filter。1、filter 表(过滤规则表)最常用的表,也是默认表,根据预定义的规则过滤符合条件的数据包,是防火墙的核心功能。仅关联 3 条链:INPUT、OUTPUT、FORWARD。2、nat 表(地址转换表)用于实现网络地址转换(NAT),包括源地址转换(SNAT)、目标地址转换(DNAT)等。关联 3 条链:PREROUTING(路由前修改目标地址)、POSTROUTING(路由后修改源地址)、OUTPUT(本机产生的数据包的地址转换)。3、mangle 表(修改表)修改数据标记位规则表,修改数据报文(修改数据包的元数据,如 TTL、服务类型、标记等),可辅助路由或过滤。关联所有 5 条链(INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING)。4、raw 表(原始表)用于关闭 nat 表启用的连接跟踪机制,减少性能消耗,加快封包穿越防火墙速度,仅处理不需要追踪的数据包。关联 2 条链:PREROUTING、OUTPUT。四、链表对应关系表 可支持的链raw PREROUTING, OUTPUTmangle PREROUTING, POSTROUTING, INPUT, OUTPUT, FORWARDnat PREROUTING, POSTROUTING, INPUT, OUTPUTfilter INPUT, FORWARD, OUTPUT五、数据包流转顺序当一个数据包进入网卡时,数据包首先进入PREROUTING链,内核根据数据包目的IP判断是否需要传送出去;如果数据包是进入本机的,则会进入INPUT链,然后交由本机的应用程序处理;如果数据包是要转发的,且内核允许转发,则数据包在PREROUTING链之后到达FORWARD链,再经由POSTROUTING链输出本机的应用程序往外发送数据包,会先进入OUTPUT链,然后到达POSTROUTING链输出数据包的走向数据流入,本机接收的数据包(目标是本机):PREROUTING 链(raw→mangle→nat)→ 路由判断(目标是本机)→ INPUT 链(mangle→filter)→ 进入本机应用程序。数据流出,本机发出的数据包(源是本机):本机应用程序 → OUTPUT 链(raw→mangle→nat→filter)→ 路由选择 → POSTROUTING 链(mangle→nat)→ 离开本机。数据转发,转发的数据包(经过本机转发):外部数据包 → PREROUTING 链(raw→mangle→nat)→ 路由判断(需要转发)→ FORWARD 链(mangle→filter)→ 路由选择 → POSTROUTING 链(mangle→nat)→ 离开本机。 六、规则匹配顺序iptables 中,每条链内的规则按从上到下的顺序依次匹配:当数据包匹配到某条规则时,会执行该规则的 “目标”(如 ACCEPT、DROP、跳转至其他链等),并停止后续规则的匹配(除非目标是 RETURN,会返回原链继续匹配)。若数据包不匹配链中任何规则,则执行该链的 “默认策略”。七、策略的设置方式1、iptables命令组成iptables 完整命令由以下部份组成:iptables [-t Table] -子命令 <链> <规则策略> [动作]即通过 iptables 命令,在某个表的某个链上设置某条过滤规则字段说明iptables:iptables命令Table:具体要操作的表,用 -t 指定,raw|mangle|nat|filter,默认 filterChain:具体要操作的链,PREROUTING|INPUT|FORWARD|OUTPUT|POSTROUTINGRule:具体规则,由匹配条件和目标组成,如果满足条件,就执行目标中的规则,目标用 -j 指定动作:基本动作ACCEPT|DROP|RETURN2、命令格式指定表-t|--table table #指定表 raw|mangle|nat|filter,如果不显式指定,默认是filter操作链-N|--new-chain chain #添加自定义新链-X|--delete-chain [chain] #删除自定义链(要求链中没有规则)-P|--policy chain target #设置默认策略,对filter表中的链而言,其默认策略有ACCEPT|DROP-E|--rename-chain old-chain new-chain #重命名自定义链,引用计数不为0的自定义链不能被重命名-L|--list [chain] #列出链上的所有规则-S|--list-rules [chain] #列出链上的的有规则-F|--flush [chain] #清空链上的所有规则,默认是所有链-Z|--zero [chain [rulenum]] #置0,清空计数器,默认操作所有链上的所有规则操作具体规则-A|--append chain rule-specification #往链上追加规则-I|--insert chain [rulenum] rule-specification #往链上插入规则,可以指定编号,默认插入到最前面-C|--check chain rule-specification #检查链上的规则是否正确-D|--delete chain rule-specification #删除链上的规则-D|--delete chain rulenum #根据编号删除链上的规则-R|--replace chain rulenum rule-specification #根据链上的规则编号,使用新的规则替换原有规则其它选项-h|--help #显示帮助-V|--version #显示版本-v|--verbose #显示详细信息-n|--numeric #以数字形式显示IP和端口,默认显示主机名和协议名,否则容易遭受hosts解析影响--line-numbers #显示每条规则编号-j|--jump # 决定了数据包在满足特定条件后的命运。ACCEPT:允许数据包通过。DROP:丢弃数据包,不给出任何回应。等客户端测试多次后,主动放弃。REJECT:直接拒绝数据包,并向发送方发送一个错误响应。查看规则选项-L #显示规则条目,后面可以接需要查看的链,不写的话表示所有链。如果规则不为空,单独 -L 选项显示时有可能会很慢,这是因为需要对主机名和服务名进行反解导致的,-n #选项查看规则的时候 主机名和端口不做解析,介于此,可以实现规避上面的问题。-v #显示详细信息--line-numbers #显示规则的标号-S #打印规则,编写命令给我们打印出来,方便我们去学习-t #指定查看的表3、默认策略默认策略(Policy)是当数据包不匹配链中任何规则时的默认处理行为,仅适用于内置链(自定义链无默认策略)。设置命令iptables -P 链名 策略AI写代码bash常用策略:ACCEPT(允许通过)、DROP(直接丢弃,不返回任何信息)、REJECT(拒绝并返回错误信息)。示例# 设置 INPUT 链默认拒绝所有未匹配的数据包iptables -P INPUT DROPAI写代码bash注:默认规则(iptables -P)是 ACCEPT,不建议修改,容易出现 “自杀” 现象。4、常见策略 设置命令# 在第1行插入一条规则iptables -t 表名 -I 链名 策略 # 在原来规则后面去追加iptables -t 表名 -A 链名 策略AI写代码bash常用策略:ACCEPT(允许通过)、DROP(直接丢弃,不返回任何信息)、REJECT(拒绝并返回错误信息)。示例# 在INPUT 链的 filter 表上设置过滤规则,将来自 10.0.0.112 的数据包丢弃掉iptables -t filter -A INPUT -s 10.0.0.12 -j DROPAI写代码bash八、自定义链配置1、创建自定义链创建命令iptables -N 自定义链名AI写代码bash示例# 创建一个名为NGINX_RULES的自定义链iptables -N NGINX_RULESAI写代码bash2、使用自定义链需通过内置链的规则引用自定义链(目标为自定义链名),数据包匹配到该规则时会跳转到自定义链处理。示例# 示例:在 INPUT 链中添加规则,将所有 TCP 80 端口的数据包跳转至 NGINX_RULES 链处理iptables -A INPUT -p tcp --dport 80 -j NGINX_RULESAI写代码bash注:自定义链中若规则匹配,按目标处理;若不匹配,会返回原链继续匹配后续规则。3、删除自定义链删除前需满足以下两个条件:自定义链中无任何规则(需先清空);无其他链的规则引用该自定义链(需先删除引用)。示例# 清空自定义链的规则iptables -F NGINX_RULES # 删除引用该链的规则(如 INPUT 链中指向 NGINX_RULES 的规则)iptables -D INPUT -p tcp --dport 80 -j NGINX_RULES # 删除自定义链iptables -X NGINX_RULES————————————————版权声明:本文为CSDN博主「siriuuus」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_38024995/article/details/154353503
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签