[Centos系统] CentOS 故障排除指南(一)

84 0
Honkers 昨天 17:38 | 显示全部楼层 |阅读模式

原文:annas-archive.org/md5/7b6e772fc80d2e15150201df989de650

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

CentOS(Community Enterprise Operating System)被认为是一款强大、稳定且通常没有问题的操作系统,尤其适合作为服务器使用。作为 RHEL 的忠实版本,CentOS 自 2004 年 5 月首次发布以来就一直陪伴我们。它被全球大量服务器使用,越来越多的个人和企业也在各种需求下选择它,并且在许多关键任务场景中都有它的身影。CentOS 被认为是 Linux 专业人士的最爱,如果配置正确、服务到位并进行妥善维护,通常情况下,基于 CentOS 的服务器不应产生任何重大问题。然而,也有可能出现故障,在这种情况下,当“重启机器”这种老掉牙的笑话并不适用时,你唯一的选择就是考虑进行系统故障排除。

本书以故障排除 CentOS 7 服务器为总体主题,旨在带领你走过一条涉及广泛问题解决方案的学习之路。你将遇到活跃进程、网络环境、包管理、用户、目录和文件、共享资源、安全性、数据库、基于 Web 的服务以及 DNS 等多个领域,最终目标是构建你的知识库,并帮助你发展一种全新的问题解决方法。

本书涵盖的内容

第一章,CentOS 故障排除基础,作为本书的引言,向你介绍了如何收集硬件信息、dmesg 的使用、处理日志文件,以及如何利用一系列命令行工具操作这些日志文件。

第二章,故障排除活跃进程,重点讨论了服务器性能调优、交换空间、内存管理、系统负载、磁盘 I/O 监控、系统巡检、发出 kill 信号以及使用更多命令行工具进行性能检查等内容。

第三章,故障排除网络环境,带你逐步诊断与网络环境相关的各种问题。ping、dig、host、traceroute、mtr、ss 和 tcpdump 只是一些工具,书中将讨论如何通过它们解决一系列网络相关的问题。

第四章,故障排除包管理和系统升级,将 yum(Yellowdog Updater, Modified)置于聚光灯下,目的是向你展示如何管理插件、添加额外的软件仓库、下载 RPM 包、恢复 RPM 数据库并收集通用的软件信息。

第五章,用户、目录和文件故障排除,着眼于持续维护,提供专业故障排除员可能面临的各种问题的信息。从用户管理到 login.defs,utmpdump 到一般的文件和目录审计。本章还建立在你现有的 XFS 文件系统知识基础上,展示如何使用 Scalpel 恢复丢失的数据。

第六章,共享资源故障排除,聚焦于 CentOS 7 中的 NFS,展示如何提供共享、管理导出,并通过客户端工作站访问它们,同时探讨 CIFS 和 autofs,提供一份全面的问题解决指南。

第七章,安全问题故障排除,在已有势头的基础上,讨论为什么你需要保持 SELinux,并展示如何使用 aureport 生成审计报告。从这一点开始,你将发现对 FirewallD 的全面回顾,并获得 Tripwire 安装指南,以便开发自己的入侵检测系统。

第八章,数据库服务故障排除,为故障排除人员和系统管理员提供帮助,通过解决 MariaDB、MySQL 和 PostgreSQL 的关键问题,提供如何处理丢失的 root 密码、数据库调优、数据库指标的概览,以及如何在 CentOS 7 上安装 MySQL 服务器。

第九章,Web 服务故障排除,从恢复问题中退后一步,探讨提高系统、网站或 Web 应用程序性能的需求。通过 cURL 的艺术,你不仅会发现如何审计你的服务器和访问 FTP,还会学到如何验证 Akamai 头部并管理 Varnish,整体目标是阐明 Dev/Ops 与故障排除之间的微妙界限。

第十章,DNS 服务故障排除,通过调查各种域名服务问题,完成我们的旅程。主机名、FQDN、BIND 和 iftop 都被深入探讨,我们将解决与带宽、缓存清除和如何进行 DNS 健康检查等相关的问题。

本书所需内容

本书的要求基于使用 CentOS 7,这是一个社区支持的发行版,源代码由 Red Hat 公开提供。因此,CentOS Linux 在功能上与 RHEL(红帽企业 Linux)兼容,尽管某些软件包名称可能已更改,以去除上游供应商的品牌和艺术设计。CentOS Linux 是免费的,无需付费,并且可以自由重新分发。

本书适合谁

本书是一本实际的指南,旨在解决 CentOS 7 社区版企业服务器的问题。假设你已经有一个运行中的服务器,具备一定的 CentOS 知识,并且能够熟悉地使用你的服务器所用的服务。我们并不要求你成为专家,但有远程管理服务器的经验会对你有所帮助。

约定

在本书中,你将看到多种文本样式,用来区分不同类型的信息。以下是这些样式的几个示例,并解释它们的含义。

文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名如下所示:“了解如何使用lscpu和lspci收集硬件系统信息。”

代码块的设置如下:

  1. /path/to/nfs/publication/directory XXX.XXX.XXX.XXX(rw,sync,root_squash,no_all_squash)
复制代码

任何命令行输入或输出都如下所示:

  1. # yum groupinstall "Base" "Development Libraries" "Development Tools"
复制代码

注意

警告或重要的注意事项会以类似这样的框展示。

小贴士

小贴士和技巧以这种形式出现。

读者反馈

我们始终欢迎读者的反馈。告诉我们你对本书的看法——你喜欢什么,或者不喜欢什么。读者反馈对我们很重要,因为它帮助我们开发出你能够从中获得最大收益的书籍。

若要向我们发送一般反馈,只需发送电子邮件至,并在邮件主题中提到书名。

如果你在某个领域有专业知识,并且有兴趣写作或为书籍贡献内容,请查看我们的作者指南,网址为www.packtpub.com/authors。

客户支持

现在你已经是一本 Packt 书籍的骄傲拥有者,我们为你提供了一些帮助,以便你从购买中获得最大收益。

勘误

尽管我们已经尽力确保内容的准确性,但错误仍然可能发生。如果你在我们的书籍中发现错误——可能是文本或代码中的错误——我们将非常感激你能向我们报告。这样,你不仅能帮助其他读者避免困扰,还能帮助我们改进书籍的后续版本。如果你发现任何勘误,请访问www.packtpub.com/submit-errata报告,选择你的书籍,点击Errata Submission Form链接,并输入勘误的详细信息。一旦你的勘误被验证,通过审核后,勘误将被上传到我们的网站,或添加到该书籍勘误列表的 Errata 部分。

若要查看已提交的勘误,请访问www.packtpub.com/books/content/support,并在搜索框中输入书名。所需的信息将出现在Errata部分。

盗版

网络上盗版受版权保护的材料是一个持续存在的问题,涵盖了所有媒体。我们在 Packt 对版权和许可的保护非常重视。如果您在网络上发现我们作品的任何非法副本,请立即向我们提供位置地址或网站名称,以便我们采取措施。

如果您发现涉嫌盗版的内容,请通过 联系我们,并提供涉嫌盗版材料的链接。

我们感谢您在保护我们的作者和帮助我们为您提供有价值内容方面的支持。

问题

如果您对本书的任何内容有疑问,可以通过 联系我们,我们将尽最大努力解决问题。

第一章:CentOS 故障排除基础

CentOS,即社区企业操作系统,以其强大、稳定和无故障的特性而闻名,特别适合作为服务器操作系统。被各类组织广泛使用,CentOS 在全球许多关键任务环境中都能找到其身影。然而,随着服务器需要按需运行且不中断地提供服务,某些时候,需要冷静但果断的手段来恢复服务,或对现有应用程序进行最后的调整,以确保能够尽快恢复到“正常工作状态”。

“服务器已经崩溃,所有的麻烦即将爆发。”

在一个不完美的世界里,事情可能会出错(并且不可避免地出错),但正是你对 CentOS 7 的整体理解以及它所提供的信心,构成了你故障排除技能的基础。记住,故障排除是一个调查过程,最终会得出诊断结果。所有系统都是不同的,对同一情况的处理方法也会根据系统的目的有所不同。因此,考虑到这一点,重要的是要意识到本书的前提并不是基于具体的操作步骤,而是更多地关注使用的工具和你将要遇到并与之互动的资源。

在本章中,我们将:

  • 学习如何在 CentOS 上安装一些基本工具

  • 探索如何使用lscpu和lspci收集基于硬件的系统信息

  • 进一步了解dmesg的重要性及其与内核的交互

  • 了解更常见的日志文件及其如何影响日志输出

  • 学习如何使用grep、tail、cat、less、truncate等命令行功能操作任何类型的文件

安装一些基本工具

本书假设你已经能够访问与服务器故障排除相关的基本工具。将提及一些较为冷僻的工具,并会提供相应的使用说明;然而,对于那些可能有或没有基本工具箱的读者,作为 root 用户,你可能想要从运行以下命令开始:

  1. # yum groupinstall "Base" "Development Libraries" "Development Tools"
复制代码

该操作(如果确认执行)将开始下载并安装 CentOS 服务器系统的常用开发工具、库和基础组件。它还包含 RPM 所需的相关工具、额外的文本编辑器以及编译自定义包所需的包。

注意

在开始时安装这些软件包是可选的,所有这些软件包都可以根据需要单独安装。然而,在灾难恢复规划至关重要的环境中,考虑到服务器在任何问题发生之前就应具备一切所需,值得一提。

所以,在为系统准备好必要的工具和实用程序后,我们将正式开始,仔细查看硬件。为了做到这一点,建议你继续以 root 权限访问相关系统。

收集硬件信息

从原则上讲,大多数人倾向于建议将所有系统信息分为硬件或软件两类。这种方法确实有助于简化问题,但在本章中,我将通过一些方式推测,在某些情况下,硬件和软件的相互作用可能是问题的根源。

因此,在开始故障排除之前,始终考虑收集系统信息是获得更多洞察和熟悉度的推荐方法。这样来看:收集硬件信息的实践并不是必须的,但这种类型的调查可能有助于你寻找最终的诊断结果。

首先,我们将通过以下命令运行一个简单的基于 CPU 的硬件报告:

  1. # cat /proc/cpuinfo
复制代码

如你所见,此命令的目的是输出与 CPU 型号、家族、架构、缓存等相关的所有信息。/proc 方法一直是一个不错的传统,但使用以下命令通常被认为是更好的做法,并且更易于使用:

  1. # lscpu
复制代码

此命令将查询系统,并以以下方式输出与 CPU 相关的所有信息:

  1. Architecture: x86_64
  2. CPU op-mode(s): 32-bit, 64-bit
  3. Byte Order: Little Endian
  4. CPU(s): 2
  5. On-line CPU(s) list: 0,1
  6. Thread(s) per core: 1
  7. Core(s) per socket: 2
  8. Socket(s): 1
  9. NUMA node(s): 1
  10. Vendor ID: GenuineIntel
  11. CPU family: 6
  12. ...
复制代码

另一方面,与其查询所有内容,你可以使用 grep(这是我们稍后会回到的主题)来指定条件,从而获取任何相关信息,像这样:

  1. # lscpu | grep op-mode
复制代码

因此,完成这些操作并记录结果以备将来参考后,我们将继续进行调查,通过以下方式运行简单的硬件报告,使用 lspci 命令:

  1. # lspci
复制代码

该命令的输出可能类似于以下信息:

  1. 00:00.0 Host bridge: Intel Corporation 82P965/G965 Memory Controller Hub (rev 02)
  2. 00:01.0 PCI bridge: Intel Corporation 82G35 Express PCI Express Root Port (rev 02)
  3. 00:05.0 Ethernet controller: Red Hat, Inc Virtio network device
  4. 00:0a.0 PCI bridge: Digital Equipment Corporation DECchip 21150
  5. 00:0e.0 RAM memory: Red Hat, Inc Virtio memory balloon
  6. 00:1d.0 USB controller: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1 (rev 02)
  7. 00:1d.7 USB controller: Intel Corporation 82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller (rev 02)
  8. 00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev f2)
  9. 00:1f.0 ISA bridge: Intel Corporation 82801HB/HR (ICH8/R) LPC Interface Controller (rev 02)
复制代码

lspci 命令提供有关服务器的 PCI 设备的所有相关信息,进一步的信息可以通过使用 -v 选项或其他 -vv / -vvv 选项来扩展,具体取决于你所需的详细程度:

  1. # lspci -v
  2. # lspci -vv
  3. # lspci -vvv
复制代码

默认情况下,上述命令将提供所有所需的信息,以便确认设备是否受到当前系统中任何模块的支持。预计你只需要在实施硬件升级后、新安装系统时,或者尝试熟悉新环境时执行此操作。然而,为了进一步简化此过程,你会高兴地知道,还可以使用“树状视图模式”。这个功能的目的是输出相关的设备 ID,并展示这些值如何与相应的总线相关联。

要做到这一点,输入以下命令:

  1. # lspci -t
复制代码

作为一名故障排除员,您会知道每个设备都必须维护一个唯一的标识符,因为 CentOS 与其他操作系统一样,将使用该标识符将驱动程序绑定到该设备。lspci命令通过扫描/sys树来检测所有连接的设备,这些设备可以包括连接端口、设备类型和类别,仅举几例。完成此操作后,lspci命令将查阅/usr/share/hwdata/pci.ids,以提供它所显示的可读条目。

例如,您可以通过输入以下带有-k选项的lspci命令来显示内核驱动程序/模块,像这样:

  1. # lspci -k
复制代码

自然,在任何基于硬件的故障排除调查中,您都会想查看系统日志以获取更多线索,但正如我们所看到的,lscpu和lspci命令在尝试发现系统中所需的硬件信息时尤其有用。

您可以随时通过查看相应的车载手册来了解更多关于这些命令的信息:

  1. $ man lscpu
  2. $ man lspci
复制代码

同时,如果您想要更多练习,一个简单的测试就是插入一个 USB 闪存驱动器,并通过仔细查看/var/log/messages中的枚举信息来分析您自己得到的结果。

注意

请记住,如果您确实尝试了这个操作,您所看到的是系统在插入 USB 驱动器后的反应;您不一定是在查看 USB 驱动器本身;关于 USB 的信息可以通过lsusb获得。

另一方面,就像我们可以将grep与lscpu一起使用一样,如果您已经习惯了这种类型的调查,那么您可能会想知道,您还可以将grep与lspci命令一起使用,以下面这种方式来发现更多关于 RAID 控制器的信息:

  1. # lspci | grep -i raid
复制代码

现在,我相信您不会感到惊讶,知道还有许多与获取硬件信息相关的命令。这些包括(但不限于)lsmod、dmidecode、hdparm、df -h,甚至是lsblk,以及在本书中将提到的许多其他命令。它们都很有用,但对于那些不想记住它们的人,可以通过简单地阅读/proc和/sys目录中的文件找到大量信息,像这样:

  1. # find /proc | less
  2. # find /sys | less
复制代码

因此,在我们继续之前,你现在应该知道,当你处理硬件分析时,提升你的技能是通过长时间接触服务器来实现的。我这么说的原因是基于这样一种观点:一个简单的安装过程几乎可以立即识别出这些问题,但没有这个便利的情况下,随着时间的推移,硬件可能需要更换或维护。RAID 电池组会故障,内存模块会故障,有时可能是某个特定驱动程序在最近一次重启时没有完全加载。在这种情况下,你可能会发现内核正以如此高的频率向系统发送随机消息,以至于它表明一个完全不同的问题导致了故障。所以,是的,硬件故障排除需要耐心和观察力,这也是为什么对lscpu和lspci命令的快速回顾成为我们故障排除 CentOS 7 的引言。

理解 dmesg

在我们深入探讨日志文件的主题之前,我想花几分钟时间讨论一下dmesg命令的重要性。

dmesg命令用于记录与硬件检测和配置过程相关的内核消息。我此时不打算深入讲解技术细节,但重要的是要意识到,这些信息来源于内核环形缓冲区;这个条件不仅在硬件故障排除时非常有帮助,而且也为理解系统硬件如何反映在可能的软件诊断上提供了证据,反之亦然。

dmesg文件位于/var/log/目录中,但与该目录中其他文件不同,查看dmesg文件内容的基本语法如下:

  1. # dmesg | less
复制代码

你可以像往常一样翻页查看结果,但如果你希望让时间戳更容易阅读,你可能希望像这样调用-T选项:

  1. # dmesg -T | less
复制代码

这些命令将向我们提供与启动过程中加载到内核中的所有硬件驱动程序相关的信息。这些信息将包括它们的状态(成功或失败),如果记录到失败,它甚至会提供一个错误消息,描述失败发生的原因。然而,由于该文件可能非常庞大,你应该使用grep查询dmesg以简化这些信息并简化输出。

为此,只需根据你的需求定制以下语法:

  1. # dmesg -T | grep -i memory
复制代码

这个命令将显示所有与服务器相关的总内存和共享内存细节的相关信息。当然,类似的方法也可以用来读取 USB 设备、直接内存访问(DMA)或甚至 tty 的具体信息。

