将-Linux-迁移到微软-Azure-一-

72 阅读1小时+

将 Linux 迁移到微软 Azure(一)

原文:zh.annas-archive.org/md5/DFC4E6F489A560394D390945DB597424

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Red Hat Enterprise Linux 是一种广泛流行的 Linux 发行版,用于从云到企业大型计算机的各种场景。如果包括 CentOS 等下游发行版,那么 Red Hat Enterprise Linux 发行版的采用率甚至更大。

与大多数事物一样,总会有人负责解决运行 Red Hat Enterprise Linux 的各种系统的问题。《Red Hat Enterprise Linux 故障排除指南》旨在为运行 Red Hat Enterprise Linux 系统的基本到高级的故障排除实践和命令提供指导。

本书旨在为您提供解决各种情景所需的步骤和知识。本书中的示例使用真实世界的问题和真实世界的解决方案。

虽然本书中的示例是情境性的,但本书也可以作为与 Linux 相关主题和命令的参考。它为读者提供了参考故障排除步骤和特定命令来解决复杂问题的能力。

本书涵盖的内容

第一章,“故障排除最佳实践”,涵盖了高层次的故障排除过程。通过将故障排除过程与科学方法相提并论,本书将解释如何分解问题以确定根本原因,无论问题有多复杂。

第二章,“故障排除命令和有用信息的来源”,为读者提供了有关有用信息的常见位置的简单介绍。它还将提供一个基本的 Linux 命令参考,可用于排除许多类型的问题。

第三章,“故障排除 Web 应用程序”,利用第一章学到的过程和第二章学到的命令来解决一个复杂的问题。本章中概述的问题是“通过示例”意味着本章的流程旨在引导您完成整个故障排除过程,从头到尾。

第四章,“故障排除性能问题”,涉及性能问题和一些最复杂的故障排除问题。通常,用户的感知与预期的性能水平相比会使问题变得更加复杂。在本章中,将再次使用第二章讨论的工具和信息来解决真实世界的性能问题。

第五章,“网络故障排除”,讨论了网络是任何现代系统的关键组成部分。本章将涵盖配置和诊断 Linux 网络所需的核心命令。

第六章,“诊断和纠正防火墙问题”,涵盖了 Linux 防火墙的复杂性,是第五章的延续。本章将介绍和强调诊断 Linux 软件防火墙所需的命令和技术。

第七章,“文件系统错误和恢复”,教会您恢复文件系统可能意味着丢失和保留数据之间的区别。本章将介绍一些核心的 Linux 文件系统概念,并演示如何恢复只读文件系统。

第八章,“硬件故障排除”,开始涉及故障排除硬件问题的过程。本章将指导您恢复失败的硬盘驱动器。

第九章,“使用系统工具排除应用程序问题”,探讨了系统管理员的角色不仅是排除操作系统问题,还包括应用程序问题。本章将向您展示如何利用常见系统工具来识别应用程序问题的根本原因。

第十章,“理解 Linux 用户和内核限制”,演示了 Red Hat Enterprise Linux 有许多组件可以防止用户过载系统。本章将探讨这些组件,并解释如何修改它们以允许合法的资源利用。

第十一章,“从常见故障中恢复”,将指导您排除内存不足的情况。这种情况在使用频繁的环境中非常常见,且很难排除故障。本章将涵盖不仅如何排除此问题,还将解释为什么会发生此问题。

第十二章,“意外重启的根本原因分析”,将对前几章学到的故障排除过程和命令进行测试。本章将指导您对意外重启的服务器进行根本原因分析。

本书所需内容

尽管本书可以独立存在,但读者将受益于拥有 Red Hat Enterprise Linux 7 系统,并且可以使用该操作系统。当您能够在测试系统上执行这些命令和资源时,您将更有效地学习本书中讨论的命令和资源。

虽然本书中涵盖的许多命令、过程和资源可以在其他 Linux 发行版中使用,但强烈建议读者使用 Red Hat 的下游发行版,如 CentOS 7,如果读者无法获得 Red Hat Enterprise Linux 7。

本书的受众

如果您是一名熟练的 RHEL 管理员或顾问,并且希望提高故障排除技能和对 Red Hat Enterprise Linux 的了解,那么本书非常适合您。我们期望您具有良好的知识水平和对基本 Linux 命令的理解。

约定

在本书中,您将找到许多文本样式,用于区分不同类型的信息。以下是这些样式的一些示例及其含义的解释。

文本中的代码词,数据库表名,文件夹名,文件名,文件扩展名,路径名,虚拟 URL,用户输入和 Twitter 用户名显示如下:“在合理范围内,不需要包括执行的每个cdls命令。”

当我们希望引起您对代码块的特定部分的注意时,相关行或项目将以粗体显示:

192.168.33.12 > 192.168.33.11: ICMP host 192.168.33.12 unreachable - admin prohibited, length 68

任何命令行输入或输出都以以下形式书写:

# yum install man-pages

新术语重要单词以粗体显示。屏幕上看到的单词,例如菜单或对话框中的单词,会以这种方式出现在文本中:"我们将在屏幕上看到一条消息,上面写着还在这里?"。

注意

警告或重要说明会出现在这样的框中。

提示

提示和技巧会以这种方式出现。

读者反馈

我们始终欢迎读者的反馈。让我们知道你对这本书的看法——你喜欢或不喜欢什么。读者的反馈对我们很重要,因为它帮助我们开发你真正能充分利用的标题。

要向我们发送一般反馈,只需发送电子邮件至 <feedback@packtpub.com>,并在主题中提及书名。

如果你在某个专题上有专业知识,并且有兴趣撰写或为一本书做出贡献,请参阅我们的作者指南 www.packtpub.com/authors

客户支持

既然你已经是 Packt 图书的自豪所有者,我们有一些事情可以帮助你充分利用你的购买。

下载示例代码

你可以从 www.packtpub.com 的账户中下载你购买的所有 Packt Publishing 图书的示例代码文件。如果你在其他地方购买了这本书,你可以访问 www.packtpub.com/support 并注册,将文件直接发送到你的邮箱。

勘误

尽管我们已经尽一切努力确保内容的准确性,但错误是难免的。如果你在我们的书中发现错误——也许是文本或代码中的错误——我们将不胜感激,如果你能向我们报告。通过这样做,你可以帮助其他读者避免挫折,并帮助我们改进本书的后续版本。如果你发现任何勘误,请访问 www.packtpub.com/submit-errata 报告,选择你的书,点击勘误提交表链接,并输入你的勘误详情。一旦你的勘误被验证,你的提交将被接受,并勘误将被上传到我们的网站或添加到该书的勘误列表下的勘误部分。

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

盗版

互联网上的盗版行为是跨所有媒体持续存在的问题。在 Packt,我们非常重视对我们版权和许可的保护。如果你在互联网上发现我们作品的任何非法副本,请立即向我们提供位置地址或网站名称,以便我们采取补救措施。

请通过 <copyright@packtpub.com> 联系我们,并附上涉嫌盗版材料的链接。

我们感谢你帮助保护我们的作者和我们提供有价值内容的能力。

问题

如果你对本书的任何方面有问题,可以通过 <questions@packtpub.com> 联系我们,我们将尽力解决问题。

第一章:故障排除最佳实践

这一章,也就是第一章,可能是最重要但技术含量最低的。本书中的大多数章节涵盖了特定问题和解决这些问题所需的命令。然而,这一章将涵盖一些可以应用于任何问题的故障排除最佳实践。

你可以把这一章看作是应用实践背后的原则。

故障排除风格

在介绍故障排除的最佳实践之前,了解不同的故障排除风格是很重要的。根据我的经验,我发现人们倾向于使用以下三种故障排除风格:

  • 数据收集者

  • 受过教育的猜测者

  • 适应者

每种风格都有其优点和缺点。让我们来看看这些风格的特点。

数据收集者

我喜欢称第一种故障排除风格为数据收集者。数据收集者通常是利用系统化方法解决问题的人。系统化的故障排除方法通常具有以下特点:

  • 向报告问题的相关方提出具体问题,期望得到详细答案

  • 运行命令以识别大多数问题的系统性能

  • 在采取行动之前运行预定义的一系列故障排除步骤

这种风格的优势在于,无论是什么级别的工程师或管理员使用它都是有效的。通过系统地处理问题,收集每个数据点,并在执行任何解决方案之前了解结果,数据收集者能够解决他们可能不熟悉的问题。

这种风格的弱点在于数据收集通常不是解决问题的最快方法。根据问题的不同,收集数据可能需要很长时间,而且其中一些数据可能并不是找到解决方案所必需的。

受过教育的猜测者

我喜欢称第二种故障排除风格为受过教育的猜测者。受过教育的猜测者通常是利用直觉方法解决问题的人。直觉方法通常具有以下特点:

  • 用最少的信息确定问题的原因

  • 在解决问题之前运行几个命令

  • 利用以前的经验来确定根本原因

这种故障排除风格的优势在于它能让你更快地找到解决方案。面对问题时,这种类型的故障排除者倾向于从经验中汲取,并且需要最少的信息来找到解决方案。

这种风格的弱点在于它严重依赖经验,因此在有效之前需要时间。在专注于解决问题时,这种故障排除者可能还会尝试多种行动来解决问题,这可能会使人觉得受过教育的猜测者并没有完全理解手头的问题。

适应者

还有一种第三种经常被忽视的故障排除风格;这种风格同时利用了系统化和直觉化的风格。我喜欢称这种风格为适应者。适应者有一种个性,使其能够在系统化和直觉化的故障排除风格之间切换。这种结合的风格通常比数据收集者风格更快,比受过教育的猜测者风格更注重细节。这是因为他们能够应用适合手头任务的故障排除风格。

选择适当的风格

虽然很容易说一个方法比另一个更好,但事实是选择适当的故障排除风格在很大程度上取决于个人。了解哪种故障排除风格最适合你自己的个性是很重要的。通过了解哪种风格更适合你,你可以学习和使用适合该风格的技术。你也可以学习和采用其他风格的技术,以应用你通常会忽略的故障排除步骤。

本书将展示数据收集者和有经验的猜测者两种故障排除风格,并定期强调哪种个性风格最适合这些步骤。

故障排除步骤

故障排除是一个既严格又灵活的过程。故障排除过程的严格性基于需要遵循基本步骤的事实。在这方面,我喜欢将故障排除过程等同于科学方法,科学方法有一系列必须遵循的特定步骤。

故障排除过程的灵活性在于可以按任何有意义的顺序遵循这些步骤。与科学方法不同,故障排除过程通常旨在快速解决问题。有时,为了快速解决问题,您可能需要跳过一步或按顺序执行它们。例如,在故障排除过程中,您可能需要解决即时问题,然后确定该问题的根本原因。

以下列表包括构成故障排除过程的五个步骤。每个步骤可能还包括几个子任务,这些子任务可能与问题相关也可能不相关。重要的是要以一颗谨慎的心态遵循这些步骤,因为并非每个问题都可以归入同一类别。以下步骤旨在作为最佳实践使用,但与所有事物一样,应根据手头的问题进行调整:

  1. 理解问题陈述。

  2. 建立假设。

  3. 试错。

  4. 寻求帮助。

  5. 文档。

理解问题陈述

使用科学方法,第一步是建立问题陈述,这另一种说法是:确定并理解实验的目标。使用故障排除过程,第一步是理解报告的问题。我们越了解问题,解决问题就越容易。

我们可以执行一些任务来更好地理解问题。这第一步是数据收集者个性的显著特点。数据收集者天生倾向于在进入下一步之前收集尽可能多的数据,而有经验的猜测者通常倾向于迅速完成这一步,然后转移到下一步,这有时可能导致错过关键信息。

适应者倾向于了解哪些数据收集步骤是必要的,哪些是不必要的。这使他们能够像数据收集者一样收集数据,但不会花费时间收集对问题没有价值的数据。

这个故障排除步骤中的子任务是提出正确的问题

提出问题

无论是通过人工还是自动化流程(如工单系统),报告问题的人通常是信息的重要来源。

工单

当他们收到一个工单时,有经验的猜测者个性通常会阅读工单的标题,假设问题并转移到理解问题的下一个阶段。数据收集者个性通常会打开工单并阅读工单的所有细节。

虽然这取决于工单和监控系统,但通常工单中可能包含有用的信息。除非问题是常见问题,并且您能够从标题中理解所有信息,通常最好阅读工单描述。即使是少量信息也可能有助于解决特别棘手的问题。

人类

然而,从人类那里收集额外信息可能是不一致的。这在很大程度上取决于所支持的环境。在某些环境中,报告问题的人可以提供解决问题所需的所有细节。在其他环境中,他们可能不理解问题,只是解释症状。

无论哪种排除故障风格最适合你的个性,能够从报告问题的人那里获得重要信息是一项重要的技能。直觉性问题解决者,如受过教育的猜测者或适应者,往往比数据收集者个性更容易找到这个过程,不是因为这些个性一定更擅长从人们那里获取细节,而是因为他们能够在较少的信息中识别模式。然而,数据收集者可以通过准备好提出故障排除问题来从报告问题的人那里获得他们需要的信息。

注意

不要害怕问显而易见的问题

我的第一份技术工作是在一个网络托管技术支持呼叫中心。在那里,我经常接到用户的电话,他们不想执行基本的故障排除步骤,只是希望问题升级。这些用户只是觉得他们已经自己执行了所有的故障排除步骤,并且已经发现了超出一级支持范围的问题。

虽然有时这是真的,但更多的时候,问题是一些他们忽视的基本问题。在那个角色中,我很快就学会了,即使用户不愿意回答基本或显而易见的问题,但在一天结束时,他们只是希望他们的问题得到解决。如果这意味着经历重复的步骤,那也没关系,只要问题得到解决。

即使在今天,作为高级工程师的升级点,我发现很多时候工程师(即使在他们的故障排除经验丰富的情况下)也会忽视简单的基本步骤。

有时问一些看似基本的简单问题是一个很好的时间节省者;所以不要害怕问。

尝试复制问题

收集信息和理解问题的最佳方法之一是亲身体验。当问题被报告时,最好是复制问题。

虽然用户可能是很多信息的来源,但他们并不总是最可靠的;用户经常会遇到错误并忽视它,或者在报告问题时简单地忘记传达错误。

通常,我会问用户如何重新创建问题。如果用户能够提供这些信息,我就能看到任何错误,并经常更快地确定问题的解决方案。

注意

有时无法复制问题

尽管复制问题通常是最好的,但并非总是可能的。每天,我与许多团队合作;有时,这些团队在公司内部,但很多时候它们是外部供应商。在关键问题时,我偶尔会看到有人发表类似于“如果我们无法复制它,我们就无法排除故障”的笼统声明。

尽管复制问题有时是找到根本原因的唯一方法,但我经常听到这种说法被滥用。复制问题应该被视为一种工具;它只是你排除故障工具箱中的众多工具之一。如果它不可用,那么你只能用其他工具。

无法找到解决方案和由于无法复制问题而不尝试找到解决方案之间存在显著的区别。后者不仅没有帮助,而且也不专业。

运行调查命令

很可能,你正在阅读这本书是为了学习排除故障红帽企业 Linux 系统的技术和命令。理解问题陈述的第三个子任务就是这样——运行调查命令以确定问题的原因。然而,在执行调查命令之前,重要的是要知道之前的步骤是有逻辑顺序的。

首先询问报告问题的用户一些基本问题的细节是最佳实践,然后在获得足够的信息后,复制问题。一旦问题被复制,下一个逻辑步骤就是运行必要的命令来排除故障和调查问题的原因。

在故障排除过程中,经常会发现自己需要返回到之前的步骤。在你确定了一些关键错误之后,你可能会发现自己必须向最初的报告者询问额外的信息。在故障排除过程中,不要害怕向后退几步,以便更清楚地了解手头的问题。

建立假设

使用科学方法,一旦问题陈述被制定出来,就是建立假设的时候了。在故障排除过程中,当你确定了问题,收集了关于问题的信息,比如错误、系统当前状态等,也是建立你认为引起或正在引起问题的原因的时候。

然而,有些问题可能不需要太多的假设。通常日志文件中的错误或系统当前状态可能会解释问题发生的原因。在这种情况下,你可以简单地解决问题,然后继续进行文档步骤。

对于那些不是非常明显的问题,你需要提出一个根本原因的假设。这是必要的,因为形成假设之后的下一步是尝试解决问题。如果你至少没有根本原因的理论,那么解决问题就会很困难。

以下是一些可以用来帮助形成假设的技术。

整理模式

在进行前面步骤的数据收集时,你可能会开始看到一些模式。模式可以是一些简单的东西,比如多个服务中相似的日志条目,发生的故障类型(比如,多个服务下线),甚至是系统资源利用率的反复波动。

这些模式可以用来制定问题的理论。为了强调这一点,让我们通过一个真实的情景来看一下。

你正在管理一个既运行 Web 应用程序又接收电子邮件的服务器。你有一个监控系统检测到 Web 服务出现错误并创建了一个工单。在调查工单时,你还接到一个电子邮件用户的电话,称他们收到了电子邮件反弹回来的消息。

当你要求用户向你读出错误时,他们提到“设备上没有剩余空间”。

让我们来分析一下这个情景:

  • 我们的监控解决方案的工单告诉我们 Apache 已经停止了

  • 我们还收到了来自电子邮件用户的报告,其中的错误表明文件系统已满

这一切可能意味着 Apache 已经停止,因为文件系统已满吗?可能。我们应该调查一下吗?当然!

这是我以前遇到过的事情吗?

上面的分析引出了形成假设的下一个技术。这可能听起来很简单,但经常被忘记。“我以前见过类似的情况吗?”

在先前的情景中,电子邮件反弹回来的错误报告通常表明文件系统已满。我们怎么知道的?很简单,我们以前见过。也许我们以前在电子邮件反弹回来时见过同样的错误,或者我们在其他服务中见过这个错误。关键是,这个错误是熟悉的,而且这个错误通常意味着一件事。

记住常见错误对于直觉类型的人(如有经验的猜测者和适应者)来说可能非常有用;这是他们自然而然会做的事情。对于数据收集者来说,一个方便的技巧是保留一张常见错误的参考表。

提示

根据我的经验,大多数数据收集者倾向于保留一组包含常见命令或程序步骤的笔记。添加常见错误和这些错误背后的含义是系统思维者(如数据收集者)更快地建立假设的好方法。

