0%

Linux 系统日志全解析:从故障排查到安全审计

系统日志是 Linux 系统的 “黑匣子”,记录了从启动到运行的各类事件,是排查故障、追踪操作、审计安全的核心依据。本文将详细介绍 Linux 中最关键的日志文件,包括其功能、内容及实用查看技巧。

核心系统日志:/var/log/messages

/var/log/messages 是 Linux 系统的通用日志中心,几乎所有非特定服务的系统级事件都会在此记录,地位相当于系统的 “主日记”。

记录内容

  • 系统启动过程中的引导信息(如内核初始化、服务启动状态);
  • 运行时的错误事件(IO 失败、网络连接中断、硬件驱动异常);
  • 进程状态变化(如服务启动 / 停止、进程被强制终止);
  • 内核消息(如内存不足、文件系统错误)。

实用场景:排查进程异常终止

当应用程序突然崩溃时,可通过该日志确认是否被内核的 OOM Killer(内存不足杀手)终止:

1
2
# 查找被 OOM Killer 杀死的 Java 进程
grep "Kill process" /var/log/messages | grep java

输出示例:

1
Out of memory: Kill process 31201 (java) score 783 or sacrifice child
  • 保护关键进程:若需避免进程被 OOM Killer 终止,可调整其优先级:

    1
    echo -17 > /proc/$PID/oom_adj  # $PID 为进程 ID,-17 表示最高保护级别

启动日志:/var/log/dmesgdmesg 命令

该日志记录系统启动阶段的内核消息,聚焦硬件初始化和驱动加载,是排查硬件问题的首选。

阅读全文 »

SSH 密钥认证:安全便捷的远程登录方式

SSH(Secure Shell)是 Linux 系统中远程登录的标准协议,除了传统的密码认证外,密钥认证机制提供了更安全、更便捷的登录方式,无需每次输入密码即可建立连接。本文将详细介绍 SSH 密钥认证的原理和配置方法。

密钥认证的工作原理

SSH 密钥认证基于非对称加密算法(如 RSA 或 ECDSA),通过一对密钥(公钥和私钥)实现身份验证:

  1. 密钥对生成:用户在本地生成一对密钥 —— 公钥(public key)和私钥(private key)。
  2. 公钥部署:将公钥上传到目标服务器的指定位置(~/.ssh/authorized_keys)。
  3. 认证过程:
    • 客户端发起 SSH 连接请求。
    • 服务器生成随机数,用客户端的公钥加密后发送给客户端。
    • 客户端用私钥解密随机数,返回给服务器。
    • 服务器验证结果,一致则允许登录。

优势

  • 安全性更高:私钥仅存于本地,无需在网络中传输密码。
  • 便捷性:配置后无需重复输入密码,适合脚本自动化操作。

密钥认证的配置步骤

1. 在本地客户端生成密钥对

使用 ssh-keygen 命令生成密钥对(默认采用 RSA 算法):

阅读全文 »

Linux 启动过程详解:从开机到用户登录的完整流程

Linux 系统的启动是一个从硬件初始化到用户空间就绪的复杂过程,涉及固件、内核、初始化系统等多个层面。理解启动流程不仅有助于系统故障排查,还能深入掌握 Linux 的底层运行机制。本文将以传统 SysVinit 系统为例,详细解析启动的五个核心阶段,并补充现代 systemd 系统的差异。

内核引导(Boot Loader 阶段)

这是启动的第一个阶段,负责从硬件到内核的交接,分为 BIOS/UEFI 自检引导程序加载 两步。

BIOS/UEFI 自检(硬件初始化)

  • BIOS(基本输入输出系统):传统固件接口,开机后首先运行,负责检测 CPU、内存、硬盘等硬件是否正常(即 “POST 自检”)。
  • UEFI(统一可扩展固件接口):现代固件接口,功能与 BIOS 类似,但支持更大的硬盘、更快的启动速度和图形化界面。
  • 核心任务:确定启动设备(如硬盘、U 盘、光驱),并读取设备的第一个扇区(MBR 主引导记录,传统 BIOS)或 EFI 系统分区(UEFI)。

引导程序(Boot Loader)加载内核

引导程序是位于启动设备第一个扇区的小程序,负责加载 Linux 内核。常见的引导程序有 GRUB(Grand Unified Bootloader)和 LILO(Linux Loader),其中 GRUB 因支持多系统引导而被广泛使用。