例如,你可以查询 dmesg 来以以下方式显示与任何以太网端口相关的硬件信息:

  1. # dmesg –T | grep -i eth0
复制代码

根据你的系统配置,输出将类似于以下内容:

  1. [Sun Apr 19 04:56:57 2015] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
复制代码

为了扩展这一方法,你可以修改之前的命令,以发现内核是否已检测到特定的硬盘。为此,请输入:

  1. # dmesg –T | grep sda
复制代码

或者,你可以使用 -i 选项忽略搜索 tty 引用时的大小写敏感性:

  1. # dmesg | grep -i tty
复制代码

正如你将看到的,dmesg 文件的输出非常冗长,文件中包含的信息可以用于故障排除几乎任何问题,从网络卡到存储问题。dmesg 文件可能不会直接给出你想要的答案,但它提供了一个拼图的另一部分,当与一些常见的 CentOS 操作系统日志文件中的信息结合使用时,它会帮助你找到解决方案。

理解日志文件

默认情况下,所有 CentOS 系统日志文件都可以在 /var/log 中找到,可以通过输入以下命令获取当前服务器的完整清单:

  1. # find /var/log
复制代码

话虽如此,每个系统都是不同的,为了简化操作,你会发现一些常见的日志文件(与 CentOS 7 最小化安装相关的)包括:

  • /var/log/messages:该文件包含与 CentOS 使用的许多本地服务相关的信息。包括(但不限于)内核日志、网络管理器、引导过程、邮件服务、cron 任务以及许多没有自己日志文件的其他服务。在许多方面,这个记录可以被认为是某种全球性日志文件,出于习惯,它可能会成为你在任何故障排除过程中首先访问的文件。

  • /var/log/boot.log:该文件包含系统启动时报告的信息。

  • /var/log/maillog:该文件包含由系统默认邮件服务器报告的信息。

  • /var/log/secure:该文件包含与认证和授权权限相关的信息。

  • /var/log/wtmp:该文件包含与用户登录记录相关的信息。

  • /var/log/btmp:该文件包含与登录失败尝试相关的信息。

  • /var/log/cron:该文件包含与 cron(和 anacron)相关的信息。

  • /var/log/lastlog:该文件包含与包含所有最后登录信息的二进制日志相关的信息。

  • /var/log/yum.log:该文件包含与 Yum 相关的信息,并报告与服务器包管理工具相关的任何活动。

现在,在继续之前,我想提醒你这些文件的重要性,因为通常建议将 /var/log 存储在与 /(根目录)不同的分区中。

一个完美的系统应为/tmp、/usr等目录维护单独的分区,但确实也有可能在某些情况下,日志文件不得不与/(根)分区存储在同一分区上。因此,请记住,如果有这样的机会,您可能需要考虑将这些目录存储在一个独立的文件系统和独立的物理卷上(如果可能),因为这被认为是保持系统安全性、完整性和性能的良好实践。

然而,话虽如此,仍然需要认识到,许多其他软件包会在其他位置创建和存储日志文件。您甚至可能需要自行指定这些位置,因此应该记住,并非所有日志都位于/var/log目录下。

例如,如果相关服务器托管一个或多个网站,并将所有相关的 Apache 虚拟主机信息存储在特定的/home目录中,那么相关的日志文件可能会存储在如下位置:

  1. /path/to/virtualhost/domain1/log/access_log
  2. /path/to/virtualhost/domain1/log/error_log
复制代码

许多其他软件包也面临同样的问题,原因在于这些软件包可能没有写入该目录所需的权限,而其他软件包则设计为将所有日志活动保存在其自己的安装目录中。因此,根据您的系统特性,您可能需要花些时间分析服务器的安装结构,以便找到适当的日志文件。

阅读日志文件并影响输出

查看或读取日志文件非常容易,且根据个人偏好,查看这些文件的基本语法可以用以下任意一种格式表达:

  1. # less /var/log/filename
  2. # more /var/log/filename
  3. # cat /var/log/filename
  4. # cat /var/log/filename | less
  5. # cat /var/log/filename | more
复制代码

注意

请记住,根据系统配置,您可能需要根用户权限才能查看特定的日志文件。试图更改任何系统文件时,也可能需要类似的权限,因此,我们将继续以根用户身份操作。然而,使用sudo或su(切换用户)的用户应相应地调整指令。

日志文件在不同的应用程序和服务之间可能有所不同,但这些文件的主要目的是记录事件的时间和日期以及安全级别,并提供一条消息或一般描述。大多数消息将是某种类型的常规通知或警告,但在某些情况下,也会捕获错误。

例如,您可能会看到如下内容:

  1. Dec 4 12:49:05 localhost postfix/postfix-script[1909]: starting the Postfix mail system
复制代码

这样的消息很普通,仅仅解释发生了什么以及何时发生。是的,你可以放心地忽略它们,但由于你看到的消息数量较多,有些人可能会觉得系统对一些事情过于敏感,导致日志文件被低级信息淹没。对于很多人来说,这些信息可能没有实际用途,但在某些情况下,你可能会认为提供的信息不够详细,可能需要更多的信息。最终,只有你能决定最适合你的需求。所以,为了举个例子,假设我们要提高日志敏感度来排查系统问题。

为此,我们将首先运行以下命令:

  1. # cat /proc/sys/kernel/printk
复制代码

前面的命令输出允许你查看当前的内核设置,典型系统中会是如下所示:

  1. 4 4 1 7
复制代码

这里存在一个关系,重要的是你理解printk维护着四个数值,这些数值控制与错误消息日志记录相关的多个设置,同时每个错误消息也有其专属的日志级别,用来定义该消息的重要性。

日志级别值可以总结如下:

  • 0:内核紧急

  • 1:内核警报;必须立即采取行动

  • 2:内核状态被认为是关键的

  • 3:一般内核,错误条件

  • 4:一般内核,警告条件

  • 5:内核正常但重要的情况通知

  • 6:内核信息性消息

  • 7:内核调试级别消息

所以,基于以上信息,4、4、1 和 7 的日志级别值告诉我们,接下来显而易见的是:

  • 第一个值(4)称为控制台日志级别。这个数值定义了打印到控制台的消息的最低优先级,意味着优先级越低,日志级别数字越高。

  • 第二个值(4)确定了所有没有专属日志级别的消息的默认日志级别。

  • 第三个值(1)确定了整体控制台日志级别的最低可能日志级别配置。优先级越低,日志级别数字越高。

  • 第四个也是最后一个值(7)确定了整体控制台日志级别的默认值。同样,优先级越低,日志级别数字越高。

因此,你现在可以考虑通过配置文件/etc/sysctl.conf来修改日志级别。这个文件使你能够对默认设置进行细微调整,并且可以通过你喜欢的文本编辑器以以下方式访问:

  1. # nano /etc/sysctl.conf
复制代码

要进行所需的更改,请使用以下语法:

  1. kernel.printk = X X X X
复制代码

这里,X的实际值是从前面描述的选项中获取的日志级别设置。

例如,你可以通过添加以下行来改变消息数量:

  1. kernel.printk = 5 4 1 7
复制代码

当然,这样的修改意味着对内核的更改,因此重启是必要的。所以,完成这一步后,你会发现运行cat /proc/sys/kernel/printk的输出现在应该反映新的值。然而,作为补充的警告,考虑到执行此操作(是的,你可以轻松地撤销任何已做的更改),重要的是要意识到关于更改这些设置的有效性存在许多问题。换个角度看:这可能完全不帮助你,因此在进行这些更改之前,你应始终阅读相关资料,以确认做出这一修改是否符合你的总体目的。

要查看内建的手册,只需使用以下命令:

  1. $ man sysctl
复制代码

另一方面,对于服务器上许多其他服务和应用程序,你将有额外的调查途径需要考虑,这些途径通常是由相关服务或应用程序本身设置的。

一个常见的例子是 Apache。因此,如果你在调试与该服务相关的 Web 问题时,你可能会倾向于打开httpd配置文件,如下所示:

  1. # nano /etc/httpd/conf/httpd.conf
复制代码

查找或搜索以下行:

  1. LogLevel warn
复制代码

然后,替换该指令为更合适的设置(在保存文件并重启服务之前)。在这种情况下,你可以使用:

  1. LogLevel debug
复制代码

幸运的是,知道大多数服务和应用程序确实支持一种调试模式,以改善日志输出,这是一件好事。这将使日志文件更加详细并且在排除服务器故障时更容易处理,但在我们结束这个话题之前,有一个小的注意事项……

当你处理日志文件时,应该意识到这些日志文件中包含的信息并不总是足以帮助你诊断当前的问题或发现问题的根本原因。日志文件不仅可能缺少必要的信息,还可能包含未知的错误和误导性的消息。毕竟,日志文件仅包含一系列(主要是)预定义的消息或包中的断点,这些消息是由程序员设计的,用于备注可能发生过或已经发生的已知事件。

注意

记住……

在影响日志文件输出时,详细的输出可能会引发性能或安全问题,而详细的日志记录还可能对 CPU 或磁盘 I/O 操作造成不必要的负担。

根据这些情况,没有固定的规则,因为我们也知道日志文件是有局限性的。所以,最终你将依赖于敏锐的观察力和大量的耐心,仅仅基于这些原因,你必须始终学会“整体倾听服务器”。

这样说吧:答案在那儿,但可能不在日志文件中。坚持不懈和冷静(但坚定)的态度将最终胜出,而这一点将贯穿本书的每一页。

使用 tail 监控日志文件

所以,掌握了之前的信息,并且知道日志文件通常通过指定事件发生的时间、严重程度和预定的消息来描述事件,成功的关键在于能够处理这些记录并以某种方式操作它们,使它们为我们提供完成任务所需的信息。

在故障排除过程中,你将使用的最有用的命令之一是 tail。以下是一个命令行表达式,可以用来读取日志文件的最后几行:

  1. # tail -n 100 /var/log/maillog
复制代码

同样,tail 也可以用来获取最近添加的行,像这样:

  1. # tail -f /var/log/maillog
复制代码

使用此命令不仅可以为你提供日志文件的最新视图,还能确保所有更新立即显示,这为你提供了一种在实时环境中阅读日志文件的即时方式。这种方法可以被描述为解决 Apache、Postfix、Nginx、MySQL 以及你的服务器可能使用的其他许多应用程序或服务故障的完美方式。

例如,你可以像这样查看 Apache 的 access_log:

  1. # tail -f /var/log/httpd/access_log
复制代码

为了进一步拓展这个功能,假设你想获取日志文件中的最后 3,000 行,知道它将无法适应你的 shell 窗口。为了满足这个需求,你可以像这样使用管道将结果与 less 命令结合:

  1. # tail -n 3000 /var/log/messages | less
复制代码

在这种情况下,你现在可以根据需要分页结果,但使用这种技术几次后,我想你会同意,它比使用通用的 cat 命令要灵活得多;除非,当然,你想做一些非常具体的事情。

使用 cat、less 和 more

cat 命令已经陪伴我们很长时间了,回到之前我们讨论的硬件和 /proc 目录的内容,你可以使用 cat 命令查看服务器 CPU 的详细信息:

  1. # cat /proc/cpuinfo
复制代码

如果你想了解更多关于服务器内存的信息,你可以使用:

  1. # cat /proc/meminfo
复制代码

然后,你总是可以通过输入以下命令来了解更多关于你的设备的信息:

  1. # cat /proc/devices
复制代码

尽管 cat 非常有用,但它也因将整个内容输出到屏幕上而闻名,如果文件超过 1,000 行,可能会显得有些笨拙。因此,在这种情况下,另一种选择是使用 less 和 more 命令,以分页的方式查看特定的(静态)文件,如下所示:

  1. # less /var/log/messages
  2. # more /var/log/messages
复制代码

然而,由于 more 命令相对较旧,大多数人会认为 less 更加优越。less 命令类似于 more,但 less 允许你在分页结果之间前后导航。所以,是的,这是一个老笑话,但从现在起,并且在任何可能的情况下,始终记住,less 确实意味着 more。

例如,less 允许你搜索特定的字符串。为此,只需像这样使用 less 打开以下文件:

  1. # less /var/log/messages
复制代码

现在,在屏幕的左下角,输入 /,后面跟着一个字符串值,像这样:

  1. /error
复制代码

输出现在将调整为突出显示搜索结果,如果你想查看更多选项,只需在 less 打开时按 H 键。

使用 grep

现在,让我们考虑一下需要在服务器的日志文件中查找特定关键字的情况。

在这种情况下,你将使用名为 grep 的命令,这也是当你想对服务器上的几乎任何文件执行高级基于字符串的搜索时,非常有用的技巧。

假设你想在邮件日志文件中查找一个特定的电子邮件地址。为此,你可以如下使用 grep 命令:

  1. # grep "user@domain.tld" /var/log/maillog
复制代码

更进一步,grep 还可以用于递归地搜索一个或多个文件中的内容。

例如,如果你想要在日志文件目录中查找一个 IP 地址(XXX.XXX.XXX.XXX),你可以将 grep 命令与 -R 选项结合使用,如下所示:

  1. # grep -R "XXX.XXX.XXX.XXX" /var/log/
复制代码

类似地,你可以通过 -n 选项为输出添加行号,如下所示:

  1. # grep -Rn "XXX.XXX.XXX.XXX" /var/log/
复制代码

此外,你还会注意到,在多文件搜索时,每个搜索结果都会显示文件名,但通过使用 -h 选项,你可以禁用此功能,如下所示:

  1. # grep -Rh "XXX.XXX.XXX.XXX" /var/log/
复制代码

你可以通过 -i 选项忽略大小写,如下所示:

  1. # grep -Ri "XXX.XXX.XXX.XXX" /var/log/
复制代码

更进一步,grep 还可以用来对搜索结果的内容进行排序,只需在原始命令末尾添加 sort 命令即可实现按字母顺序(从 a 到 z)排序,如下所示:

  1. # grep -R "XXX.XXX.XXX.XXX" /var/log/ | sort
复制代码

通过添加 -r 选项,你可以实现反向字母排序(从 z 到 a),如下所示:

  1. # grep -R "XXX.XXX.XXX.XXX" /var/log/ | sort -
复制代码

最后,如果你希望搜索多个值,你可以像这样使用 –E 参数(但不要在管道符之间包含不必要的空格):

  1. # grep -E "term 1|term 2|term 3" /var/log/messages
复制代码

当然,grep 的功能远不止这些,但为了故障排除的目的,我现在想要引起你注意的最后一个命令,diff 命令,在确定两个文件之间的差异时非常有用。

使用 diff

diff 命令通常不被认为是与日志文件相关的工具,除非你是在为特定目的比较备份文件。然而,diff 命令在比较应用程序的变化时非常有用。

例如,diff 命令可以让你比较两个 Apache 配置文件之间的差异,但通过使用 -u 选项,你还可以包含额外的信息,比如时间和日期:

  1. # diff -u /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.backup
复制代码

现在,根据文件的大小和服务器的速度,任务可能需要几秒钟(甚至几分钟)才能完成。是的,我知道我们有点偏离了日志文件的主题,但我相信随着时间的推移,你会发现这个命令非常有用。

例如,你可能想要使用 –rq 选项来比较两个文件夹的内容,这样可以让比较变得递归,如下所示:

  1. # diff –rq /path/to/folder1 /path/to/folder2
复制代码

要了解更多关于 diff 命令的信息,只需输入以下命令查看手册:

  1. $ man diff
复制代码

使用截断

因此,既然我们已经展示了处理日志文件的简便性,我们应该始终记住,像这样的记录会随着时间的推移而增长,正因如此,它们可能会变得难以处理。事实上,你应该意识到,过大的日志文件可能会影响系统性能。考虑到这一点,监控任何日志轮换过程并根据需要定期调整是一个好主意。

此外,考虑到日志轮换在中高负载环境中的重要性,我建议你有效地管理这个过程。然而,在这种过程中影响较小的情况下,下面的防护技术将允许你通过键入以下任一命令来清理日志文件:

  1. # cat /dev/null > /path/to/file
复制代码

或者更准确地说,你可以像这样使用truncate命令:

  1. # truncate --size 0 /path/to/file
复制代码

这个过程被称为截断,如前所述,这应该是最后的手段,因为之前的命令会删除文件中包含的所有数据。所以记住,如果文件包含你未来可能需要查看的重要信息,请在使用truncate之前先进行备份。

总结

本章旨在介绍故障排除 CentOS 7 的主题,目的是让你了解这一主题,而不是让你背负一堆不适合你当前情况或需求的规则、指令或流程。我们知道,故障排除是一个过程,第一章已经帮助你了解了一些概念和方法,接下来的每一页都会确保你更接近于轻松应对你即将诊断和修复的服务器。所以,是的,旅程刚刚开始,我们现在将讨论如何排查正在运行的进程。

参考资料

  • Red Hat 客户门户: access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/

  • Syslog 严重性级别: en.wikipedia.org/wiki/Syslog#Severity_levels

  • Dmesg 维基页面: en.wikipedia.org/wiki/Dmesg

  • Cat 维基页面: en.wikipedia.org/wiki/Cat_(Unix)

  • Grep 维基页面: en.wikipedia.org/wiki/Grep

  • Diff 维基页面: en.wikipedia.org/wiki/Diff_utility

  • Tail 维基页面: en.wikipedia.org/wiki/Tail

  • Less 维基页面: en.wikipedia.org/wiki/Less_(Unix)