总的来说,建立假设对所有类型的故障排除者都很重要。这是直觉思维者(如有经验的猜测者和适应者)擅长的领域。通常情况下,这些类型的故障排除者会更早地提出假设,即使有时这些假设并不总是正确的。

试错法

在科学方法中,一旦形成假设,下一个阶段就是实验。在故障排除中,这相当于尝试解决问题。

有些问题很简单,可以使用标准程序或经验步骤解决。然而,其他问题并不那么简单。有时,假设结果是错误的,或者问题最终比最初想象的更复杂。

在这种情况下,可能需要多次尝试解决问题。我个人喜欢把这看作是类似于试错。一般来说,你可能对问题出了什么问题(假设)有一个想法,以及如何解决它的想法。你试图解决它(试验),如果不起作用(错误),你就会转向下一个可能的解决方案。

首先创建一个备份

对于那些担任新角色的 Linux 系统管理员,如果我只能给出一个建议,那就是大多数人都是通过艰难的方式学到的:在进行更改之前备份所有内容

作为系统管理员,我们经常发现自己需要更改配置文件或删除一些不需要的文件以解决问题。不幸的是,我们可能认为自己知道需要删除或更改的内容,但并不总是正确。

如果已经进行了备份,那么更改可以简单地恢复到先前的状态,但是没有备份。因此,撤销更改并不那么容易。

备份可以包括许多内容,可以是使用诸如rdiff-backup之类的完整系统备份,VM 快照,或者简单地创建文件副本。

提示

对于那些有兴趣看到这个提示在实践中的程度的人,只需在任何有四名以上系统管理员并且已经存在数年的服务器上运行以下命令:

$ find /etc –name "*.bak"

寻求帮助

在许多情况下,问题在这一点上已经解决了,但就像故障排除过程中的每一步一样,这取决于手头的问题。虽然寻求帮助并不完全是故障排除的步骤,但如果你无法自己解决问题,这往往是下一个逻辑步骤。

在寻求帮助时,通常有六种资源可用:

  • 书籍

  • 团队维基或运行手册

  • 谷歌

  • 手册

  • 红帽内核文档

  • 人们

书籍

书籍(比如这本书)对于参考特定类型问题的命令或故障排除步骤是很好的。其他专门针对特定技术的书籍对于参考该技术的工作原理也是很好的。在以前的几年里,看到一位高级管理员手边放着一整排技术书籍是很常见的。

在今天的世界中,由于书籍更频繁地以数字格式出现,它们甚至更容易用作参考。数字格式使它们可以被搜索,并允许读者比传统的印刷版本更快地找到特定部分。

团队维基或运行手册

团队维基变得普遍之前,许多运营团队都有名为运行手册的实体书籍。这些书是运营团队每天使用的流程和程序列表,用于保持生产环境正常运行。有时,这些运行手册会包含有关配置新服务器的信息,有时它们会专门用于故障排除。

在今天的世界中,这些运行手册大多被团队维基所取代,这些维基通常具有相同的内容,但是在线的。它们也往往是可搜索的,更容易保持最新,这意味着它们通常比传统的印刷运行手册更相关。

团队维基和运行手册的好处在于它们不仅可以解决特定于您环境的问题,而且还可以解决这些问题。有许多配置服务(如 Apache)的方法,外部系统对这些服务创建依赖的方式更多。

在某些环境中,当出现问题时,您可能只需简单地重新启动 Apache,但在其他情况下,您可能实际上需要经历几个先决步骤。如果在重新启动服务之前需要遵循特定的流程,最佳做法是将流程记录在团队 Wiki 或 Runbook 中。

谷歌

谷歌是系统管理员如此常用的工具,以至于曾经有特定的搜索门户网站可用,如google.com/linuxgoogle.com/microsoftgoogle.com/macgoogle.com/bsd

谷歌已经停用了这些搜索门户,但这并不意味着系统管理员使用谷歌或任何其他搜索引擎进行故障排除的次数减少了。

事实上,在今天的世界中,在技术面试中听到“我会谷歌一下”这样的话并不罕见。

对于那些刚开始使用谷歌进行系统管理任务的人,一些建议是:

  • 如果您复制并粘贴完整的错误消息(删除服务器特定的文本),您可能会找到更相关的结果:

例如,搜索kdumpctl: No memory reserved for crash kernel返回 600 个结果,而搜索memory reserved for crash kernel返回 449,000 个结果。

  • 您可以通过搜索man然后是一个命令,比如man netstat,找到任何 man 页面的在线版本。

  • 您可以用双引号包裹错误以细化搜索结果,使其包含相同的错误。

  • 通常以问题的形式询问您要找的内容通常会得到教程。例如,如何在 RHEL 7 上重新启动 Apache?

虽然谷歌可能是一个很好的资源,但结果应该始终持保留态度。在谷歌上搜索错误时,您可能会找到一个建议的命令,它提供了很少的解释,只是简单地说“运行这个命令就会修复它”。在运行这些命令时要非常谨慎,重要的是您在执行系统上的任何命令之前都应该熟悉该命令。您应该在执行之前了解命令的作用。

Man 页面

当谷歌不可用,甚至有时候它可用时,关于命令或 Linux 的最佳信息来源通常是man 页面。man 页面是核心 Linux 手册文档,可以通过man命令访问。

例如,要查找netstat命令的文档,只需运行以下命令:

$ man netstat
NETSTAT(8)
Linux System Administrator's Manual
NETSTAT(8)

NAME
       netstat - Print network connections, routing tables, interface statistics, masquerade connections, and multicast memberships

正如您所看到的,这个命令不仅输出了netstat命令的信息,还包含了使用信息的快速概要,如下所示:

SYNOPSIS
      netstat  [address_family_options]  [--tcp|-t]  [--udp|-u] [--udplite|-U] [--raw|-w] [--listening|-l] [--all|-a] [--numeric|-n] [--numeric-hosts]
       [--numeric-ports] [--numeric-users] [--symbolic|-N] [--extend|-e[--extend|-e]]  [--timers|-o]  [--program|-p] [--verbose|-v]  [--continuous|-c]
       [--wide|-W] [delay]

此外,它提供了每个标志的详细描述及其作用:

   --route , -r
       Display the kernel routing tables. See the description in route(8) for details.  netstat -r and route -e produce the same output.

   --groups , -g
       Display multicast group membership information for IPv4 and IPv6.

   --interfaces=iface , -I=iface , -i
       Display a table of all network interfaces, or the specified iface.

一般来说,核心系统和库的基本手册页面是通过man-pages软件包分发的。特定命令的 man 页面,如topnetstatps,是作为该命令的安装软件包的一部分分发的。这是因为个别命令和组件的文档留给了软件包维护者。

这意味着有些命令的文档水平可能不如其他命令。然而,总的来说,man 页面是非常有用的信息来源,可以回答大多数日常问题。

阅读 man 页面

在前面的例子中,我们可以看到netstat的 man 页面包含了一些信息部分。一般来说,man 页面有一个一致的布局,其中包含一些常见的部分,这些部分可以在大多数 man 页面中找到。以下是一些常见部分的简单列表:

  • 名称

  • 概要

  • 描述

  • 示例

名称

名称部分通常包含命令的名称和对命令的非常简要的描述。以下是ps命令的 man 页面中的名称部分:

NAME
       ps - report a snapshot of the current processes.
概要

命令的 man 页面的概要部分通常会列出命令,后面是可能的命令标志或选项。这一部分的一个很好的例子可以在netstat命令的概要中看到:

SYNOPSIS
       netstat  [address_family_options]  [--tcp|-t]  [--udp|-u] [--raw|-w]  [--listening|-l]  [--all|-a] [--numeric|-n] [--numeric-hosts] [--numeric-ports]
       [--numeric-users] [--symbolic|-N] [--extend|-e[--extend|- e]] [--timers|-o] [--program|-p] [--verbose|-v] [--continuous|-c]
cat command's man page:
DESCRIPTION
       Concatenate FILE(s), or standard input, to standard output.

       -A, --show-all
              equivalent to -vET

       -b, --number-nonblank
              number nonempty output lines, overrides -n

描述部分非常有用,因为它不仅仅是查找选项。这部分通常是你会找到关于命令细微差别的文档的地方。

示例

通常 man 页面还会包括使用命令的示例:

EXAMPLES
       cat f - g
             Output f's contents, then standard input, then g's infocontents.
cat command's man page. We can see, in this example, how to use cat to read from files and standard input in one command.

这部分通常是我发现如何使用我以前多次使用的命令的新方法的地方。

其他部分

除了前面的部分,你可能还会看到诸如另请参阅文件作者历史等部分。这些部分也可能包含有用的信息;但并非每个 man 页面都会有这些部分。

Info 文档

除了 man 页面,Linux 系统通常还包含info 文档,这些文档旨在包含超出 man 页面范围的额外文档。与 man 页面类似,info 文档包含在一个命令包中,文档的质量/数量可以因包而异。

调用 info 文档的方法类似于 man 页面,只需执行 info 命令,然后跟上你想查看的主题:

$ info gzip
GNU Gzip: General file (de)compression
**************************************

This manual is for GNU Gzip (version 1.5, 10 June 2014), and documents commands for compressing and decompressing data.

   Copyright (C) 1998-1999, 2001-2002, 2006-2007, 2009-2012 Free
Software Foundation, Inc.

引用更多命令

除了使用 man 页面和 info 文档查找命令之外;这些工具也可以用来查看系统调用或配置文件等其他项目的文档。

举例来说,如果你使用 man 来搜索术语 signal,你会看到以下内容:

$ man signal
SIGNAL(2)
Linux Programmer's Manual
SIGNAL(2)

NAME
 signal - ANSI C signal handling

SYNOPSIS
 #include <signal.h>

 typedef void (*sighandler_t)(int);

 sighandler_t signal(int signum, sighandler_t handler);

DESCRIPTION
 The  behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.  See Portability below.

signal() sets the disposition of the signal signum to handler, which is either SIG_IGN, SIG_DFL, or the address of a programmer-defined  function  (a "signal handler").

Signal 是一个非常重要的系统调用和 Linux 的核心概念。知道可以使用 maninfo 命令来查找核心 Linux 概念和行为在故障排除过程中非常有用。

安装 man 页面

基于 Red Hat Enterprise Linux 的发行版通常包括 man-pages 包;如果你的系统没有安装 man-pages 包,你可以使用 yum 命令安装它:

# yum install man-pages

Red Hat 内核文档

除了 man 页面,Red Hat 发行版还有一个叫做kernel-doc的包。这个包包含了关于系统内部工作原理的大量信息。

内核文档是一组文本文件,放置在 /usr/share/doc/kernel-doc-<kernel-version>/ 中,并按其涵盖的主题进行分类。这个资源对于更深入的故障排除非常有用,比如调整内核可调整参数或理解 ext4 文件系统如何利用日志。

默认情况下,kernel-doc 包未安装,但可以使用 yum 命令轻松安装:

# yum install kernel-doc

人员

无论是朋友还是团队领导,在向他人寻求帮助时都有一定的礼仪。以下是人们在被要求解决问题时通常期望的事情列表。当我被要求帮助时,我希望你能:

  • 尝试自己解决问题:在升级问题时,最好至少尝试遵循故障排除过程中的理解问题形成假设步骤。

  • 记录你尝试过的内容:文档是升级问题或寻求帮助的关键。你记录的步骤和发现的错误越详细,其他人就越快地能够识别和解决问题。

  • 解释你认为问题是什么以及报告了什么:当你升级问题时,首先要指出的是你的假设。通常这可以帮助下一个人迅速找到可能的解决方案,而不必进行数据收集活动。

  • 提及最近这个系统是否发生了其他事情:问题通常是成对出现的,突出系统或受影响系统上发生的所有因素是很重要的。

上述列表虽然不全面,但每个关键信息都可以帮助下一个人有效地解决问题。

跟进

在升级问题时,最好跟进其他人,了解他们做了什么以及如何做的。这很重要,因为它会向你询问的人表明你愿意学习更多,这往往会导致他们花时间解释他们是如何解决和识别问题的。

这样的互动将使你获得更多知识,并帮助建立你的系统管理技能和经验。

文档

文档编制是故障排除过程中的关键步骤。在整个过程中,关键是要注意并记录正在执行的操作。为什么记录很重要?主要有三个原因:

  • 在升级问题时,你记录的信息越多,就能传递更多信息给其他人

  • 如果问题是一个再次发生的问题,文档可以用于更新团队 Wiki 或运行手册

  • 如果在你的环境中进行根本原因分析RCA),所有这些信息都将需要进行 RCA

根据环境的不同,文档可以是从保存在本地系统文本文件中的简单笔记到票务系统所需的笔记。每个工作环境都不同,但一个普遍规则是没有太多的文档

对于数据收集者来说,这一步相当自然。因为大多数数据收集者的个性通常会为自己保留相当多的笔记。对于受过教育的猜测者来说,这一步可能看起来是不必要的。然而,对于任何再次发生或需要升级的问题,文档都是至关重要的。

应该记录哪些信息?以下列表是一个很好的起点,但与大多数故障排除中的事情一样,它取决于环境和问题:

  • 问题陈述,你所理解的

  • 导致问题的假设。

  • 信息收集步骤中收集的数据:

  • 找到的具体错误

  • 相关系统指标(例如,CPU、内存和磁盘利用率)

  • 信息收集步骤中执行的命令(在合理范围内,不需要包括每个执行的cdls命令)

  • 尝试解决问题时采取的步骤,包括执行的具体命令

如果前面的项目有很好的记录,如果问题再次发生,将文档移至团队 Wiki 相对简单。这样做的好处是,其他需要在问题再次发生时解决相同问题的团队成员可以使用 Wiki 文章。

文档编制的三个原因之一是在根本原因分析期间使用文档,这将引出我们下一个话题——建立根本原因分析。

根本原因分析

根本原因分析是在事件发生后进行的过程。RCA 过程的目标是确定事件的根本原因,并确定可能的纠正措施,以防止同样的事件再次发生。这些纠正措施可能是简单的,比如建立用户培训,重新配置所有 Web 服务器上的 Apache。

RCA 过程并不局限于技术领域,在航空和职业安全等领域也是一种广泛实践的过程。在这些领域,事件往往不仅仅是几台计算机离线。这些事件可能会危及人的生命。

一个良好 RCA 的解剖结构

不同的工作环境可能以不同的方式实施 RCA 过程,但归根结底,每个良好的 RCA 都有一些关键要素:

  • 问题的报告情况

  • 问题的实际根本原因

  • 事件和采取的行动的时间表

  • 任何关键数据点

  • 防止事件再次发生的行动计划

问题的报告情况

故障排除过程中的第一步之一是确定问题;这些信息对 RCA 非常重要。根据问题的原因,其重要性可能有所不同。有时,这些信息将显示问题是否被正确识别。大多数时候,它可以作为问题影响的估计。

了解问题的影响可能非常重要,对于一些公司和问题,这可能意味着收入损失;对于其他公司,这可能意味着损害其品牌,或者根据问题的严重程度,可能什么都不意味着。

问题的实际根本原因

根本原因分析的这一要素在其重要性上相当不言而喻。然而,有时可能无法确定根本原因。在本章和第十二章中,我将讨论如何处理无法获得完整根本原因的问题。

事件和采取的行动的时间表

如果我们以航空事件为例,很容易看出事件时间表的重要性,比如飞机何时起飞,何时乘客登机,以及维护人员何时完成评估,这些都可能很有用。技术事件的时间表也可能非常有用,因为它可以用来确定影响的持续时间以及采取关键行动的时间。

一个良好的时间表应该包括事件的时间和主要事件。以下是技术事件的时间表示例:

  • 08:00,Joe B.打电话给 NOC 热线,报告 Tempe 的电子邮件服务器中断

  • 08:15,John C.登录到 Tempe 的电子邮件服务器,注意到它们的可用内存不足。

  • 08:17,根据 Runbook,John C.开始逐个重新启动 Tempe 的电子邮件服务器

验证根本原因的任何关键数据点

除了事件时间表之外,RCA 还应包括关键数据点。再次以航空事故为例,关键数据点可能是事故期间的天气条件,参与人员的工作时间,或飞机的状况。

我们的时间表示例包括一些关键数据点,其中包括:

  • 事故时间:08:00

  • 电子邮件服务器的状况:可用内存不足

  • 受影响的服务:电子邮件

无论数据点是独立的还是在时间表内,都很重要确保这些数据点在 RCA 中得到充分记录。

防止事故再次发生的行动计划

执行根本原因分析的整个目的是确定为什么发生了事故以及防止再次发生的行动计划。

不幸的是,我看到许多 RCA 忽视了这一点。RCA 流程在实施良好时可能很有用;然而,当实施不当时,它们可能会变成浪费时间和资源。

通常,对于实施不良的情况,您会发现需要对每个大或小的事件进行 RCA。这样做的问题在于,它会导致 RCA 的质量降低。只有在事件造成重大影响时才应执行 RCA。例如,硬件故障是无法预防的,您可以使用诸如smartd之类的工具主动识别硬盘故障,但除了更换它们之外,您并不能总是防止它们发生故障。要求对每次硬件故障和更换进行 RCA 是 RCA 流程实施不当的一个例子。

当工程师需要确定像硬件故障这样常见的问题的根本原因时,他们忽视了根本原因的过程。当工程师忽视某种类型的事件的 RCA 过程时,它可能会扩散到其他类型的事件,导致 RCA 的质量下降。

根本原因分析应该只针对具有重大影响的事件。轻微事件或例行事件不应该有根本原因分析的要求;但是,它们应该被跟踪。通过跟踪已更换的硬盘数量以及这些硬盘的品牌和型号,可以识别硬件质量问题。对于重置用户密码等例行事件也是如此。通过跟踪这些类型的事件,可以识别可能的改进领域。

建立根本原因

为了更好地理解根本原因分析过程,让我们使用在生产环境中看到的一个假设问题。

注意

在写入文件时,一个 Web 应用程序崩溃了

登录系统后,你发现应用程序崩溃是因为应用程序尝试写入的文件系统已满。

注意

根本原因并不总是显而易见的原因

问题的根本原因是文件系统满了吗?不是。虽然文件系统满可能导致应用程序崩溃,但这被称为一个促成因素。促成因素,如文件系统满,可以纠正,但这不会防止问题再次发生。

