如何快速排查线上问题 -copy qf

喻佳文 / 2024-07-18 / 原文

排查流程图

flowchart TB
A --> B --> C --> D --> E

subgraph A[认识问题]
A1[收集信息]
A2[确认问题]
A3[复现问题]
A4[影响范围]
A1 --> A2 --> A3 --> A4
end

subgraph B[诊断/确认问题]
B1[检查网络连接]
B2[查看浏览器控制台]
B3[捕获HTTP请求和响应]
B4[查看页面加载性能]
B5[检查兼容性问题]
B6[检查npm库版本]
B7[问题上升高度]
B1 --> B2 --> B3 --> B4 --> B5 --> B6 --> B7
end

subgraph C[解决问题]
C1[服务端问题]
C2[前端代码逻辑问题]
C3[自由库问题]
C4[第三方库问题]
C1 --> C2 --> C3 --> C4
end

subgraph D[验证修复和发布]
D1[验证修复效果]
D2[代码审查]
D3[部署和发布]
D4[用户反馈]
D1 --> D2 --> D3 --> D4
end

subgraph E[总结和文档]
E1[记录解决过程]
E2[更新文档]
E3[回顾和学习]
E1 --> E2 --> E3
end

认识问题

收集信息

首先,需要收集尽可能多的信息来了解问题的全貌。这一步至关重要,因为收集到的信息越具体,后续的排查和解决过程就会越高效。

  • 用户反馈
    • 直接沟通:通过支持渠道,例如钉钉/电话等,获取用户对问题的描述。
    • 用户截图和录像:要求用户提供问题出现时的截图或录屏,以直观了解问题现象。
    • B端用户:可以直接联系用户,引导打开控制台,直接查看报错信息
    • 网络状态:了解用户的网络连接情况,是否在使用代理,网络速度等信息。
    • 灰度情况:排除是否因灰度导致。
  • AEM日志文件
    • 前端日志:确保前端代码中有足够的日志记录,在需要时可以通过控制台或调试工具获取日志信息。
    • 监控平台日志:如果使用了监控平台(如 Sentry、Datadog),直接查看平台上报告的错误和异常。
    • 浏览器和操作系统,浏览器版本,应用发布版本等。
    • 关注AEM群消息:养成良好的习惯,定期查看AEM异常信息,
    • 新增异常:需要排查是否可能为发布导致,优先排查解决,避免问题升级。
    • top异常:专项解决,避免升级成工单。
    • 用户流信息:收集用户访问路径、点击行为、操作日志等数据,获取用户操作的全流程记录。

确认问题/影响范围

在收集到问题信息后,需要明确问题的具体表现和范围。这一步包括确定问题的影响面,以及是否与特定条件或环境相关。

  • 问题确认
    • 问题可重复性:确认是否能在相同条件下多次复现问题。
    • 示例: 在同一个浏览器和操作系统中,依照用户描述执行相同的步骤,观察是否每次都会出现相同的错误。
    • 错误类型及表现:将问题分类,例如页面崩溃、布局错误、功能失效等,并详细描述其表现。
  • 确认影响范围
    • 是否全局性或局部性:检查问题是否只在某些地区或用户群体中出现。
    • 特定页面或全站问题:确认问题是否只在某些特定页面或全站范围内发生。
    • 特定功能:确定问题是否与某些具体功能或模块相关,比如下单/列表展示等。
    • 特定时间段:确认问题是否在特定时间段内出现
    • 示例:问题是否只在高峰期间发生
  • 时间范围
    • 最近变动:确认问题是否与最近的代码更新、配置变更或第三方服务变动有关。(90%以上的问题,都是由最新发布导致)
    • 历史问题:判断问题是否之前存在,这是新出现的问题还是长期存在的隐患。查找历史日志和错误报告,确认问题是否曾经多次出现。

复现问题

