如何构建日志监控系统

lucywang 技术 2019年1月23日发布
Favorite收藏

导语:日志信息几乎可以记录攻击者需要的任何东西,包括漏洞信息、通信信息、电子邮件信息等。不过要将这些信息进行输出,没有一定的技术和付出是不可能的。本文将讲述如何构建日志监控系统。

有哪些数据类型会被监控

监控数据通常由几种类型的数据组成:

· 日志数据:丰富、详细的文本和数据;

· 可以用于遥测的标签数据;

· 运行状况检查数据;

· 来自应用程序的性能数据;

日志数据

日志信息几乎可以记录攻击者需要的任何东西,包括漏洞信息、通信信息、电子邮件信息等。不过要将这些信息进行输出,没有一定的技术和付出是不可能的。首先,你需要为日志记录本身分配字符串,比如内存和垃圾收集(适用于.NET和其他一些平台)。当你在某处进行日志记录时,磁盘空间必定要运行。如果我们遍历网络(在某种程度上是在本地),这也意味着带宽和延迟。

日志数据会记录所有的事情。如果技术能力够硬且付出一定的成本,你就能详细查看这些日志,挖掘更多内容。所以聪明的人,会通过构建日志记录,记录他们认为需要的内容。但这个构建过程并不容易,比如当出现问题时,你会发现有时新添加的功能没有正确的日志记录。

至于日志具体能记录什么?这取决于系统。在本文的示例中,我们使用StackExchange.Exceptional执行记录操作,这是我维护的一个开源.NET的数据库的中央异常日志查看器。这些异常日志会记录到SQL Server,然后通过应用程序或通过Opserver(Stack Overflow 的开源监控产品)查看。

对于像Redis,Elasticsearch和SQL Server这样的系统,我们只需使用内置的日志记录和日志回旋(Log Rotation)机制登录到本地磁盘。日志回旋(Log Rotation) 可以设定日志的回旋是基于文件大小还是基于时间间隔。当满足其中的一个条件时,当前访问日志被关闭,新的访问日志被创建。对于其他基于SNMP的系统,如network gear,我们可以将所有这些日志转发到Logstash集群,Logstash 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的 “存储库” 中。不过用Logstash之前,可以先用Kibana(一个开源的分析和可视化平台)查询。 将日志转发到Logstash集群后,Bosun会在发出警报时,询问其中的很多细节和趋势,我们将在下文中深入探讨。Bosun 是一个新型的监控和告警系统,由Stack Exchange团队打造,使用golang编写,支持定义复杂的告警规则,支持OpenTSDB、Graphite、Logstash-Elasticsearch 等数据源。

用HAProxy构建日志监控

HAProxy默认情况下并没有启用日志功能,或者说已经启用了但需配合日志软件方能有效。

在本文的示例中,我们还记录了通过HAProxy(负载均衡器)的公共HTTP请求,不过其中只记录了顶级域名,没有cookie,没有表单数据等。

在这些请求中,我们将使用某些特定的性能数字将标头发送到HAProxy, HAProxy会捕获这些标头并将这些标头剥离到我们转发的syslog行中,以便最后进行SQL处理。这些标头包括:

· SQL Count(查询);

· Redis Count(查询命中次数);

· HTTP Count(发送请求);

· Tag Engine Count (查询);

· Elasticsearch Count(查询命中);

利用这些查询,我们可以轻松查询和比较历史数据。它在我们从未真正想过的方式中也很有用。例如,我们将看到一个请求和运行的SQL查询计数,它将告诉我们用户沿着代码路径走了多远。或者当SQL连接池堆积起来时,我们可以查看特定时间内来自特定服务器的所有请求,以查看导致该争用的原因。我们所做的就是跟踪n个服务的通讯次数和时间。这个方法非常简单,但也非常有效。

监控syslog并将其保存为SQL的过程称为流量处理服务(Traffic Processing Service),因为我们计划在一天内发送报告。

除了这些标头之外,默认的HAProxy日志行格式还有一些其他计时请求:

TR:客户端向我们发送请求所用的时间(在keepalive运行时相当无用);

Tw:排队等待的时间;

Tc:等待连接到web服务器的时间;

Tr:web服务器完全呈现响应所花费的时间;