在这一点上,重要的是要确定文件系统为什么会满。进一步调查后,你发现是因为一位同事禁用了一个删除旧应用程序文件的定时任务。在禁用了定时任务后,文件系统上的可用空间逐渐减少。最终,文件系统被 100%利用。

在这种情况下,问题的根本原因是禁用的定时任务。

有时你必须牺牲根本原因分析

让我们看另一个假设情况,一个问题导致了停机。由于问题造成了重大影响,它绝对需要进行根本原因分析。问题是,为了解决问题,你需要执行一项活动,这将消除进行准确根本原因分析的可能性。

这些情况有时需要判断,是选择忍受停机更长时间,还是解决停机并牺牲进行根本原因分析的机会。不幸的是,对于这些情况没有单一答案,正确答案取决于问题和受影响的环境。

提示

在处理财务系统时,我经常发现自己不得不做出这个决定。对于关键任务系统,答案几乎总是恢复服务优先于进行根本原因分析。然而,只要可能,总是首选首先捕获数据,即使这些数据不能立即审查。

了解你的环境

本章的最后一节是我能提出的最重要的最佳实践之一。最后一节涵盖了了解你的环境的重要性。

有些人认为系统管理员的工作止步于系统上安装的应用程序,系统管理员只应关注操作系统及其组件,如网络或文件系统。

我不赞同这种观点。事实上,通常情况下,系统管理员会开始比创建它的开发团队更好地了解应用程序在生产中的工作方式。

根据我的经验,为了真正支持服务器,你必须了解在该服务器内运行的服务和应用程序。例如,在许多企业环境中,系统管理员被期望处理 Web 服务器的配置和管理(例如,Apache 和 Nginx)。然而,同一系统管理员不被期望管理 Apache 后面的应用程序(例如,Java 和 C)。

Apache 与 Java 应用程序有何不同?答案实际上是没有什么不同;归根结底,它们都是在服务器上运行的应用程序。我看到许多管理员一旦问题与应用程序有关,就会简单地放手不管。然而,如果问题与 Apache 有关,他们就会迅速采取行动。

最后,如果这些管理团队与开发团队合作,问题可以更快地得到解决。管理员有责任了解并帮助解决系统上加载的任何软件的问题,无论是操作系统分发的软件还是后来由应用团队安装的软件。

总结

在本章中,您了解到故障排除有两种主要风格,直觉式(有经验的猜测者)和系统化(数据收集者)。我们介绍了哪些故障排除步骤对这两种风格最有效,以及一些人(适应者)可以利用这两种风格的故障排除。

在本书的后续章节中,当我们排除现实生活中的场景时,我将利用本章讨论的过程中突出的直觉和系统化的故障排除步骤。

本章没有涉及技术细节;下一章将充满技术细节,我们将介绍和探讨用于故障排除的常见 Linux 命令。

第二章:故障排除命令和有用信息的来源

在第一章中,我们介绍了故障排除的最佳实践和涉及的高级流程。第一章是对故障排除的 20,000 英尺视图,而本章开始深入具体内容。

本章将回顾常见的故障排除命令以及查找有用信息的常见位置。在本书中,我们将使用 Red Hat Enterprise Linux 的 7 版(也称为 RHEL)。本章引用的所有命令都是 RHEL 7 默认安装包中包含的命令。

我们将引用默认安装的命令,因为我发现自己曾经处于这样的情况,我本可以使用特定的命令立即识别问题,但是这个命令对我不可用。通过将本章限制为默认命令,您可以确保本章涵盖的故障排除步骤不仅与大多数 RHEL 7 安装相关,而且与以前的版本和其他 Linux 发行版相关。

查找有用信息

在开始探索故障排除命令之前,我首先想要介绍有用信息的位置。有用信息是一个模糊的术语,几乎每个文件、目录或命令都可以提供有用信息。我真正打算介绍的是几乎可以找到几乎任何问题的信息的位置。

日志文件

日志文件通常是查找故障排除信息的第一个地方。每当服务或服务器遇到问题时,检查错误日志文件通常可以迅速回答许多问题。

默认位置

默认情况下,RHEL 和大多数 Linux 发行版将其日志文件保存在/var/log/中,这实际上是由 Linux 基金会维护的文件系统层次结构标准FHS)的一部分。但是,虽然/var/log/可能是默认位置,并非所有日志文件都位于那里(en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard)。

虽然/var/log/httpd/是 Apache 日志的默认位置,但可以通过 Apache 的配置文件更改此位置。当 Apache 安装在标准 RHEL 软件包之外时,这是非常常见的。

与 Apache 一样,大多数服务允许自定义日志位置。在/var/log之外找到专门用于日志文件的自定义目录或文件系统并不罕见。

常见日志文件

以下表格是常见日志文件的简要列表,以及您可以在其中找到的内容的描述。

提示

请记住,此列表特定于 Red Hat Enterprise Linux 7,而其他 Linux 发行版可能遵循类似的约定,但不能保证。

日志文件描述
/var/log/messages默认情况下,此日志文件包含所有INFO或更高优先级的 syslog 消息(除电子邮件)。

| /var/log/secure | 此日志文件包含与身份验证相关的消息项,例如:

  • SSH 登录

  • 用户创建

  • Sudo 违规和权限提升

|

/var/log/cron此日志文件包含crond执行的历史记录,以及cron.dailycron.weekly和其他执行的开始和结束时间。
/var/log/maillog这个日志文件是邮件事件的默认日志位置。如果使用 postfix,这是所有与 postfix 相关的消息的默认位置。
/var/log/httpd/此日志目录是 Apache 日志的默认位置。虽然这是默认位置,但并不是所有 Apache 日志的保证位置。
/var/log/mysql.log这个日志文件是 mysqld 的默认日志文件。与httpd日志一样,这是默认的,可以很容易地更改。
/var/log/sa/此目录包含默认每 10 分钟运行一次的sa命令的结果。我们将在本章的后续部分以及本书的整个过程中更多地利用这些数据。

对于许多问题,要审查的第一个日志文件之一是/var/log/messages日志。在 RHEL 系统上,这个日志文件接收所有INFO优先级或更高级别的系统日志。一般来说,这意味着发送到syslog的任何重要事件都会在这个日志文件中被捕获。

以下是可以在/var/log/messages中找到的一些日志消息的示例:

Dec 24 18:03:51 localhost systemd: Starting Network Manager Script Dispatcher Service...
Dec 24 18:03:51 localhost dbus-daemon: dbus[620]: [system] Successfully activated service 'org.freedesktop.nm_dispatcher'
Dec 24 18:03:51 localhost dbus[620]: [system] Successfully activated service 'org.freedesktop.nm_dispatcher'
Dec 24 18:03:51 localhost systemd: Started Network Manager Script Dispatcher Service.
Dec 24 18:06:06 localhost kernel: e1000: enp0s3 NIC Link is Down
Dec 24 18:06:06 localhost kernel: e1000: enp0s8 NIC Link is Down
Dec 24 18:06:06 localhost NetworkManager[750]: <info> (enp0s3): link disconnected (deferring action for 4 seconds)
Dec 24 18:06:06 localhost NetworkManager[750]: <info> (enp0s8): link disconnected (deferring action for 4 seconds)
Dec 24 18:06:10 localhost NetworkManager[750]: <info> (enp0s3): link disconnected (calling deferred action)
Dec 24 18:06:10 localhost NetworkManager[750]: <info> (enp0s8): link disconnected (calling deferred action)
Dec 24 18:06:12 localhost kernel: e1000: enp0s3 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
Dec 24 18:06:12 localhost kernel: e1000: enp0s8 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
Dec 24 18:06:12 localhost NetworkManager[750]: <info> (enp0s3): link connected
Dec 24 18:06:12 localhost NetworkManager[750]: <info> (enp0s8): link connected
Dec 24 18:06:39 localhost kernel: atkbd serio0: Spurious NAK on isa0060/serio0\. Some program might be trying to access hardware directly.
Dec 24 18:07:10 localhost systemd: Starting Session 53 of user root.
Dec 24 18:07:10 localhost systemd: Started Session 53 of user root.
Dec 24 18:07:10 localhost systemd-logind: New session 53 of user root.

正如我们所看到的,在这个示例中有不止一条日志消息可能在故障排除问题时非常有用。

寻找不在默认位置的日志

很多时候日志文件不在/var/log/中,这可能是因为有人修改了日志位置到默认位置之外的某个地方,或者仅仅是因为相关服务默认使用另一个位置。

一般来说,有三种方法可以找到不在/var/log/中的日志文件。

检查 syslog 配置

如果您知道某个服务正在使用 syslog 进行日志记录,查找其消息写入的日志文件的最佳位置是rsyslog配置文件。rsyslog 服务有两个配置位置。第一个是/etc/rsyslog.d目录。

/etc/rsyslog.d目录是自定义 rsyslog 配置的包含目录。第二个是/etc/rsyslog.conf配置文件。这是 rsyslog 的主配置文件,包含许多默认的 syslog 配置。

以下是/etc/rsyslog.conf的默认内容示例:

#### RULES ####

# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.*                              /dev/console

# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none  /var/log/messages

# The authpriv file has restricted access.
authpriv.*                           /var/log/secure

# Log all the mail messages in one place.
mail.*                              -/var/log/maillog

# Log cron stuff
cron.*                               /var/log/cron

通过审查这个文件的内容,很容易确定哪些日志文件包含所需的信息,如果不行,至少可以确定 syslog 管理的日志文件的可能位置。

检查应用程序的配置

并非每个应用程序都使用 syslog;对于那些不使用的应用程序,找到应用程序的日志文件的最简单方法之一是阅读应用程序的配置文件。

从配置文件中查找日志文件位置的一种快速有用的方法是使用grep命令在文件中搜索单词log

$ grep log /etc/samba/smb.conf
# files are rotated when they reach the size specified with "max log size".
  # log files split per-machine:
  log file = /var/log/samba/log.%m
  # maximum size of 50KB per log file, then rotate:
  max log size = 50
grep command is used to search the /etc/samba/smb.conf file for any instance of the pattern "log".

在审查上述grep命令的输出后,我们可以看到 samba 的配置日志位置是/var/log/samba/log.%m。需要注意的是,在这个例子中,%m实际上是在创建文件时用“机器名称”替换的。这实际上是 samba 配置文件中的一个变量。这些变量对每个应用程序都是唯一的,但这种动态配置值的方法是一种常见的做法。

其他例子

以下是使用grep命令在 Apache 和 MySQL 配置文件中搜索单词“log”的示例:

$ grep log /etc/httpd/conf/httpd.conf
# ErrorLog: The location of the error log file.
# logged here.  If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
ErrorLog "logs/error_log"

$ grep log /etc/my.cnf
# log_bin
log-error=/var/log/mysqld.log

在这两种情况下,这种方法能够识别服务日志文件的配置参数。通过前面的三个例子,很容易看出搜索配置文件的效果有多好。

使用 find 命令

我们将在本章后面深入介绍的find命令是另一种查找日志文件的有用方法。find命令用于在目录结构中搜索指定的文件。查找日志文件的快速方法是简单地使用find命令搜索以“.log”结尾的任何文件:

# find /opt/appxyz/ -type f -name "*.log"
/opt/appxyz/logs/daily/7-1-15/alert.log
/opt/appxyz/logs/daily/7-2-15/alert.log
/opt/appxyz/logs/daily/7-3-15/alert.log
/opt/appxyz/logs/daily/7-4-15/alert.log
/opt/appxyz/logs/daily/7-5-15/alert.log

上述通常被认为是最后的解决方案,大多数情况下是在之前的方法没有产生结果时使用。

提示

执行find命令时,最好的做法是非常具体地指定要搜索的目录。当针对非常大的目录执行时,服务器的性能可能会下降。

配置文件

如前所述,应用程序或服务的配置文件可以是信息的绝佳来源。虽然配置文件不会提供特定的错误,比如日志文件,但它们可以提供关键信息(例如启用/禁用的功能、输出目录和日志文件位置)。

默认系统配置目录

一般来说,大多数 Linux 发行版的系统和服务配置文件位于/etc/目录中。但这并不意味着每个配置文件都位于/etc/目录中。事实上,应用程序通常会在应用程序的home目录中包含一个配置目录。

那么,如何知道何时在/etc/而不是应用程序目录中查找配置文件?一个经验法则是,如果软件包是 RHEL 发行版的一部分,可以安全地假设配置位于/etc/目录中。其他任何东西可能存在于/etc/目录中,也可能不存在。对于这些情况,你只需要去寻找它们。

查找配置文件

在大多数情况下,可以使用ls命令对/etc/目录进行简单的目录列表,以找到系统配置文件:

$ ls -la /etc/ | grep my
-rw-r--r--.  1 root root      570 Nov 17  2014 my.cnf
drwxr-xr-x.  2 root root       64 Jan  9  2015 my.cnf.d
ls to perform a directory listing and redirects that output to grep in order to search the output for the string "my". We can see from the output that there is a my.cnf configuration file and a my.cnf.d configuration directory. The MySQL processes use these for its configuration. We were able to find these by assuming that anything related to MySQL would have the string "my" in it.

使用 rpm 命令

如果配置文件是作为 RPM 软件包的一部分部署的,可以使用rpm命令来识别配置文件。为此,只需执行带有-q(查询)标志和-c(configfiles)标志的rpm命令,然后跟上软件包的名称:

$ rpm -q -c httpd
/etc/httpd/conf.d/autoindex.conf
/etc/httpd/conf.d/userdir.conf
/etc/httpd/conf.d/welcome.conf
/etc/httpd/conf.modules.d/00-base.conf
/etc/httpd/conf.modules.d/00-dav.conf
/etc/httpd/conf.modules.d/00-lua.conf
/etc/httpd/conf.modules.d/00-mpm.conf
/etc/httpd/conf.modules.d/00-proxy.conf
/etc/httpd/conf.modules.d/00-systemd.conf
/etc/httpd/conf.modules.d/01-cgi.conf
/etc/httpd/conf/httpd.conf
/etc/httpd/conf/magic
/etc/logrotate.d/httpd
/etc/sysconfig/htcacheclean
/etc/sysconfig/httpd

rpm命令用于管理 RPM 软件包,在故障排除时非常有用。在下一节中,我们将进一步介绍这个命令,以探索故障排除的命令。

使用 find 命令

与查找日志文件类似,要在系统上查找配置文件,可以利用find命令。在搜索日志文件时,find命令用于搜索所有文件名以“.log”结尾的文件。在下面的例子中,find命令用于搜索所有文件名以“http”开头的文件。这个find命令应该至少返回一些结果,这些结果将提供与 HTTPD(Apache)服务相关的配置文件:

# find /etc -type f -name "http*"

/etc/httpd/conf/httpd.conf
/etc/sysconfig/httpd
/etc/logrotate.d/httpd

前面的例子搜索了/etc目录;然而,这也可以用于搜索任何应用程序的主目录以查找用户配置文件。与搜索日志文件类似,使用find命令搜索配置文件通常被认为是最后的手段,不应该是第一个使用的方法。

proc 文件系统

proc文件系统是一个非常有用的信息来源。这是由 Linux 内核维护的一个特殊文件系统。proc文件系统可用于查找有关运行进程以及其他系统信息的有用信息。例如,如果我们想要识别系统支持的文件系统,我们可以简单地读取/proc/filesystems文件:

$ cat /proc/filesystems
nodev  sysfs
nodev  rootfs
nodev  bdev
nodev  proc
nodev  cgroup
nodev  cpuset
nodev  tmpfs
nodev  devtmpfs
nodev  debugfs
nodev  securityfs
nodev  sockfs
nodev  pipefs
nodev  anon_inodefs
nodev  configfs
nodev  devpts
nodev  ramfs
nodev  hugetlbfs
nodev  autofs
nodev  pstore
nodev  mqueue
nodev  selinuxfs
  xfs
nodev  rpc_pipefs
nodev  nfsd

这个文件系统非常有用,包含了关于运行系统的大量信息。proc 文件系统将在本书的故障排除步骤中使用。它在故障排除各种问题时以不同的方式使用,从特定进程到只读文件系统。

故障排除命令

本节将介绍经常使用的故障排除命令,这些命令可用于从系统或运行的服务中收集信息。虽然不可能涵盖每个可能的命令,但所使用的命令确实涵盖了 Linux 系统的基本故障排除步骤。

命令行基础知识

本书中使用的故障排除步骤主要基于命令行。虽然可能可以从图形桌面环境执行许多这些操作,但更高级的项目是命令行特定的。因此,本书假设读者至少具有对 Linux 的基本理解。更具体地说,本书假设读者已经通过 SSH 登录到服务器,并熟悉基本命令,如cdcpmvrmls

对于那些可能不太熟悉的人,我想快速介绍一些基本的命令行用法,这将是本书所需的基本知识。

命令标志

许多读者可能熟悉以下命令:

$ ls -la
total 588
drwx------. 5 vagrant vagrant   4096 Jul  4 21:26 .
drwxr-xr-x. 3 root    root        20 Jul 22  2014 ..
-rw-rw-r--. 1 vagrant vagrant 153104 Jun 10 17:03 app.c

大多数人应该认识到这是ls命令,用于执行目录列表。可能不熟悉的是命令的“-la”部分是什么或者做什么。为了更好地理解这一点,让我们单独看一下 ls 命令:

$ ls
app.c  application  app.py  bomber.py  index.html  lookbusy-1.4  lookbusy-1.4.tar.gz  lotsofiles

先前执行的ls命令与以前的看起来非常不同。这是因为后者是ls的默认输出。命令标志允许用户更改命令的默认行为,为其提供特定选项。

实际上,“-la”标志是两个单独的选项,“-l”和“-a”;它们甚至可以分开指定:

 $ ls -l -a
total 588
drwx------. 5 vagrant vagrant   4096 Jul  4 21:26 .
drwxr-xr-x. 3 root    root        20 Jul 22  2014 ..
-rw-rw-r--. 1 vagrant vagrant 153104 Jun 10 17:03 app.c
ls –la is exactly the same as ls –l –a. For common commands, such as the ls command, it does not matter if the flags are grouped or separated, they will be parsed in the same way. Throughout this book, examples will show both grouped and ungrouped. If grouping or ungrouping is performed for any specific reason it will be called out; otherwise, the grouping or ungrouping used within this book is used for visual appeal and memorization.

除了分组和取消分组,本书还将以长格式显示标志。在前面的例子中,我们显示了标志-a,这被称为短标志。这个选项也可以以长格式--all提供:

