共计 14367 个字符,预计需要花费 36 分钟才能阅读完成。
为什么要进行检测
在检测的过程中一方面能够帮忙咱们了解咱们的零碎,更重要的是,这能够为客户提供卓越经营的体验。帮忙咱们更理解咱们给客户的体验是什么样的。
在 amazon.com 购物时,高提早会对客户造成十分差的购物体验,从而升高转换率。对应用 AWS 的用户,他们须要的是高可用性和低提早。
在 Amazon,咱们不仅仅去思考均匀提早,而是会去更加关注提早的异样值。比方 P99.9 或是 P99.99 这样的指标。之所以这样,是因为在升高 P99 之后,均匀提早也同样会升高,然而升高了均匀提早,P99 并不一定会升高。
更加关注高百分位提早的一个起因是,某个服务中的高提早可能会在其余服务中产生乘法效应。即,如果调用链深处的服务的 latency 减少,最终用户可能会感触到很长的提早。
Amazon 的大型零碎是由许多协同工作的服务组成。每个服务都由一支独自的团队开发和经营。领有服务的团队称为 service owner. 无论负责任何职位,该团队的每个成员均会像服务的 owner 护额 operator 一样思考。作为 service owner,团队会设定领有的每个 service 的经营绩效相干的指标。团队还须要确保能够看到 service 的运行状况,以保障咱们达成这些指标、解决呈现的任何问题和促使本人在第二年达成更高的指标。为了设定指标和取得这种可见性,团队必须对系统进行检测。检测还促使咱们可能有策略的探测和应答经营事件。
Instrumentation feeds data into operational dashboard, so that operators can view real-time metrics. It also feeds data into alarms. 运营者应用具体的检测输入疾速诊断出错的起因,这样一来,咱们能够迅速想方法先临时缓解问题,并记下该问题,之后进行解决,避免该问题再次复发。Without good instrumentation throughout the code, we sink precious time into diagnosing problems.
检测什么
为了取得必须的 metrics,service owner 必须从多个方面掂量 operational performance, 以便从多个角度理解各组件的端到端具体表现。比方,customer 通过 Load Balancer 调用某个 service,该服务会与 remote cache 和 remote database 通信。We want each component to emit metrics about its behavior. We also want metrics on how each component perceives the behavior of other components. 将来自所有这些角度的 metrics 会集起来时,service owner 就能迅速查明问题的 root cause。
许多 AWS 服务都会主动提供一些 resource 的经营倡议。例如,DDB 提供无关成功率,错误率和提早的 Amazon CloudWatch metrics。然而,当咱们构建应用这些服务的零碎时,咱们须要取得高得多的 visibility,以便理解零碎的具体表现。检测须要显示代码来记录工作要执行多长时间,某些代码门路多久执行一次,与工作执行的工作相干的元数据和工作的那些局部胜利或失败。如果团队未增加显式检测,则 service owner 将被迫把本人的服务作为黑盒来经营。
举个栗子🌰
如果咱们实现了一个按产品 ID 来检索产品信息的 service API,代码可能会相似上面的状况。此代码顺次在 local cache、remote cache 和 database 中查找产品信息:
public GetProductInfoResponse getProductInfo(GetProductInfoRequest request) {
// check our local cache
ProductInfo info = localCache.get(request.getProductId());
// check the remote cache if we didn't find it in the local cache
if (info == null) {info = remoteCache.get(request.getProductId());
localCache.put(info);
}
// finally check the database if we didn't have it in either cache
if (info == null) {info = db.query(request.getProductId());
localCache.put(info);
remoteCache.put(info);
}
return info;
}
如果咱们经营此服务,则须要在此代码中进行大量检测能力理解该服务在 production 中的 behavior. 咱们须要可能对失败或 latency 过高的申请进行故障排查,以及监控不同依赖项的调用状况。上面是雷同业务性能的代码,然而带有了一些问题正文。在真正开发时,须要可能解答这些与整个开发相干或针对特定申请的问题:
public GetProductInfoResponse getProductInfo(GetProductInfoRequest request) {
// Which product are we looking up?
// Who called the API? What product category is this in?
// Did we find the item in the local cache?
ProductInfo info = localCache.get(request.getProductId());
if (info == null) {
// Was the item in the remote cache?
// How long did it take to read from the remote cache?
// How long did it take to deserialize the object from the cache?
info = remoteCache.get(request.getProductId());
// How full is the local cache?
localCache.put(info);
}
// finally check the database if we didn't have it in either cache
if (info == null) {
// How long did the database query take?
// Did the query succeed?
// If it failed, is it because it timed out? Or was it an invalid query? Did we lose our database connection?
// If it timed out, was our connection pool full? Did we fail to connect to the database? Or was it just slow to respond?
info = db.query(request.getProductId());
// How long did populating the caches take?
// Were they full and did they evict other items?
localCache.put(info);
remoteCache.put(info);
}
// How big was this product info object?
return info;
}
用于解答所有这些问题和更多问题的代码比理论业务逻辑长很多。某些库能够帮忙缩小咱们须要本人写的检测代码的数量,但开发人员必须询问本人这些问题,而后必须将检测代码写在 servcice 中。
在对流经分布式系统的申请进行故障排查时,如果咱们只是依据一次交互来查看该申请,可能难以理解产生的状况。要整合全局,咱们发现将无关所有这些零碎的测量后果会集到一处很有用。在咱们这样做之前必须收集后果,即,必须给每个工作一个 trace ID,并将该 trace ID 流传到协同实现该工作的其余每个 service 中。这样咱们就能够依据须要在预先跨零碎针对特定 trace ID 进行集中检测,也能够应用 AWS X-Ray 之类的服务近实时的进行集中检测。
Drilling down
通过检测,咱们就能够在多个级别上进行故障排查了。从浏览 metrics 以理解是否存在因过于渺小而无奈登程警报的任何异样,到进行考察以找出这些异样的起因。
从大的方面来看,检测的后果能够聚合到 metrics 中,而后通过 metrics 咱们能够设置 alarm,或者再次封装成 dashboard。这些聚合指标能够让 operators monitor the overall request rate, the latency of the service calls, and the error rates. These alarms and metrics make use aware of anomalies or changes that should be investigated。
在看到异样后,咱们通过建设的多个 metrics 就能够找出产生异样的起因。通过检测执行申请处理过程的不同局部所需的工夫,咱们能够看到处理过程中哪个局部比平时慢或哪个局部比平时更频繁的触发谬误。
尽管 aggregate timer and metrics 可能能够帮忙咱们排查问题或确定重点考察畛域,但它们并不总能提供全面的解释。例如,咱们可能能够从 metric 中晓得谬误来自某特定的 API 操作,但这些 metrics 可能并未充沛揭示该操作为何失败的细节。At this point, we look at the raw, detailed log data emitted by the service for that time window. The raw logs then show the source of problem–either the particular error that is happening, or particular aspects of the request that are triggering some edge case.
如何进行检测
毋庸置疑,须要编写代码来反对检测。这意味着咱们在实现新性能时,须要花工夫增加额定的代码,以指出产生的事件、它曾经胜利还是曾经失败、耗用了多长时间等。因为检测是这样一种常见的编码工作,多见来 Amazon 外部造成了一套做法来解决通用模式:standardization for common instrumentation libraries, and standardization for structured log-based metric reporting.
Standardization of metrics instrumentation libraries helps library authors give consumers of their libraries visibility into how the library is operating。例如,罕用的 HTTP 客户端与这些通用库集成在一起,因而,如果服务团队执行对其余服务的近程调用,他们将主动取得无关这些调用的检测。
在被检测的利用程序运行并执行工作时,生成的遥测数据将写入到结构化的日志中。通常,该数据作为每个“工作单元”的一个日志条目发送,而不论这是对某个 HTTP service 的申请还是从队列中取出的音讯。
在 Amazon,应用程序中的测量后果并不聚合起来,但有时会刷新到指标聚合零碎中。各局部工作的所有计时器和计数器均写入到日志文件中。通过这样做,另一个零碎将在预先解决日志和计算聚合指标。这样一来,咱们最终就取得了各种数据(从高级别的聚合经营指标到申请级别的具体故障排查数据),而这是通过代码检测的办法实现的。在 Amazon 外部,咱们首先记录日志,之后再产生聚合指标。
通过日志记录进行检测
咱们通常在检测服务后发送两种类型的日志数据:request data and debugging data.
申请日志数据通常示意为结构化日志条目(每个工作单元一个条目)。此数据蕴含无关以下各项的属性:request, who made the request, what the request was for, counters of how often things happened, and timers of how long things took. 对于在服务中产生的每件事件,申请日志起着审计日志和跟踪的作用。
调试数据蕴含应用程序发送的任何调试行的非结构化数据或涣散结构化数据。通常,这些数据是非结构化条目,例如 Log4j 谬误或正告日志行。
在 Amazon 外部,这两种类型的数据通常发送到不同的日志文件中,这部分一方面是出于历史起因,另一个更重要的起因是应用同构的日志条目格局进行日志剖析可能比拟不便。
像 CloudWatch Logs Agent 这样的代理实时处理这两种类型的日志数据,并将日志发送给 CloudWatch Logs。接下来,CloudWatch Logs 会近乎实时的产生无关服务的聚合指标。Amazon CloudWatch Alarms 读取这些聚合指标并触发警报。
尽管为每个申请记录如此多的细节可能老本昂扬,但在 Amazon 外部,咱们发现这样做十分重要。毕竟咱们须要考察可用性稳定、提早激增和 customer 报告的问题。如果没有具体的日志,咱们无奈向客户提供答案,而且无奈改善他们的服务。
深刻理解详细信息
The topic of monitoring and alarming is vast. 在本文中不会探讨以下这些主题:
- setting and tuning alarm thresholds,
- organizing operational dashboards,
- measuring performance from both the server-side and client side,
- continuously running “canary” applications, and
- choosing the right system to use to aggregate metrics and analyze logs.
This article focuses on the need to instrument our applications to produce the right raw measurement data。文中将阐明 Amazon 团队在检测应用程序时努力做到或防止的事件。
申请日志最佳实际
本节将解说在 Amazon 的记录“每个工作单元”的结构化数据相干的良好习惯。合乎这个规范的日志蕴含:示意事件多久产生一次的计数器、蕴含事件占用工夫的工夫长度的计时器、蕴含每个工作单元相干元数据的属性。
记录 log 的形式
- Emit one request log entry for every unit of work. A unit of work is typically a request our service received or a message it pulls from a queue. 咱们为咱们的服务收到的每个申请编写一个服务日志条目。咱们不会将多个工作单元组合在一起。这样,当咱们对失败的申请进行故障排除时,咱们能够查看单个日志条目。该申请的相干输出参数(批示申请尝试做的事件)、发起者是谁的相干信息以及所有计时和计数器信息都蕴含在这个条目中。
- Emit no more than one request log entry for a given request. 每个工作单元具备多个日志条目会使日志剖析变得艰难,并会使曾经很高的日志记录开销成倍增长。如果咱们编写新的非阻塞服务,咱们会尝试事后布局指标的日志记录生命周期。这是因为过后再重构和修复会十分艰难。
- Break long-running tasks into multiple log entries. 与后面的倡议相同,如果咱们有一个长时间运行(数分钟或数小时)且相似于工作流程的工作,咱们可能会决定定期发送一个独自的日志条目,以便咱们能确定是否正获得停顿或者再哪个中央减慢了速度。
- Record details about the request before doing stuff like validation. 咱们发现充沛记录无关申请的信息,以便咱们晓得申请尝试实现的事件对故障排除和审计日志记录十分重要。咱们也发现尽早记录这些信息(在申请可能被验证、身份验证或限度逻辑回绝之前)很重要。如果咱们记录传入申请中的信息,咱们会确保在记录之前对输出进行清理(编码、本义、截断等)。例如,如果发起者传入一个服务日志条目,咱们不心愿它蕴含长度为 1MB 的字符串。否则会呈现填满磁盘的危险,并导致咱们在日志存储方面付出超过预期的代价。另一个清理示例是筛选出与日志格局相干的 ASCII 控制字符或转义序列。如果发起者传入本人服务日志条目,而且可能将其注入到咱们的日志中,可能会造成凌乱。
- Plan for a way to log at increased verbosity. 对于某些类型的问题进行故障排除时,日志中未蕴含与造成问题的申请相干的短缺细节,导致无奈找出申请失败的起因。或者服务中可能提供了这些信息,但信息量可能太大,以至于无奈克制能证实记录这些信息是正当的。这时,以下办法可能有用:设置一个配置旋钮,让咱们能够在考察问题时旋转这个旋钮,以临时进步日志的具体水平。咱们能够在单个主机上或者为服务机群的子集上依照某个采样率旋转此旋钮。然而切记,在实现后必须从新将旋钮转回原处。
- Keep metric names short (but not too short). Amazon 应用雷同的服务日志序列化曾经超过了 15 年。在此序列化中,每个计数器和计时器名称均在每个服务日志条目中以纯文本的模式反复。为了帮忙最大水平上减小日志记录的开销,咱们应用简短但具备描述性的计时器名称。
- Ensure log volumes are big enough to handle logging at max throughput. 咱们在最大继续负载甚至过载的状况下对服务进行数小时的负载测试。咱们须要确保在咱们的服务解决超限流量时,服务依然具备资源依照日志产生新日志条目标速度发走日志,否则磁盘最终将会填满。咱们还能够将日志记录配置为产生在与根分区不同的文件系统分区上,这样零碎就就不会在呈现过多日志记录时解体。后文将会探讨一些缓解措施(例如应用与吞吐量成正比的动静采样),但无论采纳哪种策略,测试都是至关重要的。
- Consider the behavior of the system when disks fill up. 在服务器的磁盘填满时,服务器无奈将日志记录到磁盘中。如果产生这种状况,服务是应进行承受申请,还是应删除日志并在无监控的状况下持续运行?在无日志记录的状况下运行服务回充斥危险,因而咱们对系统进行测试,确保会检测到服务磁盘将满的情况。
- Synchronize clocks. 家喻户晓,分布式系统中“工夫”的概念非常复杂。咱们在分布式算法中并不依赖时钟同步,但对于日志来说时钟同步是必须的。Amazon 运行 Chrony 或 ntpd 这样的守护过程来进行时钟同步,并且咱们监控服务器的时钟偏差。为了更轻松的做到这一点,能够参阅这里。
- Emit zero counts for availability metrics. 谬误计数很有用,但谬误百分比同样很有用。要通过检测确定“可用性百分比”指标,一个很有用的策略是:在申请胜利时发送 1,而在申请失败时发送 0。所产生的指标的“均匀”统计数据即为可用率。在其余状况下,特意发送数据 0 点也可能很有用。通过这种形式,能够在短少指标数据时收回“无数据”警报。这往往在服务呈现大规模问题(线程死亡、网络隔离、领导者选举有效等)状况下或是监控零碎呈现问题时触发。例如,如果应用程序执行领导选举,那么在某个过程成为领导时定期发送 1,而在该过程不是领导时发送 0,可能对于监督跟随者的情况很有用。这样以来,如果某过程进行发送 0,能够更容易的晓得该过程中呈现了谬误,而且,如果领导产生了情况,该过程将无奈接任领导。
- Make a child metrics object for each thread, and have each thread close its own metrics. 如果有多个线程解决同一个申请,可能会遇到一个线程运行工夫长于另一个线程的状况,这时可能会看到尝试将指标写入已敞开指标对象时抛出异样,或者咱们疏忽这些异样,但会失落指标数据。
记录 log 的内容包含?
- Log the availability and latency of all of dependencies. 咱们发现这在解答“为什么申请很慢”或是“为什么申请失败了”的问题上十分有用。如果没有此日志,咱们只能将依赖关系的图形与服务的图形进行比拟,并且猜想是否因以来服务的提早激增导致咱们正在考察的申请的失败。许多服务和客户端框架都会主动联结指标,但一些框架(例如 AWS SDK)须要手动进行检测。
- Break out dependency metrics per call, per resource, per status code, etc. 如果咱们在同一工作单元中屡次与雷同的依赖项交互,咱们将别离蕴含每个调用的指标,并明确每个申请是哪个资源互动。例如,在调用 Amazon DynamoDB 时,一些团队发现蕴含每个表、每个错误代码甚至每个重试次数的工夫和提早指标很有帮忙。这样能够更轻松的解决因为条件查看失败而导致服务因重试而变慢的状况。这些指标还揭示了客户端感知提早减少实际上是因为节流重试或后果集分页而不是数据包失落或网络提早的状况。
- Record memory queue depths when accessing them. 如果申请与队列进行交互,而且咱们正从队列中取出对象或将对象放入队列中,咱们会在解决它时将以后队列深度记录到指标对象中。对于内存队列,获取它的老本非常低。对于分布式队列,在响应 API 调用时能够收费取得此元数据。此日志记录将在将来帮忙查找积压工作和提早的起源。此外,当咱们从队列中取出对象时,咱们会测量对象在队列中停留的工夫长度。这意味着咱们首先须要将本人的“入队工夫”指标增加到音讯中,而后再将其入队。
- Add an additional counter for every error reason. 思考增加代码,对每个失败申请的特定谬误起因进行计数。应用程序日志将蕴含导致失败的信息和具体的异样音讯。然而,咱们还发现,查看指标中谬误起因随时间推移的趋势很有帮忙,无需在应用程序日志中开掘该信息。从每个失败异样类的独自指标开始是很不便的。
- Organize errors by category of cause. 如果所有谬误均纳入同一指标,该指标会变得具备烦扰性且无用。至多,咱们发现将“client’s fault”和“server’s fault”这两种谬误辨别开很重要。除此之外,进一步细分可能很有用。例如,在 DDB 中,客户端可能会发动条件写入申请,如果这些申请批改的项不合乎申请中的前提条件,这些申请会返回谬误。这些谬误是特意造成的,而且咱们预计它们会偶然产生。然而,来自客户端的“invalid request”谬误极有可能是咱们须要修复的谬误。
- Log important metadata about the unit of work. 在结构化指标日志中,咱们还蕴含了无关申请的短缺元数据,以便咱们当前能确定申请来自谁和申请尝试做什么。这包含了客户端在遇到问题向咱们求助时心愿咱们的日志蕴含的元数据。例如,DDB 会记录申请正在交互的表的名称,以及相似于读取操作是否是一致性读取的元数据。然而,它不会记录存储到数据库或从数据库检索的数据。
- Protect logs with access control and encryption. 因为日志蕴含肯定水平的敏感信息,咱们须要采取措施爱护这些数据。这些措施包含对日志进行加密、限度对问题进行故障排除的操作员的拜访以及定期检查这种拜访是否合乎基准。
- Avoid putting overly sensitive information in logs. 日志须要蕴含一些有用的敏感信息。在 Amazon,咱们发现日志蕴含足够的信息以理解给定申请来自谁很重要,但咱们不会蕴含过于敏感的信息,例如不影响路由或不影响解决申请的行为的申请参数。比方,如果代码对客户音讯进行解析,但解析失败,则很重要的是不要记录音讯内容,以便爱护客户隐衷,只管这可能会对之后的故障排除造成影响。咱们应用工具以抉择退出而不是抉择移出的形式来决定能够记录哪些信息,以避免记录当前增加的新敏感参数。API Gateway 等服务容许配置能够蕴含在其拜访日志中的数据,这起到了无效的抉择退出机制的作用。
- Log a trace ID and propagate it in backend calls. 给定的客户申请可能波及许多许多协同工作的服务。许多 AWS 申请可能仅波及两三个服务,而 amazon.com 申请可能会波及多得多的服务。为了在排除分布式系统的故障时分明理解所产生的事件,咱们在这些零碎之间流传同一个 trace ID,以便将来自不同零碎的日志排列起来,从而看到故障在哪里产生。trace ID 是一种 meta request ID,由作为工作单元终点的“front door”服务贴附到分布式工作单元上。AWS X-Ray 是一种通过提供一些这种流传来提供帮忙的服务。咱们发现将跟踪传递给咱们的依赖项很重要。在多线程环境中,让框架代表咱们进行此流传十分艰难,而且很容易出错,因而咱们曾经习惯了在办法签名中传递 trace ID 和其余申请内容(例如 metrics object)。咱们还发现在办法签名中传递上下文对象很不便,这样咱们就不用在未来找到相似的模式传递时进行重构。对于 AWS 团队来说,这不仅仅是解决咱们的零碎问题,还波及客户解决他们的零碎问题。在 AWS 服务代表客户彼此交互时,客户依赖在 AWS 服务之间传递的 AWS X-Ray 跟踪。它要求咱们在服务之间流传客户 AWS X-Ray 跟踪 ID,以便他们能取得残缺的跟踪数据。
- Log different latency metrics depending on status code and size. 谬误响应的速度通常很快,例如拜访被回绝、限度或是验证谬误响应。如果客户端开始以很高的速度受到限制,这可能会让人产生提早良好的错觉。为了防止这样的指标净化问题,咱们为胜利响应记录一个独自的计时器,并在咱们的 dashboards 和 alarms 中关注该指标,而不是应用通用的工夫指标。相似的,如果存在依据输出大小或响应大小而变慢的操作,咱们会思考收回分类的提早指标,例如 SmallRequestLatency 和 LargeRequestLatency。此外,咱们确保咱们的申请和响应失去适当的限度,以防止简单的故障模式,但即便在精心设计的服务中,这种 metric-bucketing technique 也能隔离客户行为和阻止令人分心的烦扰信息进入 dashboards。
Application log best practices
上面介绍的是 非结构化调试日志数据 相干的 best practices!
- Keep the application log free of spam. 为了帮忙在测试环境中进行开发和测试,咱们可能会在申请门路上蕴含 INFO 和 DEBUG 级别的日志语句,然而,咱们思考在生产环境中禁用这些日志级别。咱们并不依赖应用程序日志来获取申请跟踪信息,而是将服务日志视为跟踪信息的寄存地,咱们在其中能够轻松产生指标和查看一段时间内的总体趋势。然而,这里不存在非黑即白的规定。咱们的办法是:一直审查日志,看看日志的烦扰性是过高还是不够高,而后随工夫的推移调整日志级别。例如,当咱们在深入研究日志时,常常发现烦扰性过高的日志语句呈现,或者咱们心愿领有的指标没有。侥幸的是,这些改良通常易于运行。
- Include the corresponding request ID. 在咱们对应用程序日志中的谬误进行故障排查时,咱们经常心愿看到与触发该谬误的申请或发起者无关的详细信息。如果两个日志均蕴含雷同申请的 ID,则咱们能够轻松的从一个日志跳转到另一个日志。如果正确配置了应用程序日志记录库,这些库将会写出对应的申请 ID,而且该申请 ID 将设置为 ThreadLocal。如果应用程序是多线程的,在线程开始解决新申请时特地要留神设置正确的申请 ID。
- Rate-limit an application log’s error spam. 通常,服务不会向应用程序日志发送大量信息,但如果它忽然开始显示大量谬误,它可能会忽然开始以很高的速度写入十分大的日志条目(带有堆栈跟踪)。咱们发现了一种预防此问题的办法,即限度指定的日志记录程序记录日志的频率。
- Prefer format strings over String#format or string concatenation. 较旧的应用程序日志 API 操作承受单个字符串音讯而不是 log4j2 的 varargs 格局字符串 API。如果应用 DEBUG 语句来检测代码,但在 ERROR 级别下配置生产环境,则格式化会被疏忽的 DEBUG 音讯字符串可能是节约功夫。某些日志记录 API 操作反对传入任何对象,这些对象只有在写出日志条目时才会调用它们的 toString() 办法。
没懂
- Log request IDs from failed service calls. 如果调用某个服务且该服务返回谬误,它可能会返回申请 ID。咱们发现字啊日志中蕴含申请 ID 很有用,这样做能让咱们在须要跟进该服务拥有者时有方法让他们轻松找到本人的响应服务日志条目。不过超时谬误会带来麻烦,起因是服务可能尚未返回申请 ID,或者客户端库可能未解析该 ID。尽管如此,如果咱们取得了服务返回申请的 ID,咱们会记录该 ID。
高吞吐量服务的 best practices
对于 Amazon 的绝大多数服务,为每个申请进行日志记录不会强行加上不合理的老本开销。吞吐量较高的服务会进入一个灰色地带,但咱们通常仍会为每个申请进行日志记录。例如,DDB 最高峰时每秒解决超过 2000 万个申请(仅仅是 amazon 外部的流量),因而人们很天然会假设该服务不会记录十分多的信息,但实际上,出于排除故障以及审计和合规的起因,它会记录每个申请。上面提供了一些在 amazon 应用的高级技巧,以更高的单主机吞吐量下进步日志记录的效率:
- Log sampling. 思考每隔 N 个条目写入一个条目,而不是写入每个条目。每个条目还要包含跳过了多少条目,以便指标聚合零碎能够预计它计算的指标中的实在日志量。蓄水池采样之类的其余采样算法提供了更具代表性的样本。在其余算法中,日志记录谬误或迟缓的申请优先于胜利的疾速申请。然而,通过采样,失去了帮忙客户和排除特定故障的能力。某些合规要求齐全禁止这样做。
- Offload serialization and log flushing to a separate thread. 这是一个简略且罕用的办法。
- Frequent log rotation. 每小时转换一次日志文件的日志看起来很不便,能缩小您须要解决的文件,不过每分钟轮换一次能在几个方面带来改良。例如,读取和压缩日志文件的代理将从页面缓存而不是磁盘读取文件,而且压缩和发送日志所需的 CPU 和 IO 操作将扩散到整个小时中执行,而不总是在小时完结时触发。
- Write logs pre-compressed. 如果日志发送代理在向存档服务发送日志之前压缩日志,则零碎 CPU 和磁盘将定期呈现操作顶峰。通过将压缩的日志流式传输到磁盘,能够摊派此开销并将磁盘 IO 操作缩小一半。不过这会带来一些危险。咱们发现,应用能在应用程序解体时解决截断的文件的压缩算法很有用。
- Write to a ramdisk / tmpfs. 让服务将日志写入到内存(直至日志从服务器中发走)可能比写入到磁盘更为容易。依据咱们的教训,这在每分钟而不是每小时轮换一次日志的状况下成果最好。
- In-memory aggregates. 如果必须在单台计算机上每秒解决数万个事务,则为每个申请写入一个日志条目可能会因为代价过高而不可行。然而,逃过这一步会显著升高可见性,因而咱们发现不要过早优化是有帮忙的。
- Monitor resource utilization. 咱们亲密关注咱们离某些扩大限度还有多近。咱们测量每个服务器的 IO 和 CPU 资源应用状况,以及日志记录代理耗费了多少资源。当咱们执行负载测试时,咱们会运行它们足够长时间,以便咱们能够证实咱们的日志发送代理可能跟得上咱们的吞吐量。
部署适合的日志剖析工具
在 amazon 外部,咱们经营本人编写的服务,因而,咱们全都须要成为它们的故障排除专家。这包含可能毫不费力的进行日志剖析。咱们能够应用许多工具 – 从用于查看绝对较少日志的本地日志剖析,到用于筛选并聚合来自海量日志的后果的分布式日志剖析。
咱们发现,投资于团队的工具和 Runbook 十分重要。如果当初日志很小,但服务预计会随工夫的推移而增长,咱们会关注咱们以后的工具何时会进行扩大,以便咱们能够投资采纳分布式日志剖析解决方案。
本地日志剖析
为了执行日志剖析过程,可能须要具备应用不同 Linux 命令行实用程序的教训。例如,对于常见的“在日志中找到最大流量生产者的 IP 地址”工作,只须要执行以下命令:
cat log | grep -P "^RemoteIp=" | cut -d= -f2 | sort | uniq -c | sort -nr | head -n20
然而还能够应用许多其余实用工具来解答无关日志的更简单的问题,这些工具包含:
- jq: https://stedolan.github.io/jq/
- RecordStream: https://github.com/benbernard…
分布式日志剖析
任何大数据分析服务都能够用来执行分布式日志剖析,这些服务包含 Amazon EMR、Athena、Aurora、Redshift 等。然而,某些服务曾经福袋了日志记录零碎,例如 CloudWatch Logs。
- CloudWatch Logs Insights
- AWS X-Ray:https://aws.amazon.com/xray/
- Amazon Athena:https://aws.amazon.com/athena/
论断
作为 service owner 和 SDE,咱们会破费大量工夫来查看检测的输入(例如:graphs on dashboards, individual log files)和实用分布式日志剖析工具(例如 CloudWatch Logs Insights)。当咱们钻研日志时,首先能够提出一些问题,例如“为何此指标会在这里呈现峰值”,或者“能够升高次操作的提早吗”。在咱们无法回答这些问题时,咱们能够找出一些对代码很有用的某些检测,而后增加该检测、进行测试并给组员收回 CR。
只管咱们应用的托管服务附带了许多 metrics,但咱们须要破费大量的心理来检测咱们本人的服务,以便取得更加无效经营这些服务所需的可见性。如果呈现经营事件,咱们须要迅速确定产生问题的起因,以及能缓解该问题的对策。dashboards 上蕴含适合的 metrics 非常重要,这能够让咱们疾速进行诊断。此外,因为咱们一直扭转服务、增加新性能以及扭转服务与其依赖项交互的形式,因而,更新和增加正确工具的行为将会永远继续进行。