常见的微服务故障

文摘   2024-09-01 16:40   云南  

 


点击上方蓝字关注我们


 

 

背景

 

     微服务架构指的是将大型复杂系统按功能或者业务需求垂直切分成更小的子系统,这些子系统以独立部署的子进程存在,它们之间通过轻量级的、跨语言的同步(比如REST,gRPC)或者异步(消息)网络调用进行通信。


微服务架构分层


 

现象

 

微服务生态系统堆栈的顶层是各个微服务。对于开发团队来说,因为它们完全依赖于良好的开发实践、良好的部署实践以及开发团队构建、运行和维护其单个微服务的方式。

假设微服务层下面的基础设施相对稳定,微服务经历的大多数事件和中断几乎都是自行造成的。应该让的开发人员针对其微服务中,自己发现完整的根本原因和故障,即他们收到的告警,将来自其微服务的关键指标的变更触发(有关监视、日志记录、告警和微服务密钥指标的详细信息)。

如是一个服务失败示例, 通常需要隔离它


服务失败示例


还有一些情况是,服务之间有依赖的,其有一个服务失败导致多个服务失败。这时你需要多个故障转移Failover



多个服务失败需要多个故障转移Failover

故障转移Failover方案

1. 依赖管理

  • 服务依赖图:绘制服务之间的依赖关系图,识别关键路径和依赖关系,以便在故障发生时能够迅速定位影响的服务。

  • 异步通信:尽量使用异步通信(如消息队列)来减少服务之间的紧耦合,降低服务间依赖造成的故障影响。

2. 故障检测与恢复

  • 健康检查:实现服务健康检查机制,定期检测服务的健康状态,及时发现故障。

  • 自动重启:对于短暂的故障,可以配置服务自动重启,恢复正常状态。

3. 故障转移策略

  • 主备模式:为关键服务配置主备实例,在主实例故障时,自动切换到备实例。

  • 负载均衡:使用负载均衡器(如 Nginx、HAProxy)分发请求,确保在某个服务实例故障时,流量能够转发到其他健康实例。

  • 降级策略:在某些服务不可用时,实施服务降级,提供部分功能以减少用户影响。

4. 数据一致性与恢复

  • 数据备份:定期备份重要数据,并保存到可靠的存储中,以防数据丢失。

  • 事务管理:使用分布式事务管理方案(如 Saga 模式)来处理跨服务的事务,确保数据一致性。

 

微服务故障

 

1.代码质量差测试覆盖率低

代码审查Code Review不完整、缺乏适当的测试覆盖率以及不规范开发流程(具体来说,缺乏标准化开发流程)会导致将错误代码部署到生产环境中,而通过跨微服务团队标准化开发流程是可以避免故障。

原因

代码审查不完整

    • 缺乏多样性:如果代码审查只依赖于少数开发人员,可能会产生偏见,导致错误被忽视。

    • 时间压力:在快速开发的环境中,代码审查可能被简化或省略,导致潜在问题未被发现。

缺乏适当的测试覆盖率

    • 测试不足:没有足够的单元测试、集成测试和端到端测试,无法确保功能的正确性和系统的整体稳定性。

    • 测试文化缺失:开发团队可能没有形成良好的测试习惯,导致对代码质量的忽视。

不规范的开发流程

    • 缺乏标准化:没有统一的开发流程和规范,各团队可能各自为政,导致代码风格和质量不一致。

    • 沟通不畅:跨团队的协作可能因缺乏标准化流程而受阻,导致错误的理解和实现。

解决方案

加强代码审查流程

    • 多样化审查团队:确保代码审查由不同背景的开发人员参与,增加多样性和覆盖面。

    • 设定审查标准:制定明确的代码审查标准,确保每次审查都遵循这些标准,包括功能、性能和安全性等方面。如Alibaba Java Coding Guidelines

    • 引入工具:使用代码审查工具(如 GitHub Pull Requests、Gerrit)来自动化审查流程,确保每次提交都得到审查。

    • 知识分享:定期组织代码审查培训和知识分享会,提高团队成员的审查能力。