$ ls -l --all
total 588
drwx------. 5 vagrant vagrant   4096 Jul  4 21:26 .
drwxr-xr-x. 3 root    root        20 Jul 22  2014 ..
-rw-rw-r--. 1 vagrant vagrant 153104 Jun 10 17:03 app.c

“-a”和--all标志本质上是相同的选项;它可以简单地以短格式和长格式表示。

一个重要的事情要记住的是,并非每个短标志都有长形式,反之亦然。每个命令都有自己的语法,有些命令只支持短形式,其他命令只支持长形式,但许多命令都支持两种形式。在大多数情况下,长标志和短标志都将在命令的手册页面中得到记录。

管道命令输出

本书中将多次使用的另一种常见的命令行实践是将输出“传输”。具体来说,例如以下示例:

$ ls -l --all | grep app
-rw-rw-r--. 1 vagrant vagrant 153104 Jun 10 17:03 app.c
-rwxrwxr-x. 1 vagrant vagrant  29390 May 18 00:47 application
-rw-rw-r--. 1 vagrant vagrant   1198 Jun 10 17:03 app.py

在前面的例子中,ls -l --all的输出被传输到grep命令。通过在两个命令之间放置|或管道字符,第一个命令的输出被“传输”到第二个命令的输入。将执行ls命令的示例;随后,grep命令将搜索该输出中的任何app模式的实例。

在本书中,将经常使用将输出传输到grep,因为这是将输出修剪为可维护大小的简单方法。许多时候,示例还将包含多个级别的管道:

$ ls -la | grep app | awk '{print $4,$9}'
vagrant app.c
vagrant application
vagrant app.py

在前面的代码中,ls -la的输出被传输到grep的输入;然而,这一次,grep的输出也被传输到awk的输入。

虽然许多命令可以进行管道传输,但并非每个命令都支持这一点。一般来说,接受来自文件或命令行的用户输入的命令也接受管道输入。与标志一样,命令的手册页面可用于确定命令是否接受管道输入。

收集一般信息

在长时间管理相同服务器时,您开始记住关于这些服务器的关键信息。例如物理内存的数量,文件系统的大小和布局,以及应该运行的进程。但是,当您不熟悉所讨论的服务器时,收集这种类型的信息总是一个好主意。

本节中的命令是用于收集此类一般信息的命令。

w-显示谁登录了以及他们在做什么

在我系统管理职业生涯的早期,我有一个导师告诉我:我每次登录服务器时都会运行 w。这个简单的提示实际上在我的职业生涯中一次又一次地非常有用。w命令很简单;当执行时,它将输出系统正常运行时间,平均负载以及谁登录了:

# w
 04:07:37 up 14:26,  2 users,  load average: 0.00, 0.01, 0.05
USER     TTY        LOGIN@   IDLE   JCPU   PCPU WHAT
root     tty1      Wed13   11:24m  0.13s  0.13s -bash
root     pts/0     20:47    1.00s  0.21s  0.19s -bash

当与不熟悉的系统一起工作时,这些信息可能非常有用。即使您熟悉该系统,输出也可能很有用。通过这个命令,您可以看到:

  • 上次系统重启时:

04:07:37 up 14:26:这些信息可能非常有用;无论是像 Apache 服务宕机的警报,还是用户因为被系统锁定而打进来。当这些问题是由意外重启引起时,报告的问题通常不包括这些信息。通过运行w命令,很容易看到自上次重启以来经过的时间。

  • 系统的平均负载:

平均负载:0.00, 0.01, 0.05:平均负载是系统健康的一个非常重要的衡量标准。总结一下,平均负载是一段时间内处于等待状态的进程的平均数量。w命令输出中的三个数字代表不同的时间。

这些数字从左到右依次是 1 分钟、5 分钟和 15 分钟。

  • 谁登录了以及他们在运行什么:

  • USER TTY LOGIN@ IDLE JCPU PCPU WHAT

  • root tty1 Wed13 11:24m 0.13s 0.13s -bash

w命令提供的最后一条信息是当前登录的用户以及他们正在执行的命令。

这基本上与who命令的输出相同,包括已登录的用户、他们登录的时间、他们已经空闲了多长时间,以及他们的 shell 正在运行的命令。列表中的最后一项非常重要。

在与大团队合作时,往往会有多个人响应一个问题或工单是很常见的。在登录后立即运行w命令,你将看到其他用户在做什么,避免你覆盖其他人已经采取的故障排除或纠正步骤。

rpm – RPM 软件包管理器

rpm命令用于管理Red Hat 软件包管理器RPM)。使用这个命令,你可以安装和删除 RPM 软件包,以及搜索已安装的软件包。

在本章的前面,我们看到rpm命令可以用来查找配置文件。以下是我们可以使用rpm命令查找关键信息的几种额外方式。

列出所有安装的软件包

在故障排除服务时,一个关键的步骤是确定服务的版本以及它是如何安装的。要列出系统上安装的所有 RPM 软件包,只需执行带有-q(查询)和-a(所有)的rpm命令:

# rpm -q -a
kpatch-0.0-1.el7.noarch
virt-what-1.13-5.el7.x86_64
filesystem-3.2-18.el7.x86_64
gssproxy-0.3.0-9.el7.x86_64
hicolor-icon-theme-0.12-7.el7.noarch

rpm命令是一个非常多样化的命令,有很多标志。在前面的例子中使用了-q-a标志。-q标志告诉rpm命令正在进行的操作是一个查询;你可以把它想象成进入了“搜索模式”。-a--all标志告诉rpm命令列出所有软件包。

一个有用的功能是在前面的命令中添加--last标志,因为这会导致rpm命令按安装时间列出软件包,最新的排在最前面。

列出软件包部署的所有文件

另一个有用的rpm功能是显示特定软件包部署的所有文件:

# rpm -q --filesbypkg kpatch-0.0-1.el7.noarch
kpatch                    /usr/bin/kpatch
kpatch                    /usr/lib/systemd/system/kpatch.service

在前面的例子中,我们再次使用-q标志来指定我们正在运行一个查询,以及--filesbypkg标志。--filesbypkg标志将导致rpm命令列出指定软件包部署的所有文件。

当试图确定服务的配置文件位置时,这个例子非常有用。

使用软件包验证

在这第三个例子中,我们将使用rpm的一个非常有用的功能——验证。rpm命令有能力验证指定软件包部署的文件是否已经被更改。为了做到这一点,我们将使用-V(验证)标志:

# rpm -V httpd
S.5....T.  c /etc/httpd/conf/httpd.conf

在前面的例子中,我们只是运行了带有-V标志的rpm命令,后面跟着一个软件包名称。由于-q标志用于查询,-V标志用于验证。使用这个命令,我们可以看到只有/etc/httpd/conf/httpd.conf文件被列出;这是因为rpm只会输出已经被更改的文件。

在这个输出的第一列中,我们可以看到文件失败的验证检查。虽然这一列起初有点神秘,但 rpm 手册中有一个有用的表格(如下列表所示),解释了每个字符的含义:

  • S: 这意味着文件大小不同

  • M: 这意味着模式不同(包括权限和文件类型)

  • 5: 这意味着摘要(以前是MD5 校验和)不同

  • D: 这意味着设备主/次编号不匹配

  • L: 这意味着readLink(2)路径不匹配

  • U: 这意味着用户所有权不同

  • G: 这意味着组所有权不同

  • T: 这意味着mTime不同

  • P: 这意味着caPabilities不同

使用这个列表,我们可以看到httpd.conf文件大小、MD5校验和和mtime(修改时间)与httpd.rpm部署的不同。这意味着很可能httpd.conf文件在安装后被修改过。

虽然rpm命令一开始可能不像是一个故障排除命令,但前面的例子显示了它实际上是一个多么强大的故障排除工具。通过这些例子,很容易识别重要文件以及这些文件是否已经从部署版本中修改。

df - 报告文件系统空间使用情况

df命令在故障排除文件系统问题时非常有用。df命令用于输出已挂载文件系统的空间利用情况:

# df -h
Filesystem             Size  Used Avail Use% Mounted on
/dev/mapper/rhel-root  6.7G  1.6G  5.2G  24% /
devtmpfs               489M     0  489M   0% /dev
tmpfs                  498M     0  498M   0% /dev/shm
tmpfs                  498M   13M  485M   3% /run
tmpfs                  498M     0  498M   0% /sys/fs/cgroup
/dev/sdb1              212G   58G  144G  29% /repos
/dev/sda1              497M  117M  380M  24% /boot

在前面的例子中,df命令包括了-h标志。这个标志会导致df命令以“人类可读”的格式打印任何大小值。默认情况下,df会简单地以千字节打印这些值。从例子中,我们可以快速看到所有挂载文件系统的当前使用情况。具体来说,如果我们看输出,我们可以看到/filesystem目前使用了 24%:

Filesystem             Size  Used Avail Use% Mounted on
/dev/mapper/rhel-root  6.7G  1.6G  5.2G  24% /

这是一个非常快速简单的方法来识别任何文件系统是否已满。此外,df命令还非常有用,可以显示已挂载的文件系统的详细信息以及它们被挂载到哪里。从包含/filesystem的那一行,我们可以看到底层设备是/dev/mapper/rhel-root

通过这个命令,我们能够识别出两个关键信息。

显示可用的 inode

df的默认行为是显示已使用的文件系统空间量。但是,它也可以用来显示每个文件系统可用、已使用和空闲的inodes数量。要输出 inode 利用率,只需在执行df命令时添加-i(inode)标志:

# df -i
Filesystem              Inodes IUsed    IFree IUse% Mounted on
/dev/mapper/rhel-root  7032832 44318  6988514    1% /
devtmpfs                125039   347   124692    1% /dev

仍然可以使用-h标志与df一起以人类可读的格式打印输出。但是,使用-i标志,这将把输出缩写为M表示百万,K表示千,依此类推。这个输出很容易与兆字节或千字节混淆,所以一般情况下,我不会在与其他用户/管理员共享输出时使用人类可读的 inode 输出。

free - 显示内存利用率

执行free命令时,将输出系统上可用内存和已使用内存的统计信息:

$ free
             total       used       free     shared    buffers     cached
Mem:       1018256     789796     228460      13116       3608     543484
-/+ buffers/cache:     242704     775552
Swap:       839676          4     839672

从前面的例子可以看出,free命令的输出提供了总可用内存、当前使用的内存量和空闲内存量。free命令是识别系统内存当前状态的一种简单快速的方式。

然而,free的输出一开始可能有点令人困惑。

所谓的空闲,并不总是空闲

Linux 与其他操作系统相比,利用内存的方式不同。在前面的输出中,您将看到有 543,484 KB 被列为缓存。这个内存,虽然在技术上被使用,实际上是可用内存的一部分。系统可以根据需要重新分配这个缓存内存。

一个快速简单的方法来查看实际使用或空闲的内容可以在输出的第二行看到。前面的输出显示系统上有 775,552 KB 的内存可用。

/proc/meminfo 文件

在以前的 RHEL 版本中,free命令的第二行是识别可用内存量的最简单方法。但是,随着 RHEL 7,/proc/meminfo文件已经进行了一些改进。其中一个改进是增加了MemAvailable统计信息:

$ grep Available /proc/meminfo
MemAvailable:     641056 kB

/proc/meminfo文件是位于/proc文件系统中的许多有用文件之一。该文件由内核维护,包含系统当前的内存统计信息。在排除内存问题时,此文件非常有用,因为它包含的信息比free命令的输出要多得多。

ps – 报告当前运行进程的快照

ps命令是任何故障排除活动的基本命令。执行此命令将输出运行进程的列表:

# ps
  PID TTY          TIME CMD
15618 pts/0    00:00:00 ps
17633 pts/0    00:00:00 bash

ps命令有许多标志和选项,可显示有关运行进程的不同信息。以下是一些在故障排除期间有用的ps命令示例。

以长格式打印每个进程

以下ps命令使用-e(所有进程)、-l(长格式)和-f(完整格式)标志。这些标志将导致ps命令不仅打印每个进程,还将以提供相当多有用信息的格式打印它们:

# ps -elf
F S UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY   TIME CMD
1 S root   2     0   0  80  0 - 0 kthrea Dec24 ?   00:00:00 [kthreadd]

ps -elf的前面输出中,我们可以看到kthreadd进程的许多有用信息,例如父进程 IDPPID)、优先级PRI)、niceness 值NI)和运行进程的驻留内存大小SZ)。

我发现前面的示例是一个非常通用的ps命令,可以在大多数情况下使用。

打印特定用户的进程

前面的示例可能会变得非常庞大,使得难以识别特定进程。此示例使用-U标志来指定用户。这会导致ps命令打印作为指定用户运行的所有进程;在以下情况下是后缀:

ps -U postfix -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY       TIME CMD
4 S    89  1546  1536  0  80   0 - 23516 ep_pol ?    00:00:00 qmgr
4 S    89 16711  1536  0  80   0 - 23686 ep_pol ?  00:00:00 pickup

需要注意的是,–U标志也可以与其他标志结合使用,以提供有关运行进程的更多信息。在前面的示例中,-l标志再次用于以长格式打印输出。

按进程 ID 打印进程

如果进程 ID 或 PID 已知,可以通过指定–p(进程 ID)标志来进一步缩小进程列表:

# ps -p 1236 -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY       TIME CMD
4 S     0  1236     1  0  80   0 - 20739 poll_s ?    00:00:00 sshd

当与–L(显示带有 LWP 列的线程)或–m(显示进程后的线程)标志结合使用时,这可能特别有用,这些标志用于打印进程线程。在排除多线程应用程序故障时,-L-m标志可能至关重要。

打印带有性能信息的进程

ps命令允许用户使用-o(用户定义格式)标志自定义打印的列:

# ps -U postfix -o pid,user,pcpu,vsz,cmd
  PID USER     %CPU    VSZ CMD
 1546 postfix   0.0  94064 qmgr -l -t unix -u
16711 postfix   0.0  94744 pickup -l -t unix -u

–o选项允许使用许多自定义列。在前面的版本中,我选择了与 top 命令中打印的类似的选项。

top 命令是最受欢迎的 Linux 故障排除命令之一。它用于按 CPU 使用率(默认情况下)显示前几个进程。在本章中,我选择省略 top 命令,因为我认为ps命令比 top 命令更基本和灵活。随着对ps命令的熟悉,学习和理解 top 命令将变得容易。

网络

网络对于任何系统管理员来说都是一项基本技能。没有正确配置的网络接口,服务器就没有多大用处。本节中的命令专门用于查找网络配置和当前状态。这些命令是必须学习的,因为它们不仅对故障排除有用,而且对日常设置和配置也很有用。

ip – 显示和操作网络设置

ip命令用于管理网络设置,如接口配置、路由和基本上与网络相关的任何内容。虽然这些通常不被认为是故障排除任务,但ip命令也可以用于显示系统的网络配置。如果无法查找网络详细信息,如路由或设备配置,将很难排除与网络相关的问题。

以下示例展示了使用ip命令识别关键网络配置设置的各种方法。

显示特定设备的 IP 地址配置

ip命令的一个核心用途是查找网络接口并显示其配置。为了做到这一点,我们将使用以下命令:

# ip addr show dev enp0s3
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:6e:35:18 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3
       valid_lft 45083sec preferred_lft 45083sec
    inet6 fe80::a00:27ff:fe6e:3518/64 scope link
       valid_lft forever preferred_lft forever

在前面的ip命令中,提供的第一个选项addr(地址)用于定义我们要查找的信息类型。第二个选项show告诉ip显示第一个选项的配置。第三个选项dev(设备)后面跟着所讨论的网络接口设备;enp0s3。如果省略了第三个选项,ip命令将显示所有网络设备的地址配置。

对于那些有经验的 RHEL 之前版本的人来说,设备名称enp0s3可能看起来有点奇怪。这个设备遵循了systemd引入的较新的网络设备命名方案。从 RHEL 7 开始,网络设备将使用基于设备驱动程序和 BIOS 详细信息的设备名称。

要了解更多关于 RHEL 7 的新命名方案的信息,请参考以下 URL:

access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/ch-Consistent_Network_Device_Naming.html

显示路由配置

ip命令还可以用于显示路由配置。这些信息对于排除服务器之间的连接问题至关重要。

# ip route show
default via 10.0.2.2 dev enp0s3  proto static  metric 1024
10.0.2.0/24 dev enp0s3  proto kernel  scope link  src 10.0.2.15
192.168.56.0/24 dev enp0s8  proto kernel  scope link  src 192.168.56.101

前面的ip命令使用route选项,后面跟着show选项来显示此服务器的所有定义路由。与前面的例子一样,也可以通过添加dev(设备)选项后跟设备名称来限制此输出到特定设备:

# ip route show dev enp0s3
default via 10.0.2.2  proto static  metric 1024
10.0.2.0/24  proto kernel  scope link  src 10.0.2.15

显示指定设备的网络统计信息

前面的例子展示了查找当前网络配置的方法,而这个命令使用-s(统计)标志来显示指定设备的网络统计信息:

# ip -s link show dev enp0s3
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 08:00:27:6e:35:18 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast
    109717927  125911   0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    3944294    40127    0       0       0       0

在前面的例子中,使用了link(网络设备)选项来指定统计信息应该限制在指定的设备上。

显示的统计信息在排除丢包或识别哪个接口具有更高的网络利用率时非常有用。

netstat - 网络统计

netstat命令是任何系统管理员工具包中的基本工具。这可以通过netstat命令普遍适用于即使不传统使用命令行进行管理的操作系统来看出。

打印网络连接

netstat的主要用途之一是打印现有的已建立的网络连接。这可以通过简单执行netstat来完成;然而,如果使用了-a(所有)标志,输出也将包括监听端口:

# netstat -na
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address      Foreign Address    State
tcp        0      0 127.0.0.1:25       0.0.0.0:*          LISTEN
tcp        0      0 0.0.0.0:44969      0.0.0.0:*          LISTEN
tcp        0      0 0.0.0.0:111        0.0.0.0:*          LISTEN
tcp        0      0 0.0.0.0:22         0.0.0.0:*          LISTEN
tcp        0      0 192.168.56.101:22  192.168.56.1:50122 ESTABLISHED
tcp6       0      0 ::1:25               :::*               LISTEN

虽然在前面的netstat中使用了-a(所有)标志来打印所有监听端口,但-n标志用于强制输出为数字格式,例如打印 IP 地址而不是 DNS 主机名。