明确问题后,尽量在你自己的开发环境或测试环境中复现问题。这有助于找到问题的根本原因并制定解决方案。

  • 重现步骤
    • 详细步骤记录:根据用户提供的信息,记录重现问题的详细步骤。这些步骤应尽量详细,确保每次执行都能复现问题。
  • 环境模拟
    • 相同浏览器和操作系统环境:在用户报错的相同环境中重现问题(可以使用虚拟机、浏览器模拟工具等)。
    • 网络条件模拟:使用网络限制工具模拟不同的网络状态(例如慢速网络或高延迟环境)来重现问题。
  • 浏览器开发工具
    • 启用开发者工具:使用 Chrome DevTools 或其他浏览器开发工具来观察控制台输出、网络请求、DOM 和样式变化。
    • 设置断点:在怀疑有问题的代码位置设置断点,通过逐步执行代码来排查问题。
  • 日志和错误分析
    • 查看控制台日志:分析控制台中的错误日志,确定具体报错信息和出错的代码位置。
    • 抓包分析:使用抓包工具(如 Charles、LightProxy)分析 HTTP 请求和响应,查看是否有异常。
  • 服务端配合
    • 服务端修改数据库:部分场景需要服务端改库才能复现的,请求服务端协助。(一切资源都是你排查问题的手段)

诊断/确认问题

确定问题原因,问题解一半。

检查网络连接

确保用户的网络连接没有问题是排查线上问题的第一步,因为许多前端问题可能是由于网络延迟、连接不稳定等原因导致。

  • 用户网络状态检查
  • 排除CDN或第三方服务问题
    • 主应用中包含很多 <script src="xxx" /> 引入方式,检查资源访问是否正常
  • 检查用户是否使用最新app版本
    • 灰度状态下,检查用户是否在灰度内

查看浏览器控制台

浏览器控制台是排查前端问题的重要工具,它可以提供关于页面加载、脚本执行等各方面的详细信息。

  • 分析常见问题
    •  
  • 引导用户打开控制台
    • B端用户:可以直接联系用户,引导打开控制台,直接查看报错信息
  • SourceMap
    • AEM查看错误堆栈信息
    • 本地使用sourcemap调试

捕获HTTP请求和响应

