背景
软件系统的稳定性,主要决定于整体的系统架构设计,然而也不可忽略编程的细节,正所谓“千里之堤,溃于蚁穴”,一旦考虑不周,看似无关紧要的代码片段可能会带来整体软件系统的崩溃。
稳定性的工作,一般都是水下的工作。就像冰山,真正强大的系统下,要有更加强大的底层支撑,水面下的问题才是真正需要解决的问题。当然不一样的工作内容,水下的工作是不同的,对于盖楼来说,可能就是地基的深度。对于我们写业务逻辑来说,水下的工作就是catchException的处理,异常情况的处理。对于系统来说,水下的工作可能是一些接口系统的稳定性。类似于金字塔结构,下层基础决定上层建筑。对于软件系统来说,稳定性至关重要。
稳定性定义
我们通常用平台的可用性去量化平台的稳定性,但是线上故障和线上问题也是稳定性的重要衡量指标。
稳定性建设目标
架构设计源于生活,稳定性建设也肯定是源于生活,一般会把稳定性和消防放在一起进行比喻方便大家的理解,处理火灾主要是阶段:在火灾前预防火灾,在第一时间知道发生火灾了,在发生火情的时候如何快速救火。通过火灾处理对比软件系统的稳定性,也就是预防(事前)、发现和处理(事中)了,最后(事后)我们加入了复盘。发生问题不可怕,可怕的是已发生的问题重复发生。一定要杜绝有问题的事情第二次发生。
防火的最高境界是,防患于未然。这也就催生了,现代软件系统里面,大家把更多的精力放在事前(全链路压测和故障演练方面)。
软件系统中的稳定性前中后
事前:
- 流程规范,保证研发的交付质量。
- 全链路压测、故障演练。
- 告警治理。(目前阶段的要求,项目初期的业务迭代很快,需要尽量做到重点告警不被淹没,避免告警风暴)
事中:
- 核心链路的梳理,输出系统的关键信息。(双11 双12,核心链路方法论支撑)
- 监控告警的完善,确保快速发现问题定位问题。
- 容灾容错,保证系统的稳定性。
事后:
- 日常稳定性工作,核心指标check。
- 总结并持续建设研发的可用性保障意识,积累适合当前业务的sop和问题排查指南。
稳定性治理
影响稳定性的主要在两个阶段,一个阶段是非运行期,一个阶段是运行期。非运行期主要就是我们日常进行开发的时候,方案设计,代码书写,线上操作配置等引发的稳定性问题。运行期主要是因服务自身问题、外部调用问题,外部依赖问题引发的稳定性,所以治理也主要从这两个方面出发。
非运行期
针对于非运行期的时候,我们主要使用的思路就是,流程化和规范化,大部分在此环节出现问题,并且影响线上稳定性的事情都是因为没有遵守流程和规范导致的。加强Review!!
引发稳定性问题的类别 | 杜绝 | 目标 |
---|---|---|
方案设计 | 代码搭车上线服务回滚时遗漏回滚代码服务启动或者回滚时间过长配置文件缺少有效的校验机制小流量后的修改没有经过严格的测试和灰度验证新功能不加降级开关 | 谨慎!!!****可回滚!****可灰度!****可监控! |
代码变更 | hotfix代码不review就上线 | |
配置变更 | 不review就生效 | |
数据库操作 | 没有经过explain就上线,导致慢查询 | |
缓存失效 | 缓存不预热,就直接线上并发读 | |
线上发布 | 步长特别大的发布 |
运行期
服务的运行状态,在这个状态服务的内容可能涉及到 外部的影响产生一些变化,本质就是说对于内/外部变化的监控和处理。
阶段细分 | 策略 | 检查点 | |
---|---|---|---|
事前预防 | 设计阶段 (主要是服务可用性和可维护性(监控指标)设计) | 方案对比 | 核心服务:尽量采用业界通用方案或经过验证的方案非核心服务:可以适当增加一定比例的新技术 |
隔离策略(结合一下DDD的思路,传统开发和DDD的模式) 1. 保证异常出现时,影响范围可控2. 保证功能高内聚,降低耦合 | 分层隔离:按主要接入方隔离按业务隔离(服务拆分)按功能核心程度隔离:非核心服务核心服务隔离方式:物理隔离 | 逻辑隔离读写隔离(*、mysql、kafka、rocketmq老数据、redis) | ||
部署隔离机房隔离(异地容灾)进程隔离(防止抢占机器cpu资源) | |||
资源隔离线程池隔离数据库隔离,慢sql隔离(统计库)基础组件隔离:如redis、mysql、tair、ES等使用单独机器(核心服务) | |||
热点隔离抢占式资源,避免线程饿死。(CPU密集型业务和一个普通业务要尽量区分开) | |||
冗余策略 | 服务冗余部署,水平扩展(资源的抢占),节假日增长。 | ||
各基础设施(Mysql、DB中间件、Tair、Redis、MQ、ES)冗余部署,提供多副本存储,数据一致性 | |||
数据多备份,数据一致。可以快速切换 | |||
监控指标设计监控和告警,可以从:用户、调用方、我们自己以及我们下游这几个角度考虑。站在不同的角度,会有不同的关注点 | 机器指标监控网卡流量(*)内存占用磁盘占用cpu负载 | ||
Jvm指标监控新生代、老年代。线程数。gc时间、是否fullgc。高峰期停顿时间。swap区是否合理(*)(吞吐量gc 还有 停顿时间gc) | |||
性能监控:核心接口的性能,TP99,TP999,失败数,失败率。线程池中活跃线程数量,队列阻塞任务数。(*)中间件性能。异常日志监控。 | |||
业务监控产品级别(对外和对内):核心链路正向流程指标(提、推、接、发配送)。逆向流程指标(消单)。入口流量。服务级别:重点逻辑监控(召回、精排、过滤等)事件监控(例如一些返回值为0的事件需要我们第一时间感知)数据层面:数据同步状态监控。数据一致性监控。(*) | |||
可降级 | 非核心链路是否可降级:降级说明和sop(出问题的时候最好靠流程来保证,否则有可能恶化问题)有损降级和无损降级。 | ||
可限流(上游/下游) | 上游调用进行限流。必要性(api服务启动不了的问题)。 | ||
削峰 | 大促削峰秒杀场景削峰 | ||
错流 | 秒杀场景 | ||
熔断 | 非核心链路的调用要能具备有损降级自动熔断。 | ||
服务超时和重试 | 超时需要跟下游sla进行约定重试需要考虑业务和流量,防止将下游打挂,一般1~2次,重试时间递增。下游服务幂等性(业务重试 和 tcp层的重试) | ||
幂等和无状态 | 接口尽量做到幂等。多机器间尽量做到无状态,若需要有状态,需要特殊说明,并进行重点强调和关注 | ||
消息队列 | 重复消费幂等。消费数据丢失重试。注意顺序性(*)死信消息的处理。 | ||
缓存 | 空值填充。大key、大value预警热点key | ||
数据对接及管理 | 数据来源可追溯,被谁加工过 | ||
failover策略 | 上游数据验证快速失败(*) | ||
可回滚 | 服务可回滚设计回滚策略,如果设计多方上线,需要有回滚演练尽量有新功能关闭的一键开关,能够快速回滚 | ||
测试 | 单元测试性能测试,性能拐点测试服务器负载达到 60%~70% 的时候,看 QPS 是多少线上 QPS = 单机 QPS 机器数 0.8。后面会乘以一个系数(0.8)是因为线上 put 上去的时候总会存在一些损耗。(线上环境往往不像压测环境这种纯粹的场景)回滚测试有状态的内容是否可以回滚(参考红包发放这种问题)降级方案测试(*)降级 异常情况的流程 | ||
灰度(产品风险较大,可以提出灰度策略) | 按地区灰度按新老用户灰度上线时,按照机房灰度先上线一个机房一台机器上线一个机房30%机器上线一个机房所有机器上线剩下机房各30%机器上线所有机器蓝绿部署。set化部署。 | ||
事务 | 代码中严禁使用事务注解,可通过一致性保障平台进行最终一致性的检测 | ||
日常巡检 | 发版失败率 | 某次发版后,错误数量较原来每次发版,错误数是否明显上涨 | |
容量评估 | 每季度至少一次容量评估。重大活动前容量评估(一般依赖全连路压测)。监控系统容量预警。日常容量30%冗余。保证双机房互备。 | ||
故障演练 | 是否有常规的故障演练机制,针对于异常场景的测试。 | ||
全连路压测 | 暴露性能问题。 | ||
事中发现 | 异常检测 (及时发现故障) | 核心基础设施监控 | 核心基础设施监控是否覆盖 |
应用级别监控 | JVM监控项是否覆盖 | ||
业务监控覆盖率 | |||
服务质量监控 (业务监控和技术监控) | 流量波动监控告警 | ||
TPS/QPS是否有监控告警 | |||
请求错误是否监控,请求正确率监控 | |||
线程池监控 | |||
异常日志监控 | |||
sql监控 | 慢查询监控,配置db慢查询参数。(*) | ||
报警分级 | 报警是否分级:04_报警定级规范 | ||
报警阀值 | 报警是否设置合理的阀值 | ||
事中处理 | 故障处理 (快速修复)故障发生时恢复大于原因查找,也就是说需要通过各种手段,把事故的影响面减到最少,并且尽快恢复服务 | 重启动作 | 明确服务重启流程 |
扩容动作 | 明确扩容操作方式 | ||
切流量动作 | 明确机器禁用/负载策略调整 | ||
降级 | 核心链路手动一键降级;非核心链路自动降级 | ||
限流动作 | 明确限流操作手册 | ||
回滚 | 按照架构设计的回滚方案进行回滚 | ||
故障处理SOP | 是否有故障处理SOP,checklist | ||
事后复盘 | 故障报告 | 故障处理的整个过程故障原因分析:5w分析法(问五个为什么)故障后续整改计划,完善规范和流程。 | |
会议 | 回顾上个周中的所有事故;统计所有事故故障后续整改计划执行情况;总结易犯错误,给出解决方案,并完善规范跟流程; |
最后
在软件架构上有一句名言,没有最完美的架构,只有最适合的架构。推广到稳定性上,没有完全完美的稳定性方案,只有适合的稳定性方案。
稳定性建设是一个系统的基石,也是一个持续的过程,面对业务的不同发展阶段,对稳定性的落地要求不同,取舍也不同(适合的才是最好的~),但随着业务发展,占比越来越大,关注点也会越来越高。