前面的例子将在第五章网络故障排除中大量使用,我们将在那里进行网络连接故障排除。

打印所有监听 tcp 连接的端口

我曾经看到许多情况下,一个服务正在运行,并且可以通过ps命令看到;但是,客户端连接的端口没有绑定和监听。在解决服务的连接问题时,以下netstat命令非常有用:

# netstat -nlp --tcp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address State       PID/Program name
tcp        0      0 127.0.0.1:25            0.0.0.0:* LISTEN      1536/master
tcp        0      0 0.0.0.0:44969           0.0.0.0:* LISTEN      1270/rpc.statd
tcp        0      0 0.0.0.0:111             0.0.0.0:* LISTEN      1215/rpcbind
tcp        0      0 0.0.0.0:22              0.0.0.0:* LISTEN      1236/sshd
tcp6       0      0 ::1:25                  :::* LISTEN      1536/master
tcp6       0      0 :::111                  :::* LISTEN      1215/rpcbind
tcp6       0      0 :::22                   :::* LISTEN      1236/sshd
tcp6       0      0 :::46072                :::* LISTEN      1270/rpc.statd

前面的命令非常有用,因为它结合了三个有用的选项:

  • –l(监听)告诉netstat只列出正在监听的套接字

  • --tcp告诉netstat将输出限制为 TCP 连接

  • –p(程序)告诉netstat列出在该端口上监听的进程的 PID 和名称

延迟

netstat的一个经常被忽视的选项是利用延迟功能。通过在命令的末尾添加一个数字,netstat将持续运行,并在执行之间休眠指定的秒数。

如果执行以下命令,netstat命令将每五秒打印所有正在监听的 TCP 套接字:

# netstat -nlp --tcp 5

延迟功能在调查网络连接问题时非常有用。因为它可以很容易地显示应用程序何时为新连接绑定端口。

性能

虽然我们稍微提到了使用freeps等命令来解决性能问题,但本节将展示一些非常有用的命令,这些命令可以回答“为什么慢”的古老问题。

iotop - 一个简单的类似 top 的 I/O 监视器

iotop命令是 Linux 上相对较新的命令。在以前的 RHEL 版本中,虽然可用,但默认情况下未安装iotop命令。iotop命令提供了一个类似 top 命令的界面,但它不是显示哪些进程正在使用最多的 CPU 时间或内存,而是显示按 I/O 利用率排序的进程:

# iotop
Total DISK READ :       0.00 B/s | Total DISK WRITE :       0.00 B/s
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN      IO COMMAND
 1536 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % master -w
    1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % systemd --switched-root --system --deserialize 23

与以前的一些命令不同,iotop非常专门用于显示正在使用 I/O 的进程。但是,有一些非常有用的标志可以改变iotop的默认行为。例如–o(仅)告诉iotop仅打印使用 I/O 的进程,而不是其默认行为打印所有进程。另一组有用的标志是-q(安静)和–n(迭代次数)。

连同-o标志一起,这些标志可以用来告诉iotop仅打印使用 I/O 的进程,而不清除下一次迭代的屏幕:

# iotop -o -q -n2
Total DISK READ :     0.00 B/s | Total DISK WRITE :       0.00 B/s
Actual DISK READ:     0.00 B/s | Actual DISK WRITE:       0.00 B/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN   IO   COMMAND
Total DISK READ :     0.00 B/s | Total DISK WRITE :       0.00 B/s
Actual DISK READ:     0.00 B/s | Actual DISK WRITE:       0.00 B/s
22965 be/4 root       0.00 B/s    0.00 B/s  0.00 %  0.03 % [kworker/0:3]

如果我们看一下前面的示例输出,我们可以看到iotop命令的两个独立迭代。但是,与以前的示例不同,输出是连续的,允许我们看到每次迭代时使用 I/O 的进程。

默认情况下,iotop迭代之间的延迟是 1 秒;但是,可以使用-d(延迟)标志进行修改。

iostat - 报告 I/O 和 CPU 统计信息

iotop显示正在使用 I/O 的进程,iostat显示正在被利用的设备:

# iostat -t 1 2
Linux 3.10.0-123.el7.x86_64 (localhost.localdomain)   12/25/2014 _x86_64_  (1 CPU)

12/25/2014 03:20:10 PM
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.11    0.00    0.17    0.01    0.00   99.72

Device:            tps    kB_read/s    kB_wrtn/s    kB_read kB_wrtn
sda               0.38         2.84         7.02     261526 646339
sdb               0.01         0.06         0.00       5449 12
dm-0              0.33         2.77         7.00     254948 644275
dm-1              0.00         0.01         0.00        936 4

12/25/2014 03:20:11 PM
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.00    0.00    0.99    0.00    0.00   99.01

Device:            tps    kB_read/s    kB_wrtn/s    kB_read kB_wrtn
sda               0.00         0.00         0.00          0 0
sdb               0.00         0.00         0.00          0 0
dm-0              0.00         0.00         0.00          0 0
dm-1              0.00         0.00         0.00          0 0

前面的iostat命令使用-t(时间戳)标志在每个报告中打印时间戳。两个数字是间隔和计数值。在前面的示例中,iostat以一秒的间隔运行,总共迭代两次。

iostat命令对诊断与 I/O 相关的问题非常有用。但是,输出通常会产生误导。当执行时,第一个报告中提供的值是系统上次重启以来的平均值。随后的报告是自上一个报告以来的。在这个例子中,我们执行了两个报告,相隔一秒。您可以看到第一个报告中的数字比第二个报告中的数字要高得多。

因此,许多系统管理员简单地忽略第一个报告,但他们并不完全理解为什么。因此,对于不熟悉iostat的人来说,对第一个报告中的值做出反应并不罕见。

iostat命令有一个-y标志(省略第一个报告),这实际上会导致iostat省略第一个报告。这是一个很好的标志,可以教给那些可能不太熟悉使用iostat的用户。

操纵输出

iostat命令也有一些非常有用的标志,允许您操纵它呈现数据的方式。例如-p(设备)标志允许您将统计信息限制为指定的设备,或者-x(扩展统计)将打印扩展统计信息:

# iostat -p sda -tx
Linux 3.10.0-123.el7.x86_64 (localhost.localdomain)   12/25/2014 _x86_64_  (1 CPU)

12/25/2014 03:38:00 PM
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.11    0.00    0.17    0.01    0.00   99.72

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.01     0.02    0.13    0.25     2.81     6.95 51.70     0.00    7.62    1.57   10.79   0.85   0.03
sda1              0.00     0.00    0.02    0.02     0.05     0.02 3.24     0.00    0.24    0.42    0.06   0.23   0.00
sda2              0.01     0.02    0.11    0.19     2.75     6.93 65.47     0.00    9.34    1.82   13.58   0.82   0.02

前面的示例使用了-p标志来指定sda设备,-t标志来打印时间戳,-x标志来打印扩展统计信息。在测量特定设备的 I/O 性能时,这些标志非常有用。

vmstat - 报告虚拟内存统计信息

iostat用于报告有关磁盘 I/O 性能的统计信息,而vmstat用于报告有关内存使用和性能的统计信息:

# vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
2  0      4 225000   3608 544900    0    0     3     7   17   28 0  0 100  0  0
0  0      4 224992   3608 544900    0    0     0     0   19   19 0  0 100  0  0
0  0      4 224992   3608 544900    0    0     0     0    6    9 0  0 100  0  0

vmstat的语法与iostat非常相似,您可以在命令行参数中提供间隔和报告计数。与iostat一样,第一个报告实际上是自上次重启以来的平均值,随后的报告是自上一个报告以来的。不幸的是,与iostat命令不同,vmstat命令没有包含一个标志来省略第一个报告。因此,在大多数情况下,简单地忽略第一个报告是合适的。

虽然vmstat可能不包括省略第一个报告的标志,但它确实有一些非常有用的标志;例如-m(slabs),这会导致vmstat以定义的间隔输出系统的slabinfo,以及-s(stats),它会打印系统的内存统计的扩展报告:

# vmstat -stats
      1018256 K total memory
       793416 K used memory,
       290372 K active memory
       360660 K inactive memory
       224840 K free memory
         3608 K buffer memory
       544908 K swap cache
       839676 K total swap
            4 K used swap
       839672 K free swap
        10191 non-nice user cpu ticks
           67 nice user cpu ticks
        11353 system cpu ticks
      9389547 idle cpu ticks
          556 IO-wait cpu ticks
           33 IRQ cpu ticks
         4434 softirq cpu ticks
            0 stolen cpu ticks
       267011 pages paged in
       647220 pages paged out
            0 pages swapped in
            1 pages swapped out
      1619609 interrupts
      2662083 CPU context switches
   1419453695 boot time
        59061 forks

前面的代码是使用-s--stats标志的示例。

sar - 收集、报告或保存系统活动信息

一个非常有用的实用程序是sar命令,sarsysstat软件包附带的实用程序。sysstat软件包包括各种实用程序,用于收集磁盘、CPU、内存和网络利用率等系统指标。默认情况下,这个收集将每 10 分钟运行一次,并作为cron作业在/ettc/cron.d/sysstat中执行。

虽然sysstat收集的数据可能非常有用,但在高性能环境中有时会删除这个软件包。因为系统利用率统计数据的收集可能会增加系统的利用率,导致性能下降。要查看sysstat软件包是否已安装,只需使用 rpm 命令和-q(查询)标志:

# rpm -q sysstat
sysstat-10.1.5-4.el7.x86_64

使用 sar 命令

sar命令允许用户查看sysstat实用程序收集的信息。当不带标志执行sar命令时,将打印当天的 CPU 统计信息:

# sar | head -6
Linux 3.10.0-123.el7.x86_64 (localhost.localdomain)   12/25/2014   _x86_64_  (1 CPU)

12:00:01 AM     CPU     %user     %nice   %system   %iowait %steal     %idle
12:10:02 AM     all      0.05      0.00      0.20      0.01 0.00     99.74
12:20:01 AM     all      0.05      0.00      0.18      0.00 0.00     99.77
12:30:01 AM     all      0.06      0.00      0.25      0.00 0.00     99.69

每天午夜,systat收集器将创建一个新文件来存储收集的统计信息。要引用该文件中的统计信息,只需使用-f(文件)标志来针对指定的文件运行sar

# sar -f /var/log/sa/sa13
Linux 3.10.0-123.el7.x86_64 (localhost.localdomain)   12/13/2014   _x86_64_  (1 CPU)

10:24:43 AM       LINUX RESTART

10:30:01 AM     CPU     %user     %nice   %system   %iowait %steal     %idle
10:40:01 AM     all      2.99      0.00      0.96      0.43 0.00     95.62
10:50:01 AM     all      9.70      0.00      2.17      0.00 0.00     88.13
11:00:01 AM     all      0.31      0.00      0.30      0.02 0.00     99.37
11:10:01 AM     all      1.20      0.00      0.41      0.01 0.00     98.38
11:20:01 AM     all      0.01      0.00      0.04      0.01 0.00     99.94
11:30:01 AM     all      0.92      0.07      0.42      0.01 0.00     98.59
11:40:01 AM     all      0.17      0.00      0.08      0.00 0.00     99.74
11:50:02 AM     all      0.01      0.00      0.03      0.00 0.00     99.96

在前面的代码中,指定的文件是/var/log/sa/sa13;这个文件包含了当月第 13 天的统计信息。

sar命令有许多有用的标志,远远不止在本章中列出的。以下列出了一些非常有用的标志:

  • -b:这会打印类似于iostat命令的 I/O 统计信息

  • -n ALL:这会打印所有网络设备的网络统计信息

  • -R:这会打印内存利用率统计信息

  • -A:这会打印所有收集的统计信息。它基本上等同于运行sar -bBdHqrRSuvwWy -I SUM -I XALL -m ALL -n ALL -u ALL -P ALL

虽然sar命令显示了许多统计信息,但我们已经涵盖了诸如iostatvmstat之类的命令。sar命令最大的好处在于能够回顾过去的统计数据。当排除发生在短时间内或已经被缓解的性能问题时,这种能力是至关重要的。

总结

在本章中,您了解到日志文件、配置文件和/proc文件系统是故障排除过程中的关键信息来源。我们还介绍了许多基本故障排除命令的基本用法。

在阅读本章的过程中,您可能已经注意到,相当多的命令也用于日常生活中的非故障排除目的。如果我们回顾一下来自第一章 故障排除最佳实践 的故障排除过程,第一步包括信息收集。

虽然这些命令本身可能无法解释问题,但它们可以帮助收集有关问题的信息,从而实现更准确和快速的解决方案。熟悉这些基本命令对于您在故障排除过程中取得成功至关重要。

在接下来的几章中,我们将使用这些基本命令来解决现实世界中的问题。下一章将重点解决与基于 Web 的应用程序相关的问题。

第三章:故障排除 Web 应用程序

在本书的第一章和第二章中,我们介绍了故障排除过程、信息的常见位置和有用的故障排除命令。在本章中,我们将通过一个示例问题来运行,以演示多种故障排除和补救步骤。特别是,我们将看一下解决基于 Web 的应用程序问题所需的步骤。

在本章中,我将逐步介绍故障排除过程的每一步,并解释每一步背后的原因。虽然本章涵盖的问题可能不是一个非常常见的问题,但重要的是看待解决问题的过程和使用的工具。本章中使用的过程和工具可以应用于大多数 Web 应用程序问题。

一个小小的背景故事

在本书的每一章中,您都会找到一个示例问题,涵盖了常见的故障排除主题。虽然本书的重点是展示解决这些类型问题所需的命令和概念,但展示解决问题的过程也是很重要的。为了做到这一点,我们将探讨这些问题,就好像我们是最近加入新公司的新系统管理员一样。

每个问题都会以稍微不同的方式呈现,但每个问题都将以报告问题的方式开始。

报告的问题

在新公司开始新角色时,我们被指派接听公司网络运营中心NOC)的电话。在这个角色中,我们将专注于解决公司环境中的问题,并且期望能够非常快速地解决问题。对于我们的第一个问题,我们接到了一个电话;在电话的另一端是一个有问题的业务用户。突然间,我们的博客显示的是一个安装页面,而不是我们的帖子!

既然我们已经有了一个报告的问题,让我们开始逐步进行故障排除过程。

数据收集

如果我们回顾一下第一章,故障排除最佳实践,故障排除过程的第一步是理解问题陈述。在本节中,我们将探讨问题是如何报告的,并尝试收集任何数据,以找到问题的根本原因。

在这个示例中,我们是通过电话通知的问题。这实际上是幸运的,因为我们有一个最终用户在电话那头,可以向他/她提问以获取更多信息。

在要求报告问题的人提供更多信息之前,让我们先看看已经得到的回答。突然间,我们的博客显示的是一个安装页面,而不是我们的帖子!

一开始,你可能觉得这个问题陈述模糊不清;这是因为它确实模糊不清。然而,在这个简单的句子中仍然包含了相当多有用的信息。如果我们分析一下报告的问题,我们就可以更好地理解问题。

  • “我们的博客显示的是一个安装页面”

  • “突然间”

  • “不是我们的帖子!”

从这三个部分中,我们可以假设以下内容:

  • 博客显示了一个意外的页面

  • 这个博客以前显示过帖子

  • 在某个时候,这种情况发生了变化,而且似乎是最近发生的

虽然以上内容对于确定是否存在问题以及问题的相关性是一个不错的开始,但它还不足以让我们得出假设。

提问

为了制定假设,我们需要更多信息。获取这些信息的一种方法是询问报告问题的人。为了获取更多信息,我们将向业务用户提出以下问题:

  1. 你上次看到博客工作是什么时候?

昨晚。

  1. 博客的地址是什么?

http://blog.example.com

  1. 你有收到其他错误吗?

没有。

虽然以上问题还不足以确定问题,但它们给了我们一个开始寻找问题的起点。

复制问题

如前所述,在第一章中,故障排除最佳实践中找到信息的最佳方法之一是复制问题。在这种情况下,似乎我们可以通过简单地访问提供的地址来复制问题。

复制问题

在前面的屏幕截图中,我们可以看到博客的表现与用户描述的一样。当我们访问提供的 URL 时,我们看到了一个默认的 WordPress 安装界面。

这是否给我们提供了关于问题原因的任何线索?不,实际上并没有,除非我们之前见过这个问题。虽然这可能不告诉我们问题的原因,但它确实确认了用户报告的问题是可以重现的。这一步还告诉了我们正在排查的软件的名称:WordPress。

WordPress 是最流行的开源博客平台之一。在本章中,我们假设我们没有管理 WordPress 的经验,需要通过在线来源找到我们需要的关于这个 Web 应用程序的任何信息。

了解环境

由于我们是新的系统管理员,在这一点上,我们对这个环境知之甚少,这意味着我们对这个博客是如何部署的知之甚少。事实上,我们甚至不知道它是从哪个服务器运行的。

这个博客托管在哪里?

然而,我们知道的一件事是,我们公司管理的所有服务器的 IP 都在 192.168.0.0/16 子网内。为了确定这是否是我们可以解决的问题,我们首先需要确定博客是否在我们公司管理的服务器上。如果这个博客不是在我们公司管理的服务器上,我们的故障排除选项可能会受到限制。

确定博客托管位置的一种方法是简单地查找blog.example.com地址的 IP 地址。

使用 nslookup 查找 IP

有许多方法可以查找 DNS 名称的 IP 地址;我们将讨论的命令是nslookup命令。要使用这个命令,只需执行nslookup,然后是要查找的 DNS 名称:例如,对于这个例子,是blog.example.com

$ nslookup blog.example.com
Server:    192.0.2.1
Address:  192.0.2.1#53

Non-authoritative answer:
Name:  blog.example.com
Address: 192.168.33.11

在前面的输出中,对于那些不熟悉nslookup的人来说,结果可能有点令人困惑。

Non-authoritative answer:
Name:  blog.example.com
Address: 192.168.33.11

我们知道前面的信息是nslookup查询的结果。这个块表示blog.example.com域的地址是192.168.33.11nslookup的输出的第一个块只是告诉我们使用了哪个 DNS 服务器来查找这些信息。

Server:    192.0.2.1
Address:  192.0.2.1#53

从这个块中我们可以看到使用的 DNS 服务器是192.0.2.1

ping、dig 或其他工具呢?