另一个简单但重要的例子是,Tr和AspNetDurationMs报头(一个计时器在请求的开始和结束时开始和结束)之间的增量,会告诉我们在操作系统中花费了多少时间,在IIS中等待线程等。

运行状况检查

在任何负载分配设置(例如一起工作的服务器集群或一组服务器前面的负载均衡器)中,运行状况检查是一种查看成员是否符合角色或任务的方法。例如,在Elasticsearch中,如果一个节点宕机后,当节点恢复运行时,再次执行此操作。在Web层中,负载均衡器将停止向下行节点发送流量,并继续在运行流量节点之间进行操作。

在HAProxy中,我们使用了内置的运行状况检查和警告。截至2018年末,在我们编写这篇文章时,仍用的是ASP.NET MVC5。一个重要的细节是我们的错误页面是一个重定向的,例如出现/questions的时候,会定向到/error?aspxerrorpath=/questions。应该说这是旧.NET基础结构的运行细节,但是当与HAProxy结合使用时,就成了问题。例如,如果你有:

server ny-web01 10.x.x.1:80 check

然后它将接受200-399个HTTP状态码响应(它只会发出一个HEAD请求),如果是400或500个HTTP状态码响应,则不会触发运行,但我们的302重定向不会发生此情况。发生重定向后,浏览器将获得5xx状态代码,但HAProxy实际上不会这样做。你可以在同一后端使用http-check expect 200(或任何状态代码或范围或正则表达式)来更改此设置,这意味着我们的运行检查终端只允许200。

不同的应用程序因运行检查端点而异,但对于stackoverflow.com,由于它是主页,它会检查我们可能无法检查的事情,全面检查很重要。我的意思是,如果用户点击同一页面,它会全面检查吗?,如果我们进行了运行检查,数据库和一些缓存和理智检查了我们知道需要联机的大事,那就太棒了,就这样了有总比没有好。如果我们对数据库和缓存进行了运行检查,检查我们需要的大数据。但是,假设我们在代码中放入了一个漏洞,此时一个看起来并不重要的缓存都没有重新被正确加载,此时所有用户都会呈现在顶栏。

我们还在数据库内进行了运行检查,最简单的表现就是心跳(Heartbeat)进程的检查。例如,StackExchange.Redis用于定期检查与Redis的套接字连接是否处于运行状态。我们会使用相同的方法来查看套接字是否仍然打开,并在Stack Overflow(一个与程序相关的IT技术问答网站)上利用WebSocket实现数据的实时推送。这是一种没有在这里大量使用的监控,但它确实被使用了。

其他运行检查还包括标签引擎服务器,我们可以通过HAProxy来平衡负载(这会增加一个跳转),但是让每个Web层服务器直接了解每个标签服务器对我们来说都是更好的选择。我们可以监控的信息如下:

1.选择如何分配负载;

2.更容易测试新构建;

3.获取每服务器操作计数指标和性能数据;

我们可以通过一个简单的“ping”命令进行运行状况检查,例如它最后一次在数据库更新的时间。

所以,这可以保证对你的运行状态的绝对监控。Microsoft .NET团队一直致力于开发一个在ASP.NET Core中进行运行检查的统一方法。

不过,对运行状态的监控与运行的频率有关,比如每100毫秒的运行监控与每秒、5秒或每分钟的监控都不一样。

Stack Overflow就是一个实际的例子:当你将HAProxy后端服务器从MAINT(维护模式)切换到ENABLE时,后端会正常运行,直到检查运行状态发现问题时,才会停止。但是,当你从DRAIN切换到ENABLE时,后端会先停止运行,必须通过3次状态检查才能获得流量。当我们处理线程池增长限制和缓存试图启动时(比如我们的Redis连接),由于运行状况检查,我们可能会遇到非常讨厌的线程池饥饿(thread pool starvation)问题。这个影响是巨大的。因为在进行模式切换时,我们需要大约8-20秒才能完全准备好在新构建的Web服务器上提供流量。

使用httpUnit构建监控系统

HttpUnit是基于JUnit构建的一个开源测试框架,专门针对Web应用的测试,解决使用JUnit框架无法对远程Web内容进行测试的弊端。