第二章:故障排除活动进程

对 CentOS 7 中底层活动进程的深入理解是任何故障排除人员的必要技能。从高负载平均值到响应时间缓慢,从系统过载到死掉或将死的进程,每台服务器都会经历开始变得迟缓、表现不佳或无法响应的时刻,因此,它将需要你立即关注。

在本章中,我们将:

  • 了解内存管理、交换空间、交换性和抖动

  • 了解如何使用vmstat、top和ps命令分析活动进程

  • 了解如何使用iotop、iostat和lsof监控服务器

  • 了解系统负载和systemd

  • 了解如何查找进程 ID、识别父进程 ID 和孤儿进程,并启动各种类型的kill信号

通过内存管理和交换空间调整服务器性能

无论你怎么看,内存使用问题始终是系统生命周期中的关键问题。无论你是在维护系统健康状态还是排除特定服务或应用程序的故障,你都需要记住,内存的使用是系统的关键资源。基于这一原因,我们将首先通过以下方式调用free命令:

  1. # free -m
复制代码

前面命令的主要元素看起来将类似于以下内容:

  1. Total used free shared buffers cached
  2. Mem: 1837 274 1563 8 0 108
  3. -/+ buffers/cache: 164 1673
  4. Swap: 2063 0 2063
复制代码

在所示示例中,我使用了-m选项来确保输出的结果以兆字节为单位进行格式化。这样可以更容易阅读,但为了排除故障,我们不需要尝试理解每个显示的数字值,而是将原始输出的范围缩小,突出显示相关问题区域:

  1. -/+ buffers/cache: 164 1673
复制代码

这一行的重要性在于,它考虑了相关的缓冲区和缓存,以说明当前使用了多少内存以及多少内存被保留。第一个值表示使用的内存量,第二个值则告诉我们应用程序可用的内存量。在所示示例中,这意味着使用了 164 MB 内存,剩余 1673 MB 内存可用。

记住这一点,我请你注意最后一行,以便我们可以研究交换空间的重要性:

  1. Swap: 2063 0 2063
复制代码

交换通常发生在内存使用影响性能时。正如我们从前面的示例中看到的,第一个值告诉我们系统交换总量为 2063 MB,第二个值表示使用了多少交换空间(0 MB),而第三个值显示系统整体上还有多少交换空间可用(2063 MB)。因此,是的,基于此示例数据,我们可以得出结论:这是一个健康的系统,当前没有使用交换空间,但在这里,我们利用这段时间来进一步了解系统的交换空间。

首先,我们将重新访问proc目录,并通过输入以下命令来揭示交换空间的总大小和已用大小:

  1. # cat /proc/swaps
复制代码

假设你理解了显示的输出,那么你可以通过以下命令来调查系统使用的交换性水平:

  1. # cat /proc/sys/vm/swappiness
复制代码

完成后,你现在应该会看到一个介于 0 到 100 之间的数字值。该数字值是百分比,意味着例如如果你的系统值为 30,它将在 RAM 占用率达到 70%时开始使用交换内存。

所有 Linux 系统的默认值通常设置在 30 到 60 之间,但你可以使用以下命令中的任何一个来临时更改和修改系统的交换性。

你可以通过输入以下命令,将X的值替换为 1 到 100 之间的数字值来实现:

  1. # echo X > /proc/sys/vm/swappiness
复制代码

或者,更具体地说,也可以通过以下方式实现:

  1. # sysctl -w vm.swappiness=X
复制代码

如果你在任何时候改变主意,你有两个选项来确保没有做出永久更改。你可以重复执行前面两条命令中的任何一条,将值恢复到原来的状态,或者进行一次完整的系统重启。

另一方面,如果你想让更改生效并持久化,那么你应该编辑/etc/sysctl.conf文件,并以如下方式添加你的交换性偏好:

  1. vm.swappiness=X
复制代码

完成后,只需保存并关闭文件,以确保更改生效。

交换性值控制内核将进程从物理 RAM 移到交换磁盘的倾向。这是内存管理的一部分,但需要意识到,交换并不会立即发生,因为交换性值实际上是以百分比的形式表示的。因此,交换的过程应该更多地视为在使用缓存时的偏好度量,正如每个管理员都知道的那样,你可以通过使用命令swapoff -a和swapon -a来清除交换,以达到所需的效果。

黄金法则是要意识到,系统的交换性(swappiness)接近最大值(100)时,它会倾向于开始交换不活跃的页面。这是因为值为 100 代表着 RAM 的占用率为 0%。相比之下,系统的交换性越接近最低值(0),发生交换的可能性就越小,因为 0 代表着 RAM 的占用率为 100%。

一般来说,我们大多数人可能都会同意,拥有大量 RAM 的系统并不需要激进的交换。但为了让事情变得更加复杂,让我们换个角度来看。我们都知道,桌面电脑会从较低的交换性值中受益,但在某些情况下,你可能也会发现,拥有大量 RAM 的系统(运行批处理作业)也可能受益于适度到激进的交换,这与一个尝试做很多事情但仅使用少量 RAM 的系统类似。所以,实际上,并没有硬性规定;交换的使用应根据具体系统的需求,而不是寻找一个可以普遍适用的单一解决方案。

更进一步,在修改交换值时应特别小心,因为未被应用程序使用的内存会作为磁盘缓存使用。在这种情况下,通过减少交换性,你实际上是在增加该应用程序不被交换出去的概率,从而减少磁盘缓存的整体大小,这可能会导致磁盘访问变慢。然而,如果增加交换的优先级,由于硬盘比内存模块慢,它可能会导致整个系统响应时间变慢。交换操作可能会令人困惑,但了解这些之后,我们也能体会到交换性的隐含讽刺。正如牛顿的第三定律所说,每一个动作都会有一个相等且相反的反应,而找到最优的交换性值可能需要一些额外的实验。

使用 vmstat 管理内存

另一种内存管理的方式可以通过使用vmstat命令来实现。vmstat被认为是与内存、进程和分页相关的摘要报告功能,输入以下命令即可看到其运行:

  1. # vmstat -a
复制代码

使用-a选项调用所有活动和非活动内存时,vmstat输出中最有意义的列可以描述如下:

  • si: 该列显示从磁盘交换进来的值

  • so: 该列显示交换到磁盘的值

  • bi: 该列显示发送到块设备的值

  • bo: 该列显示从块设备接收的值

  • us: 该列显示用户时间

  • sy: 该列显示系统时间

  • id: 该列显示空闲时间

显示刚开始看起来可能会有些困惑,但对于我们的目的来说,我们需要集中注意以下在交换列下的几列:

  1. free si so
  2. 1645452 0 0
复制代码

其中free显示当前的空闲内存分配,si显示页面调入,而so提供页面调出。遗憾的是,单纯通过这种方式查看它,发现它对我们的需求有些局限,因此最有效的查看方法是通过在原始命令中添加延迟选项来管理输出,如下所示:

  1. # vmstat X N
复制代码

在这里,X是以秒为单位的数字时间值,N表示我们希望调用vmstat的次数;此代码格式的工作示范如下:

  1. # vmstat 3 5
复制代码

在这个示例中,我添加了值3和5,其中第一个数字表示延迟的秒数,第二个数字表示调用的结果次数。在这种情况下,vmstat 3 5将以3秒的延迟运行vmstat,并将显示5次更新,如下所示:

  1. free si so
  2. 1645452 0 0
  3. 1645452 0 0
  4. 1645452 0 0
  5. 1645452 0 0
  6. 1645452 0 0
复制代码

或者,你可以通过简化命令格式,减少复杂性,保持vmstat每N秒运行一次:

  1. # vmstat N
复制代码

所以,通过运行vmstat 10,vmstat会每10秒刷新一次所有活动的报告。然而,如果你需要了解事件发生的时间,可以使用-t选项,如下所示,调用一个带有时间戳的类似报告:

  1. # vmstat -t X N
复制代码

最后,由于默认的vmstat命令会以千字节为单位生成报告,为避免混淆,通常最好使用以下表达式让vmstat以兆字节为单位显示报告:

  1. # vmstat -S M X N
复制代码

当你启动一个应用程序并且信息被“调入”时,通常会发生页面调入(si)。然而,偶尔或间歇性的页面调出(so)也会发生,尤其是在内核释放内存的时期。定期的页面调出(so)或页面调出的增长是我们不希望看到的。如果这些事件的频率呈指数增长,那么这些事件就会表现为通常称为“抖动”的行为。

抖动是指系统在管理页面调度的时间超过了为应用程序或服务提供支持的时间。这不一定是一个严重的事件,但它表明故障排除人员应重新评估某些操作的价值,并考虑将它们分散到工作日的不同时间段进行处理。你总是可以为系统购买更多的 RAM,这可能在短期内有所帮助,但这并不能缩小问题的根源,也无法阻止事件的重复发生。因此,为了让我们的工作稍微轻松一点,下一步是使用top命令。

使用top命令检查系统负载

可以随时通过输入以下命令调用top命令:

  1. # top
复制代码

top命令是检查系统负载(RAM/MEM 和 CPU)的标准命令。它包含许多与内核相关的任务信息;显示内容会实时更新,最高负载因素以 CPU 或 MEM 的百分比表示。然而,重要的是要意识到,top可能会将这些值显示为超过预期的百分位范围。这是因为所有单独的核心都以百分比表示,且这些核心的多个实例会被加总。例如,一个双核系统可能会显示第一个核心为 70%,第二个核心为 60%,在这种情况下,top可能会显示合计 130%的结果,但你将无法得知每个核心的具体值。

你可以使用M键按内存对top进行排序,但正如你所见,top不仅会显示空闲内存的数量(如通过free命令看到的那样),它还会提供你在做某些操作和任务判断时可能需要的交换区细节。此外,你还可以通过定制输出内容来扩展top的功能,以显示特定用户,如下所示:

  1. # top -u <username>
复制代码

正如你所注意到的,top 会自动刷新;因此,在做出任何决定之前,尝试观察它几分钟。为了帮助这个过程,你可以要求 top 在 10 次循环后退出,如下所示:

  1. # top -n 10
复制代码

使用 top 时,你应该始终注意某些进程是由 child-processes(子进程)生成的,这些进程往往会单独显示(httpd 和 php-fpm 是这方面的典型例子),你可以预期这些服务会消耗最多的内存。

尽管可以看到一系列子进程使用了大量的内存,但你应该避免将 %MEM 列的数值相加,因为这些进程通常使用共享内存。因此,在很多情况下,你应该注意到所显示的值可能会具有误导性,出于这个原因,top 提供的结果不应作为你在做出最终决定之前唯一的依据。

你可以通过查看手册来了解更多关于 top 命令的信息,如下所示:

  1. $ man top
复制代码

使用 iotop 监控磁盘 I/O

每个管理员都知道,系统可能因为磁盘 I/O 活动过于繁重而开始变慢。然而,作为故障排除人员,你可能希望知道是哪些进程或(在多用户系统中)哪些用户是罪魁祸首,正因如此,你会想要使用 iotop——一个实时显示最消耗 I/O 的进程列表的工具,它以类似 top 的界面呈现。

首先,你需要通过输入以下命令来安装 iotop:

  1. # yum install iotop
复制代码

下载非常小,要开始一个发现会话,只需使用以下命令:

  1. # iotop
复制代码

运行没有任何参数的 iotop 会列出所有现有的进程,无论它们是否有磁盘 I/O 活动,因此,如果你只希望 iotop 报告那些有磁盘 I/O 活动的进程,你应该改用以下命令:

  1. # iotop –o
复制代码

输出非常详细,因为它的工作方式类似于 top 命令,所以熟悉后你会感到得心应手。然而,与 top 不同,iotop 显示了所有进程和线程的列表,以及磁盘活动的测量(总磁盘读取和实际磁盘读取),以便你可以快速识别哪些进程正在影响服务器上的当前 I/O 活动。

你可以通过查看手册了解更多关于 iotop 的信息,如下所示:

  1. $ man iotop
复制代码

使用 ps 命令检查进程

对于大多数希望更全面了解其系统中运行的进程的故障排除人员,我们可以使用 ps 命令,如下所示:

  1. # ps aux | less
复制代码

另外,信息可以以用户友好的树状视图模式显示,如下所示:

  1. # ps axjf | less
复制代码

如果你希望获得更少的细节,可以尝试:

  1. # ps auxf | less
复制代码

当然,我们可以在ps命令中使用更多的选项。例如,命令可以通过管道传输并与grep或tail结合使用,你还可以使用诸如ps -e这样的显式语句(显示系统中的所有进程)。或者,你也可以通过输入以下命令来定位特定进程:

  1. # ps aux | grep <process_name>
复制代码

此外,你甚至可以扩展其用法,显示所有进程(除了以 root 身份运行的进程),通过以下变化:

  1. # ps -U root -u root -N
复制代码

对于特定用户,你可以使用:

  1. # ps -u <username> u
复制代码

最后,你可以获得更多的安全信息,并将结果输出到文本文件中,方式如下:

  1. # ps axZ > /path/to/filename.txt
复制代码

基于这一点,我想你会同意说ps不仅有用,而且它的灵活性和可定制性使其成为故障排除工具箱中一个重要的工具。ps命令可以用于显示系统当前进程的快照,但对于本章来说,我们更关心的是ps命令还能为我们提供相关的进程 ID。通常简化称为PID,这个关键信息将在我们稍作岔开后重新提到,我们将深入了解系统负载。

使用 iostat 和 lsof 检查性能

在已经发现vmstat可以用于提供与内存管理相关的统计信息后,解决与性能相关的问题时,过载的 CPU 是另一个需要关注的领域。为此,我们可以像下面这样使用iostat命令:

  1. # iostat
复制代码

然而,要显示更互动的 CPU 利用率报告,你可以使用–c选项(并提供一个以秒为单位的数值,如 5 秒),像这样:

  1. # iostat –c 5
复制代码

大多数列应该是自解释的,但如果系统变得繁忙,你会看到%iowait的增加,这用于报告任何 I/O 请求完成等待时间的增加。基于此,如果服务器正在传输或复制大量文件,你可能还会注意到额外的时间花费在系统级别,因为文件将被移动进出相关的磁盘分区。在尝试监控存储设备以寻找可能的瓶颈时,iostat与数值参数结合使用是特别有用的,如下所示:

  1. # iostat 5
复制代码

正如你所看到的,要检查读/写操作,我们只是简单地为iostat添加了一个轮询选项。当然,你可以将这些知识与运行vmstat –d或vmstat –p 命令获得的见解结合使用,但通过使用–t选项,你还可以为该命令添加时间戳,像这样:

  1. # iostat –t 5
复制代码

你应该知道iostat报告会持续运行,直到该进程被取消。然而,通过这些观察,现在使用top和其他所有命令应该会让你感到更加满意。使用以下命令的技巧特别受欢迎,因为你可以通过lsof命令查看打开的文件列表:

  1. # lsof | less
复制代码

注意

使用 lsof 时,重要的是要注意,第一列将显示使用相关文件的命令、该命令的进程 ID(PID)、用户以及打开的文件名。

因此,考虑到这一点,并意识到本章中讨论的每个命令都是相互关联的,我们回到系统负载这一重要话题。

计算系统负载

系统负载是衡量计算机系统当前正在执行的处理量的指标。它不是衡量计算机性能的完美方式,但它确实为故障排除人员提供了修复系统所需的附加证据。

与负载计算最常相关的表达式是:

实际负载 = 总负载(运行时间)/ CPU 数量

如你所知,CPU 数量已知,你可以通过查看 top 命令的结果或输入以下命令来计算运行时间:

  1. # uptime
复制代码

前述命令的输出可能如下所示:

  1. 09:59:41 up 2:36, 1 user, load average: 0.01, 0.02, 0.05
复制代码

服务器负载是基于 1 分钟、5 分钟和 15 分钟的读取时间表示的数值。因此,通过查看前述输出中的最后三个值,我们可以看到,对于该系统,平均负载为 0.01(1 分钟时),0.02(5 分钟时)和 0.05(15 分钟时)。

当前,示例系统没有出现疲劳的迹象,但由于高负载的原因可能各异,这并不意味着该机器的当前状态在工作日内不会发生变化。高负载可能是数据库连接、磁盘输入输出、编码不良、网站访问频率、电力消耗大的应用程序或电子商务网站、脚本攻击、垃圾邮件、批处理作业等原因引起的。如果你遇到这种情况,只需运行 top 命令,并按常规方式开始排查系统。大多数情况下,可以找到短期解决方案(尤其是在网站在高峰时段接收到大量访问时),但只有长期计划才能防止这种情况再次发生。

在故障排查负载时,重要的是要知道,当负载增加时,处理器会排队,如果有多个处理器,负载会均匀分布到服务器的各个核心上以平衡工作负载。通常认为,服务器的理想负载值应设置为 1\。这并不意味着一旦达到或超过此值就需要立即按下“紧急按钮”,但如果你在一段时间内开始看到双位数的响应,那么是的,期望服务器(负载值 > 1)可能会在工作负载(负载值 > 10)的压力下开始出现问题。