HTTP 请求和响应的状态和内容可以提供大量排障信息,特别是涉及到数据的加载和交互问题。

  • 分析常见问题
    • 400 Bad Request

      描述:服务器无法理解请求的格式,因为请求有错误或不正确的语法。

      解决方案:检查并确保请求的URL和参数格式正确。检查请求头部和请求体是否符合API规范。清除浏览器缓存和Cookie。

      401 Unauthorized

      描述:请求要求身份验证。客户端必须提供正确的认证凭据。

      解决方案: 确保正确的身份验证信息(如API Key、Token)已包含在请求中。 检查认证凭据是否过期,如果过期,重新获取新的凭据。 确认用户具有访问资源的权限。

      403 Forbidden

      描述:服务器理解请求但拒绝执行。

      解决方案:确认用户是否有权限访问请求的资源。检查服务器上相关文件或目录的权限设置。若使用白名单机制,确保客户端IP地址在白名单中。

      404 Not Found

      描述:服务器找不到请求的资源。

      解决方案:检查请求的URL是否正确。确认资源是否存在或者是否已被移动。检查路由和路径配置是否正确。

      500 Internal Server Error

      描述:服务器遇到错误,无法完成请求。解决方案:检查服务器端代码和日志,以找出错误的具体原因。确保服务器资源(如内存、CPU)充足,检查是否有系统资源问题。检查服务器配置和依赖项是否正确。

      502 Bad Gateway

      描述:作为网关或代理的服务器从上游服务器收到无效响应。

      解决方案:检查上游服务器(如应用服务器、数据库服务器)是否正常运行。检查网络配置和防火墙设置,确保服务器之间的通信正常。重新启动相关服务或服务器。

      503 Service Unavailable

      描述:服务器目前无法处理请求,因为它暂时过载或进行维护。

      解决方案:检查服务器资源使用情况,解决可能的过载问题。确认服务器是否在进行维护,并等待维护结束。配置适当的负载均衡机制来分配负载。

      504 Gateway Timeout

      描述:作为网关或代理的服务器没有及时从上游服务器收到响应。

      解决方案:检查上游服务器的响应时间,确保其性能正常。优化上游服务器的查询或处理逻辑以加快速度。检查网络连接,确保无延迟或中断。这些是一些常见的HTTP错误及其可能的解决方案。具体问题需要具体分析,可以通过检查服务器日志、调试代码和改善网络设置来解决问题。

       

       

  • 抓包分析
    • 使用抓包工具(如 Charles、Fiddler)捕获和分析 HTTP 流量,以更详细地查看请求和响应的内容和头部信息。 通过抓包工具,可以模拟不同的网络环境,进行深度分析,例如查看 HTTPS 加密的详细内容。
    • 利用好traceId,让服务端协助我们去解决问题。
  • 熟悉微服务架构
    • 熟悉微服务架构,了解发起请求的整个链路,确认问题可能出现在哪个环节。
    • 示例:熔断/限流/降级等
  • 服务端相关问题
    • API接口问题
    • 检查 API 响应状态码,例如 500(服务器内部错误)、502(网关错误)、503(服务不可用)、504(网关超时)。 与后端开发人员沟通,提供错误日志和请求示例,明确问题所在。 使用 Postman 或 cURL 模拟请求,查看是否能在开发环境中复现问题。 检查 API 文档(max),确保前端调用参数和数据格式正确。
    • 数据库问题
    • 服务器配置问题
    • 检查服务器配置是否正确,例如 HTTP 头部、缓存策略、负载均衡等。 使用服务器日志(如 Nginx、Apache 日志)分析服务器运行状态和错误信息。
    • 服务端性能问题
    • 使用性能监控工具,查看服务器性能状态,
    • 如 CPU、内存、网络、QPS、尖刺等

检查页面加载性能

