本文转载自微信公众号“小姐姐的味道”,作者小姐姐养的狗。转载本文请联系味觉小姐公众号。你要知道,线下和测试开发环境能发现的bug都是小儿科。只有当线上出现bug的时候,你才会知道它的残酷。数据乱了,逻辑中断了,进程挂掉了。你在这样的问题场景中,你还好吗?问题频发,故障定位困难。CTO怒骂道:“你就不能在线调试问题根源吗?形成一个可行的方法论!”从这种讲课可以看出,CTO的技术水平一般,但是太极修养很好。在平时的表达中,在报告中,不出现专业术语,不说话太生硬,是CTO的基本素养。但工作总要有人来做,公司里每个人都打太极拳,最终会形成一个虚幻的世界,不利于整个组织的健康发展。今天就简单说说网上手续和留下什么证据。1、证据的问题是因为它留下了证据。没有证据,虽然可以看到效果,但是找不到罪魁祸首。比如一个同学在办公室的饮水机里放了巴豆,让所有的同事都发泄了出来。但是由于没有安装监控,你是找不到这个可恶的同学的。而且这个问题通常是人为的,当它发现找不到的时候,它总是会再次出现。就好像犯罪分子发现了一个漏洞并试图再次利用它。所以,为了处理线上问题,需要留下问题发生的证据,这是最重要的。没有这些东西,你的公司肯定会陷入无休止的扯皮。1.1日志证据日志是最常见的做法。通过在程序逻辑中打点,配合Logback等日志框架,可以快速定位到出现问题的代码行。我们需要查看bug的详细发生过程,详细记录可能出现问题的逻辑,进行更详细的日志输出。当出现问题时,我们可以切换到debug进行调试。在SpringBoot中,可以通过执行器动态调整对应类的日志级别。在下面的路径中,可以看到日志级别的具体信息。localhost:8080/actuator/{loggers}可以通过向特定日志控制器发送POST请求来动态更改。curl-XPOST\http://localhost:8080/actuator/loggers/\-d'{"configuredLevel":""}'但是出现bug的频率可能很小,我们启用了debug之后,又等了好几天,同样的问题没有再出现。这是最麻烦的事情。接入一些APM平台是很有必要的。最新的opentelemetry同时记录Traces、Metrics、Logs三种格式的数据,对问题分析有很好的支持。还需要记录详细的监控信息。您可以看到监控指标的历史时间序列,帮助我们发现和排查问题。1.2JVMproof通常在出现意外的时候不会那么温和。你可能会在半夜接到报警电话,因为很多定时任务都设置在夜深人静的时候执行。这个时候再看jstat已经来不及了,我们需要保留现场。这是看门狗的工作,可以通过设置一些JVM参数来配置。Java8的gc日志配置与Java8及之后的版本有很大不同。下面直接给出相应的配置示例。java8:-verbose:gc-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintGCApplicationStoppedTime-XX:+PrintTenuringDistribution-Xloggc:/tmp/logs/gc_%p.log-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/tmp/logs-XX:ErrorFile=/tmp/logs/hs_error_pid%p.log-XX:-OmitStackTraceInFastThrowjava8+:-verbose:gc-Xlog:gc,gc+ref=debug,gc+heap=debug,gc+age=trace:file=/tmp/logs/gc_%p.log:tags,uptime,time,level-Xlog:safepoint:file=/tmp/logs/safepoint_%p.log:tags,uptime,time,level-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/tmp/logs-XX:ErrorFile=/tmp/logs/hs_error_pid%p.log-XX:-OmitStackTraceInFastThrow2。分析问题分析是最困难的部分。有了证据链接,我们就避免了靠猜测找问题的现状,但是如何在这些零散的信息和复杂的路径中找到问题的根源是非常具有挑战性的。如果是大规模bug,强烈建议直接在线调试。不推荐使用Arthas等工具动态修改字节码进行测试,当然也不推荐使用IDEA的远程调试。相反,建议采用类似金丝雀发布的方式,导出极小部分流量,构建新版本进行测试。如果你没有金丝雀发布平台,像Nginx这样的负载均衡工具也可以通过权重来做类似的事情。在这个新的小版本中,你可以随心所欲地输出日志,将所有的输入输出都打印到日志中。在大多数情况下,您可以通过日志快速找到这个问题。缓存将是影响bug产生的一个非常重要的因素。因为缓存和数据库通常不在同一个基础设施中,所以通常存在一致性问题。即使选择cacheaside模式实现延迟双删,在某些情况下还是会出现数据一致性问题。这种偶发的不一致问题,因为出现的频率不高,触发条件苛刻,一旦出现会很难发现。因此,一些非常关键的业务通常会提供一键删除缓存的功能。如果清除缓存后问题消失,那么就没有必要在这种小概率事件上浪费时间了。多线程是另一个容易出问题的地方,每个逻辑都要仔细评估。因为多线程是异步的,所以有些逻辑只能靠人工推理,而灰度在线程序可能永远不具备达到这一点的条件。这时候,给线程起一个合适的名字就非常有必要了,这通常是由ThreadFactory来完成的。比如有些同学喜欢把字符串拼接起来,直接打印成日志。logger.debug("therequestinfo:userId:{}tel:{},role:{},timeCost:{}")这两个方法还不错,但是处理问题的时候会遇到很多阻碍,log输出不应该太随意。logger.debug("therequestinfo$userId{}|tel:{}|role:{}|timeCost:{}")这样我们就可以很方便的使用linux的各种工具,比如sed,awk,grepanalyze。输出日志时,必须要有一定的技巧,否则只能用肉眼来分析。3.总结要解决问题,就得经过不断的试错。试错不是盲目的,一定要有各种证据的支持。最有效的手机证据是通过日志,尤其是具有一定规则的日志信息。除了分析正常的业务逻辑,数据问题或者多线程问题也是导致bug的常见原因。日志系统和监控系统对硬件的要求比较大,尤其是当你的请求体和返回体比较大的时候,对存储和计算资源的要求就更高了。其硬件成本在整个基础设施中所占比例较高。但是这样的证据信息对于分析问题是非常必要的。所以即使再贵一些,很多企业还是会有很多的投入在上面,包括硬件投入和人力投入。如果你想要这样的功能但是没有钱又没有人?其实没关系,请一个会说话的CTO,你所有的问题和bug都会在你面前烟消云散。作者简介:品味小姐姐(xjjdog),一个不允许程序员走弯路的公众号。专注于基础架构和Linux。十年架构,每天百亿流量,与你探讨高并发世界,给你不一样的滋味。