因此,考虑到这一点,我们回到进程 ID 的话题。

使用 pgrep 和 systemctl 查找进程 ID

与其使用 ps,另一种查找特定进程 ID 的方法是使用 pgrep 命令,如下所示:

  1. # pgrep <servicename>
复制代码

在大多数情况下,使用此命令将显示进程 ID 或PID。但是,采用这种方法时,输出也可能提供多个值。所以请记住,如果某个应用程序(如httpd或ssh)提供了一个或多个进程 ID,你可以安全地假设最小的数字(代表系统生成的第一个PID)是最重要的。这个值被称为PPID或父进程 ID。

另一方面,一种更简洁的方法可以通过利用systemd,使用以下命令:

  1. # systemctl status <service_name>.service
复制代码

前述命令的输出将类似于以下示例,正如我们所见,Apache 的主PID是2413:

  1. httpd.service - The Apache HTTP Server
  2. Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled)
  3. Active: active (running) since Sun 2014-12-14 01:26:37 GMT; 2min 56s ago
  4. Main PID: 2413 (httpd)
  5. Status: "Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec"
  6. CGroup: /system.slice/httpd.service
  7. ├─2413 /usr/sbin/httpd -DFOREGROUND
  8. ├─2414 /usr/sbin/httpd -DFOREGROUND
  9. ├─2415 /usr/sbin/httpd -DFOREGROUND
  10. ├─2416 /usr/sbin/httpd -DFOREGROUND
  11. ├─2417 /usr/sbin/httpd -DFOREGROUND
  12. └─2418 /usr/sbin/httpd -DFOREGROUND
复制代码

Linux 注重选项,没错,有许多方法可以获取所需的进程 ID(PID)或父进程 ID(PPID),但我们不会遍历所有选项(包括旧的和新的)。单就速度而言,我想你会同意,利用systemd命令有其自身的优势。

更多关于 systemd 的信息

systemd系统和服务管理器负责控制 CentOS 7 上如何管理服务。现在的情况发生了很大变化,结果是,你需要认识到,脚本的位置已经更改为/usr/lib/systemd/systemd,而旧的命令将被弃用到一定程度(最终)它们将被彻底移除。

例如,当使用systemd检查状态或启动或停止服务时,你可以使用以下命令之一:

  1. # systemctl status <service_name>.service
  2. # systemctl stop <service_name>.service
  3. # systemctl start <service_name>.service
复制代码

此外,与其使用chkconfig来启用和禁用引导序列中的服务,现在你应该使用:

  1. # systemctl enable <service_name>.service
  2. # systemctl disable <service_name>.service
复制代码

你可能对这种方法持有不同意见,但与其纠结于变化的主题,不如考虑如何利用新命令让故障排除变得更加轻松。为此,我们将从一个简单的方法开始:列出当前所有服务,使用以下命令:

  1. # systemctl list-units --type service
复制代码

现在,一切都被称为单元,认识到这一点后,相同的命令还可以修改为显示所有挂载:

  1. # systemctl list-units --type mount
复制代码

与此同时,调用以下命令可以列出所有服务的依赖项:

  1. # systemctl list-dependencies <service_name>.service
复制代码

此外,systemd还自带了自己的top版本,若要查看与特定服务相关的进程,可以使用system-cgtop命令,如下所示:

  1. # systemd-cgtop
复制代码

正如你会注意到的,这个命令提供了所有相关进程的总结,并显示了路径、任务数量、CPU 使用百分比、内存分配以及相对的输入和输出。它的工作方式类似于top,但不同的是,它的使用可以修改为输出递归的服务内容列表,如下所示:

  1. # systemd-cgls
复制代码

输出将类似于以下内容:

  1. ├─smb.service
  2. │ ├─2472 /usr/sbin/smbd
  3. │ └─2473 /usr/sbin/smbd
  4. ├─httpd.service
  5. │ ├─2394 /usr/sbin/httpd -DFOREGROUND
  6. │ ├─2395 /usr/sbin/httpd -DFOREGROUND
  7. │ ├─2396 /usr/sbin/httpd -DFOREGROUND
  8. │ ├─2397 /usr/sbin/httpd -DFOREGROUND
  9. │ ├─2398 /usr/sbin/httpd -DFOREGROUND
  10. │ └─2399 /usr/sbin/httpd -DFOREGROUND
  11. ├─polkit.service
  12. │ └─875 /usr/lib/polkit-1/polkitd --no-debug
  13. ├─auditd.service
  14. │ └─672 /sbin/auditd -n
复制代码

所以,正如我们所看到的,在许多方面,systemd虽然冗长,但它确实在试图获取有关活动进程的某些信息时节省了我们的时间。在这个阶段,重要的是要意识到,我们只触及了systemd的皮毛,但就本章的目的而言,我相信你继续使用它的过程将会既富有成效又愉快。

发出终止信号

想要了解进程 ID 的最常见原因是将这些信息传递给kill命令。进程 ID 确实有其他用途,但我们的主要关注点是通过发出终止信号(SIGTERM)来移除有问题的服务或应用程序,如下所示:

  1. # kill pid_of_process
复制代码

kill信号指示进程终止,从而使相关进程能够执行一些基本的清理操作,并以有序的方式退出。这种方法被称为“安全终止”。然而,根据你的具体情况,更好的解决方案可能是强制让服务或应用程序挂起,从而启用守护进程的自动重新加载,如下所示:

  1. # kill -1 pid_of_process
复制代码

这个命令被称为SIGHUP或挂起命令。另一方面,如果进程似乎崩溃了,并且安全终止或重新加载操作无法产生任何效果,那么通过传递以下命令,你将能够直接终止该进程:

  1. # kill -9 pid_of_process
复制代码

在此命令中使用选项9表示发出一个信号终止(SIGKILL),与原始的终止命令(SIGTERM)不同,这个替代版本直接发给内核,从而以更为突然的方式终止进程。此命令没有清理操作或安全退出,因此它被称为“强制终止”。

最后,为了进一步解决“强制终止”问题,使用pkill命令也是完全合适的,语法如下:

  1. # pkill -9 httpd
复制代码

另外,你可以使用pgrep命令确保所有与相关搜索词相关的进程被移除:

  1. # pgrep httpd
复制代码

所以,涵盖了kill命令的最常见用法后,剩下的技巧之一是基于需要处理孤儿进程。

处理孤儿进程

孤儿进程并不是常见的问题,但它们确实会发生,解决这些问题的第一步是通过匹配显示的PID或PPID与init进程本身使用的 ID。使用ps命令可以显示,二者的PPID都等于1。说实话,你可能会意识到孤儿进程和守护进程之间几乎没有区别,唯一的区别是孤儿进程是由于错误产生的。因此,这里的黄金法则是记住,通过一个相对简单的技巧可以识别孤儿进程,并且它可以通过标准方式终止。

孤儿进程可能由多种原因引起,尽管它们已经被 init 进程采纳,你仍然会发现它们在执行命令。因此,孤儿进程是潜在的危险,因为它们会继续占用系统资源,导致系统资源短缺。在某些情况下,过多的孤儿进程可能会导致 init 进程过载,并造成系统挂起。虽然这种情况不常见,但删除这些错误的守护进程对于故障排除人员来说是一个重要任务,如果你的系统容易发生这种情况,那么你应该时刻关注它。

总结

本章的目的是阐明一些关于故障排除活动进程的概念,在这方面,我们已经涵盖了 swap、vmstat、top、ps、进程 ID、kill 和 pkill 等内容。当然,除了这些工具,你还可以使用更多其他工具,但对于大多数故障排除人员(无论是初学者还是有经验的),了解如何监控和测量内存使用情况;确定服务器负载;关注耗电的应用程序、服务或用户;删除孤儿进程;以及使用 systemd,这将对你大有帮助,之后我们可以继续考虑如何故障排除网络问题。

参考资料

  • Red Hat Enterprise Linux 7 系统管理员指南: access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/chap-Managing_Services_with_systemd.html

  • Swappiness 维基百科页面: en.wikipedia.org/wiki/Swappiness

  • vmstat 命令维基百科页面: en.wikipedia.org/wiki/Vmstat

  • iostat 命令维基百科页面: en.wikipedia.org/wiki/Iostat

  • lsof 命令维基百科页面: en.wikipedia.org/wiki/Lsof

  • kill 命令维基百科页面: en.wikipedia.org/wiki/Kill_(command)

  • pkill 命令维基百科页面: en.wikipedia.org/wiki/Pkill

  • SysVinit 到 Systemd 备忘单: fedoraproject.org/wiki/SysVinit_to_Systemd_Cheatsheet

  • 孤儿进程维基百科页面: en.wikipedia.org/wiki/Orphan_process

第三章:网络环境故障排除

从幽灵连接到数据包错误,从流失败到连接错误,再到缺少路由,故障排除网络环境可能是一个缓慢且艰难的过程,通常从物理层开始。然而,一旦你确认物理节点正常工作,下一步就是考虑和查阅你系统中可用的各种工具。

在本章中,我们将:

  • 了解一些基本工具,这些工具将帮助你排查与网络环境相关的各种问题。本讨论将涵盖 ping、dig、host、traceroute 和 mtr 的详细使用。

  • 了解如何使用 ss 命令监控网络连接。

  • 学习如何使用 tcpdump 检查数据包传输。

使用 ping、dig、host、traceroute 和 mtr

故障排除员最常用的一些工具有 ping、dig、host、traceroute 和 mtr。将这些工具一起使用,可以为故障排除员提供做出判断所需的证据,几乎可以解决任何网络相关的问题。这是网络工具包的基础,但需要强调的是,这些命令用于不同的目的,因此我们将分别介绍它们。

ping 命令

ping 命令是一个小型工具,可以用来确定是否可以访问特定的 IP 地址。ping 命令在大多数计算机系统中都是常见的,它允许你查询 IP 地址或完全限定的域名,以检查是否有可用的连接。

ping 命令的基本语法如下:

  1. # ping <ip_address>
  2. # ping <domain_name>
复制代码

ping 命令通过向指定的目标发出 ICMP 回显请求来验证和检查网络连接,正是这一简单的命令使其成为诊断任何基于网络的连接问题时非常有用的工具。