页面加载缓慢或资源加载失败可能会影响用户体验,需要通过性能检查找到瓶颈和问题。

  • 分析常见问题
    • 大量的初始资源加载

      问题: 初始加载时需要加载大量的JavaScript、CSS和图片文件,导致页面加载时间过长。

      解决方案: 使用代码拆分(Code Splitting)和按需加载(Lazy Loading)来减小初始加载的资源大小。 使用React.lazy和Suspense进行组件的懒加载。 使用webpack等工具进行资源的按需打包。

      非优化的图片资源

      问题: 大量高分辨率且未压缩的图片会显著增加页面加载时间。

      解决方案: 压缩图片,使用WebP等现代图片格式。 使用图片懒加载(Lazy Load Images)技术,只在需要时加载图片。 使用响应式图片(Responsive Images)技术,加载合适大小的图片。

      未压缩的静态资源

      问题: 未压缩的JavaScript和CSS文件会增加加载时间。

      解决方案: 使用gzip、Brotli等压缩技术对静态资源进行压缩。 在生产环境中启用CSS和JavaScript的最小化(Minification)和压缩。

      不必要的重渲染

      问题: 一些不必要的组件重渲染会导致性能下降。

      解决方案: 使用React.memo或PureComponent来避免不必要的重渲染。 使用shouldComponentUpdate生命周期方法进行手动优化。 使用React的性能分析工具(如React Profiler)找出性能瓶颈。

      长时间的JavaScript执行

      问题: 复杂的JavaScript逻辑和大量的计算会阻塞主线程,导致页面卡顿和加载延迟。

      解决方案: 优化繁重的JavaScript逻辑,使用Web Workers来进行后台处理。 使用防抖(Debouncing)和节流(Throttling)技术来减少事件触发频率。 使用虚拟列表(Virtualized Lists)来优化长列表的渲染。

      使用不当的第三方库

      问题: 引入和使用大量的第三方库会增加应用的体积并可能导致性能问题。

      解决方案: 去掉不必要的库,用原生JavaScript或轻量级的替代品。 动态引入第三方库,使用如React Loadable等工具进行按需加载。

      非高效的样式处理

      问题: 使用大量的CSS-in-JS解决方案或者不高效的样式处理会影响性能。

      解决方案: 使用静态提取的CSS,减少运行时的样式计算。 优化CSS选择器的复杂度,避免使用过于嵌套的选择器。

      HTTP请求过多

      问题: 页面加载时发起大量的HTTP请求,增加服务器负载和页面加载时间。

      解决方案: 合并资源文件(如CSS和JS文件)。 使用HTTP/2,允许多个请求在一个连接上并行完成。 使用CDN缓存静态资源,减少服务器负担和加快加载速度。 通过这些方法和技巧,可以显著提升React前端页面的加载性能,带来更好的用户体验。

       

      常见解决方案

      使用浏览器开发者工具

      Chrome DevTools 和 Firefox Developer Tools 提供了一些非常强大的工具来帮助你识别和分析性能瓶颈。

      Performance(性能)面板

      打开开发者工具(通常通过按 F12 或 Ctrl+Shift+I)。

      找到并打开Performance面板(在Chrome中,名称可能有所区别)。

      点击录制按钮,进行页面操作以触发长时间执行的JavaScript代码。

      停止录制,查看时间线,找到时间消耗过多的脚本部分。你可以点击展开每个部分,查看具体的函数调用栈。

      Profiler(分析)面板

      打开Profiler面板。

      点击录制按钮,进行页面操作,触发长时间执行的JavaScript代码。

      停止录制并查看分析结果,找到性能瓶颈。

      可以在长时间执行的代码区域添加console.timeconsole.timeEnd来测量具体代码块的执行时间

      console.time('longRunningCode');
      // 要测量的代码块
      console.timeEnd('longRunningCode');
      

      性能优化技巧

      优化算法和数据结构确保你使用的是高效的算法和合适的数据结构。有时候,简单的代码重构就能显著提高性能。

      使用requestAnimationFrame

      如果代码中有需要重复执行的任务(如动画),使用requestAnimationFrame代替setTimeout或setInterval,以更好地协调任务与浏览器的刷新周期。

      function animate() {
        // 动画逻辑
        requestAnimationFrame(animate);
      }
      requestAnimationFrame(animate);
      

      使用Web Workers

      对于CPU密集型任务,如复杂计算,可以将其移到Web Workers中。Web Workers在后台线程执行,不会阻塞主线程。(还可以考虑WASM)

      const worker = new Worker('worker.js');
      worker.postMessage(data); // 发送数据到Web Worker
      
      worker.onmessage = function(e) {
        console.log('Message received from worker', e.data);
      }

      检查内存泄漏

      内存泄漏会导致性能问题,你可以在Chrome DevTools的Memory面板中检查和分析内存使用情况。

      使用堆快照

      捕获前后的堆快照,比较两者的内存差异,找出潜在的内存泄漏。

      定期Profile代码

      将性能测试作为常规开发的一部分,不断监控与优化。

      通过上述步骤,你可以系统地分析和优化长时间执行的JavaScript代码,提高应用的响应速度和用户体验。

兼容性问题