GRUB 的工作流程:
  1. 阶段 1:从 MBR 加载 GRUB 核心代码(占 512 字节,仅够启动下一步)。
  2. 阶段 1.5:加载位于 MBR 之后的驱动,使 GRUB 能识别内核所在的文件系统(如 ext4、xfs)。
  3. 阶段 2:读取 /boot/grub/grub.cfg 配置文件,显示启动菜单(如选择不同内核版本或操作系统)。
  4. 加载内核:用户选择后,GRUB 将 Linux 内核(/boot/vmlinuz-<version>)和初始 RAM 磁盘(/boot/initramfs-<version>.img)加载到内存。
    • 内核(vmlinuz):Linux 核心程序,负责硬件管理和进程调度。
    • 初始 RAM 磁盘(initramfs):临时根文件系统,包含启动阶段必需的驱动(如硬盘驱动),帮助内核挂载实际根分区。

内核初始化(Kernel 阶段)

内核被加载到内存后,接管系统控制权,完成从硬件到用户空间的过渡。

阅读全文 »

TCP 粘包与拆包问题及 Netty 解决方案详解

TCP 作为面向连接、面向流的传输协议,在保证可靠性的同时,也因 “流” 特性导致了粘包和拆包问题。本文将深入解析问题根源,并详细介绍 Netty 提供的多种解决方案,帮助开发者在实际项目中正确处理消息边界。

TCP 粘包与拆包的本质

TCP 协议以 “流” 的形式传输数据,数据被分割为多个 TCP 报文段发送,接收端无法直接区分消息的边界,从而导致:

  • 粘包:多个小消息被合并为一个大报文段发送,接收端无法区分。
  • 拆包:一个大消息被分割为多个小报文段发送,接收端需等待所有片段才能还原完整消息。

示例
客户端连续发送 ["Hello", "World"],接收端可能收到:

  • 粘包:"HelloWorld"(两个消息合并)。
  • 拆包:"He""lloWorld"(一个消息被拆分,另一个被合并)。

粘包与拆包的产生原因

粘包的原因

  • Nagle 算法优化:TCP 默认启用 Nagle 算法,将短时间内的小数据包合并为一个大数据包(减少网络交互次数),导致粘包。
  • 发送端缓冲区未满:发送端缓冲区未达到阈值时,多个小消息会被缓存并批量发送。
  • 接收端处理不及时:接收端未及时读取缓冲区数据,导致多个消息堆积并被一次性读取。

拆包的原因

  • 超过缓冲区大小:消息长度超过发送端缓冲区或接收端缓冲区大小,被拆分为多个片段。
  • 超过 MSS 限制:TCP 报文段长度不能超过 MSS(最大报文段大小,通常为 1460 字节),大消息会被拆分。
  • IP 分片:当 TCP 报文段超过 MTU(最大传输单元,通常为 1500 字节),IP 层会进行分片。
阅读全文 »

Netty ChannelHandler 与 ChannelPipeline 详解:事件驱动的核心机制

Netty 的 ChannelHandlerChannelPipeline 是实现事件驱动模型的核心组件,类似于 Servlet 中的过滤器链(Filter Chain),负责管理网络事件的流转与处理。本文将深入解析二者的工作原理、事件传播机制及实战应用,帮助理解 Netty 如何通过组件协作实现高效的网络通信。

ChannelPipeline:事件流转的容器

ChannelPipelineChannelHandler 实例的双向链表容器,负责定义网络事件在处理器之间的传播规则。每个 Channel 被创建时会自动绑定一个独立的 ChannelPipeline,二者生命周期一致。

数据结构与核心特性

  • 双向链表:ChannelPipeline内部通过AbstractChannelHandlerContext节点形成双向链表,包含头节点(head)和尾节点(tail)。

    1
    2
    final AbstractChannelHandlerContext head; // 头节点(内置入站处理器)
    final AbstractChannelHandlerContext tail; // 尾节点(内置出站处理器)
  • 动态修改:支持在运行时通过addLast()、remove()等方法添加或移除ChannelHandler,无需重启服务。

    1
    2
    3
    // 向 pipeline 末尾添加处理器
    pipeline.addLast("handler1", new Handler1());
    pipeline.addLast("handler2", new Handler2());

事件类型与传播方向

Netty 中的事件分为两类,传播方向完全相反:

阅读全文 »