Java - 记录多节点环境中的最佳实践

时间:2017-04-19 13:08:22

标签: java http elasticsearch logback apache-httpclient-4.x

在我公司,我在一个多节点基础设施中管理一个大型应用程序(> 100k用户),由3个(但可能更多)的应用程序服务器组成。 每个应用程序服务器都有5个不同的日志文件,其中几乎记录了有关http / s(REST或SOAP)请求和对其他(外部)子系统的响应的每个信息。我使用Apache Http客户端来处理REST流,将wsimport生成的客户端用于SOAP请求,使用Logback作为日志记录技术。

目前,当我要求调试某些内容时,我要做的最复杂和最耗时的任务是确定我必须调试的节点。在那之后,为了发现发生了什么,我必须实际上使用大量的线条。说实话,我发现它非常无聊和过时,也很复杂。

为了让我的生活更轻松,让我的日志更有趣,我过去几天看了一下elasticsearch堆栈(elasticsearch,logstash,kibana),并使用他们的docker图像进行了游戏。我发现它们非常有趣,我想在我的应用程序中介绍它们但在此之前我想知道是否有最佳实践/模式来做类似的事情。

这些是我的怀疑:

  • 是否有最佳实践可以通过logstash轻松解析Http / s REST和SOAP请求/响应(我需要查看所有内容:url,header,path,body,cookies,...) / elasticsearch?
  • 考虑到我的基础架构,我应该使用elasticsearch appender进行我的logback实现,还是使用Logstash作为日志处理器(我想每个应用服务器都有一个)?
  • 是否有有效的logback和elasticsearch技术替代方案来满足我的要求?

我不希望得到一个简单易行的答案。我想了解不同的经历,以便做出最适合我的解决方案的选择

谢谢!

3 个答案:

答案 0 :(得分:3)

以下是其中一个复杂的答案:) ELK堆栈绝对可以让您在分布式环境中更轻松地生活。 但是,为了从中受益,您可以考虑以下做法:

  • 在ElasticSearch的日志消息中,您应该看到以下内容(除了明显的时间,级别,消息本身):

    • 已制作大量消息的服务器
    • 发起请求的用户
    • 如果您的申请是多租户 - 请求已经进行的承租人
  • 所有消息应具有相同的结构(布局)

  • 由于您使用Java,异常可能成为潜在问题(它们是多线的),因此需要特殊处理。 Logstash可以通过

  • 来处理它
  • 如果您的流可以分布在不同的服务器上(您说您有3个且可能更多),请考虑为每个请求生成一个特殊的相关ID。一些可以识别流量的随机数。

所有这些都有助于应用过滤器,并从Elastic Search中受益更多。

考虑将TTL用于日志。可能您不需要在超过一周或两周之前保留创建的日志。

现在关于HTTP请求。通常只记录所有内容可能是一个安全问题,因为您无法确定是否会记录某些“敏感”信息。所以你要保持这种保护(至少你的安全人员会想:))。可能记录URL,服务器,http方法和一些用户标识符(或者如果需要的话,租户)就足够了,但这完全是我的看法。

现在关于appender vs logstash(文件)方法。 这两种方法都有优点和反差。 例如: 如果使用logstash方法,则必须解析日志文件的每一行。如果您的应用程序生成许多日志,它可能会影响性能,因为解析可以通过CPU costy(特别是如果您在logstash中使用grok过滤器)。 另一方面 - appender允许完全避免解析(你将在java的内存中获得所有信息)。

另一方面,应仔细设置appender。我没有使用logback Elasticsearch appender的经验,但我认为它至少应该是:

  • 异步(否则您的业务流程可能会卡住)
  • 能够应对失败(你不会因为当前ES不可用或其他东西而抛出异常。最终用户不应该真正感受到这一点。)
  • 可能维护一些队列/使用破坏程序,只是因为你可以产生比你的appender可能发送给ES更多的日志,所以最终日志消息将丢失。例如,如果您有一个大小为1000的队列,并且日志中有超过1000条消息,则可以对FIFO将执行的操作进行映像。

还有另一件事需要考虑: 让我们想象一下,由于某种原因,其中一个应用程序服务器存在问题。所以你可能想要重新启动它(优雅与否)。如果你使用im-memory appender这些消息会发生什么?你想在ElasticSearch中看到它们来分析post mortum吗? 因此,底线内存中的方法无法处理重启。

另一方面,logstash进程将很乐意处理存储在文件中的任何内容。

至于appender与logstash的替代方法,您可能会考虑使用Apache Flume作为传输。如果你采用appender方法,你可以使用嵌入式水槽代理,并在它上面写一个非常好的appender。 Flume将提供基于磁盘的持久性,像api这样的事务等。

话虽如此,据我所知,很多人只是采用了logstash方法。

还有一件事,可能是我想到的最后一件事:

  • 你不应该直接写ElasticSearch。而是使用一些中间服务器(在logstash中它可以是Redis或RabbitMQ)。在水槽方法中,您可以使用其他水槽工艺(开箱即用的扩展选项支持)。

这将允许您在架构方面抽象ElasticSearch并在日志存储服务器上应用一些额外的处理(它可以从RedM获取数据/从RabbitMQ获取接收消息)。在水槽中,类似的行为也是可以实现的。