例如,如果你向 Google 发出 ping 请求(# ping google.com),那么根据你的网络环境和条件,输出将类似于以下内容:

  1. PING google.com (216.58.210.14) 56(84) bytes of data.
  2. 64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=1 ttl=55 time=10.5 ms
  3. 64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=2 ttl=55 time=10.9 ms
  4. 64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=3 ttl=55 time=36.2 ms
  5. 64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=4 ttl=55 time=11.0 ms
  6. 64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=5 ttl=55 time=10.1 ms
  7. 64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=6 ttl=55 time=32.0 ms
  8. 64 bytes from lhr08s06-in-f14.1e100.net (216.58.210.14): icmp_seq=7 ttl=55 time=10.6 ms
复制代码

这些结果展示了一个成功的 ping,可以描述为一个本地计算机系统向 google.com (216.58.210.14) 发出的回显请求的旅程。

请求从主机计算机发起,然后通过本地网络传送,最后经过互联网。一旦请求成功接收,目标将进行响应,并且测量完成此过程所需的时间,以生成平均响应或延迟时间。但是,如果没有响应,则很可能是网络本身存在物理问题,或者是一些基本问题,如位置不正确或不可用,目标计算机未响应 ping 请求,或者主机路由表错误。

注意

在在线游戏中,ping 请求(也称为“高 ping”或“低 ping”)通常与从本地机器到外部游戏服务器的速度测量相关。例如,一个低 ping(例如 10 毫秒)的玩家会比一个 180 毫秒 ping 的玩家拥有更好的游戏体验。

此外,你还应该意识到,如果你的 ping 值超过 500 毫秒,则意味着任何请求需要超过半秒才能到达服务器并返回。这个条件很明显,因为你可能会经历“帧抖动”或“帧跳跃”——在在线游戏中被称为“橡皮带现象”。

ping 命令很简单易用,但在其默认形式下,它会一直执行,直到被取消。在某些情况下,这可能会很有用,但通常更容易使用 -c 选项,以减少回显请求的次数,并获取事件的总结。

例如,如果你想将回显请求的数量限制为 4 次,你需要输入以下命令:

  1. # ping -c 4 google.com
复制代码

在前面的例子中,ping 命令将在 4 次循环后停止发出回显请求,基于我们之前的例子,输出会类似于此:

  1. PING google.com (216.58.208.78) 56(84) bytes of data.
  2. 64 bytes from lhr14s27-in-f14.1e100.net (216.58.208.78): icmp_seq=1 ttl=55 time=11.9 ms
  3. 64 bytes from lhr14s27-in-f14.1e100.net (216.58.208.78): icmp_seq=2 ttl=55 time=16.7 ms
  4. 64 bytes from lhr14s27-in-f14.1e100.net (216.58.208.78): icmp_seq=3 ttl=55 time=35.4 ms
  5. 64 bytes from lhr14s27-in-f14.1e100.net (216.58.208.78): icmp_seq=4 ttl=55 time=15.1 ms
  6. --- google.com ping statistics ---
  7. 4 packets transmitted, 4 received, 0% packet loss, time 3005ms
  8. rtt min/avg/max/mdev = 11.985/19.827/35.462/9.187 ms
复制代码

在我们结束对 ping 命令的介绍之前,有几点关于任何 ping 请求需要考虑的事项。这些点可能不一定表示问题,但它们会影响 ping 测试的结果:

  • 与目标的距离:假设你住在美国,并尝试连接到欧洲的服务器。在这种情况下,你应该预期 ping 值会高于你尝试连接的另一台距离你更近的美国服务器。此外,你还应该预期,不同地理位置之间的速度可能会有所不同。

  • 互联网连接速度:如果你的网络带宽较低(即上传和下载速度差),则 ping 请求的响应时间会比高速带宽的宽带连接(即上传和下载速度较好)更长。

  • 跳数:跳数是一个通用术语,指的是 ping 请求必须经过的路线和服务器,以便到达目标并返回。因此,就像在现实生活中一样,如果你住得离主要火车线路较远,你就需要做更多的“连接”或“跳跃”,才能到达最终目的地。

基本原则始终表明,低 ping 始终是可取的,因为它对基于时间的指令至关重要。然而,在进行 ping 测试时,你不仅要考虑实际到达目标站点的 ping 总数,还要仔细记录相关 ping 的平均值和标准差。

从这个角度看:如果 ping 请求没有到达,这可能表明由于你计算机和目标之间的互联网连接不稳定,可能会出现数据包丢失的情况。然而,如果 ping 率较低,但在特定时间段内显示出一个逐渐增大的变化率,那么在某些情况下,这种环境并不总是比同一时间段内的恒定速率更可取。

dig和host命令

dig命令可以用来验证 DNS 映射、互联网连接、主机地址和 MX 记录,并且可以帮助发现与潜在的反向 DNS 问题相关的信息,这些问题可能导致垃圾邮件和被列入黑名单。通过bind-utils包提供的dig命令,返回的信息分为四个主要部分,包括:头部部分(使用的选项列表)、问题部分(查询类型)、答案部分(相关位置的地址)、查询部分(包含关于查询时间、名称服务器等的统计信息)。dig命令是为了替代nslookup而推出的,基本语法如下:

  1. # dig google.com
复制代码

结果将如下所示:

  1. ; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.1 <<>> google.com
  2. ;; global options: +cmd
  3. ;; Got answer:
  4. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18657
  5. ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  6. ;; OPT PSEUDOSECTION:
  7. ; EDNS: version: 0, flags:; udp: 512
  8. ;; QUESTION SECTION:
  9. ;google.com. IN A
  10. ;; ANSWER SECTION:
  11. google.com. 299 IN A 216.58.210.78
  12. ;; Query time: 100 msec

  13. ;; SERVER: 8.8.8.8#53(8.8.8.8)
  14. ;; WHEN: Sat Apr 25 13:45:02 EDT 2015
  15. ;; MSG SIZE rcvd: 55
复制代码

你会注意到,这种输出中包含了大量信息,因此让我们从全局选项部分开始逐步解析:

  1. ; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.1 <<>> google.com
  2. ;; global options: +cmd
复制代码

然后是一个输出,报告查询的答案:

  1. ;; Got answer:
  2. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18657
  3. ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  4. ;; OPT PSEUDOSECTION:
  5. ; EDNS: version: 0, flags:; udp: 512
复制代码

紧接着,dig会重复原始问题:

  1. ;; QUESTION SECTION:
  2. ;google.com. IN A
复制代码

答案如下所示:

  1. ;; ANSWER SECTION:
  2. google.com. 299 IN A 216.58.210.78
复制代码

最后,我们将看到一些关于查询本身的一般统计数据:

  1. ;; Query time: 100 msec
  2. ;; SERVER: 8.8.8.8#53(8.8.8.8)
  3. ;; WHEN: Sat Apr 25 13:45:02 EDT 2015
  4. ;; MSG SIZE rcvd: 55
复制代码

同样,通过将XXX.XXX.XXX.XXX替换为相关的 IP 地址,你可以像这样查询特定的名称服务器:

  1. # dig google.com @XXX.XXX.XXX.XXX
复制代码

所以,如果你运行以下命令:

  1. # dig google.com @8.8.8.8
复制代码

你可以期望看到以下结果:

  1. ; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.1 <<>> google.com @8.8.8.8
  2. ;; global options: +cmd
  3. ;; Got answer:
  4. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5496
  5. ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  6. ;; OPT PSEUDOSECTION:
  7. ; EDNS: version: 0, flags:; udp: 512
  8. ;; QUESTION SECTION:
  9. ;google.com. IN A
  10. ;; ANSWER SECTION:
  11. google.com. 299 IN A 216.58.210.78
  12. ;; Query time: 92 msec
  13. ;; SERVER: 8.8.8.8#53(8.8.8.8)
  14. ;; WHEN: Sat Apr 25 13:46:54 EDT 2015
  15. ;; MSG SIZE rcvd: 55
复制代码

此外,dig命令的默认操作是查找A记录,你可以通过调整dig语法来获取基于特定记录类型的信息,方法如下:

  1. # dig google.com MX
  2. # dig google.com TXT
  3. # dig google.com NS
  4. # dig google.com SOA
复制代码

作为替代方法,并为了使结果更具普适性,你可以通过输入ANY查询来尽可能多地获取信息:

  1. # dig google.com ANY
复制代码

此外,dig命令还可以用来执行反向查找,以根据特定的 IP 地址获取相关的 DNS 信息。

这可以通过输入以下命令来实现:

  1. # dig -x 8.8.8.8
复制代码

前述命令随后会以以下方式响应:

  1. ; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.1 <<>> -x 8.8.8.8
  2. ;; global options: +cmd
  3. ;; Got answer:
  4. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34651
  5. ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  6. ;; OPT PSEUDOSECTION:
  7. ; EDNS: version: 0, flags:; udp: 512
  8. ;; QUESTION SECTION:
  9. ;8.8.8.8.in-addr.arpa. IN PTR
  10. ;; ANSWER SECTION:
  11. 8.8.8.8.in-addr.arpa. 21599 IN PTR google-public-dns-a.google.com.
  12. ;; Query time: 35 msec
  13. ;; SERVER: 8.8.8.8#53(8.8.8.8)
  14. ;; WHEN: Sat Apr 25 13:49:13 EDT 2015
  15. ;; MSG SIZE rcvd: 93
复制代码

如你所见,dig是一个灵活的命令行工具,它可以让你执行有效的 DNS 查询。它的输出非常详细,但可以通过+short开关来简化并提供一个简洁的答案,像这样:

  1. # dig -x 209.132.183.81 +short
复制代码

上述命令应该以以下方式响应:

  1. www.redhat.com.
复制代码

dig命令是一个极其有用的网络故障排除工具,它的成功主要归功于它能够返回问题、答案、权威和附加部分的能力。

然而,话虽如此,另一种选择是使用host命令,方法如下:

  1. # host –a google.com
复制代码

host 命令的工作方式与 dig 命令类似,但其输出如下所示:

  1. Trying "google.com"
  2. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60735
  3. ;; flags: qr rd ra; QUERY: 1, ANSWER: 14, AUTHORITY: 0, ADDITIONAL: 0
  4. ;; QUESTION SECTION:
  5. ;google.com. IN ANY
  6. ;; ANSWER SECTION:
  7. google.com. 299 IN A 216.58.210.78
  8. google.com. 299 IN AAAA 2a00:1450:4009:801::200e
  9. google.com. 21599 IN NS ns3.google.com.
  10. google.com. 21599 IN TYPE257 \# 19 0005697373756573796D616E7465632E636F6D
  11. google.com. 599 IN MX 20 alt1.aspmx.l.google.com.
  12. google.com. 21599 IN NS ns4.google.com.
  13. google.com. 21599 IN SOA ns1.google.com. dns-admin.google.com. 2015041501 7200 1800 1209600 300
  14. google.com. 3599 IN TXT "v=spf1 include:_spf.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all"
  15. google.com. 599 IN MX 40 alt3.aspmx.l.google.com.
  16. google.com. 21599 IN NS ns1.google.com.
  17. google.com. 599 IN MX 30 alt2.aspmx.l.google.com.
  18. google.com. 599 IN MX 50 alt4.aspmx.l.google.com.
  19. google.com. 21599 IN NS ns2.google.com.
  20. google.com. 599 IN MX 10 aspmx.l.google.com.
复制代码

如你所见,host 命令与 dig 的作用类似,但它更加简洁。

例如,一个基本的 host 查询如下所示:

  1. # host www.google.com
复制代码

返回的输出将如下所示:

  1. www.google.com has address 216.58.210.68
  2. www.google.com has IPv6 address 2a00:1450:4009:801::2004
复制代码

另外,你也可以通过以下方式指定第三方 DNS 服务器:

  1. # host www.redhat.com 8.8.8.8
复制代码

这将报告使用替代 DNS 服务器的情况,并显示如下内容:

  1. Using domain server:
  2. Name: 8.8.8.8
  3. Address: 8.8.8.8#53
  4. Aliases:
  5. www.redhat.com is an alias for wildcard.redhat.com.edgekey.net.
  6. wildcard.redhat.com.edgekey.net is an alias for wildcard.redhat.com.edgekey.net.globalredir.akadns.net.
  7. wildcard.redhat.com.edgekey.net.globalredir.akadns.net is an alias for e1890.b.akamaiedge.net.
  8. e1890.b.akamaiedge.net has address 23.195.127.72
复制代码

最后,host 可以执行反向查找,如下所示:

  1. # host XXX.XXX.XXX.XXX
复制代码

所以,假设你对 Red Hat 的 Akamai Edge 服务器进行反向查找,使用以下命令:

  1. # host 23.195.127.72
复制代码

输出将如下所示:

  1. 72.127.195.23.in-addr.arpa domain name pointer a23-195-127-72.deploy.static.akamaitechnologies.com.
复制代码

那么从这个角度来看:为了故障排除网络,你可以使用 dig 或 host。这两个命令在用途和功能上是相似的,但 host 提供了简单性,而 dig 则提供了更高级的、适合脚本使用的选项。

traceroute 命令

traceroute 命令旨在显示到远程目的地的路径,以及每个停靠点发生的延迟。大多数管理员都熟悉 traceroute,它有三个主要目标,可以总结如下:

  • 提供数据包将要经过的整个路径的详细信息

  • 提供路径上找到的设备和路由器的名称及其身份

  • 报告网络延迟的情况,评估在给定路径上向每个设备发送和接收数据所花费的时间

简单来说,traceroute 命令是一个工具,用于验证数据将要经过的路径,而不会使用任何数据,所使用的语法基于以下内容:

  1. # traceroute google.com
复制代码

输出将提供指定的主机、该域的 IP 地址、所需的最大跳数以及将使用的包大小。随后的行将报告跳数、主机名、IP 地址和数据包的往返时间。你当然也可以使用 -n 选项以以下方式避免反向 DNS:

  1. # traceroute -n google.com
复制代码

traceroute 命令每次发送三个包,带有每个 TTL,并将显示往返时间 (RTT),这表示从发出探测到接收到响应包之间的时间差。这对于发现网络瓶颈非常有用,如果你开始看到星号(*),则表明路由到该主机可能存在问题,因为星号可能表示数据包丢失或丢弃数据包。然而,也需要认识到,解释 traceroute 结果需要理解并接受它固有的特点。

traceroute命令被认为是 TCP/IP 故障排除的基石。它开始时会发出一个基于 UDP 的数据包,TTL 值为 1。如果数据包到达目标,网关会发送响应包并报告其结果。然而,如果数据包没有到达目标,那么接收网关会将 TTL 值减少 1。如果 TTL 值为 0,则网关会丢弃数据包,并在发出一个增加了 TTL 值的新数据包后报告结果,以绕过下一个阶段的同一网关。这个过程会一直重复,直到到达目标主机或达到最大 TTL 值为止。

有三种不同类型的traceroute实现,分别涵盖 UDP、TCP 和 ICMP。

例如,如果你想使用 ICMP 变种,你可以输入:

  1. # traceroute –I google.com
复制代码

同样,你可以像这样使用–n选项绕过 DNS:

  1. # traceroute -I -n 8.8.8.8
复制代码

这种变种的工作方式与之前使用 UDP 的示例类似,traceroute程序将发送回显请求,途中经过的每一跳都会做出回应。然而,与 UDP 版本不同的是,这个过程将使用 ICMP。

最终的方法是使用以下方式的 TCP 变种:

  1. # traceroute -T google.com
复制代码

在许多方面,TCP 选项可能是最有效的方法,因为大多数网络都会允许这种流量。如果你的目标是 80 端口,尤其如此。然而,没有硬性规定来确定你可以或想要使用哪种版本的traceroute。这些规则将由网络配置设定,因为某些网络默认会阻止 UDP 请求(通常是 33434 到 33534 端口)。所以,基于这一点,为什么不尝试所有版本,看看哪个最适合你的环境呢?

让我们这样来看:了解traceroute的工作原理仅仅是赢得了半场胜利。如果traceroute可以到达主机,但无法到达目标,那么问题很可能出在目标上。然而,如果traceroute无法到达主机,那么问题可能出在路由本身,这不仅涉及到一些路由器拒绝traceroute数据包,还有其他一些路由器在带宽和延迟上表现出显著的差异、防火墙,以及过滤traceroute数据包的其他各种陷阱。在这种情况下,应选择多个目标(你还应该考虑使用 UDP、ICMP 和 TCP 发送请求,以绕过任何网络问题),并且考虑到互联网本质上是非对称的,通常最好在两个方向上执行traceroute操作,以便评估整体网络效率。

总的来说,traceroute是一个很好的工具,但它可能会误导你,因此在分析结果时要小心,并始终用额外的调查来补充你的工作。

mtr 命令

作为traceroute的替代方案,有mtr命令。在某些 Linux 系统上,你需要以 root 用户身份运行此命令,或者与sudo一起使用,但无论你使用哪种方法,该命令的语法非常简单,并按如下方式工作:

  1. # mtr google.com
复制代码

输出可能类似于traceroute,但显示是实时的,从而使你能够监控趋势和平均值,反映网络性能随时间的变化。因此,与traceroute不同,mtr通过收集更长时间的数据,不仅能简单地拍摄一次旅程的快照,还能检查间歇性的数据包问题。此外,作为实时更新的替代方案,mtr还将提供一个报告选项,向每个遇到的跳点发出 10 个数据包的结果:

  1. # mtr --report google.com
复制代码

所以,经过反思,可以认为mtr在监控网络连接方面优于traceroute。它确实有许多优点,并且可以提供大量细节,但考虑到你无法控制外部网络的工作方式,经验丰富的故障排除人员应始终保持警觉,并选择检查所有可用的工具。

使用ss命令监控网络连接

套接字统计命令(ss)是netstat的继任者;它不仅更快,而且能够显示更多的信息。然而,与通过/proc目录中的各种文件获取信息的netstat不同,ss命令直接从内核空间获取信息。

ss命令的基本语法如下:

  1. # ss | less
复制代码

使用这种语法,我们只是调用了所有 TCP、UDP 和 Unix 套接字连接的输出,并可选择通过管道将其发送到less,以确保结果可以在屏幕上查看。当然,您可以将此命令与-t、-u或-x选项结合使用,以限制输出仅显示 TCP、UDP 或 Unix 套接字连接,但为了使输出更加信息丰富,你可能想要将这些附加选项与-a选项结合使用,以报告连接和监听套接字,如下所示:

  1. # ss -ta
复制代码

正如你所注意到的,在前面的例子中,我们只报告了当前的 TCP 环境,可以通过类似的方式将其更改为适用于 UDP(ss -ua)或 Unix 套接字连接(ss -xa)。然而,如果你喜欢一定程度的精确性,你会欣慰地知道,ss命令可以通过使用–A选项与查询结合使用,如下所示:

  1. # ss -a -A tcp
复制代码

限制输出确实能使信息更加简洁,但要进一步提升,可以使用以下语法应用附加的过滤器:

  1. # ss [ OPTIONS ] [ STATE-FILTER ] [ ADDRESS-FILTER ]
复制代码

例如,考虑到所有标准的 TCP 状态,你可以以下列方式显示所有已建立的 IPv4 TCP 套接字:

  1. # ss -t4 state established
复制代码

你可以像这样显示所有关闭的 TCP 状态:

  1. # ss -t4 state closed
复制代码

现在,可以说使用ss命令的效果与使用netstat -a类似。部分是正确的,但(记住你可以将-t替换为-u或-x)考虑到通过不解析主机名来提高执行速度(ss -nt),只显示监听套接字(ss -ltn),显示套接字内存使用情况(ss -t -m),显示使用特定套接字的进程(ss -t -p),打印进程名称(ss -ltp),显示 IPv4 或 IPv6(ss -tl4或ss -tl6),并显示时间信息(ss -tn -o),你会发现我们才刚刚触及ss命令的表面。

例如,你甚至可以运行查询,通过使用以下语法来发现谁在使用端口 22(SSH):

  1. # ss -lpn | grep 22
复制代码

另外,你可以使用以下语法来显示从远程 IP 地址连接的所有端口:

  1. # ss dst XXX.XXX.XXX.XXX
复制代码

然后使用以下变体将查询过滤到特定端口:

  1. # ss dst XXX.XXX.XXX.XXX:22
复制代码

记住,熟悉你的网络环境总是会有所帮助,掌握了这个命令后,你应该能在问题连接发生之前就能识别它们。

使用 tcpdump 进行数据包分析

tcpdump命令是一种数据包分析工具,它能够捕获并提供通过网络接口传输的流量描述。它是大多数 Linux 发行版的标准工具,提供了一个独特的网络数据包层级视图,在网络故障排除时非常有用。

使用tcpdump的基本语法如下:

  1. # tcpdump -i <device_name>
复制代码

你还可以像这样指定协议:

  1. # tcpdump -i <device_name> tcp
复制代码

端口值可以按以下方式使用:

  1. # tcpdump -i <device_name> port 22
复制代码

可以使用-v或-vv选项发出详细信息选项,而通过使用-n选项可以避免 DNS 解析。然而,由于tcpdump会一直运行,直到请求被取消,因此最好使用-c选项来捕获预定数量的事件,像这样:

  1. # tcpdump -c 10 -i <device_name>
复制代码

更进一步,你可以通过调用src选项(源)或dst选项(目的地)来从特定 IP 地址捕获10个数据包,像这样:

  1. # tcpdump -c 10 -i <device_name> src XXX.XXX.XXX.XXX
复制代码

设备名称本身可以通过运行以下选项获取:

  1. # tcpdump -D
复制代码

tcpdump命令可以在读取模式和写入模式下运行。然而,后者意味着使用-w选项,这会导致tcpdump将数据包数据保存到文件中以供后续分析,而前者,通过使用-r选项,意味着tcpdump只会从已保存的数据包文件中读取。如你所知,在写入模式下你应该指定相关的设备名称(即eth0),但在这两种情况下,只有匹配表达式的数据包才会被匹配并显示出来。

例如,在读取模式下,这个命令的基本语法如下:

  1. # tcpdump -r <file_name>
复制代码

在写入模式下,你可以以以下方式发送整个以太网帧进行进一步分析:

  1. # tcpdump -w /path/to/file -i <device_name>
复制代码

如你所见,tcpdump最常见的应用是验证双向通信是否正常。tcpdump命令可以用来记录网络片段,在认识到这一点后,我们仅仅触及了它灵活性的表面。

因此,我希望你能已经看到,当排查你的网络环境问题时,这个小工具可以成为一个重要的工具。

总结

本章的目的是提供一个起点,以便在尝试排查网络环境中的问题时使用。当然,学习的内容总是有更多,而了解这些将带你踏上远超dig、ping甚至tcpdump基本语法的旅程。然而,通过学习多个命令和工具,你现在可以看到,成为一个有效的故障排除者正变成一个可以实现的目标。为了进一步推动这一目标,我们将把注意力转向包管理的故障排除需求。

参考文献

  • TCP 的维基百科页面:en.wikipedia.org/wiki/Transmission_Control_Protocol

  • Ping 的维基百科页面:en.wikipedia.org/wiki/Ping_(networking_utility)

  • Traceroute 的维基百科页面:en.wikipedia.org/wiki/Traceroute

  • ss命令的官方页面:www.cyberciti.biz/files/ss.html

  • ARP 的维基百科页面:en.wikipedia.org/wiki/Address_Resolution_Protocol

  • dig命令的维基百科页面:en.wikipedia.org/wiki/Dig_(command)

  • tcpdump的维基百科页面:en.wikipedia.org/wiki/Tcpdump

第四章。解决包管理和系统升级问题

Yellowdog Updater, Modified (Yum) 已经存在一段时间了。它易于使用,并在安装或升级 CentOS 软件包时减少了依赖管理的复杂性。更常被称为 Yum,本章将假设您已经精通其基本用法(包括安装软件包、更新软件包、删除软件包和搜索软件包),因为我们的目的是通过接近包管理和系统升级的主题来继续本书的总体前提。

在本章中,我们将:

  • 学习如何使用 RPM 和 YUM 收集软件信息

  • 学习如何使用 Yum 插件使故障排除过程更轻松

  • 故障排除与包安装及更新相关的问题

  • 发现如何扩展系统并安装额外的 Yum 仓库

  • 学习如何使用 Yum 下载 RPM 软件包

  • 学习如何恢复 RPM 数据库

  • 讨论管理小系统升级的复杂性

收集软件信息

在开始解决 YUM 之前,我们将稍微偏离一下,把注意力转向收集必要的软件信息,以便更多地了解系统整体情况。

为此,我们将从运行以下命令开始:

  1. # cat /etc/redhat-release; lscpu | grep -i arch; yum repolist all; ls -alsh /etc/yum.repos.d;
复制代码

在这个阶段,我不会解释上面示例中显示的每个命令,但您会注意到输出内容冗长,并详细描述了 CentOS 的发布信息。显示的信息包括服务器的整体架构、域、时间和日期信息,以及 Yum 使用的仓库列表的范围、状态和权限。

到目前为止一切顺利,但是如果我需要了解服务器上已安装的基于 RPM 的软件包呢?与其浏览整个系列的配置文件(甚至是做一个有根据的猜测),为什么不简单地使用以下命令:

  1. # rpm -qa | sort | less
复制代码

如您所见,根据服务器上安装的内容,上述命令将输出大量(或者相对较少)基于 RPM 的软件包列表。如果这显得太详细,而您只是想快速了解安装历史,您可以输入以下命令来显示基于 RPM 的软件包总数:

  1. # rpm -qa | wc -l
复制代码

正如我们使用了wc命令,输出将被限制为表示所请求信息的数字值。对于您的确切需求来说,这可能过于简单或模糊,但它将为您提供关于所讨论的服务器当前使用情况的坚实基础(特别是如果此任务在特定时间段内重复执行)。

那么,为什么要止步于此?如果您感到更加好奇,那么您还可以通过输入以下命令来请求关于安装的 Yum 软件包的信息:

  1. # yum list installed | sort | less
复制代码

注意

在这个阶段,你可能会问,yum list installed 和之前提到的 rpm –qa 命令有什么区别?简单来说,前者是基于 Yum 的命令,它还会列出包依赖关系,因此你应该在输出中看到更多的细节。

再次说明,这个列表的内容可能会根据所涉及服务器的用途而有所不同,但对于那些喜欢良好管理的人来说,这个功能可以通过将输出打印到你选择的文件中来加以改进,命令如下:

  1. # yum list installed | sort > /path/to/filename.txt
复制代码

再次说明,在这个阶段并没有什么复杂的内容,但在我们完成这些初步步骤之前,需要意识到,我们刚刚揭开了一个以前未知的 CentOS 服务器的一些秘密。我们对系统的熟悉程度正在不断提高,随着我们活动的进行,你现在会对新环境感到更加舒适和自如。毕竟,当服务器宕机,其他人都在惊慌失措时,这里获得的信心将有助于你最终的成功。

使用 Yum 插件

Yum 是最广泛使用的包管理工具之一,但许多管理员并不知道它自带一个插件系统,可以用来扩展其功能。可以说,许多插件是默认安装的,但由于假设你对当前系统一无所知(这对于任何故障排除人员来说都是常见的情况),我们将从安装 yum-skip-broken 包开始。

那么,我们从输入以下命令开始:

  1. # yum install yum-skip-broken
复制代码

完成了这个步骤(并确认该套包现在已被系统识别),我们可以使用 --skip-broken 插件来处理任何想要更新或升级某个包,但由于报告依赖关系损坏而被拒绝的情况。

为此,可以使用以下命令的组合:

  1. # yum update --skip-broken && yum upgrade --skip-broken
复制代码

当然,你可以简化上述命令,以便符合自己的需求(例如将命令分成两行),但需要注意的是,这些情况下发生错误的原因通常与混合(不兼容的)第三方仓库有关。在这方面,为了实现长期解决方案,你需要减少使用的第三方仓库的数量。然而,在尝试这一操作之前,你应该回顾 Yum 过去的事务,以了解这会如何影响系统。

这可以通过输入以下命令来实现:

  1. # yum history
复制代码

上述命令现在将生成一个包含 Yum 所有历史操作的列表,从而提供一个非常有用的详细信息层级,当你尝试调试一个故障服务、修正包依赖或协助减少对第三方仓库的依赖时,这个信息会非常有用。此外,在这个命令生成的列表中,你还会注意到每个事务都有一个唯一的标识符。

唯一标识符可以用来获取有关特定事件的更多信息,输入以下命令:

  1. # yum history info <unique_identifier>
复制代码

或者,在不需要如此详细信息的情况下,你可以通过输入以下命令始终获得所有最近事件的摘要:

  1. # yum history summary
复制代码

话虽如此,既然我们谈论到了 Yum 插件,你还应该知道,changelog信息并不是直接可以通过 Yum 包管理器获得的。同样,这类信息可能很有用,但为了进一步了解,你需要通过输入以下命令安装changelog插件:

  1. # yum install yum-plugin-changelog
复制代码

完成此操作后,你就能够像这样查询 Yum 的changelog:

  1. # yum changelog all <package_name>
复制代码

由于此输出可能会让人感到有些不知所措,因此知道你可以通过简单地将all替换为表示要显示记录数量的数字值来限制显示的信息,这一点非常有帮助。所以,如果你想查看 Postfix 的5个最近更新,你可以输入:

  1. # yum changelog 5 postfix
复制代码

此外,安装了这个插件后,你可以通过输入以下命令来查看任何包安装之前的相关changelog信息:

  1. # yum update --changelog
复制代码

这是一个小巧但有趣的功能,可以通过输入以下命令来扩展显示所有最近的changelog信息:

  1. # yum changelog all recent
复制代码

或者,你可以通过输入以下命令查看所有过时的包:

  1. # yum changelog all obsoletes
复制代码

最后,在我们结束关于使用 Yum 插件的讨论之前,可能会有一种情况需要使用yum-utils,如果它当前没有在系统中安装,你可以通过输入以下命令来安装:

  1. # yum install yum-utils
复制代码

这一补充使得包管理变得更加轻松,考虑到需要解决的一系列问题,包括删除孤立包或重复包,以及包清理操作的执行。

例如,要删除孤立包,可以输入:

  1. # package-cleanup --orphans
复制代码

要删除重复项,可以使用:

  1. # package-cleanup --dupes
复制代码

为了方便删除旧内核,你可以输入:

  1. # package-cleanup --oldkernels
复制代码

参考上述示例,如果你的系统维护着多个旧的内核,可以通过运行命令rpm -q kernel来查询它们。正如你所看到的,这个简单的操作可以提供你所需的信息,从而决定是否可以释放磁盘空间。如果看到旧的内核,你可以按照常规方式将其删除。然而,我并不建议你非得这么做,我揭示这个功能的目的是证明yum-utils有许多有趣的功能,值得探索,因为它是 Yum 中一个被低估的方面,在故障排除包管理时能发挥重要作用。

修复 Yum 操作

现在,需要意识到的是,在许多情况下,Yum 出错的普遍原因可能与网络环境、磁盘空间、混合仓库或系统的 DNS 设置有关。然而,也有一些情况,常见的操作错误需要通过刷新 Yum 本身来解决,可以使用以下命令中的一个或多个:

要清除旧的包信息,您应使用:

  1. # yum clean headers
复制代码

要清除所有缓存的包,请使用以下命令:

  1. # yum clean packages
复制代码

要清除所有缓存的基于 XML 的数据,请使用以下命令:

  1. # yum clean metadata
复制代码

然而,如果您希望完全刷新 Yum 缓存(包括所有头信息、元数据、下载的包等),您可以随时使用以下命令完成此过程:

  1. # yum clean all
复制代码

安装额外的 Yum 仓库

安装额外的仓库不一定被视为故障排除任务,但它确实有助于缓解许多与包依赖性相关的问题,并尽量保持您的系统在 Dev/Ops 环境中具有相关性。

在接下来的文本中,我已包含一些最流行的仓库的安装说明。然而,您应该意识到,这些仓库的位置在 CentOS 的不同版本中会有所不同,并且这些链接会随着时间的推移而更新。更多信息可以在本章末尾找到,供日后参考。

EPEL

企业 Linux 附加软件包EPEL)仓库提供了官方 CentOS Linux 仓库中未包含的有用软件包,其中一些将在本书的后续章节中介绍。它也是许多其他第三方仓库的依赖项。