HttpUnit通过模拟浏览器的行为,包括提交表单(form)、处理页面框架(frames)、基本的http验证、cookies及页面跳转(redirects)处理等。通过HttpUnit提供的功能,用户可以方便的和服务器端进行信息的交互,将返回的网页内容作为普通文本、XML Dom对象或者是作为链接、页面框架、图像、表单、表格等的集合进行处理,然后使用JUnit框架进行测试,还可以导向一个新的页面,然后进行新页面的处理,这个功能使你可以处理一组在一个操作链中的页面。总的来说,httpUnit是一个相当简单易用的工具,我们用它来检查端点的状态,看看此URL是否返回我们期望的状态代码? 

通过不断检查并在失败时提供警报,我们可以快速识别问题,尤其是那些来自基础架构的无效配置更改的问题。在应用用户负载之前,我们还可以轻松测试新的配置或基础架构,防火墙规则等。

使用Fastly构建监控系统

Fastly作为美国的CDN厂商,近年来不断在边缘云领域深度布局。你可以将Fastly视为负载均衡器时,它类似于HAProxy后端,内置了运行检查。

监控指标

监控指标可以是时间序列数据,这意味其中你有一个名称、一个时间戳、一个值,在本文的示例中,有一些标签。例如,单个条目看起来如下所示:

· 名称:dotnet.memory.gc_collections

· 时间:2018-01-01 18:30:00(UTC)

· 值:129389139

· 标签:服务器:NY-WEB01,应用程序:StackExchange-Network

条目中的值也可以采用几种形式,但一般情况下是计数器。计数器会报告一个不断增加的值(通常在重新启动时重置为0)。通过计算值随时间的差值,你可以找到窗口中的Delta值。例如,如果我们在10分钟之前有129389139个进程,我们就知道在那十分钟内该服务器上的进程运行了100个Gen 0垃圾收集通道。另一个例子是报告一个绝对时间点的值,例如“此GPU当前为87°”,那么我们用什么来处理这些监控到的数据问题呢?

警报信息的处理

我们如何处理所有这些数据呢? Bosun是我们内部的主要警报源,它由OpenTSDB支持存储。它是一个基于HBase构建的时间序列数据库,具有很高的可扩展性。bosun是常用的报警系统,通过配置metrics(items)图可以得到某一个参数在指定时间内的变化,比如设为10s,每隔10s就会监控这个数据并画图,依据这个图可以实现对某些参数的监控,以此作为报警的依据。 

在.NET中,我们使用我们维护的另一个开源NuGet库BosunReporter发送监控指标。它看起来像如下这样:

// Set it up once globallyvar collector = new MetricsCollector(new BosunOptions(ex => HandleException(ex)){
	MetricsNamePrefix = "MyApp",
	BosunUrl = "https://bosun.mydomain.com",
	PropertyToTagName = NameTransformers.CamelToLowerSnakeCase,
	DefaultTags = new Dictionary<string, string>
		{ {"host", NameTransformers.Sanitize(Environment.MachineName.ToLower())} }});// Whenever you want a metric, create one! This should be likely be static somewhere// Arguments: metric name, unit name, descriptionprivate static searchCounter = collector.CreateMetric<Counter>("web.search.count", "searches", "Searches against /search");// ...and whenever the event happens, increment the countersearchCounter.Increment();

我们还可以在Bosun的数据计数器中,添加更多标签,例如,计数器在哪个服务器上运行(通过主机标签),我们可以在IIS中添加应用程序池,或者用户点击的Q&A网站等。

许多其他系统都可以发送指标,scollector为Redis、Windows、Linux等提供了大量的内置功能。我们用于关键监控的另一个外部示例是一个小型Go服务,它可以监控Fastly日志的实时流。有时Fastly可能会返回503,错误的原因也许是被切断的套接字,或者是路由问题,或者是坏的证书。无论原因是什么,我们都希望在这些请求失败并且用户感觉到失败时系统会发出警报。这个小服务只会监控日志流,不过它从每个条目中解析一些信息,并将它们汇总后发送给Bosun。

我真正喜欢Bosun的一个关键特性是,它能够监控历史警报。这有助于我们了解警报具体是何时触发的,这是一个很棒的监控过程。说实话,很多监控来自经验教训,警报经常是在事情发生之后,才将出错的信息添加到其中。

3.1.png

3.2.png

你可以看到在11月18日有一个很低的系统值,低到足以触发安全警告。