有许多命令可以用来查找这个域的 IP 地址。我们可以使用dighost,甚至ping。我们选择nslookup命令的原因是,它大多数情况下都包含在大多数操作系统中。因此,无论您需要从 Windows、Mac 还是 Linux 桌面查找 IP 地址,您都可以使用nslookup命令。

然而,nslookup命令的一个注意事项是,它专门使用 DNS 来查找地址。它不尊重/etc/hosts中的值或/etc/nsswitch.conf中指定的任何其他名称服务。这是我们将在后面的章节中更多探讨的内容;现在,我们将假设192.168.33.11的 IP 地址是正确的。

好的,它在我们的环境中;现在怎么办?

由于我们正在使用 Linux 服务器,管理该服务器的最常见方式是通过Secure ShellSSH)。SSH 是一种安全的网络服务,允许用户远程访问服务器的 shell。对于本书,我们将假设您已经熟悉通过 SSH 登录服务器。无论您使用 SSH 命令行客户端还是像 PuTTY 这样的桌面客户端,我们假设您能够使用 SSH 登录服务器。

在这种情况下,我们使用的是一个具有自己 shell 环境的笔记本电脑。要登录到我们的服务器,我们只需从终端窗口执行ssh命令。

$ ssh vagrant@blog.example.com
vagrant@blog.example.com's password:

登录后,我们执行的第一个信息收集命令是w命令。

$ w
 18:32:17 up 2 days, 12:05,  1 user,  load average: 0.11, 0.08, 0.07
USER     TTY        LOGIN@   IDLE   JCPU   PCPU WHAT
vagrant  pts/1     00:53    2.00s  0.00s  0.08s sshd: vagrant [priv]

在第二章中,故障排除命令和有用信息的来源,我们介绍了w命令,并提到它是第一个执行的命令。我们可以在w命令的输出中看到相当多有用的信息。

从这个输出中,我们可以确定以下内容:

  • 当前只有 1 个用户登录(这是我们的登录会话)

  • 问题的服务器已经运行了 2 天

  • 负载平均值很低,这表明正常

总的来说,乍一看,服务器似乎表现正常。问题是昨晚开始的,这表明问题并不是在 2 天前的重启之后开始的。负载平均值低,因此在这一点上可以安全地假设问题与系统负载无关。

安装并运行了哪些服务?

由于我们以前从未登录过这台服务器,并且对这个环境完全不熟悉,我们应该首先找出这台服务器上运行着哪些服务。

由于我们从安装页面得知博客是 WordPress 博客,我们可以搜索 Google 关于它所需服务的信息。我们可以通过使用搜索词“WordPress 安装要求”来做到这一点。

这个搜索字符串返回了以下 URL 作为第一个结果:wordpress.org/about/requirements/。这个页面包含了 WordPress 的安装要求,并列出了以下内容:

  • PHP 5.2.4

  • MySQL 5.0 或更高版本

  • 要么是 Apache 要么是 Nginx Web 服务器

从我们可以访问安装页面这一事实,我们可以假设已安装并且部分工作的是一个 Web 服务器和 PHP。然而,最好的做法是验证而不是假设。

验证 Web 服务器

由于 WordPress 推荐使用ApacheNginx Web 服务器,我们首先需要确定安装了哪一个,更重要的是,确定这个 WordPress 应用程序正在使用哪一个。

以下是几种识别已安装和正在运行的 Web 服务器的方法:

  • 我们可以使用rpm来查看已安装的软件包。

  • 我们可以使用ps来查看正在运行的进程

  • 我们可以简单地通过浏览器访问一个不存在的页面,看看错误页面显示的是哪个 Web 服务器在运行

  • 我们还可以进入/var/logs并查看周围存在或不存在的日志文件

所有这些方法都是有效的,并且都有自己的好处。在这个例子中,我们将使用一个第五种方法(之前没有提到过),它将回答关于这个服务器上 Web 服务器配置的两个问题。

这种方法的第一步将是确定哪个进程在端口 80 上监听。

$ su -
# netstat -nap | grep 80
tcp6       0      0 :::80                   :::* LISTEN      952/httpd
unix  3      [ ]         STREAM     CONNECTED     17280  1521/master

如第二章中所讨论的,故障排除命令和有用信息的来源netstat命令可以用来确定使用-na标志的端口。如果我们简单地添加-p(端口)标志到netstat,我们还可以看到每个端口上监听的进程。

提示

为了确定每个端口上监听的进程,必须以超级用户级别权限执行netstat命令。因此,我们使用su命令在执行netstat之前切换到root用户。

在本书中,任何以$开头的命令都是作为非特权用户运行的,而以#开头的命令是作为 root 用户执行的。

端口 80 是 HTTP 请求的默认端口;因此,如果我们回顾一下复制问题的步骤,我们可以看到使用的地址是http://blog.example.com。由于这是一个 HTTP 地址,没有指定不同的端口,这意味着提供 WordPress 安装页面的服务正在监听 80 端口。

netstat命令的输出中,我们可以看到进程 952 正在监听 80 端口。netstat输出还显示进程 952 正在运行httpd二进制文件。在 RHEL 系统上,这个httpd二进制文件往往是 Apache。

我们可以使用ps命令和第二章, 故障排除命令和有用信息来源中讨论的–elf标志来验证这一点。我们还将使用grep命令搜索ps命令的输出,搜索字符串"952":

$ ps -elf | grep 952
4 S root       952     1  0  80   0 - 115050 poll_s Jan11 ? 00:00:07 /usr/sbin/httpd -DFOREGROUND
5 S apache    5329   952  0  80   0 - 115050 inet_c 08:54 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
5 S apache    5330   952  0  80   0 - 115050 inet_c 08:54 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
5 S apache    5331   952  0  80   0 - 115050 inet_c 08:54 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
5 S apache    5332   952  0  80   0 - 115050 inet_c 08:54 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
5 S apache    5333   952  0  80   0 - 119196 inet_c 08:54 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND

通过上面的输出,我们可以看到进程 952 及其子进程是在apache用户下运行的。这证实了所使用的软件很可能是 Apache,但为了更加谨慎,我们可以使用httpd二进制文件和–version标志来打印 Web 服务器软件的版本。

$ httpd -version
Server version: Apache/2.4.6
Server built:   Jul 23 2014 14:48:00

httpd二进制文件的输出显示,它实际上是 Apache Web 服务器,符合 WordPress 的要求。

到目前为止,我们已经发现了关于此服务器使用的 Web 服务器的以下事实:

  • Web 服务器是 Apache

  • Apache 进程正在运行

  • Apache 版本是 2.4.6

  • Apache 进程正在监听 80 端口

也可以通过其他方法识别相同的信息,比如使用rpm。这种方法的好处是,如果服务器安装了两个 Web 服务器服务,我们就知道这些服务中的哪一个正在监听 80 端口。这也告诉我们哪个服务提供了 WordPress 安装页面。

验证数据库服务

常见的 WordPress 实现是在一个服务器上同时运行 Apache、PHP 和 MySQL 服务。然而,有时 MySQL 服务会从另一个服务器或多个服务器上运行。为了更好地了解环境,我们应该检查这个环境是在本地运行 MySQL 还是从另一个服务器运行。

为了检查这一点,我们将再次使用ps命令;不过这一次,我们将使用grep来搜索与字符串"mysql"匹配的进程:

$ ps -elf | grep mysql
4 S mysql     2045     1  0  80   0 - 28836 wait   Jan12 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
0 S mysql     2203  2045  0  80   0 - 226860 poll_s Jan12 ? 00:00:42 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log- error=/var/log/mariadb/mariadb.log --pid- file=/var/run/mariadb/mariadb.pid -- socket=/var/lib/mysql/mysql.sock

从前面的输出中可以看出,实际上有一个 MySQL 进程正在运行。还需要注意的是,ps输出显示mysqld进程正在使用以下选项:–log-error=/var/log/mariadb/mariadb.log

这一点很重要,有两个原因:第一,这是mysqld进程的日志文件的位置,第二,这个日志文件是MariaDB的,与 MySQL 不同。

我们可以通过使用rpmegrep命令来确认是否安装了 MySQL 或 MariaDB。

$ rpm -qa | egrep "(maria|mysql)"
php-mysql-5.4.16-23.el7_0.3.x86_64
mariadb-5.5.40-2.el7_0.x86_64
mariadb-server-5.5.40-2.el7_0.x86_64
mariadb-libs-5.5.40-2.el7_0.x86_64

egrep命令类似于grep;但是,它接受正则表达式形式的搜索字符串。在上面的命令中,我们使用egrep来搜索字符串"mariadb"或字符串"mysql"。从前面的输出中,我们可以看到这台服务器实际上安装了 MariaDB,但没有安装 MySQL。

有了这些信息,我们可以假设正在运行的mysqld进程实际上是一个 MariaDB 二进制文件。我们可以使用rpm命令和–q(查询)以及–l(列出所有文件)标志来验证这一点。

$ rpm -ql mariadb-server | grep "libexec/mysqld"
/usr/libexec/mysqld

我们可以从rpm命令的输出中看到,运行的/usr/libexec/mysqld二进制文件是作为mariadb-server软件包的一部分部署的。这表明运行的数据库进程实际上是 MariaDB,并且是通过 mariadb-server 软件包安装的。

到目前为止,我们已经发现了关于此服务器上运行的数据库服务的以下事实:

  • 数据库服务实际上是 MariaDB

  • MariaDB 正在运行

  • 此服务的日志文件位于/var/log/mariadb/

虽然 MariaDB 是 MySQL 的可替代品,但 WordPress 的要求中并未将其列为首选数据库服务。重要的是要注意这种差异,因为它可能确定报告的问题的根本原因。

验证 PHP

由于我们知道 WordPress 需要 PHP,我们还应该检查它是否已安装。我们可以再次使用rpm命令验证这一点。

$ rpm -qa | grep php
php-mbstring-5.4.16-23.el7_0.3.x86_64
php-mysql-5.4.16-23.el7_0.3.x86_64
php-enchant-5.4.16-23.el7_0.3.x86_64
php-process-5.4.16-23.el7_0.3.x86_64
php-xml-5.4.16-23.el7_0.3.x86_64
php-simplepie-1.3.1-4.el7.noarch
php-5.4.16-23.el7_0.3.x86_64
php-gd-5.4.16-23.el7_0.3.x86_64
php-common-5.4.16-23.el7_0.3.x86_64
php-pdo-5.4.16-23.el7_0.3.x86_64
php-PHPMailer-5.2.9-1.el7.noarch
php-cli-5.4.16-23.el7_0.3.x86_64
php-IDNA_Convert-0.8.0-2.el7.noarch
php-getid3-1.9.8-2.el7.noarch

PHP 本身并不是设计为像 Apache 或 MySQL 那样作为服务运行,而是作为 Web 服务器模块。但是,可以使用诸如php-fpm之类的服务作为应用程序服务器。这允许 PHP 作为服务运行,并由上游 Web 服务器调用。

要检查此服务器是否运行php-fpm或任何其他用于前端 PHP 的服务,我们可以再次使用psgrep命令。

$ ps -elf | grep php
0 S root      6342  5676  0  80   0 - 28160 pipe_w 17:53 pts/0    00:00:00 grep --color=auto php

通过使用ps命令,我们没有看到任何特定的 PHP 服务;然而,当访问博客时,我们能够看到安装页面。这表明 PHP 配置为直接通过 Apache 运行。我们可以通过再次执行带有-M(模块)标志的httpd二进制文件来验证这一点。

$ httpd -M | grep php
 php5_module (shared)

-M标志将告诉httpd二进制文件列出所有加载的模块。在此列表中包括php5_module,这意味着 Apache 的此安装能够通过php5_module运行 PHP 应用程序。

已安装并正在运行的服务摘要

在这一点上,我们已经从我们的数据收集中确定了以下内容:

  • 已安装并运行了 Apache 的 WordPress 要求

  • MariaDB 似乎满足了 WordPress 对 MySQL 的要求,已安装并运行

  • 已安装并似乎正在运行 WordPress 的 PHP 要求

  • 看起来 WordPress 部署在单服务器设置中,而不是多服务器设置中

我们暂时可以假设这些事实意味着问题不是由缺少 WordPress 要求引起的。

通过收集所有这些数据点,我们不仅了解了我们正在解决故障的环境,还排除了这个问题的几种可能原因。

寻找错误消息

现在已经确定了已安装和配置的服务,我们知道从哪里开始查找错误或有用的消息。在数据收集的下一阶段,我们将浏览这些服务的各种日志文件,以尝试识别可能指示此问题原因的任何错误。

Apache 日志

由于 Apache 在进行 Web 请求时调用 PHP,最有可能包含与 PHP 相关错误的日志文件是 Apache 错误日志。RHEL 的httpd软件包的默认日志位置是/var/log/httpd/。但是,我们还不知道运行的httpd服务是否是 RHEL 打包版本。

查找 Apache 日志的位置

由于我们不知道 Apache 日志的位置,我们需要找到它们。查找日志文件的一种方法是简单地在/var/log中查找与所讨论服务的名称匹配的任何文件或文件夹。然而,这种解决方案对于我们的例子来说太简单了。

要找到httpd日志文件的位置,我们将使用第二章中讨论的一种方法,故障排除命令和有用信息来源,并搜索服务的配置文件。/etc文件夹是系统配置文件的默认文件夹。它也是服务配置的标准位置。因此,可以相当安全地假设/etc/文件夹将包含httpd服务的配置文件或文件夹。

# cd /etc/httpd/
# ls -la
total 20
drwxr-xr-x.  5 root root   86 Jan  7 23:29 .
drwxr-xr-x. 79 root root 8192 Jan 13 16:10 ..
drwxr-xr-x.  2 root root   35 Jan  7 23:29 conf
drwxr-xr-x.  2 root root 4096 Jan  7 23:29 conf.d
drwxr-xr-x.  2 root root 4096 Jan  7 23:29 conf.modules.d
lrwxrwxrwx.  1 root root   19 Jan  7 23:29 logs -> ../../var/log/httpd
lrwxrwxrwx.  1 root root   29 Jan  7 23:29 modules -> ../../usr/lib64/httpd/modules
lrwxrwxrwx.  1 root root   10 Jan  7 23:29 run -> /run/httpd

在前面的命令中,我们可以看到我们可以切换到包含多个配置文件的/etc/httpd文件夹。由于我们不知道哪个配置文件包含日志配置,我们可能需要花费相当长的时间阅读每个配置文件。

为了加快这个过程,我们可以使用grep命令来搜索所有文件中的字符串“log”。由于/etc/httpd/文件夹包含子文件夹,我们可以简单地添加-r(递归)标志,使grep命令搜索这些子文件夹中包含的文件。

# grep -r "log" /etc/httpd/*
./conf/httpd.conf:# with "/", the value of ServerRoot is prepended -- so 'log/access_log'
./conf/httpd.conf:# server as '/www/log/access_log', whereas '/log/access_log' will be
./conf/httpd.conf:# interpreted as '/log/access_log'.
./conf/httpd.conf:# container, that host's errors will be logged there and not here.
./conf/httpd.conf:ErrorLog "logs/error_log"
./conf/httpd.conf:# LogLevel: Control the number of messages logged to the error_log.
./conf/httpd.conf:<IfModule log_config_module>
./conf/httpd.conf:    <IfModule logio_module>
./conf/httpd.conf:    # define per-<VirtualHost> access log files, transactions will be
./conf/httpd.conf:    # logged therein and *not* in this file.
./conf/httpd.conf:    #CustomLog "logs/access_log" common
./conf/httpd.conf:    # If you prefer a log file with access, agent, and referer information
./conf/httpd.conf:    CustomLog "logs/access_log" combined
./conf.modules.d/00-base.conf:LoadModule log_config_module modules/mod_log_config.so
./conf.modules.d/00-base.conf:LoadModule logio_module modules/mod_logio.so
./conf.modules.d/00-base.conf:#LoadModule log_debug_module modules/mod_log_debug.so

提示

While there is quite a bit of output from the preceding grep command, if we review the returned data, we can see that there are actually two log files defined for the httpd service: logs/access_log and logs/error_log.
./conf/httpd.conf:ErrorLog "logs/error_log"
./conf/httpd.conf:    CustomLog "logs/access_log" combined

定义的日志使用相对路径logs/;这个路径是相对于运行文件夹的httpd服务。在这种情况下,这意味着日志文件夹实际上是/etc/httpd/logs;然而,这并不总是这种情况。要验证是否是这种情况,我们可以简单地在/etc/httpd文件夹中使用ls命令进行文件夹列表。

# ls -la /etc/httpd | grep logs
lrwxrwxrwx.  1 root root   19 Jan  7 23:29 logs -> ../../var/log/httpd

ls命令中,我们可以看到/etc/httpd/logs存在;然而,这不是一个文件夹,而是一个符号链接到/var/log/httpd/。这意味着这两个日志文件,即access_logerror_log,实际上位于/var/log/httpd/文件夹内。

审查日志

现在我们知道日志文件的位置,我们可以搜索这些日志文件以获取任何有用的信息。为此,我们将使用tail命令。

tail命令是一个有用的命令,可以用来读取文件的最后部分。默认情况下,当tail没有任何标志地执行时,该命令将打印指定文件的最后 10 行。

对于我们的故障排除,我们不仅想看到最后 10 行数据,还想观察文件是否有任何新的数据被追加。为此,我们可以使用-f(跟踪)标志,告诉tail跟踪指定的文件。

# tail -f logs/access_log logs/error_log
==> logs/access_log <==
192.168.33.1 - - [12/Jan/2015:04:39:08 +0000] "GET /wp-includes/js/wp-util.min.js?ver=4.1 HTTP/1.1" 200 981 "http://blog.example.com/wp-admin/install.php" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36"
"http://blog.example.com/wp-admin/install.php" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36"
192.168.33.1 - - [12/Jan/2015:04:39:08 +0000] "GET /wp-admin/js/password-strength-meter.min.js?ver=4.1 HTTP/1.1" 200 737 "http://blog.example.com/wp-admin/install.php" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36"
::1 - - [13/Jan/2015:16:08:33 +0000] "GET / HTTP/1.1" 302 - "-" "curl/7.29.0"
192.168.33.11 - - [13/Jan/2015:16:10:19 +0000] "GET / HTTP/1.1" 302 - "-" "curl/7.29.0"