提高测试覆盖率:

    • 引入自动化测试:使用CI/CD工具(GitLab, Jenkins)来自动运行测试,确保每次提交都经过严格的测试。

    • 建立测试文化:在团队中推广测试驱动开发(TDD)和行为驱动开发(BDD),鼓励开发人员编写单元测试用例, 接口自动化测试,实现研发自测流程。

    • 持续集成(CI):设置 CI 系统,确保每次代码提交后自动运行测试,及时发现问题。

    • 代码覆盖率工具:使用代码覆盖率工具(如 JaCoCo、Coverage.py)定期检查测试覆盖率,确保达到预定标准。

实施标准化开发流程

    • 制定标准流程:创建一个统一的开发流程文档,包含从需求分析到部署的所有阶段,并确保团队遵循。
      制定开发规范文档
      :为微服务架构制定统一的开发规范,包括代码风格、提交信息、版本控制等。

    • 跨团队协作:定期举行跨团队的开发会议,分享最佳实践和经验,确保各团队之间的沟通顺畅。

持续改进与反馈

    • 引入反馈机制:定期收集反馈,评估现有流程的有效性,必要时进行调整。

    • 进行回顾会议:在每个迭代结束时召开回顾会议,分析问题并讨论改进措施。

2.没有稳定可靠的部署管道

如果没有一个稳定可靠的部署管道,其中包含Staging、金丝雀(金丝雀对矿场中的毒气比较敏感,所以在矿场开工前工人们会放一只金丝雀进去,以验证矿场是否存在毒气,这便是金丝雀发布名称的由来。)和生产阶段的设置,在将任何错误完全部署到生产服务器之前捕获任何错误,在开发阶段测试未捕获的任何问题都可能导致微服务本身、其依赖项以及依赖于它的微服务生态系统的任何其他部分出现严重事件和中断。

原因

  1. 部署风险:没有良好的部署管道,错误可能直接被推送到生产环境,导致服务中断或故障。

  2. 缺乏测试:在开发阶段未能捕获的问题可能在生产环境中引发严重事件。

  3. 依赖关系复杂性:微服务之间相互依赖,如果其中一个服务出现问题,可能会影响其他服务,导致连锁反应。

解决方案

建立稳定的部署管道

    • 确保有清晰的Staging、金丝雀和生产环境设置。

    • Staging环境用于模拟生产环境进行充分测试。

    • 金丝雀发布策略允许在小范围内发布新版本,及时捕获问题。

自动化测试

    • 在各个阶段进行自动化测试,包括单元测试、接口测试、安全测试、集成测试和端到端测试,以确保代码在部署前是稳定的。

监控与回滚机制

    • 实施监控工具,实时监测系统状态,及时发现并响应异常情况。

    • 建立回滚机制,以便在发现问题时迅速恢复到上一个稳定状态。

3.缺少自动化监控

当我们平台缺少微服务应用层监控时,不能及时收到告警,做出决策,最终可能会引起大规模的微服务实例失败。

原因

实时性不足:缺乏监控使得团队无法及时发现系统异常,延误了问题的响应时间。
决策延迟:没有及时的告警信息,导致决策层无法做出迅速有效的响应,影响业务连续性。
服务实例失败:由于监控缺失,微服务的健康状况不能被及时评估,可能导致大量实例同时失败,造成业务中断。

解决方案

引入全面的监控工具:

选择合适的监控工具(如 Prometheus、Grafana、ELK Stack)来监控微服务的健康状况、性能指标和日志。

设置告警机制:

配置告警规则,以便在关键指标(如响应时间、错误率、CPU 和内存使用率)超过阈值时,能够及时通知相关人员。

实施分布式追踪:

使用分布式追踪工具(如 Jaeger、Zipkin、SkyWalking)来监测微服务之间的调用链,帮助识别性能瓶颈和故障点。

定期审查与优化:

建立定期审查机制,分析监控数据,优化微服务架构和性能,确保系统的可用性和稳定性。

培训与文化建设:

提高团队对监控重要性的认识,培养数据驱动的决策文化,确保每个团队成员都能关注系统的健康状态。

4.软件设计存在问题

那些本身模块或服务设计有问题,如不规范的程序重试逻辑,不正确的缓存使用场景。

原因

不规范的程序重试逻辑

    • 重试机制设计不当可能导致重复请求、资源浪费或服务过载。

    • 没有合适的重试间隔、最大重试次数,可能导致请求失败后不断重试,影响系统性能。

