复杂性、正常运行时间和世界末日
实施不力的监控系统会让管理员发疯。往好了说,它们会让人分心。往坏了说,它们会让值班人员连续几个晚上睡不着觉。本文讨论了设计系统的最佳实践,这些系统将保持您的系统正常运行,并在一切正常时保持安静。
在计算机行业工作了 20 多年后,我意识到每个人都能同意一件事:无论任何技术多么新、多么稳定或多么出色,它都会崩溃。
幸运的是,系统管理员会为此做好计划。无论是数据中心中的冗余服务器,还是 EC2 中的第二个可用区,确保正常运行时间的第一个也是最好的方法是减少整个网络中的单点故障数量。但是,这种方法也有缺点。将 Web 集群从一台增加到十台,将硬件故障导致整个站点瘫痪的可能性降低了十分之一。虽然这增加了冗余,但也大大增加了网络的成本和复杂性。现在不是运行单个服务器,而是一系列带有共享数据存储和负载均衡器的盒子。这种复杂性带来了缺点。硬件故障发生的可能性是原来的十倍,系统管理员会醒来,而这仅仅计算了实际的 Web 服务器。无论您是在数据中心还是在云中,这种服务分层都会显着增加单个设备发生故障并在半夜发出警报的可能性。
防止这种情况通常是系统管理员愿望清单上的首要任务,即使在实践中它往往被推到优先级列表的较低位置。半夜醒来修复服务器或软件对生产力和士气不利。有两个步骤可以帮助确保这种情况不会发生。第一步是在不增加系统复杂性的前提下,实施必要的冗余量,使其能够运行。第二步是实施一个监控系统,该系统允许您准确监控您想要监控的内容,而不是担心哪个单独的盒子使用了多少 RAM。
世界末日方法是一种思想实验,旨在帮助选择应用程序所需的冗余和复杂性级别。它有助于确定可接受的停机场景。通常,当您询问人们他们的站点何时可以接受停机时,他们会说永远不能,但这并不完全正确。如果小行星撞击地球并摧毁了大部分人类,站点是否需要保持运行?如果应用程序是 NORAD,那么可能是必要的,但对于 Groupon 来说,就没那么必要了。这种正常运行时间需要放置在全球战略位置的大型基础设施,以及只有大型政府通常才能获得的资本投资和人员配置。
从这种过度的灾难一步步退后,您可以找到可接受的水平。如果灾难仅限于大陆呢?此时可以接受停机吗?如果站点专注于这些客户,则可能是。如果站点是国际工具,例如亚马逊或谷歌,则可能不是。如果它位于数据中心或可用区本地,您的盒子保存在那里呢?即使反铲切断了他们数据中心的电源,大多数商店也希望保持运行。
当问题以这种方式构架时,很明显存在可接受的停机时间级别。管理员可以找到正常运行时间和复杂性之间的最佳点。找到这些要求的外部界限将揭示监控整个服务的要求。请注意,这是一个服务,而不是服务器。虽然很容易监控网络接口是否可用,但监控整个集群的健康状况更有意义。在我们的十台服务器集群中,如果 www6 在夜间利用率达到 40% 的集群上宕机,可能不值得为此起床。如果整个 Web 服务宕机,则需要立即采取行动。
监控系统基本上是一个调度程序和数据收集工具,它针对服务执行检查并将结果报告回公共仪表板上显示。它似乎是一个无害的软件,就像网络图或日志分析一样在后台运行,但它具有损害整个工程部门的隐藏能力。误报会让人在半夜醒来,并导致对值班的持续恐惧。这导致人们将事物置于维护模式以消除误报,并可能导致未被注意到的服务故障。
处理误报通常更多的是策略问题而不是设计问题。选择监控什么比选择如何监控更重要。许多公司都有监控 CPU 和 RAM 使用情况的历史。他们认为有时峰值是崩溃的先兆,因此对此发出警报是合理的。这里的问题是可能导致计算机使用 CPU 和 RAM 的东西,其中大多数都在操作系统的正常范围内。当系统管理员检查盒子时,资源正在使用中,但应用程序运行正常。除非在 RAM 超过一定水平与服务崩溃之间存在明确记录的联系,否则跳过对此类资源使用情况的警报会导致误报大大减少。监视器应与特定生产服务的已定义的好值或坏值相关联。
导致大量误报的另一条途径是在不同配备的盒子中使用百分比。例如,如果一个系统有一个 137G 的驱动器,其已满 95%,则仅剩约 6G 的可用空间。在流量大的站点或代码中包含大量检测的站点上,6G 可能很快就会用完。将此监视器应用于具有 2TB 磁盘的同一 Web 服务器似乎不那么紧急。在系统上隔夜仅保留 100G 的可用空间通常不是问题。如果特定盒子的日常平均磁盘使用量为 5G,则监控剩余 15G 的可用空间,并且仅允许在工作时间内发出警报将提前三天发出通知。提前这么长时间发出警报可以让系统管理员计划系统的停机时间(如果需要),以便可以在不中断支持服务的情况下维护服务器。
两个最流行的开源监控系统是 Zenoss 和 Nagios。这两个系统都提供类似的监控功能。Zenoss 提供了更多的功能和易用性,集成了节点的基本自动发现、内置 RRD 图形、syslog 管理和重复数据删除事件的能力。Nagios 提供了比 Zenoss 更大的社区和更轻的安装,这允许管理员使用他们自己的图形解决方案,而无需重复软件。最好的是它们具有用于监控脚本的通用格式;这些进程执行服务的实际检查。
虽然这两个系统都带有用于监控 HTTP 端口和类似流行服务的基本模板,但这些系统的大部分功能都来自编写自定义脚本的能力。这是检查不仅 Web 服务器是否启动,而且应用程序本身是否正常工作的好方法。以下是一个脚本示例,该脚本将通过调用 Hudson 的 JSON API 来监控 Hudson 作业的成功情况
#!/usr/bin/env ruby
# Call as:
# check_hudson_job.rb ${jobname} ${hostname}
require 'rubygems'
require 'json'
require 'net/http'
jobname = ARGV[0]
hostname = ARGV[1]
url = URI.parse("http://#{hostname}/job/#{jobname}/
↪lastBuild/api/json")
res = JSON.parse(Net::HTTP.get_response(url).body)
lastResult = res["result"]
if lastResult == "SUCCESS"
puts "OK|Status=0"
exit(0)
else
failurl = URI.parse("http://#{hostname}/job/
↪#{jobname}/api/json")
failres = JSON.parse(Net::HTTP.get_response(failurl).body)
health = failres["healthReport"][0]["description"]
puts "Job #{jobname} broke: #{health}"
exit(1)
end
监控系统使用作业名称和主机名称的命令行参数调用代码。然后,代码查找来自 Hudson 服务器的结果并检查是否成功。返回值和退出代码是监控脚本如何响应监控系统的方式。非零退出代码表示失败,返回值是系统显示为失败原因的字符串。在 Zenoss 上,这也用于重复数据删除。成功时,监控脚本的退出代码为 0,并以特殊形式返回字符串供系统处理(参见代码)。
使用这种结构,系统管理员可以与开发人员合作构建自定义 URL,监控系统可以访问这些 URL 以确定应用程序的健康状况,而无需担心集合中的每个系统。
可能很难接受隔夜关闭一个盒子是可以接受的。它可能是导致多个服务器宕机的级联故障中的第一个,最终导致服务宕机,但这可以直接从负载均衡器或前端设备解决,而不是间接查看盒子本身。使用此方法,可以将警报设置为在一定数量的盒子在一天中的某些时间发生故障后触发,并且无需解决更难的问题,例如要求每个盒子都知道整个集群的状态。
到目前为止,系统的设计在地理位置和云足迹方面相当不可知。对于大多数应用程序来说,这没有太大区别。通常,在多个地理位置的情况下,每个数据中心都有自己的监控系统实例,每个实例都监控其他位置的兄弟节点。在云中运行提供了更大的灵活性。虽然仍然需要监控监控系统,但这可以使用亚马逊的强大但配置性差得多的系统轻松完成,以监控 Nagios 或 Zenoss EC2 实例。
亚马逊云真正突出的是它的弹性。将 EC2 命令行程序连接到监控服务将允许在某些盒子由于资源匮乏、负载或程序在盒子上崩溃而遇到问题时启动新盒子。当然,这需要加以控制,否则实例的数量可能会失控,但在合理的范围内,从监控脚本内部启动新实例来代替崩溃或过载的实例相对容易。
以下是一个监控 Hadoop 集群负载并在运行作业数量增加时添加更多盒子的脚本示例
#!/bin/bash
# Call as:
# increase_amazon_set.sh ${threshold} ${AMI}
THRESHOLD=$1
AMI=$2
NUM_JOBS=`/opt/hadoop/current/bin/hadoop job -list |
↪head -1 | awk {'print $1'}`
if [[ $NUM_JOBS -gt $THRESHOLD ]] ; then
echo "Warning: $NUM_JOBS running, increasing cluster size by 3"
ec2-run-instances $AMI -n 3 --availability-zone us-east-1a
exit 1;
else
echo "OK|Status=0"
exit 0;
fi
这遵循与上一个脚本相同的格式,从命令行传入变量,并使用退出条件和返回的字符串将值返回给监控系统。这里最大的区别在于,您不仅仅是监控问题并将其传递给系统管理员来处理。此脚本充当编排器,尝试修复它看到的问题。虽然应注意对这种工作方式设置适当的界限,并且计算机不应能够在网络上横冲直撞,但这种智能调度程序可以成为自动化任务的强大工具。
虽然从头开始设置一个新的监控系统,并具有出色的警报规则和智能编排是一个好主意,但这通常是不可能的。大多数组织已经有一个监控系统到位,并且通常它充满了旧警报和已置于维护模式的盒子,因为它们比损坏更吵闹。如果是这种情况,就该剔除冗余了。删除所有当前警报,并将所有未实际进行维护的项目从维护模式中取出。取出前十个嘈杂且行为不端的设备,要么停止监控引发误报的项目,要么重写脚本,以便它们提供更有意义的数据。当最初的十个设备受到控制时,移动到下一组。可能需要几天的时间进行几次迭代,但最终,您会更关心来自可能对您来说非常强大的工具的消息。
监控系统通常被忽视为一种必需的烦恼,但只要稍加努力,就可以让它们为您工作。监控服务、查看集群应用程序以及仅对可以处理的实际错误发出警报,可以提供用于容量规划的真实指标,并让系统管理员睡个好觉,以便他们可以从日常工作中更加积极主动。
信标照片,通过 Shutterstock.com。