对于 CentOS 7,您应按照此过程安装 EPEL 仓库:

  1. # cd /root
  2. # wget https://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
  3. # yum install epel-release-7-5.noarch.rpm
复制代码

完成相关步骤后,只需确认是否继续安装,然后输入以下命令以确保其已启用:

  1. # yum repolist all
复制代码

EPEL 通常被认为是一个基础仓库,许多其他仓库也常常依赖它。鉴于我们希望保持系统的更新,我已包含了安装 Remi 和 IUS 仓库的程序。然而,带着强烈的警告,我建议只使用其中一个,以避免在同一系统上使用它们可能引发的冲突。

Remi

Remi 仓库依赖于 EPEL 仓库,并向 CentOS 核心 Linux 仓库提供软件的新版本;因此,安装了此仓库后,您可以预期在下次运行 yum update 时,CentOS 系统会进行多次更新。

对于 CentOS 7,您应按照此过程安装 Remi 仓库:

  1. # cd /root
  2. # wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
  3. # rpm -Uvh remi-release-7*.rpm
复制代码

默认情况下,Remi 仓库是禁用的;要启用它,我们需要更新配置文件并将其标记为活动状态。

要执行此操作,请在您喜欢的文本编辑器中打开以下文件:

  1. # nano /etc/yum.repos.d/remi.repo
复制代码

现在,改变:

  1. enabled = 0
复制代码

阅读:

  1. enabled = 1
复制代码

此外,如果您想使用 PHP 5.5 库,只需在同一文件 remi.repo 中取消注释 [remi-php55] 引用。完成后,保存并关闭文件,然后输入以下命令以确保其已启用:

  1. # yum repolist all
复制代码

IUS 仓库

作为 Remi 的替代方案,IUS 仓库也向核心 CentOS Linux 仓库提供更新的版本,但开发人员强调,IUS 通常使用不同的包名,以避免软件版本更新时可能出现的冲突。这个简单的包名方法在 CentOS 社区中得到了广泛支持,因为这种控制级别在关键任务环境中非常有用。IUS 仓库依赖于 EPEL 仓库,但再次强调,我建议不要将这个仓库与其他来源混合使用。

对于 CentOS 7,你应该按照以下步骤安装 IUS 仓库:

  1. # cd /root
  2. # wget http://dl.iuscommunity.org/pub/ius/stable/CentOS/7/x86_64/ius-release-1.0-13.ius.centos7.noarch.rpm
  3. # rpm -Uvh ius-release*.rpm
复制代码

此外,鉴于 IUS 仓库的工作方式独特,你应该知道有一个叫做 yum-plugin-replace 的包,它用于帮助从默认包升级到 IUS packageXY 风格的包。

再次,我在本章结尾提供了一个关于如何使用这个工具的链接(预计这些指令可能会随时间改变),但目前,你可以通过输入以下命令开始:

  1. # yum install yum-plugin-replace
复制代码

总体而言,无论你是使用 Remi 还是 IUS,请记住,黄金法则是不混合使用它们,但无论你选择哪个仓库,预期它们都会对你有帮助。

使用 Yum 下载 RPM 包

如果有需要下载一个包但不安装它的情况,可以通过 Yum 来实现。然而,在开始这个过程之前,你需要确保你的系统已经安装了以下工具:

  1. # yum install yum-plugin-downloadonly
复制代码

在大多数情况下,它可能已经被安装(因为它是之前提到的 yum-utils 包的一部分),但完成这个任务后(或者确认它已经存在),你可以通过自定义以下命令,将所需的包下载到你选择的目录:

  1. # yum install <package_name> --downloadonly --downloaddir=/path/to/folder
复制代码

例如,为了理解之前的命令,你可以通过输入以下命令,将 Samba 及其所有依赖项下载到用户目录中:

  1. # yum install samba --downloadonly --downloaddir=/home/username
复制代码

或者,你也可以调用以下变体,尽管这个版本的命令假设下载的文件会存储在你当前的目录:

  1. # yumdownloader <package_name>
复制代码

完成这一步后,接下来的步骤是提取使用 yumdownloader 下载的包内容,以便通过以下命令访问相关的 RPM:

  1. # rpm2cpio <package_name> | cpio -idmv
复制代码

cpio 命令通常用于备份,其功能是便于将文件进出 cpio 压缩包。它的工作方式类似于 tar,但与 tar 不同,cpio 可以与 find 命令结合使用。

例如,要进行备份,你可以通过以下方式访问相关目录:

  1. # cd /path/to/directory
复制代码

列出目录内容,确保所有内容都在:

  1. # ls -altr
复制代码

现在,以以下方式运行备份目录的命令:

  1. # find . -print | cpio -ocv > /path/to/backup-name.cpio
复制代码

所以,通过几步简单的操作,我们已经学会了如何通过 Yum 下载一个软件包,并使用cpio命令提取相关的包数据。这个过程在排查特定服务或应用程序的依赖问题时可能会非常有用。这可能是你第一次接触cpio命令,也许你不会感到惊讶,因为我们仅仅触及了它的一小部分功能。因此,我鼓励你深入学习它,因为你会发现它在未来某些时候会非常有用。

关于cpio命令的更多信息可以在本章末尾找到,但作为参考,你可以通过输入以下命令开始你的探索:

  1. $ man cpio
复制代码

诊断损坏的 RPM 数据库

RPM 是一个包管理工具,它将软件包的信息存储在位于/var/lib/rpm的数据库中,但有时会观察到该数据库可能会失败。如果发生这种情况,rpm命令将无法使用,在这种情况下,系统可能会开始出现与任何基于 Yum 或 RPM 的进程相关的故障迹象。

例如,在进行典型的 Yum 更新过程时,你可能会看到以下消息:

  1. "error: cannot open Packages database in /var/lib/rpm"
复制代码

在此,我不得不强调良好备份策略的重要性,但作为故障排查人员,这可能超出你的控制范围。因此,在这种情况下,可以通过完成以下步骤来诊断恢复 RPM 数据库的基本过程:

  1. # cd /var/lib/rpm
  2. # rm -rf __db*
  3. # rpm -v --rebuilddb
复制代码

完成上述步骤后,你应该能够运行各种健康检查,以确认是否没有段错误,可以通过以下命令之一或多个进行检查:

  1. # db_verify Packages
  2. # db_stat -CA
  3. # rpm -qa
  4. # rpm -Va
  5. # yum update
复制代码

例如,运行命令db_verify Packages后,你应该看到以下类型的输出:

  1. BDB5105 Verification of Packages succeeded.
复制代码

希望这个过程能够解决问题。然而,需要认识到,这个过程并不是绝对的,它可能会失败。换个角度来看,为了避免这种情况,定期备份/var/lib/rpm应视为所有 CentOS/RHEL 系统的常规操作。如果包验证过程失败,你需要考虑从最近的备份中进行完全恢复。

小版本升级

对于 CentOS 7 用户,完成小版本升级的简便方法只是使用 Yum,但和往常一样,在继续操作之前,你应该进行完整备份。

你应该备份的文件类型因系统而异,但通常包括配置文件、重要的系统文件、用户数据、数据库、网站版本控制和应用程序文件。此外,如果你使用的是专有软件,在进行更新之前,你应与原开发者确认任何升级的可行性。

因此,在考虑了所有这些措施之后,如果可能的话,我建议您在操作前备份整个系统,您可以放心,备份中会有所有内容。

要开始进行小幅升级,您可以通过输入以下命令查看当前 CentOS 版本信息:

  1. # cat /etc/redhat-release
复制代码

然后,您可以通过以下命令查看 Linux 信息:

  1. # uname -mrs
复制代码

现在,在您调用 Yum 获取更新包列表之前,通常最好先输入以下命令:

  1. # yum clean all
复制代码

然后,按照以下说明清除 Yum:

  1. # yum check-update
复制代码

现在,您将看到所选系统的更新列表。这些待更新的内容将以常见的格式显示,详细列出包名和版本信息。

如果您希望更新系统,请使用以下命令:

  1. # yum update
复制代码

任何更新所需的时间可能会有所不同,因此您可能需要耐心等待。然而,在成功完成此步骤后,您可能想考虑重新启动系统。如果更新需要在启动阶段对内核进行任何更改,重启系统尤为有利。

要执行此操作,请输入:

  1. # reboot
复制代码

最后,在重新启动完成后,您可以使用以下命令验证系统更新:

  1. # uname -a
复制代码

现在,运行以下一个或多个命令以确保所有服务和应用程序都正常运行:

  1. # tail -f /var/log/messages
  2. # netstat -tulpn
  3. # ps aux | less