Hops this help

答案 1 :(得分:1)

  

是否有最佳实践格式[/ protocol]?

我不知道已经具有您想要的字段的任何日志记录标准。所以你需要一种可以存储自定义元数据的格式。您可以使用RFC5424格式向syslog消息添加元数据。我还看到各种日志服务通过套接字连接接受JSON格式的消息。

  

我应该使用elasticsearch appender吗?

我建议直接发送到logstash,而不是直接发送到ElasticSearch。

  1. Logstash旨在接收&以各种格式解析消息,因此以logstash理解的格式比以ElasticSearch理解的格式更容易发送消息。
  2. 随着您的日志记录要求的发展:您将能够实现这一目标 在一个地方更改 - Logstash - 而不是重新配置您的每个应用程序实例。

    • 这包括操作更改,例如更改ElasticSearch集群的地址。
  3. Logstash可以执行诸如审查日志之类的操作(删除看似密码或地址的内容)

  4. Logstash可以将日志发送到各种下游服务。例如:如果遇到重要错误,它可以触发PagerDuty通知或Slack消息。
  5. Logstash可以使用其他元数据丰富日志消息(例如,从IP地址解析地理坐标)
  6. 也可能存在规模问题。我不足以对这些进行评论,但这是我的直觉:我希望Logstash能够很好地处理大量连接(以及优雅地处理连接失败)。我不知道这在ElasticSearch集群的设计中是否具有类似的优先级,或者ElasticSearch的搜索性能是否会受到同时连接到它的大量代理的影响。我更有信心Logstash的设计考虑到了这种用途。

    您可能还发现ElasticSearch appender存在局限性。 appender需要为许多事情提供良好的支持。首先想到的是:

    • 选择协议,加密
    • 选择压缩
    • 完全控制日志消息的格式(包括自定义字段)
    • 控制特殊消息,例如发送例外

    您可以通过坚持一个受到良好支持的标准(例如syslog appender)来避免技术特定的appender的任何限制。

      

    是否有有效的logback和elasticsearch技术替代方法来满足我的要求?

    你的意思是说 logstash (即“有替代ELK堆栈吗?”)如果这是你的意图,那么我没有答案。

    但就 logback 的替代方案而言......我使用的是log4j2。它提供异步日志记录,以减轻应用程序的性能负担。也许logback也有这个功能。在log4j2日志消息中发送自定义字段很难(目前很难支持转义JSON。插件可用,但您的构建需要正确设置才能支持这些)。对我来说最简单的方法是使用RFC5424 syslog appender。

    考虑设计Java应用程序以调用日志记录外观(即SLF4J),而不是直接调用logback。这使您可以在将来轻松切换到其他日志记录提供程序。

答案 2 :(得分:0)

我和你有同样的问题,并决定避免任何中间日志收集器(如Logstash / Flume)。

https://github.com/internetitem/logback-elasticsearch-appender目前并不理想,但配置比https://github.com/logstash/logstash-logback-encoder

更有弹性

例如,logstash-logback-encoder修复了https://logback.qos.ch/apidocs/ch/qos/logback/classic/spi/ILoggingEvent.html

的标准字段的名称

logback-elasticsearch-appender目前缺少对本地FS存储的持久性,如果响铃已满且缺少可用ES服务器的迭代(只能指定一个)。

请注意,默认情况下,Logstash不是https://www.elastic.co/guide/en/logstash/current/persistent-queues.html

的安全措施
  

默认情况下,Logstash在管道阶段(输入→管道工作者)之间使用内存中有界队列来缓冲事件。这些内存中队列的大小是固定且不可配置

因此,您需要使用Redis,RabbitMQ或Kafka创建一些架构。在我看来,ES集群比Logstash(ES安全在Elasic.io广告中)更安全。

另请注意,Logstash在Ruby中实现,所以单线程应用!我们不能在这里谈论可扩展性。期望高达10000 req / s(这是我在Internet上找到的性能报告中的典型数字)。

Flume有更好的表现。我看到它缺乏文档。准备好在邮件列表上提问))

有许多商业优惠:

  • Splunk <http://www.splunk.com/en_us/products/splunk-light.html>
  • Scalyr <https://www.scalyr.com/pricing>
  • Graylog <https://www.graylog.org/support-packages/>
  • Loggly <https://www.loggly.com/product/>
  • Motadata <https://www.motadata.com/elk-stack-alternative/>

由于明智的原因,它们每年花费数千美元。

您可以查看一个日志收集供应商难以设计好的appender:https://logz.io/blog/lessons-learned-writing-new-logback-appender/

使用集中式日志记录解决方案,您应该更改记录方式:

  • https://www.slf4j.org/api/org/slf4j/MDC.html添加上下文可以是客户电话号码,IP地址,票号或其他任何内容。 您需要一种快速过滤重要数据的方法

  • 开始使用https://www.slf4j.org/api/org/slf4j/Marker.html进行需要立即反应的意外事件。 不要隐藏或忽略问题

  • 计划如何命名MDC参数和标记并记录它们,以便操作团队知道发生了什么,而不是在午夜打电话给你。

  • 在ES群集中​​设置复制。这允许您关闭部分ES节点以进行维护。