不正确的缓存使用场景

    • 缓存设计不当可能导致数据不一致或过期数据被使用。

    • 没有正确识别需要缓存的数据或缓存失效策略,可能导致频繁访问数据库,增加延迟。

    • 使用缓存传递变量

解决方案

改进重试逻辑

    • 实现指数回退算法(Exponential Backoff),在重试时逐渐增加间隔时间。

    • 设置合理的最大重试次数,避免无限重试。

    • 记录重试日志,以便于后续问题排查。

优化缓存机制

    • 明确缓存的使用场景,识别哪些数据适合缓存。

    • 实现合理的缓存失效策略,如 TTL(生存时间)或 LRU(最少使用算法)。

    • 定期进行缓存清理,确保缓存数据的准确性和有效性。

这些都会导致某个微服务的失败,这些需要在测试过程时需要发现与解决,包括架构设计评审。

5.服务故障

任何特定于微服务体系结构也可能失败,包括任何数据库、消息中间件、任务处理系统等。

原因

单点故障

    • 某些数据库或消息中间件如果没有冗余设置,会成为单点故障。

网络问题

    • 微服务之间的通信依赖于网络,如果网络不稳定,服务调用可能失败。

依赖性管理

    • 微服务之间的紧密耦合可能导致某个服务的失败影响其他服务。

资源限制

    • 资源(如 CPU、内存)不足可能导致服务崩溃或响应缓慢。

版本不兼容

    • 不同微服务间的版本更新不一致,可能导致兼容性问题。

解决方案

冗余和高可用性

    • 使用主从复制、集群等方法来确保数据库和消息中间件的高可用性。

服务发现和负载均衡

    • 使用服务发现工具(如 Eureka、Consul)和负载均衡器(如 Nginx、Kubernetes)来管理服务调用。

熔断器模式

    • 实施熔断器(如 Hystrix)来避免 cascading failures,允许系统在部分服务不可用时继续运行。

资源监控和自动扩展

    • 监控服务的资源使用情况,使用 Kubernetes 等平台进行自动扩展。

版本控制和蓝绿部署

    • 实施蓝绿部署或灰度发布策略,以减少版本更新带来的风险。

蓝绿部署

6. 不正确的错误和异常处理

这也是微服务中的常规和特定代码错误会导致故障以及不正确的错误和异常处理:当微服务失败时,未处理的异常是经常被忽视的罪魁祸首。最后,如果服务未做好突发增长做好准备,流量的增加可能会导致服务失败。

原因

未处理的异常

    • 微服务在运行过程中可能会出现各种异常,如果这些异常没有被正确捕获和处理,就会导致服务崩溃或不稳定。

错误的错误处理

    • 在微服务架构中,错误处理机制可能不完善,导致无法有效地捕捉和响应错误,进而影响服务的可用性。

流量突增

    • 微服务如果没有针对突发流量进行优化和扩展,可能会因为请求过多导致服务超负荷,从而出现故障。


解决方案

增强错误处理机制

    • 实施全局异常处理,确保所有异常都能够被捕获并妥善处理,避免未处理的异常导致服务崩溃。

使用重试和断路器模式

    • 通过重试机制和断路器模式来处理临时故障,在服务不可用时防止请求泛滥。

流量管理与负载均衡

    • 采用负载均衡和自动扩展策略,确保服务能够根据流量变化动态调整资源,以应对突发流量。

监控与日志记录

    • 建立完善的监控系统,实时跟踪服务的运行状态和异常情况,通过日志记录分析和排查问题。

性能测试与压力测试

    • 在部署前进行性能测试与压力测试,确保微服务能够承受预期的负载和突发流量。


 

总结

 

一些最常见的微服务故障包括:

• 不完整的代码审查
• 糟糕的架构和设计
• 缺乏适当的单元和集成测试
• 部署错误
• 缺乏适当的监控
• 错误和异常处理不当
• 数据库故障
• 可伸缩性限制

注意:我们不能依赖容器编排平台Kubernetes来解决以上问题,很多时候是研发流程的问题,通过事前过程来预防微服务的失败,而不是通过事后控制。

 

 


Megadotnet
为您介绍各体系平台的新闻,系统研发相关框架,组件,方法,过程,运维,设计。企业IT与互联网信息系统或产品解决方案。开源项目,项目管理。
 最新文章