复制代码

摘要

在本章中,我们迅速了解了包管理故障排除的细节。虽然还有很多内容可以进一步学习,但作为系统管理员,您不仅发现了一系列可以用来解决 Yum 相关常见问题的工具,还讨论了通过各种插件扩展 Yum、安装第三方仓库、启用 Yum 下载 RPM 包以及恢复 RPM 数据库的能力。

如您所见,在我们继续讨论用户、目录和文件之前,通过一些 lateral thinking(横向思维)和一点练习,您现在应该能够排除大量问题,并将几乎所有的包管理问题抛诸脑后。

参考资料

  • CentOS 升级工具:wiki.centos.org/TipsAndTricks/CentOSUpgradeTool

  • 如何从 Enterprise Linux 6 升级到 Red Hat Enterprise Linux 7?:access.redhat.com/solutions/637583

  • CPIO 的维基百科页面:en.wikipedia.org/wiki/Cpio

  • cpio 命令:www.gnu.org/software/cpio/manual/cpio.html

  • EPEL/epel7beta-faq:fedoraproject.org/wiki/EPEL/epel7beta-faq

  • EPEL/epel7:fedoraproject.org/wiki/EPEL/epel7

  • /pub/epel/7/x86_64/e 的索引: dl.fedoraproject.org/pub/epel/7/x86_64/e/

  • Les RPM de Remi - 博客: blog.famillecollet.com/pages/Config-en

  • Remi 索引: rpms.famillecollet.com/enterprise/

  • IUS 社区项目: iuscommunity.org/pages/IUSClientUsageGuide.html

  • /pub/ius/stable/CentOS 的索引: dl.iuscommunity.org/pub/ius/stable/CentOS/

  • IUS 包替换指南: iuscommunity.org/pages/IUSClientUsageGuide.html

  • ATrpms 仓库: atrpms.net/about/

  • Nux 仓库: li.nux.ro/repos.html

  • RPM 首页: rpm.org

  • RPM 恢复诊断: www.rpm.org/wiki/Docs/RpmRecovery

第五章:故障排除用户、目录和文件

与之前讨论的主题不同,故障排除用户、目录和文件的过程可以看作是一个持续的过程,需要在服务器的生命周期中不断关注。它将成为日常事务,因此,我们将从用户管理的基本原则开始,目的是向你展示如何恢复默认的文件和文件夹权限,恢复丢失的文件,并带你走过许多相关主题,为你准备应对专业故障排除人员可能遇到的各种问题。

在本章中,我们将:

  • 了解如何有效管理添加、删除、修改用户的过程,并使用login.defs实现系统范围的更改

  • 了解如何使用utmpdump监控用户活动

  • 了解如何重置 root 密码并启动基于 root 的日志记录,以实现更好的命令行安全审计

  • 了解如何使用 Scalpel 恢复丢失的数据

  • 了解如何恢复默认的权限和所有权

  • 通过了解如何进行持续修复和检查碎片整理,进一步探索 XFS 文件系统

  • 了解如何审计目录和文件

  • 了解如何可视化目录和文件

用户

用户管理是与管理服务器相关的基础技能,在这方面,它无疑是解决任何系统问题时的一个里程碑。因此,考虑到这一点,我们将快速分析管理用户的过程,以消除任何困惑。

添加用户并强制密码更改

你可以使用以下命令添加新用户(并为他们创建主目录):

  1. # adduser <username>
复制代码

你可以这样为新用户提供密码:

  1. # passwd <username>
复制代码

或者,如果你想强制重置密码,意味着用户必须重置其密码,那么以下命令就足够了:

  1. # chage -d 0 <username>
复制代码

此外,你可以通过输入以下命令为特定用户取消密码:

  1. # usermod -p "" <username>
复制代码

但是,如果你想授予新用户使用sudo的权限,那么请输入以下命令:

  1. # gpasswd -a <username> wheel
复制代码

最后,如果你想了解更多关于用户的信息,使用以下命令将显示他们当前的属性:

  1. # id <username>
复制代码

删除用户

删除用户账户的操作通常是直接的,但它可能涉及多个容易被忽视的步骤。因此,为了避免在大规模用户系统中出现任何未来的问题,在删除用户之前,应先按以下方式锁定账户:

  1. # passwd -l <username>
复制代码

然后,你需要使用tar备份用户的主目录,并通过输入以下命令来确认是否存在与该账户关联的活动进程:

  1. # ps aux | grep -i <username>
复制代码

完成这些后,你现在可以通过以下命令结束与该账户关联的任何活动进程:

  1. # pkill -u <username>
复制代码

或者,你可以像这样删除单独的进程 ID:

  1. # kill -9 <pid>
复制代码

通过使用pkill,您调用了SIGTERM命令,这将简化移除与该账户关联的任何活动进程的任务。因此,在这个阶段,您应该考虑移除任何文件、打印作业,并重新分配或删除与该账户关联的任何cron作业。

您可以通过键入以下命令来执行此操作:

  1. # find / -user <username> -print
复制代码

完成这些操作后,您可以安全地删除用户:

  1. # userdel -r <username>
复制代码

使用-r选项还会删除与该账户关联的主目录,但如果您希望删除用户、其主目录并移除任何SELinux映射,您应该使用:

  1. # userdel -rZ <username>
复制代码

然而,如果遇到任何困难,您可以始终以以下方式使用强制选项:

  1. # userdel -rfZ <username>
复制代码

最后,您需要考虑移除与该用户关联的任何 SSH 密钥。确保该账户没有启用sudo或su,然后逐一处理您的应用程序和服务(包括数据库、电子邮件、文件共享、htaccess、网页目录、CGI 文件等),同时为系统可能使用的任何公共账户重新分配新的设置。

修改用户

对于故障排除人员来说,用户管理的一个最有用的方面是能够修改现有的用户账户。可能有许多原因需要执行此任务,但最好的说明这种技能的方法是从修改以下文件中的默认adduser属性开始:

  1. # nano /etc/default/useradd
复制代码

从这里,您可以重新定义使用的 shell、主目录的默认位置以及是否设置默认的邮件队列。

例如,您可以使用此技术将主目录的默认位置从/home更改为/home/<公司名>。然而,如果您更倾向于手动操作(逐个案例处理),为了更改主目录的位置,您需要使用usermod命令结合-d选项(新目录的路径)和-m选项(移动当前主目录的内容),如下所示:

  1. # usermod -m -d /path/to/new/home/directory <username>
复制代码

在运行上述命令时,重要的是要意识到,如果该用户正在使用系统,控制台上将显示一个 PID,在进行任何修改之前,必须终止该进程。

最后,如果需要将现有用户转移到不同的组,可以通过调用-g选项来实现,如下所示:

  1. # usermod -g <new_group_name> <username>
复制代码

然而,完成这些操作后,就像删除用户一样,您必须手动更改任何crontab文件或任务的所有权,并通过对任何剩余(相关/现有)服务进行必要的修改来完成该过程。

了解 login.defs

在管理用户时,另一种替代方法或长期方法是考虑修改/etc/login.defs中找到的默认设置,这样您就可以更改删除命令的行为。

例如,假设您发现以下行被注释掉,如下所示:

  1. #USERDEL_CMD /usr/sbin/userdel_local
复制代码

取消注释这一行,它将确保移除所有at/cron/print任务。此外,你还可以使用login.defs文件来确定分配给用户邮件目录、密码加密方式、密码过期周期、userid、groupid等的默认值。

使用 utmpdump 监控用户活动

跟踪用户活动是任何 Linux 管理员最基本的技能之一。在需要解决与用户管理相关的故障排除问题时,我们可以使用utmpdump。

用户历史通常存储在以下位置:

  • /var/run/utmp:这个二进制文件的目的是记录打开的会话。你可以使用utmpdump /var/run/utmp查看该文件的内容。

  • /var/run/wtmp:这个二进制文件的目的是记录连接历史。你可以使用utmpdump /var/log/wtmp查看该文件的内容。

  • /var/log/btmp。这个二进制文件的目的是记录失败的登录尝试。你可以使用utmpdump /var/log/btmp查看该文件的内容。

更进一步,你还可以通过输入以下命令来查看/var/run/wtmp中当前记录的会话历史:

  1. # last
复制代码

你可以通过输入以下命令查看/var/run/btmp中当前记录的会话历史:

  1. # lastb
复制代码

然而,鉴于对这些文件的简单查看对于我们的需求来说有些冗余,你可以使用以下命令查看这些文件的当前状态:

  1. # stat /var/run/utmp
  2. # stat /var/log/wtmp
  3. # stat /var/log/btmp
复制代码

这些命令的输出可能类似于以下内容:

  1. Access: 2015-04-26 07:29:13.143818061 -0400
  2. Modify: 2015-04-26 06:24:02.444728081 -0400
  3. Change: 2015-04-26 06:24:02.444728081 -0400
复制代码

由于二进制文件无法通过基本的阅读命令如cat、less和more进行查看,因此,除了简单依赖last、who、lastb等基本命令外,另一种方法是使用utmpdump命令,方式如下:

  1. # utmpdump /path/to/binary
复制代码

如前所述,如果你想读取/var/run/utmp,可以使用以下命令:

  1. # utmpdump /var/run/utmp
复制代码

而其余的文件可以通过以下方式访问:

  1. # utmpdump /var/log/wtmp
  2. # utmpdump /var/log/btmp
复制代码

使用完这三个命令后,你会注意到输出格式是熟悉的,最明显的区别是wtmp的结果按逆序显示,而utmp和btmp则按时间顺序显示。

utmpdump的结果格式如下:

  • 第一列显示会话标识符;值 7 通常与新登录事件关联,而值 8 则与登出事件关联。

  • 第二列显示 PID。

  • 第三列可以根据以下任一条件包含一个相对变量:

    • ~~,表示运行级别或系统重启变化

    • bw,或称为启动等待进程

    • 一个数字或 TTY 值

    • 一个字符/数字,表示 PTY 值(伪终端)。

  • 第四列有时可能为空,或者保留一个关联的用户名、运行级别或重启值。

  • 第五列(如果该信息可用)将显示 TTY 或 PTY 值。

  • 第六列将显示远程主机的身份。在大多数本地情况下,你最多只会看到一个运行级别信息,但对于远程访问,你会看到 IP 地址或名称。

  • 第七列将显示远程主机的 IP 地址,或者如果是本地访问,则显示 0.0.0.0。

  • 第八列(最后一列)将指示记录创建的时间和日期信息。

你还应该注意,如果没有进行 DNS 解析,第六列和第七列将显示相同的信息。

所以,考虑到前述信息,通过一点练习,并使用我们在前几章中发现的技巧,utmpdump可以用来执行广泛的查询,例如显示像这样的常规访问信息:

  1. # utmpdump /var/log/wtmp
复制代码

此外,你可以使用grep显示特定记录的详细信息。

例如,如果你想显示某个特定用户的wtmp记录,你可以输入:

  1. # utmpdump /var/log/wtmp | grep <username>
复制代码

进一步来说,你可以使用grep以以下方式识别来自特定 IP 地址的登录次数:

  1. # utmpdump /var/log/wtmp | grep XXX.XXX.XXX.XXX
复制代码

或者使用以下语法检查 root 访问系统的次数:

  1. # utmpdump /var/log/wtmp | grep root
复制代码

然后使用以下命令来监视失败登录尝试的次数:

  1. # utmpdump /var/log/btmp
复制代码

请记住,btmp的输出应该是最小化的,因为这个二进制文件将显示与使用错误密码或尝试使用未知用户名登录相关的各种问题。特别是当 tty1 被显示为正在使用时,后者尤其重要,因为这表示一个未知的人访问了你机器上的终端。从这个角度来看,注意到这样一个重要问题可能会激发你运行安全审计,检查访问权限和密钥,通过以下命令创建一个基本的基于文本的输出文件:

  1. # utmpdump /var/log/btmp > btmp-YYYY-MM-DD.txt
复制代码

重置 root 密码并增强日志记录

随着 CentOS 7 的发布,你可能会发现重置 root 密码的过程发生了变化。所以,如果你忘记了 root 密码,你需要按照这些重要步骤进行操作。

启动计算机,并在内核屏幕阶段按E键。在下一个屏幕上,滚动文本并查找以下行:

  1. root=/dev/mapper/centos-root ro
复制代码

现在,替换字母ro为以下内容:

  1. rw init=/sysroot/bin/sh
复制代码

它应该看起来像这样:

  1. root=/dev/mapper/centos-root rw init=/sysroot/bin/sh
复制代码

完成后,按Control + XCtrl + X 以使用 bash shell /sysroot/bin/sh进入单用户模式。

在单用户模式下,输入:

  1. # chroot /sysroot
复制代码