浏览器兼容性问题通常表现为在不同浏览器下代码表现不一致。需要测试多个浏览器,并使用 Polyfill、CSS 前缀等技术解决

  • 分析常见问题
    • 图片格式和加载问题

      问题: 不同浏览器对某些图片格式的支持不一致(如WebP格式)。

      解决方案: 提供多种格式的图片备用方案。 使用服务端检测和处理图片格式,或JS库进行图片格式的检测和切换。

      JavaScript API 的兼容性

      问题: 不同浏览器对某些新的JavaScript API的支持不一致,如fetch(), promises等。

      解决方案: 使用Polyfill填补API。例如,使用Babel编译现代JS代码,并使用polyfill服务(如polyfill.io)加载缺失的API。 使用库包装API(如Axios替代fetch)。

      字体和图标的兼容性

      问题: 不同浏览器对自定义字体和图标字体的渲染和加载方式不同,导致显示差异。

      解决方案: 确保字体文件格式全面(.woff, .woff2, .ttf, .eot, .svg))。 使用Font-face声明中的跨浏览器优化技术。

      CSS样式不一致

      问题: 不同浏览器对CSS属性的支持和解释可能有所不同。

      解决方案: 使用CSS Reset或Normalize.css重置默认样式。 使用前缀自动添加工具,如Autoprefixer。 避免使用浏览器特定的CSS属性。

      npm库版本升级问题

npm未锁版本,可能导致发布时升级小版本,小版本有bug导致,不容易发现。

  • 对比线上正常运行的yarn.lock版本
    • 通过二分法查看出问题的版本
  • 查看npm文档的ChangeLog.md

问题上升

解决不了的问题,请考虑把问题向上反馈,首先反馈到应用负责人,应用负责人依然解决不了,反馈到梦华

解决问题

已经发现并确认问题原因,解决起来就比较快了

服务端问题

当确定问题源自服务端时,需要与后端开发团队协作解决。

  • API接口问题
    • 确认前端调用参数和数据格式正确,回归可能影响的范围,验证。

前端代码逻辑问题

目的:修复问题时不影响其他功能

方案:

  • 代码修改
    • 根据分析结果,针对性地修改代码,并确保新的逻辑更加稳健。
  • 集成测试
    • 进行端到端测试,确保修复后的代码在整个应用流程中正常工作。
    • 使用 Cypress 等工具编写集成测试用例,模拟用户操作和业务流程。
  • code review
    • 找项目负责人CR,说明问题原因以及解决思路,通过后方可发布

自有库问题

  • 代码修改(同上)
  • 单元测试
    • 编写或更新单元测试,验证修改后的代码逻辑是否正确无误。
    • 使用 Jest 等测试框架编写全面的测试用例,覆盖关键逻辑和边界情况。
  • 集成测试(同上)
  • 版本号管理
    • 根据修改的性质,确定版本号的变更方式(如遵循 SemVer 规范)。
    • 修复问题: 增加 PATCH 版本号,例如从 1.0.0 增加到 1.0.1。
    • 添加新功能但不破坏现有功能: 增加 MINOR 版本号,例如从 1.0.0 增加到 1.1.0。
    • 重大变更或破坏性修改: 增加 MAJOR 版本号,例如从 1.0.0 增加到 2.0.0。
  • code review(同上)

第三方库问题

三方库一般比较稳定,多查看issue,确认可实施版本。

确认与重现问题

版本锁定

确认你使用的第三方库版本,并检查 package.json 中是否正确锁定了版本。

"dependencies": {
  "third-party-lib": "1.2.3"
}

最小可重现示例

创建一个最小可重现示例项目,确认问题是否存在于特定版本的库中。

官网和文档

查看第三方库的官方文档,查看是否有已知问题的相关信息。

 

检查社区资源

GitHub Issues 页面

访问第三方库的 GitHub 仓库,查看 Issues 页面,确认是否有其他用户报告了相同问题。

提交问题

如果确认是库的问题,可以在 GitHub 上提交一个新的 Issue,把具体的问题说明、重现步骤和环境信息提供给维护者。

尝试解决与替代方案

升级库

尝试升级到第三方库的最新版本,可能已经修复了问题。

降级库

如果升级不能解决问题,尝试降级到以前的稳定版本。

代码临时修复

fork代码

使用替代库

如果问题长期无法解决或维护不善,可以评估并使用功能类似的替代库。

 

复杂的问题请整理落入文档

详细记录每一步的诊断和解决过程,包括遇到的困难和解决方案。

将常见问题和解决方法加入团队的知识库,帮助团队其他成员快速响应类似问题。