我们还通过以下几种方式监控(通过Bosun)错误:

1.通过每个应用程序总结我们的异常错误日志;

2.通过Fastly和HAProxy;

如果我们在这两种应用程序上都看到了高错误率,那么一两分钟后,带有详细信息的消息就会出现在聊天中。由于它们是基于聚合计数的,因此不能立即执行。

5.png

另一种传递警报的方式是电子邮件,Bosun就有这个功能。电子邮件可能只是一个简单的提醒。比方说,磁盘空间正在减少,或者CPU处于高位运行,而电子邮件中的一个简单图表就能说明很多问题。要想得到更复杂的警报,我们可以为电子邮件本身添加故障和详细信息。你可以得到更好的信息来处理(或者甚至决定忽略)一封电子邮件的提醒,而无需进一步深入。这是本文的示例中,NY-TSDB03的CPU突发事件的邮件示例,其中包括了最近的10个事件。

6.png

7.png

8.png

Grafana

Grafana是一个开源的度量分析和可视化套件,它最常用于可视化基础设施和应用程序分析的时间序列数据。

如果监控数据,你看不到,那么这些数据有什么用呢?所以时间序列数据的图形化可视化是一种很好的方式。这就是我们为什么使用Grafana的地方,它是一个优秀的开源工具,为此我们提供了一个Bosun插件,这样它就可以成为一个数据源。 (从技术上讲,你可以直接使用OpenTSDB)。注意:我们对Grafana的使用过程,会使用图片的方式来解释。

以下是一个状态仪表板,显示了Fastly的运作方式。因为我们的插件会支持他们的DDoS保护和更快的内容发送,所以当前显示的状态也是我们的当前状态。

9.png

这是一个随机的仪表盘,它是按地域划分的,你可以看到当人们醒着的时候,世界各地的网络流量分布情况。

客户端计时

关于上面提到的所有内容,一个重要的注意事项是它是服务器端。记住,渲染网页的速度并不重要,这一点至关重要。

几年前,当我们需要的部分首次在浏览器中可用时,我构建了一个客户机计时管道。这个概念很简单:使用web浏览器中可用的导航计时API并记录它。要了解其工作原理,请访问teststackoverflow.com

12.png

13.png

MiniProfiler

有时,你要捕获的数据比上述方案更具体和详细。MiniProfiler是一款针对.NET, Ruby, Go and Node.js的性能分析的轻量级程序。可以对一个页面本身,及该页面通过直接引用、Ajax、Iframe形式访问的其它页面进行监控,监控内容包括数据库内容,并可以显示数据库访问的SQL(支持EF、EF CodeFirst等 )。并且以很友好的方式展现在页面上。MiniProfiler的一个特别有用的功能是它与数据库框架的集成。除了.NET原生的DbConnection类,MiniProfiler还内置了对实体框架(Entity Framework)以及LINQ to SQL、RavenDb和MongoDB的支持。任何执行的Step都会包括当时查询的次数和所花费的时间。为了检测常见的错误,如N+1反模式,profiler将检测仅有参数值存在差异的多个查询。

15.png

默认情况下,你可以看到这个数字,但是你可以将其展开以查看树形式中哪些内容需要花费多长时间。在那里链接的命令也是可见的,因此你可以Fastly查看运行的SQL或Elastic查询,或发出的HTTP调用,或者获取的Redis缓存等。

16.png

由于MiniProfiler的运行成本很低,我们可以在每个请求上运行它。为此,我们在Redis中保留了每MVC路由的配置文件样本。例如,我们在给定时间保留任何路由的100个最慢的配置文件。这样我们就可以看到用户可能会遇到的问题,我们可以看到Bosun中的路由速度很慢,HAProxy日志中的点击率下降了,还有需要深入研究的配置文件快照。

17.png

使用Opserver构建日志监控系统

那么,什么是Opserver?Opserver是Stack Overflow的开源监控产品,stackoverflow网站是基于asp.net开发的,它是一个基于网络的仪表板和监控工具。大约5年前,我们遇到了一个问题,即SQL Server AlwaysOn可用性组在SSMS仪表板上显示为绿色(由主服务器提供支持),但是副本已经好几天没有看到新数据了。这是一个监控极度失效的例子。发生的情况是HADR线程池耗尽,并停止更新处于“all good”状态的视图。这样的设计不一定是有缺陷的,但是当缓存/存储一个事物的状态时,它需要有一个时间戳。如果尚未在<选择阈值>中更新,则为红色警报。无论如何,进入Opserver。它做的第一件事是监控每个SQL节点而不是信任主节点。