在井号(#)后,输入:

  1. # passwd root
复制代码

按照屏幕上的指示进行操作,并继续重置密码,但如果你确实需要更新SELINUX,在做任何操作之前,使用命令touch /.autorelabel。

当你准备好完成时,输入以下命令以按通常的方式访问机器:

  1. # exit
复制代码

现在,以通常的方式重新启动你的系统:

  1. # reboot
复制代码

做得好!你现在应该能够使用新的 root 密码完全访问系统。然而,如果你决定更新所有系统命令的日志记录,只需在你喜欢的文本编辑器中打开以下文件:

  1. # nano /etc/bashrc
复制代码

向下滚动到文件底部并添加以下行:

  1. readonly PROMPT_COMMAND='history -a >(logger -t "$USER[$PWD] $SSH_CONNECTION")'
复制代码

完成这一步后,你会发现所有基于 SSH 的命令行活动都被记录在/var/log/messages中,如下所示:

  1. Jan 11 11:38:14 centurion1 journal: root[/root] 192.168.1.17 53421 192.168.1.183 22: last
  2. Jan 11 11:38:26 centurion1 journal: root[/var/log] 192.168.1.17 53421 192.168.1.183 22: cd /var/log
  3. Jan 11 11:38:32 centurion1 journal: root[/var/log] 192.168.1.17 53421 192.168.1.183 22: cat messages
  4. Jan 11 11:38:49 centurion1 journal: root[/var/log] 192.168.1.17 53421 192.168.1.183 22: last
复制代码

使用 Scalpel 恢复丢失或删除的文件

如果文件不小心从系统中删除,你可以使用一个名为 Scalpel 的小工具来恢复它。Scalpel 是 Foremost 的一个更快的替代工具,Foremost 最初由美国空军特种调查办公室和信息系统安全研究中心开发。如今,它是一个通常与数字取证调查和文件恢复相关的工具,你可以通过键入以下命令来安装它:

  1. # yum install scalpel
复制代码

你需要 EPEL 仓库来完成这个过程(这在前一章中讨论过),但是当你准备好时,只需更新以下配置文件,以确定你希望搜索哪些类型的文件:

  1. # nano /etc/scalpel.conf
复制代码

完成这一步后,你应该创建一个恢复目录,然后转到/etc目录以使用scalpel.conf,如图所示:

  1. # cd /etc
复制代码

你可以通过定制以下命令来扫描相关设备:

  1. # scalpel /path/to/device -o /path/to/recovery/directory
复制代码

上述命令的示例看起来像这样:

  1. # scalpel /dev/sda1 -o /tmp/recovery-session1
复制代码

Scalpel 将通过创建工作队列来开始,但请注意,整个操作需要一定的时间才能完成。简单来说,完成扫描所需的实际时间将取决于磁盘大小、删除文件的数量、机器的性能以及系统当前正在执行的其他活动。

你可以使用ls命令像这样查看结果:

  1. # ls -la /path/to/recovery/directory
复制代码

最后,在开始之前,你需要注意,每次运行 Scalpel 时都必须创建一个新的恢复目录(所以你可能需要考虑使用一个备用硬盘),因为结果将由一个单一的审计文件维护。

可以通过键入以下命令来查看这个特定文件:

  1. # less /path/to/recovery/directory/audit.txt
复制代码

记住,Scalpel 可以与各种文件系统格式或原始分区一起工作,从这个角度来看,它可以视为一个非常有用的故障排除工具。

你可以通过查看手册来了解更多关于 Scalpel 的内容,方法如下:

  1. # man scalpel
复制代码

恢复文件和目录权限

文件和目录权限非常重要,要查看特定目录中所有文件的当前状态,可以运行以下命令:

  1. # ll
复制代码

或者,你可以通过运行以下命令来定位特定目录:

  1. # ll /path/to/directory
复制代码

然而,在某个系统文件或文件夹的权限被误改的情况下,可以通过以下基于 RPM 的命令来修复这一灾难性情况:

  1. # rpm --setugids PACKAGENAME
  2. # rpm --setperms PACKAGENAME
复制代码

另一方面,如果整个目录被错误地使用 chown 或 chmod 命令更新,那么以下命令会更加有用:

  1. # for package in $(rpm -qa); do rpm --setugids $package; done
  2. # for package in $(rpm -qa); do rpm --setperms $package; done
复制代码

根据前面显示的命令,第一个命令将重置所有文件和文件夹的所有权值到默认状态,而第二个命令将重置相对的文件权限。因此,在运行这些命令后,你可能会看到以下消息:

  1. chgrp: cannot access '/usr/share/man/zh_TW/man5x': No such file or directory
  2. chown: cannot access '/usr/share/man/zh_TW/man6': No such file or directory
  3. chgrp: cannot access '/usr/share/man/zh_TW/man6': No such file or directory
  4. chown: cannot access '/usr/share/man/zh_TW/man6x': No such file or directory
复制代码

不用担心!无论列出的是哪个文件或目录,这些通知都可以安全忽略。

使用和扩展 XFS 文件系统

XFS 最早于 1993 年由 Silicon Graphics 开发,其主要目的是不仅支持创建能够进行元数据日志记录的大型文件系统,还提供一种可以在挂载和活动状态下进行碎片整理和扩展的技术。作为故障排除者,这些信息对你可能没什么用,但你应该知道,最新版本的 CentOS 默认使用的文件系统就是 XFS。如果你没有对分区进行过大的自定义,那么你可能会发现 XFS 是你需要处理的文件系统。

你可以通过以下命令快速确认系统的结构:

  1. # df -Th
复制代码

上述命令(忽略磁盘大小和分区)可能会产生类似于以下输出的结果:

  1. Filesystem Type Size Used Avail Use% Mounted on
  2. /dev/mapper/centos-root xfs 42G 1.5G 40G 4% /
  3. devtmpfs devtmpfs 913M 0 913M 0% /dev
  4. tmpfs tmpfs 919M 0 919M 0% /dev/shm
  5. tmpfs tmpfs 919M 8.4M 911M 1% /run
  6. tmpfs tmpfs 919M 0 919M 0% /sys/fs/cgroup
  7. /dev/sda1 xfs 494M 139M 356M 29% /boot
  8. /dev/mapper/centos-home xfs 21G 33M 21G 1% /home
复制代码

在标记为 type 的列下,如果出现 xfs,那就是我们要找的。如果发现服务器确实使用了 XFS 文件系统,那么可以使用以下命令安装 XFS 工具和实用程序文件 xfsprogs.x86_64:

  1. # yum install xfsprogs
复制代码

一般来说,你应该了解,如果服务器系统相对较小,XFS 可能会导致性能轻微下降。在这些情况下,ext4 在一些单线程和元数据密集型工作负载下通常会更快。此外,由于 XFS 不支持缩小,你应该知道,即使在未挂载时,该技术也不允许文件系统缩小。因此,当不需要大文件系统或大文件时,你可能会选择继续使用 ext4。

从更广泛的角度来看,你会感到宽慰,因为创建 XFS 所需的基本语法与其他文件系统相似:

  1. # mkfs.xfs /dev/device
复制代码

所以,没什么意外的,而且由于与其他文件系统的相似性,我假设你可以舒适地完成这整个过程。然而,在你开始之前,应该始终了解服务器的硬件配置,因为在开始操作之前,可能会有一些你需要注意的显著问题。

例如,假设服务器超过了 2 TB。所以,在完成初步的 fdisk 操作以构建文件系统布局后(挂载之前),你可能会决定对系统进行基准测试,因为每个优秀的故障排除者都知道 XFS 启用了写入屏障,以确保文件系统的完整性。

你可以通过输入以下命令来完成这个简单的操作:

  1. # mount -o inode64 /dev/device /mount/point
复制代码

默认情况下,写入屏障将有助于保护文件系统免受电源故障、重置和系统崩溃等问题的影响,但如果你的硬件具有良好的写入缓存,可能更明智的做法是禁用写入屏障,以减少对性能的影响。

在这方面,你可以通过以下方式挂载设备:

  1. # mount -o nobarrier /dev/device /mount/point
复制代码

完成后,你可以始终使用以下语法请求有关特定卷的更多信息:

  1. # xfs_info /mount/point
复制代码

正如我们所看到的,XFS 确实有许多优秀的功能和工具,但在排查服务器问题时,正是这些差异可能会成为问题的根源。

在这方面,正如我们现在看到的,XFS 应该与类似的基于 ext3 或 ext4 的系统有所不同对待。然而,如果你需要扩展文件系统,那么你会高兴地发现,XFS 配备了一种名为 xfs_growfs 的标准工具,可以通过以下方式使用:

  1. # xfs_growfs -d /mount/point
复制代码

假设你已经查看了 man 页,显然可以指出,你的语法会使用 -d 选项来将文件系统扩展到设备所支持的最大大小。

对 XFS 进行修复

XFS 是为了支持极大的文件系统而创建的。在高负载下,它表现得非常出色,并且能够扩展大文件,但也因此更容易受到损坏。正因为如此,我们现在考虑一组工具,帮助我们排查服务器问题并恢复文件系统。

这个被称为 xfs_repair 的工具,用于确认文件系统的一致性并修复发现的问题。这个过程不会恢复丢失的数据,但应该可以恢复相关设备上的文件系统。

xfs_repair 使用的基本语法如下:

  1. # xfs_repair /mount/point
复制代码

然而,为了避免任何错误信息,该过程需要你首先 umount 相关设备。整个过程如下所示:

  1. # umount /mount/point
  2. # xfs_repair /mount/point
复制代码

结果输出将继续经过一系列阶段,并确认相关事件。完成后,只需按常规方式重新挂载设备以完成任务。然而,如果 xfs_repair 失败,请再次重复此过程,并对相关错误信息进行研究。

如果 xfs_repair 第三次未能修复一致性问题,依据错误信息,你可能需要考虑为服务器制定一个替代的救援计划,因为应该假设数据恢复只能通过备份来完成。

注意

话虽如此,你也可以考虑采取额外的步骤来恢复相关设备。

在当前阶段,你应该假设数据恢复只能通过备份进行,你的计划现在是基于仅恢复文件系统。然而,值得记住的是,你不应采取任何可能影响生产环境的操作。

通过备份和恢复文件系统上的文件,可能能够从磁盘恢复文件。要做到这一点,请以只读模式挂载文件系统,然后使用xfsdump进行备份。从此以后,你需要重新创建分区并使用xfsrestore恢复文件。有关详细信息,请查阅man xfsdump和man xfsrestore。

或者,如果日志恢复失败,可能可以通过以只读模式挂载文件系统,并使用no recover选项来恢复部分数据。这将避免运行日志恢复过程,但使用这种方法,文件系统可能不一致,并且无法保证所有数据都会恢复。

xfs_repair工具用于修复文件系统。它与文件系统的大小无关(无论大文件系统还是小文件系统都一样处理),但与其他修复工具不同,它不会在启动时运行,并且只会在挂载时启动日志记录,以确保文件系统的一致性。如果xfs_repair遇到损坏的日志文件,它将无法修复文件系统,因此如果发生这种情况,你需要清除相关日志,挂载然后卸载 XFS 文件系统,这可以通过添加-L选项来强制清零日志,如下所示:

  1. # xfs_repair -L /mount/point
复制代码

请记住,重置日志可能会导致文件系统处于不一致状态。这通常会导致数据丢失和/或数据损坏。因此,只应在仅打算恢复文件系统的情况下应用这些方法。记住,xfs_repair命令并非用于恢复该文件系统上的数据。

调查 XFS 上的碎片化

在文件系统运行缓慢的情况下,可能是碎片化影响了你的服务器。在这种情况下,如果你怀疑发生了或正在发生碎片化,可以在相关设备上运行以下命令:

  1. # xfs_db -c frag -r /mount/point
复制代码

使用此命令时,我们让xfs_db以只读模式(-r选项)打开文件系统,并传递一个命令(-c选项)来获取该设备的文件碎片数据(frag)。当我们使用frag命令时,它只会返回与文件数据相关的信息,而不会关注空闲空间的碎片化。因此,根据系统的具体情况,输出结果可能如下所示:

  1. fragmentation factor 0.31%
复制代码

在更严重的情况下,它可能会报告以下输出:

  1. fragmentation factor 93.39%
复制代码

通过将你的注意力引导到前面示例中的碎片因素(以百分比表示),你可能已经找到了至少一个需要故障排除的原因。修复这种情况只需要调用文件系统重组工具,也就是 xfs_fsr。我们只需要系统重组我们的分区或设备,以类似于 Microsoft Windows 桌面的方式优化磁盘使用。在这方面,使用 xfs_fsr 的最基本语法如下:

  1. # xfs_fsr /path/to/device
复制代码

而对于单个文件,你可以使用:

  1. # xfs_fsr /path/to/file
复制代码

然而,考虑到这些事件完成的时间可能相当长,这个命令的更简洁用法是指定一个要重组的文件系统列表(-m),一个以秒为单位计算的时间选项 -t,以及一个详细选项 -v,以清晰指示发生的情况,如下所示:

  1. # xfs_fsr -m /etc/mtab -t 7200 -v
复制代码

对应的输出将显示 inode 前后范围的数量。默认情况下,xfs_fsr 会在完成过程之前执行十次遍历,除非你决定使用选项 -p 来减少遍历次数,如下所示:

  1. # xfs_fsr -m /etc/mtab -t 7200 -v -p 2
复制代码

你应该知道,xfs_fsr 不应被用来碎片整理整个系统,因为这通常被认为是不必要的,它可能导致空闲空间碎片化,因此你可以分阶段完成此任务,并知道操作可以被干净地中断。这样将保持文件系统的一致性。如果你中断了过程(使用 Ctrl + C),xfs_fsr 会将碎片整理过程保存到以下位置:

  1. # /var/tmp/.fsrlast_xfs
复制代码

然而,在你深入了解之前,真正需要注意的问题是,应该小心谨慎地在实时系统上处理碎片问题,因为在高负载期间对设备或分区进行碎片整理将给你的服务器带来不必要的负担。因此,在这种情况下,最好的做法是在相关设备或分区未满载或在较轻工作负荷期间运行 xfs_fsr。

最后,在完成碎片整理过程后,你可以使用以下命令确认已完成的工作量:

  1. # xfs_db -c frag -r /mount/point
复制代码

因此,在完成这些简单操作后,或需要未来的(并可能是重复的)定时任务,你应该能立即注意到文件和文件夹移动及传输速度的改善。

审计目录和文件

处理故障排除的一个重要任务可以来自于对与文件读写操作相关的活动的理解。CentOS 7 提供了一个简单的实用工具。这个工具称为 auditd,它在启动过程中启动。事件会记录到一个关联的日志文件,位于 /var/log/audit,并且由于它在后台运行,你可以通过以下命令检查当前服务状态:

  1. # systemctl status | grep audit
复制代码

审计服务是可以自定义的,你可以通过访问以下文件,并使用你喜欢的文本编辑器,直接管理日志文件的大小、位置和相关属性:

  1. # nano /etc/audit/auditd.conf
复制代码

此外,如果你不希望丢失任何审计数据,你可以在无法执行审计时禁用机器。为此,打开配置文件 auditd.conf,并添加或修改以下几行:

  1. max_log_file_action = keep_logs
  2. space_left_action = email
  3. action_mail_acct = root
  4. admin_space_left_action = halt
复制代码

这个操作很严重,在没有做好充分准备的情况下不建议贸然进行,但它会移除旋转日志文件的默认操作,并用发送电子邮件给 root 用户的指令来替代。

最后,如果你希望对每个进程利用审计服务标志,只需打开 /etc/default/grub 并将以下参数添加到内核行:

  1. audit=1
复制代码

记得使用以下命令重新生成 grub 并重启:

  1. # grub2-mkconfig -o /boot/grub2/grub.cfg
复制代码

这将确保在启动序列启动后,每个进程都设置一个可审计的标志,为了更简便,我们可以通过编辑以下文件来构建一套独特的规则:

  1. # nano /etc/audit/rules.d/audit.rules
复制代码

为了简化操作,最好的方法是找到服务器的 stig.rules 文件,路径为 /usr/share/doc/audit-X.X.X/stig.rules,并将其复制到 /etc/audit/rules.d/audit.rules。根据当前的包版本(以我为例),stig.rules 文件可以在 /usr/share/doc/audit-2.3.3/stig.rules 找到。因此,我运行了以下命令来创建默认规则集:

  1. # cp /usr/share/doc/audit-2.3.3/stig.rules /etc/audit/rules.d/audit.rules
复制代码

因此,在自定义规则并重启 auditd 服务后,你会发现可以使用以下语法发起查询:

  1. # ausearch -f /path/to/directory/or/file
  2. # ausearch -f /path/to/directory/or/file | less
  3. # ausearch -f /path/to/directory/or/file -i | less
复制代码

作为替代方案,你可以使用 aureport 以以下方式生成一系列审计:

要监控异常行为,可以使用:

  1. # aureport --key --summary
复制代码

要构建用户登录报告,可以使用:

  1. # aureport -l -i -ts yesterday -te today
复制代码

要审查访问违规行为,可以尝试:

  1. # ausearch --key access --raw | aureport --file --summary
复制代码

最后,要查看异常情况,可以使用:

  1. # aureport --anomaly
复制代码

当然,我们没有涵盖审计服务的每个方面,但前面的示例应该能帮助你入门。记住,所有示例都可以添加到 cron 作业中,如果你想了解更多内容,可以随时通过输入以下命令查看 aureport 手册:

  1. # man ausearch
  2. # man aureport
复制代码

可视化目录和文件

良好的管理始于良好的家务处理,因此,维护关于服务器布局的详细记录通常被认为是任何 Linux 管理员的良好起点。这项任务不仅能让你随时了解系统整体所做的更改,还可以作为调试的有效方法。此外,因为你可能继承了这个系统,或者和其他管理员共享访问权限,因此考虑运行一次最新的更改清单可能是个好主意。

所有可以访问的目录、文件夹和文件都会以树状结构排列在一个特定的基于 Linux 的系统中。从根目录 (/) 开始,这个层次结构可能包含本地或远程文件、本地或远程文件系统,以及本地或远程块设备。

要查看此树,只需确保你已经安装了以下软件包:

  1. # yum install tree
复制代码

默认情况下,tree 命令将从当前位置开始索引,因此首先,只需将位置更改为启动目录,如下所示:

  1. # cd /boot
复制代码

现在,运行以下命令:

  1. # tree
复制代码

tree 命令在技术上被描述为 递归目录列表命令,它以树状格式显示服务器的内容。它高度可定制,因此如果你希望从当前位置指定一个特定目录,可以使用:

  1. # tree /path/to/folder
复制代码

你可能已经注意到,tree 命令默认不会显示隐藏文件。因此,为了查看所有文件(包括所有隐藏文件),请使用 -a 选项,如下所示:

  1. # tree -a /path/to/folder
复制代码

然而,如果你希望 tree 功能仅显示文件夹名称,你应该使用 -d 选项,如下所示:

  1. # tree -d /path/to/folder
复制代码

如果一切看起来有些平凡无奇,你可以通过 -C 选项为输出添加一些颜色,如下所示:

  1. # tree -C /path/to/folder
复制代码

最后,你可以将之前的选项组合起来,通过输入以下命令将输出打印到文本文件中:

  1. # tree > /folder/name/filename.txt
复制代码

例如,如果你想维护一个列出当前权限的文件清单,可以使用 -p 选项,如下所示:

  1. # tree -p > /folder/name/filename.txt
复制代码

或者,如果你更愿意显示嵌入了 HTML 代码的输出以便导出,可以尝试:

  1. # tree -H /path/to/folder
复制代码

因此,无论你是采用了新服务器,还是被访问并写入文件的用户数量所困扰,tree 功能提供了一个相对的解决方案,可以通过输入以下命令来保持对你的服务器或设备的可视化审计:

  1. # tree -d /sys/devices
复制代码

那为什么不把它与定时任务(cron job)结合使用呢?这样你就可以定期监控潜在问题的出现,甚至保持一个视觉记录,了解这些变化何时发生。从这个角度看,你可以断言 tree 软件包是一个非常有用的工具,要了解更多,你可以随时通过输入以下命令查看手册:

  1. # man tree
复制代码

总结

在本章中,我们讨论了与用户、目录和文件相关的多个主题,同时介绍了与 XFS 文件系统发布相关的一些主题。从强制更改密码到可视化目录结构,从恢复 root 密码到理解磁盘碎片整理的必要性,我们对 CentOS 7 故障排除的探索表明,解决系统基础问题所获得的知识与持续的人为问题密切相关。可以说,你永远无法预演一个灾难性场景,因为每个事件可能是独特的,可能仅适用于一个或多个系统,但正如我们所看到的,无论你是在监控用户、修改用户、恢复数据,还是在维护整个文件系统,通过遵循一些简单的步骤,许多与文件、目录和用户相关的问题都可以快速有效地解决;这也自然引导我们进入了共享资源故障排除的话题。

参考资料

  • Red Hat 客户门户: access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/

  • Tree 项目主页: mama.indstate.edu/users/ice/tree/

  • XFS 常见问题解答: xfs.org/index.php/XFS_FAQ

  • XFS 用户指南: xfs.org/docs/xfsdocs-xml-dev/XFS_User_Guide//tmp/en-US/html/index.html

  • Red Hat XFS 指南: access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Storage_Administration_Guide/ch-xfs.html

  • XFS 维基页面: en.wikipedia.org/wiki/XFS

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

特级红客

关注
  • 3324
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行