==> logs/error_log <==
[Sun Jan 11 06:01:03.679890 2015] [auth_digest:notice] [pid 952] AH01757: generating secret for digest authentication ...
[Sun Jan 11 06:01:03.680719 2015] [lbmethod_heartbeat:notice] [pid 952] AH02282: No slotmem from mod_heartmonitor
[Sun Jan 11 06:01:03.705469 2015] [mpm_prefork:notice] [pid 952] AH00163: Apache/2.4.6 (CentOS) PHP/5.4.16 configured -- resuming normal operations
[Sun Jan 11 06:01:03.705486 2015] [core:notice] [pid 952] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND'

提示

RHEL 7 实现的tail命令实际上可以同时跟踪多个文件。要做到这一点,只需在执行命令时指定您希望读取或跟踪的所有文件。上面是使用tail同时读取两个文件的示例。

虽然最后 10 行没有立即由 PHP 错误引起的错误,但这并不一定意味着这些文件不会显示我们需要的错误。由于这是一个基于 Web 的应用程序,我们可能需要加载应用程序以触发任何错误。

我们可以简单地打开我们的浏览器,再次导航到http://blog.example.com。然而,对于这个例子,我们将利用一个非常有用的故障排除命令:curl

使用 curl 调用我们的 Web 应用程序

curl命令可以用作客户端来访问许多不同类型的协议,从 FTP 到 SMTP。这个命令在故障排除 Web 应用程序时特别有用,因为它可以用作 HTTP 客户端。

在故障排除 Web 应用程序时,您可以使用curl命令向指定的 URL 发出HTTPGETPOST请求,当以-v(详细)标志的详细模式放置时,可以产生相当多的有趣信息。

$ curl -v http://blog.example.com
* About to connect() to blog.example.com port 80 (#0)
*   Trying 192.168.33.11...
* Connected to blog.example.com (192.168.33.11) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: blog.example.com
> Accept: */*
>
< HTTP/1.1 302 Found
< Date: Tue, 13 Jan 2015 21:10:51 GMT
< Server: Apache/2.4.6 PHP/5.4.16
< X-Powered-By: PHP/5.4.16
< Expires: Wed, 11 Jan 1984 05:00:00 GMT
< Cache-Control: no-cache, must-revalidate, max-age=0
< Pragma: no-cache
< Location: http://blog.example.com/wp-admin/install.php
< Content-Length: 0
< Content-Type: text/html; charset=UTF-8
<
* Connection #0 to host blog.example.com left intact

前面的输出显示了我想要强调的四个关键信息。

* Connected to blog.example.com (192.168.33.11) port 80 (#0)

前一行显示了当我们访问名为blog.example.com的页面时,我们实际上去了192.168.33.11服务器。虽然我们已经确定blog.example.com解析为192.168.33.11,但这行确认了这个命令的输出产生了来自预期系统的数据。

< HTTP/1.1 302 Found

第二个关键信息显示了 Web 服务器提供的 HTTP 状态代码。

在这种情况下,Web 服务器以302状态代码回复,用于指示临时重定向。当浏览器请求页面并且 Web 服务器以 302 状态代码回复时,浏览器知道将最终用户重定向到另一个页面。

< Location: http://blog.example.com/wp-admin/install.php

下一个页面由Location HTTP 标头确定。这个标头由 Web 服务器分配,以及 302 的 HTTP 状态代码将导致任何浏览器将最终用户重定向到/wp-admin/install.php页面。

这解释了为什么当我们导航到blog.example.com时会看到一个安装页面,因为 Web 服务器只是以 302 重定向简单地响应。

< X-Powered-By: PHP/5.4.16

第四个关键信息是 HTTP 头X-Powered-By;这是 PHP 添加的 HTTP 头。当请求的页面被 PHP 处理时,PHP 会添加这个头,这意味着我们的 curl 请求实际上是由 PHP 处理的。

更重要的是,我们可以看到 PHP 的版本(5.4.16)符合 WordPress 规定的最低要求。

请求非 PHP 页面

当请求一个非 PHP 页面时,我们可以看到 Web 服务器的回复中没有添加X-Powered-By头。我们可以通过请求一个无效的 URL 来验证这一点。

# curl -v http://192.168.33.11/sdfas
* About to connect() to 192.168.33.11 port 80 (#0)
*   Trying 192.168.33.11...
* Connected to 192.168.33.11 (192.168.33.11) port 80 (#0)
> GET /sdfas HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.33.11
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Tue, 13 Jan 2015 21:18:57 GMT
< Server: Apache/2.4.6 PHP/5.4.16
< Content-Length: 203
< Content-Type: text/html; charset=iso-8859-1

当我们请求一个非 PHP 页面时,我们可以看到得到的输出中没有 X-Powered-By 头。这表明 Web 服务器没有将此页面处理为 PHP。

X-Powered-By 头的存在告诉我们,当我们请求blog.example.com页面时,它是由 PHP 处理的。这也意味着 302 的 HTTP 状态码是 WordPress 提供的响应。这一信息很重要,因为它意味着 PHP 很可能在没有任何问题的情况下处理页面,至少目前来看,排除了 PHP 作为报告问题的可能根本原因。

我们可以通过查看从上述 Web 请求生成的任何日志条目来进一步验证这一点。

审查生成的日志条目

当使用curl进行上述请求时,我们应该已经导致新的日志消息被追加到两个httpd日志中。由于我们使用tail命令持续跟踪日志文件,我们可以返回到我们的终端并查看新的消息。

==> logs/access_log <==
192.168.33.11 - - [13/Jan/2015:23:22:17 +0000] "GET / HTTP/1.1" 302 - "-" "curl/7.29.0"

在我们对博客 URL 的 HTTP 请求之后,两个日志中唯一的条目是前面的一个。然而,这只是一个信息日志消息,而不是一个可以解释问题的错误。然而,信息日志消息也是一个关键的数据点。如果 PHP 代码或处理出现问题,类似以下的错误消息将会生成。

[Tue Jan 13 23:24:31.339293 2015] [:error] [pid 5333] [client 192.168.33.11:52102] PHP Parse error:  syntax error, unexpected 'endif' (T_ENDIF) in /var/www/html/wp-includes/functions.php on line 2574

PHP 错误的缺失实际上证实了 PHP 正在按预期工作。这与curl的结果结合起来,让我们有信心地假设 PHP 不是根本原因。

我们从 httpd 日志中学到了什么

虽然httpd服务日志可能没有显示出可以解释为什么出现这个问题的错误,但它们已经帮助我们排除了一个可能的原因。在故障排除过程中,你经常会发现自己在找到问题的确切原因之前排除了许多可能的原因。前面提到的故障排除步骤就是这样,因此排除了可能的原因。

验证数据库

早些时候在检查哪些服务正在运行时,我们发现 MariaDB 服务正在运行。然而,我们没有验证我们是否可以访问该服务,或者 WordPress 应用程序是否可以访问这个数据库服务。

为了验证我们是否可以访问 MariaDB 服务,我们可以简单地使用mysql命令。

# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 28
Server version: 5.5.40-MariaDB MariaDB Server

Copyright (c) 2000, 2014, Oracle, Monty Program Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

mysql命令实际上是一个 MariaDB 客户端命令。当以root用户的身份从命令行运行(如上所示)时,默认情况下,mysql命令将作为 MariaDB 的 root 用户登录到 MariaDB 服务。虽然这是默认行为,但是可以配置 MariaDB 服务禁止直接的根登录。

上述结果暗示了 MariaDB 允许直接的根登录,这表明 MariaDB 服务本身正在运行并接受连接。它们没有透露的是 WordPress 应用程序是否能够访问数据库。

为了确定这一点,我们需要使用与应用程序相同的用户名和密码登录到 MariaDB 服务。

验证 WordPress 数据库

为了使用与 WordPress 相同的凭据连接到 MariaDB 服务,我们需要获取这些凭据。我们可以向报告问题的人请求这些详细信息,但作为业务用户,他们很可能不知道。即使他们每天都在使用 WordPress,通常数据库用户名和密码是由一个人配置并且只在安装过程中使用。

这意味着我们必须自己找到这些信息。一种方法是查看 WordPress 的配置,因为每个连接到数据库的 Web 应用程序都必须从某个地方获取登录凭据,而最常见的方法是将它们存储在配置文件中。

这种方法的一个有趣挑战是,本章假设我们对 WordPress 知之甚少。找到 WordPress 存储其数据库凭据的位置将会有些棘手;特别是因为我们也不知道 WordPress 应用程序安装在哪里。

查找 WordPress 的安装路径

我们知道的是,WordPress 是一个由httpd服务提供的 Web 应用程序。这意味着httpd服务将在其配置文件的某个地方定义安装路径。

httpd的默认配置是从默认文件夹中为单个域提供服务。默认文件夹可能会因发行版而有所不同,但一般来说,对于 RHEL 系统,它位于/var/www/html下。

可以配置httpd来为多个域提供服务;这是通过虚拟主机配置完成的。此时,我们不知道这个系统是配置为托管多个域还是单个域。

检查默认配置

在默认的单域配置中,指向服务器 IP 的任何和所有域都将提供相同的.html.php文件。通过虚拟主机,您可以配置 Apache 根据请求所涉及的域来提供特定的.html.php文件。

我们可以通过执行简单的grep命令来确定httpd服务是配置为虚拟主机还是单域。

# grep -r "DocumentRoot" /etc/httpd/
/etc/httpd/conf/httpd.conf:# DocumentRoot: The folder out of which you will serve your
/etc/httpd/conf/httpd.conf:DocumentRoot "/var/www/html"
/etc/httpd/conf/httpd.conf:    # access content that does not live under the DocumentRoot.

由于/etc/httpd文件夹有多个子文件夹,我们再次使用了-r(递归)标志来进行grep。该命令在整个/etc/httpd文件夹结构中搜索DocumentRoot字符串。

DocumentRoot 是 Apache 配置项,指定包含指定域的.html.php文件的本地文件夹。对于配置为多个域的系统,DocumentRoot设置将出现多次,而对于单域配置,只会出现一次。

从上面的输出中,我们可以看到在这台服务器上,DocumentRoot只定义了一次,并设置为/var/www/html。由于这是 RHEL 系统的默认设置,可以相当安全地假设httpd服务配置为单域配置。

为了验证这是否是 WordPress 的安装文件夹,我们可以简单地执行ls命令来列出此路径中的文件和文件夹。

# ls -la /var/www/html/
total 156
drwxr-xr-x.  5 root root  4096 Jan  9 22:54 .
drwxr-xr-x.  4 root root    31 Jan  7 23:29 ..
-rw-r--r--.  1 root root   418 Jan  9 21:48 index.php
-rw-r--r--.  1 root root  4951 Jan  9 21:48 wp-activate.php
drwxr-xr-x.  9 root root  4096 Jan  9 21:48 wp-admin
-rw-r--r--.  1 root root   271 Jan  9 21:48 wp-blog-header.php
-rw-r--r--.  1 root root  5008 Jan  9 21:48 wp-comments-post.php
-rw-r--r--.  1 root root  3159 Jan  9 22:01 wp-config.php
-rw-r--r--.  1 root root  2726 Jan  9 21:48 wp-config-sample.php
drwxr-xr-x.  6 root root    77 Jan  9 21:48 wp-content
-rw-r--r--.  1 root root  2956 Jan  9 21:48 wp-cron.php
drwxr-xr-x. 10 root root  4096 Jan 13 23:25 wp-includes
-rw-r--r--.  1 root root  2380 Jan  9 21:48 wp-links-opml.php
-rw-r--r--.  1 root root  2714 Jan  9 21:48 wp-load.php
-rw-r--r--.  1 root root 33435 Jan  9 21:48 wp-login.php
-rw-r--r--.  1 root root  8252 Jan  9 21:48 wp-mail.php
-rw-r--r--.  1 root root 11115 Jan  9 21:48 wp-settings.php
-rw-r--r--.  1 root root 25152 Jan  9 21:48 wp-signup.php
-rw-r--r--.  1 root root  4035 Jan  9 21:48 wp-trackback.php
-rw-r--r--.  1 root root  3032 Jan  9 21:48 xmlrpc.php

ls命令的输出中,我们可以看到 WordPress 实际上是安装在/var/www/html/中的。我们可以根据大量的.php文件以及这些文件的"wp-"命名方案来得出这个结论。然而,下一步将对此进行确认。

查找数据库凭据

现在我们已经确定了安装文件夹,我们只需要在 WordPress 应用程序的配置文件中找到数据库凭据。不幸的是,我们对 WordPress 并不是很熟悉,也不知道这些文件中哪些包含数据库凭据。

那么,我们要如何找到它们呢?当然是通过谷歌搜索。

正如我们在第一章中所介绍的,故障排除最佳实践,Google 可以成为系统管理员的好朋友。由于 WordPress 是一个常见的开源应用程序,很可能会有在线帮助文档,涵盖了如何配置或至少恢复数据库密码的内容。

要开始,我们只需通过 Google 搜索WordPress 数据库配置。在搜索 Google 时,我们发现其中一个最初的结果链接到 WordPress 论坛,一个用户询问在 WordPress 中如何找到数据库详细信息。

第一个答案是查看wp-config.php文件。

提示

虽然对于流行的开源项目来说,通过谷歌搜索这种类型的信息很容易,但对于闭源应用程序来说也同样有效,因为很多时候即使闭源应用程序也有在线文档,并被谷歌索引。

要获取数据库详细信息,我们可以使用less命令读取wp-config.php文件。less命令是一个简单的命令,允许用户通过命令行读取文件。对于大文件来说,这特别有用,因为它会缓冲输出,而不是像cat命令一样简单地将所有内容倒出到屏幕上。

# less /var/www/html/wp-config.php

// ** MySQL settings - You can get this information from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');

/** MySQL database username */
define('DB_USER', 'wordpress');

/** MySQL database password */
define('DB_PASSWORD', 'password');

/** MySQL hostname */
define('DB_HOST', 'localhost');

通过阅读配置文件,我们可以清楚地看到数据库凭据,这些凭据方便地位于文件的顶部。以下是我们可以从该文件中提取的详细信息列表:

  • WordPress 正在尝试使用的数据库的NAMEwordpress
define('DB_NAME', 'wordpress');
  • WordPress 正在尝试连接的HOSTlocalhost
define('DB_HOST', 'localhost');
  • WordPress 正在尝试进行身份验证的USERwordpress)数据库
define('DB_USER', 'wordpress');
  • PASSWORDpassword)它用于身份验证
define('DB_PASSWORD', 'password');

有了上述详细信息,我们可以以与 WordPress 应用程序相同的方式连接到 MariaDB 服务。这将是我们故障排除过程中的关键步骤。

以 WordPress 用户身份连接

现在我们有了数据库凭据,我们可以使用mysql命令再次测试连接性。要使用特定的用户名和密码连接到 MariaDB,我们需要使用mysql命令的-u(用户)和-p(密码)标志。

# mysql –uwordpress -p
Enter password: Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 30
Server version: 5.5.40-MariaDB MariaDB Server
MariaDB [(none)]>

在上述命令中,我们可以看到我们在-u标志后添加了用户名,但没有在-p后包含密码。由于我们没有包含密码,mysql客户端在我们按回车键后简单地要求输入密码。虽然可以在-p后包含密码,但从安全的角度来看,这被认为是一种不好的做法。最好让mysql客户端要求输入密码,以减少密码被查看命令历史的人泄露的机会。

mysql客户端连接,我们可以看到通过使用与 WordPress 相同的凭据,我们能够登录到 MariaDB 服务。这很重要,因为无法连接到数据库服务将影响 WordPress 应用程序,并可能是报告的问题的可能原因。

验证数据库结构

由于我们可以使用 WordPress 凭据连接到 MariaDB 服务,接下来我们应该验证数据库结构是否存在且完整。

提示

在本节中,我们将从 MariaDB 命令行界面执行结构化查询语言SQL)语句。这些语句不是 shell 命令,而是 SQL 查询。

SQL 是与 MySQL、MariaDB、Postgres 和 Oracle 等关系数据库交互的标准语言。虽然 SQL 不一定是每个管理员都需要了解的语言,但我建议任何支持大量数据库的系统管理员至少应该了解 SQL 的基础知识。

如果您支持的环境没有专门的数据库管理员来管理数据库和数据库服务,这一点尤其重要。

要验证的第一项是数据库本身是否已创建并可访问。我们可以通过使用show databases查询来做到这一点。

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test               |
| wordpress          |
+--------------------+
3 rows in set (0.00 sec)

我们可以看到 WordPress 数据库实际上在这个输出中列出,这意味着它是存在的。为了验证 WordPress 数据库是可访问的,我们将使用use SQL 语句。

MariaDB [(none)]> use wordpress;
Database changed

通过Database changed的结果,似乎我们已经确认了数据库本身是创建并且可访问的。那么,这个数据库中的表呢?我们可以通过使用show tables查询来验证数据库表是否已经创建。

MariaDB [wordpress]> show tables;
+-----------------------+
| Tables_in_wordpress   |
+-----------------------+
| wp_commentmeta        |
| wp_comments           |
| wp_links              |
| wp_options            |
| wp_postmeta           |
| wp_posts              |
| wp_term_relationships |
| wp_term_taxonomy      |
| wp_terms              |
| wp_usermeta           |
| wp_users              |
+-----------------------+
11 rows in set (0.00 sec)

从结果来看,似乎存在相当多的表。

由于我们对 WordPress 还很陌生,有可能我们会缺少一个表,甚至不知道。由于 WordPress 在网上有很多文档,我们很可能会通过搜索WordPress 数据库表列表来找到一个表列表,这返回了 WordPress 文档页面上非常有用的数据库描述:(codex.wordpress.org/Database_Description)

通过比较show tables查询的输出和数据库描述页面,我们发现没有缺少表。

由于我们知道哪些表是存在的,我们应该检查这些表是否可访问;我们可以通过运行select查询来做到这一点。

MariaDB [wordpress]> select count(*) from wp_users;
ERROR 1017 (HY000): Can't find file: './wordpress/wp_users.frm' (errno: 13)

终于,我们找到了一个错误!

然而,我们发现的错误非常有趣,因为它不是您通常从 SQL 查询中看到的错误。事实上,这个错误似乎表明存在一个包含表数据的文件的问题。

从数据库验证中我们学到了什么

在这一点上,经过验证数据库之后,我们学到了以下内容:

  • MariaDB 可以被 root 用户和 WordPress 应用程序访问

  • 正在访问的数据库是由 WordPress 用户创建并可访问的

  • 在查询数据库表中的一个时,会显示一个错误