从那时起,我在基于Web的Fastly视图中为我们想要的其他系统添加了监控功能。

Opserver:主要仪表板

登陆仪表板是一个服务器列表,显示了内容的概述。用户可以按名称、服务标签、IP地址、VM主机等进行搜索。你还可以深入查看每个节点上CPU、内存和网络的历史记录图表。

19.png

在每个节点内看起来像这样:

20.png

如果使用Bosun并运行Dell服务器,则我们添加了如下硬件元数据。

21.png

Opserver:SQL Server

在SQL仪表板中,我们可以看到服务器状态以及可用性组的工作方式。我们可以看到每个节点在任何给定时间有多少活动,以及哪个节点是主节点(蓝色部分)。底部是AlwaysOn可用性组,我们可以看到每个可用性组的主服务器是谁,复制的进度落后了多少,以及备份了多少队列。如果事情变糟并且副本不运行,则会出现更多指示符,例如哪些数据库存在问题以及T-logs中涉及的所有驱动器的主数据库上的可用磁盘空间(因为如果复制仍然停止,它们将开始增长):

22.png

还有一个顶级的全部作业视图,用于Fastly监控和启用/禁用:

23.png

在每个实例视图中,我们可以看到有关服务器、缓存等的统计信息,我们发现它们随着时间的推移而变得相关。

24.png

对于每个实例,我们还报告顶级查询(基于计划缓存,而不是查询存储),active-right – now查询(基于sp_whoisactive)、连接和数据库信息。

25.png

26.png

如果你想深入到一个顶部的查询,它看起来是这样的。

28.png

在数据库视图中,可以查看表、索引、视图、存储过程、存储使用情况等。

29.png

30.png

31.png

32.png

33.png

Opserver:Redis

对于Redis,我们希望查看主要副本和副本的拓扑链以及每个实例的总体状态:

34.png

35.png

请注意,你可以终止客户端连接、获取运行配置、更改服务器拓扑以及分析每个数据库中的数据(可通过Regexes配置)。最后一个是KEYS和DEBUG OBJECT扫描,因此我们在副本节点上运行它或允许在主服务器上强制运行它(为了安全起见)。分析看起来像这样:

SO-Monitoring-Opserver-Redis-Analyze.png

Opserver:Elasticsearch

对于Elasticsearch,我们通常希望看到集群视图中的内容,因为这就是它的行为方式。下面没有看到的是,当索引变为黄色或红色时。当这种情况发生时,仪表板的新增的部分将显示出有问题的碎片、它们正在做什么(初始化、重新定位等),并且计数将出现在每个集群中,汇总有多少碎片处于哪种状态。

1.png

2.png

Opserver:异常

Opserver中的异常是基于StackExchange.Exceptional。在这种情况下,我们特别关注Exceptional的SQL Server存储提供程序。Opserver是许多应用程序共享单个数据库和表布局的一种方式,并允许开发人员在一个地方查看其异常。

40.png

此处的顶级视图可以只是应用程序(默认),也可以按组配置。在上面的例子中,我们按团队配置应用程序组,这样团队就可以标记或快速单击他们负责的异常。在每个例外页面中,详细信息如下所示。

360截图16171107134336.jpg

还记录了详细信息,例如请求标头(带有安全过滤器,因此我们不会记录身份验证cookie),查询参数以及添加到异常的任何其他自定义数据。

Opserver:HAProxy

HAProxy部分非常简单,我们只是简单地呈现当前的HAProxy状态并允许对其进行控制。这是主仪表板的样子:

41.png

对于每个后台组,特定后端服务器,整个服务器或整个层,它还允许一些控制。如果我们需要将其关闭以进行紧急维护等,可以让后端服务器停止运作,或者让整个后端关闭,或者让web服务器退出所有后端。

42.png

本文翻译自:https://nickcraver.com/blog/2018/11/29/stack-overflow-how-we-do-monitoring/如若转载,请注明原文地址: https://www.4hou.com/technology/15524.html
点赞 3
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论