有了这些信息,我们可以通过建立一个假设来进入故障排除过程的下一步。

建立假设

在故障排除过程的这个阶段,我们将收集到的所有信息,并用它来建立一个关于为什么出现问题以及如何解决问题的想法。

首先,让我们首先回顾一下我们从数据收集步骤中学到的东西。

  • 一个已经建立的博客网站目前显示的是一个设计为仅在博客软件的初始安装期间显示的页面

  • 这个博客使用开源软件 WordPress

  • WordPress 是用 PHP 编写的,并且利用了 Apache 和 MariaDB 服务

  • Apache 和 PHP 都正常工作,没有显示错误

  • WordPress 安装在/var/www/html目录下

  • MariaDB 服务正在运行并接受连接

  • WordPress 应用程序能够连接到数据库服务

  • 当从数据库表中读取数据时,我们收到一个错误,表明包含数据库数据的文件存在问题

我们可以从所有这些数据点中得出的假设是:

在某个时候,MariaDB 的数据文件,特别是 WordPress 数据库,对 MariaDB 服务是不可访问的。当 WordPress 连接到数据库时,它似乎无法查询表;因此,它认为应用程序尚未安装。由于 WordPress 认为应用程序尚未安装,它呈现了一个安装页面。

我们可以根据以下关键信息点来制定这个假设:

  1. 我们看到的唯一错误是来自 MariaDB 的错误。

  2. 这个错误不是典型的 SQL 错误,消息本身表明存在访问数据库文件的问题。

  3. 在 Apache 日志中没有 PHP 错误。

  4. 关于 WordPress 环境的其他一切似乎都是正确的。

现在我们已经形成了一个假设,我们需要通过尝试解决问题来验证这一点。这将引导我们到故障排除过程的第三阶段:试错

解决问题

在这个阶段,我们将尝试解决这个问题。为了做到这一点,让我们看看这些数据文件是什么,它们用于什么。

理解数据库数据文件

除了仅内存数据库之外,大多数数据库都有一种用于在文件系统上存储数据的文件;这通常被称为持久存储。MariaDB 和 MySQL 也不例外。

根据使用的数据库存储引擎,可能会有一个大文件或多个具有不同文件扩展名的文件。无论文件类型或文件存储在何处/如何存储,最终,如果这些文件无法访问,数据库将出现问题。

查找 MariaDB 数据文件

由于我们对这个环境还很陌生,我们目前不知道 MariaDB 数据文件存储在哪里。确定这些文件的位置将是纠正问题的第一步。识别数据文件夹的一种方法是查看数据库服务的配置文件。

由于/etc文件夹是大多数(但不是所有)配置文件的所在地,这是我们应该首先查找的地方。

# ls -la /etc/ | grep -i maria

为了确定正确的配置文件,我们可以使用ls命令列出/etc文件夹,并使用grep命令在结果中搜索包含maria字符串的内容。上述的grep命令使用了-i(不区分大小写)标志,这会导致grep搜索大写和小写字符串。如果文件夹或文件具有混合大小写名称,这可能会有所帮助。

由于我们的命令没有输出,所以在名称中没有包含maria的文件夹或文件。这意味着 MariaDB 服务的配置要么命名为我们不期望的名称,要么不在/etc/文件夹中。

由于 MariaDB 应该是 MySQL 的一个可替换的解决方案,我们还应该检查是否有一个名为mysql的文件夹或文件。

# ls -la /etc/ | grep –i mysql

看起来也没有与这个名称匹配的文件夹或文件。

我们可以使用ls命令来花费几个小时来寻找 MariaDB 的配置文件。幸运的是,有一种更快的方法来找到配置文件。

由于 MariaDB 是通过 RPM 软件包安装的,我们可以使用rpm命令列出软件包部署的所有文件和文件夹。早些时候在检查 MariaDB 的安装方式时,rpm命令显示了多个 MariaDB 软件包。我们感兴趣的软件包是mariadb-server软件包。该软件包安装了 MariaDB 服务以及默认配置文件。

早些时候,我们使用了rpm-q-l标志列出了该软件包部署的所有文件。如果我们只想限制查询到配置文件,我们可以使用-q-c标志。

$ rpm -qc mariadb-server /etc/logrotate.d/mariadb
/etc/my.cnf.d/server.cnf
/var/log/mariadb/mariadb.log

从上面可以看出,mariadb-server软件包部署了三个配置文件。mariadb.loglogrotate.d文件不太可能包含我们正在寻找的信息,因为它们与日志记录过程有关。

这留下了/etc/my.cnf.d/server.cnf文件。我们可以使用cat命令读取这个文件。

# cat /etc/my.cnf.d/server.cnf
#
# These groups are read by the MariaDB server.
# Use it for options that only the server (but not clients) should see
#
# See the examples of server my.cnf files in /usr/share/mysql/
#

# this is read by the standalone daemon and embedded servers
[server]

# this is only for the mysqld standalone daemon
[mysqld]

# this is only for embedded server
[embedded]

# This group is only read by MariaDB-5.5 servers.
# If you use the same .cnf file for MariaDB of different versions,
# use this group for options that older servers don't understand
[mysqld-5.5]

# These two groups are only read by MariaDB servers, not by MySQL.
# If you use the same .cnf file for MySQL and MariaDB,
# you can put MariaDB-only options here
[mariadb]

[mariadb-5.5]

不幸的是,这个文件也不包含我们希望的数据文件夹的详细信息。然而,这个文件确实给了我们一个线索,告诉我们接下来应该去哪里找。

server.conf文件的父文件夹是/etc/my.cnf.d文件夹。文件夹名称末尾的.d很重要,因为这种命名约定在 Linux 中有特殊用途。.d(点 D)文件夹类型旨在允许用户简单地为服务添加一个文件或多个文件,以进行自定义配置。当服务启动时,该文件夹中的所有文件都会被读取,并应用配置。

这允许用户配置服务而无需编辑默认配置文件;他们可以通过在.d文件夹中创建一个新文件来简单地添加他们想要添加的配置。

重要的是要注意,这是一种配置方案,并非每个服务都支持这种方案。然而,似乎 MariaDB 服务确实支持这种方案。

然而,有趣的是,这个.d文件夹的名称。通常,.d配置文件夹的命名约定是服务名称或文件夹用途后跟.d。您可以在/etc/cron.d/etc/http/conf.d文件夹中看到这一点。MariaDB 的.d文件夹的名称表明主配置文件可能被命名为my.cnf

如果我们检查这样的文件是否存在,我们会发现确实存在。

# ls -la /etc/ | grep my.cnf
-rw-r--r--.  1 root root      570 Nov 17 12:28 my.cnf
drwxr-xr-x.  2 root root       64 Jan  9 18:20 my.cnf.d

这个文件似乎是主 MariaDB 配置文件,希望其中包含数据文件夹配置。要找出,我们可以使用cat命令读取这个文件。

# cat /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd

[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid

#
# include all files from the config folder
#
!includedir /etc/my.cnf.d

正如预期的那样,这个文件实际上包含了数据文件夹的配置。

datadir=/var/lib/mysql

有了这些信息,我们现在可以对 WordPress 数据库的数据文件的当前状态进行故障排除。

解决数据文件问题

如果我们切换到/var/lib/mysql文件夹并使用ls命令列出文件夹内容,我们会看到相当多的数据库数据文件/文件夹。

# cd /var/lib/mysql/
# ls -la
total 28712
drwxr-xr-x.  6 mysql mysql     4096 Jan 15 00:20 .
drwxr-xr-x. 29 root  root      4096 Jan 15 05:40 ..
-rw-rw----.  1 mysql mysql    16384 Jan 15 00:20 aria_log.00000001
-rw-rw----.  1 mysql mysql       52 Jan 15 00:20 aria_log_control
-rw-rw----.  1 mysql mysql 18874368 Jan 15 00:20 ibdata1
-rw-rw----.  1 mysql mysql  5242880 Jan 15 00:20 ib_logfile0
-rw-rw----.  1 mysql mysql  5242880 Jan  9 21:39 ib_logfile1
drwx------.  2 mysql mysql     4096 Jan  9 21:39 mysql
srwxrwxrwx.  1 mysql mysql        0 Jan 15 00:20 mysql.sock
drwx------.  2 mysql mysql     4096 Jan  9 21:39 performance_schema
drwx------.  2 mysql mysql        6 Jan  9 21:39 test
drwx------.  2 mysql mysql     4096 Jan  9 22:55 wordpress

看起来,这台服务器上创建的每个数据库都存在于/var/lib/mysql/下的一个文件夹中。从ls输出中还可以看出,这些文件夹处于正常状态。由于问题出在 WordPress 数据库上,我们将专注于这个数据库,切换到wordpress文件夹。

# cd wordpress/
# ls -la
total 156
drwx------. 2 mysql mysql  4096 Jan  9 22:55 .
drwxr-xr-x. 6 mysql mysql  4096 Jan 15 00:20 ..
-rw-rw----. 1 mysql mysql    65 Jan  9 21:45 db.opt
----------. 1 root  root   8688 Jan  9 22:55 wp_commentmeta.frm
----------. 1 root  root  13380 Jan  9 22:55 wp_comments.frm
----------. 1 root  root  13176 Jan  9 22:55 wp_links.frm
----------. 1 root  root   8698 Jan  9 22:55 wp_options.frm
----------. 1 root  root   8682 Jan  9 22:55 wp_postmeta.frm
----------. 1 root  root  13684 Jan  9 22:55 wp_posts.frm
----------. 1 root  root   8666 Jan  9 22:55 wp_term_relationships.frm
----------. 1 root  root   8668 Jan  9 22:55 wp_terms.frm
----------. 1 root  root   8768 Jan  9 22:55 wp_term_taxonomy.frm
----------. 1 root  root   8684 Jan  9 22:55 wp_usermeta.frm
----------. 1 root  root   8968 Jan  9 22:55 wp_users.frm

在执行ls命令后,我们可以看到这个文件夹中的文件有些不寻常。

突出的问题只是所有的.frm文件都具有000的文件模式。这意味着所有者、组或其他 Linux 用户都无法读取或写入这些文件。这包括 MariaDB 运行的用户。

如果我们回顾一下从 MariaDB 收到的错误,我们会发现错误似乎支持这样的假设,即无效的权限实际上导致了问题。要纠正这个错误,我们只需要将权限重置为正确的值。

由于我们对 MariaDB 还很陌生,目前我们不知道这些值应该是什么。

幸运的是,有一种简单的方法可以弄清楚权限应该是什么:只需查看另一个数据库的文件权限。

如果我们回顾一下/var/lib/mysql文件夹的列表输出,我们会发现有几个文件夹。其中至少一个其他文件夹也应该是数据库的数据文件夹。要确定我们的.frm文件应该具有什么权限,我们只需要找到其他.frm文件。

# find /var/lib/mysql -name "*.frm" -ls
134481927   12 -rw-rw----   1 mysql    mysql        9582 Jan  9 21:39 /var/lib/mysql/mysql/db.frm
134481930   12 -rw-rw----   1 mysql    mysql        9510 Jan  9 21:39 /var/lib/mysql/mysql/host.frm
134481933   12 -rw-rw----   1 mysql    mysql       10630 Jan  9 21:39 /var/lib/mysql/mysql/user.frm
134481936   12 -rw-rw----   1 mysql    mysql        8665 Jan  9 21:39 /var/lib/mysql/mysql/func.frm
134481939   12 -rw-rw----   1 mysql    mysql        8586 Jan  9 21:39 /var/lib/mysql/mysql/plugin.frm
134481942   12 -rw-rw----   1 mysql    mysql        8838 Jan  9 21:39 /var/lib/mysql/mysql/servers.frm
134481945   12 -rw-rw----   1 mysql    mysql        8955 Jan  9 21:39 /var/lib/mysql/mysql/tables_priv.frm
134481948   12 -rw-rw----   1 mysql    mysql        8820 Jan  9 21:39 /var/lib/mysql/mysql/columns_priv.frm
134481951   12 -rw-rw----   1 mysql    mysql        8770 Jan  9 21:39 /var/lib/mysql/mysql/help_topic.frm
134309941   12 -rw-rw----   1 mysql    mysql        8700 Jan  9 21:39 /var/lib/mysql/mysql/help_category.frm

find命令是一个非常有用的故障排除命令,可以在许多不同的情况下使用。在我们的示例中,我们使用find命令通过–name标志搜索/var/lib/mysql文件夹中以“.frm”结尾的任何文件。–ls(文件夹列表)标志告诉find命令以长列表格式打印它找到的任何文件,这将显示每个文件的权限,而无需运行第二个命令。

find命令的输出中,我们可以看到.frm文件的权限设置为-rw-rw----;这个的数字表示是660。这些权限似乎适用于我们的数据库表,并允许所有者和组读写这些文件。

为了重置 WordPress 数据文件的权限,我们将使用chmod命令。

# chmod -v 660 /var/lib/mysql/wordpress/*.frm
mode of '/var/lib/mysql/wordpress/wp_commentmeta.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_comments.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_links.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_options.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_postmeta.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_posts.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_term_relationships.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_terms.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_term_taxonomy.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_usermeta.frm' changed from 0000 (---------) to 0660 (rw-rw----)
mode of '/var/lib/mysql/wordpress/wp_users.frm' changed from 0000 (---------) to 0660 (rw-rw----)

在前面的命令中,使用了–v(详细)标志与chmod,以便我们可以看到每个文件的权限在命令执行时的变化。

验证

现在权限已经设置好,我们可以再次使用 SQLselect查询进行验证。

MariaDB [wordpress]> select count(*) from wp_users;
ERROR 1017 (HY000): Can't find file: './wordpress/wp_users.frm' (errno: 13)

从上面的查询中,我们可以看到 MariaDB 访问这些文件仍然存在错误。这意味着我们可能没有纠正所有数据文件的问题。

# ls -la
total 156
drwx------. 2 mysql mysql  4096 Jan  9 22:55 .
drwxr-xr-x. 6 mysql mysql  4096 Jan 15 00:20 ..
-rw-rw----. 1 mysql mysql    65 Jan  9 21:45 db.opt
-rw-rw----. 1 root  root   8688 Jan  9 22:55 wp_commentmeta.frm
-rw-rw----. 1 root  root  13380 Jan  9 22:55 wp_comments.frm
-rw-rw----. 1 root  root  13176 Jan  9 22:55 wp_links.frm
-rw-rw----. 1 root  root   8698 Jan  9 22:55 wp_options.frm
-rw-rw----. 1 root  root   8682 Jan  9 22:55 wp_postmeta.frm
-rw-rw----. 1 root  root  13684 Jan  9 22:55 wp_posts.frm
-rw-rw----. 1 root  root   8666 Jan  9 22:55 wp_term_relationships.frm
-rw-rw----. 1 root  root   8668 Jan  9 22:55 wp_terms.frm
-rw-rw----. 1 root  root   8768 Jan  9 22:55 wp_term_taxonomy.frm
-rw-rw----. 1 root  root   8684 Jan  9 22:55 wp_usermeta.frm
-rw-rw----. 1 root  root   8968 Jan  9 22:55 wp_users.frm

通过查看ls命令的输出,我们可以看到与示例.frm文件的另一个不同之处。

134481927   12 -rw-rw----   1 mysql    mysql        9582 Jan  9 21:39 /var/lib/mysql/mysql/db.frm

wordpress文件夹中文件的所有者和组权限设置为root,而其他.frm文件的所有者和组为mysql用户。

660的权限意味着只有文件的所有者和组成员可以访问它。对于我们的 WordPress 文件,这意味着只有 root 用户和 root 组的任何成员可以访问这些文件。

由于 MariaDB 以mysql用户运行,MariaDB 服务仍然无法访问这些文件。我们可以使用chown命令重置所有权和组成员。

# chown -v mysql.mysql ./*.frm
changed ownership of './wp_commentmeta.frm' from root:root to mysql:mysql
changed ownership of './wp_comments.frm' from root:root to mysql:mysql
changed ownership of './wp_links.frm' from root:root to mysql:mysql
changed ownership of './wp_options.frm' from root:root to mysql:mysql
changed ownership of './wp_postmeta.frm' from root:root to mysql:mysql
changed ownership of './wp_posts.frm' from root:root to mysql:mysql
changed ownership of './wp_term_relationships.frm' from root:root to mysql:mysql
changed ownership of './wp_terms.frm' from root:root to mysql:mysql
changed ownership of './wp_term_taxonomy.frm' from root:root to mysql:mysql
changed ownership of './wp_usermeta.frm' from root:root to mysql:mysql
changed ownership of './wp_users.frm' from root:root to mysql:mysql

现在文件的所有权和组成员是mysql,我们可以重新运行我们的查询,看看问题是否已解决。

MariaDB [wordpress]> select count(*) from wp_users;
count(*)
1

最终,我们通过查询 WordPress 数据库表解决了错误。

最终验证

由于我们已解决了数据库错误,并且在故障排除过程中没有发现其他错误,下一个验证步骤是查看博客是否仍然显示安装屏幕。

最终验证

通过从浏览器访问http://blog.example.com,我们现在可以看到我们不再收到安装页面,而是博客的首页。此时,问题似乎已经解决了。

一般来说,当处理由某人报告的问题时,最佳做法是让最初报告问题的人验证一切是否已恢复到预期状态。我见过许多情况,其中一个事件是由多个问题引起的,虽然更明显的问题很快得到解决,但其他问题往往被忽视。让用户验证我们已经解决了整个问题将有助于确保一切都已真正解决。

对于这种情况,当我们询问报告问题的业务用户是否问题已解决时,他/她回答说一切看起来都修复了。谢谢!

摘要

在本章中,我们通过使用在现实世界中可能经常发生的问题来走过了故障排除过程。我们详细介绍了故障排除过程的步骤 1、2 和 3,以收集数据、建立假设和解决问题;这些步骤在第一章故障排除最佳实践中有详细介绍。我们还使用了在第二章故障排除命令和有用信息来源中学到的几个命令和日志文件,以及一些新的命令。

虽然学习本章中使用的命令对于任何与 Web 应用程序一起工作的系统管理员来说都很重要,但更重要的是看我们遵循的过程。我们开始处理问题时对环境或应用程序没有先验知识,但通过一些基本的数据收集和反复试验,我们可以解决问题。

在下一章中,我们将使用相同的故障排除过程和类似的工具来解决性能问题。