简介
目的: 站点能持续提供服务
前提设定:
- 故障是必然会发生的
- 人工操作内容越多越容易触发误操作
可靠性三板斧
- 减少故障的发生
- 故障发生了也不影响业务
- 有应急计划, 影响了业务也能快速恢复
一、减少故障发生
-
可靠的程序;
尽量少 BUG, 尽量不要运行着自己挂了;
尽量少维护, 避免每天都要去配几个参数才能可靠运行这种情况; -
可靠的硬件
老旧硬件就默认它处于随时可能宕机的状态;
新硬件就默认它可能不稳定; -
可靠的平台
指操作系统,云平台, 网络设施, 软件框架等 -
可靠的架构设计
不要因为某个节点的问题, 影响了整个系统;
二、降低故障对业务的影响
-
快速拉起新服务, 接替故障应用;
例如某个服务挂了, 但 0.001 秒后, 就有新服务启动并接替了它, 那么我们完全可以认为未造成影响;传统的重启脚本就是为了这个目的, 只不过一般都只能做到分钟级别的恢复时间,很难压得更低;
新的k8s集群在应用无状态后, 配合健康检查, 做得细的话,能把新节点的拉起速度控制到分钟内; -
热备接管
因为拉起新服务需要很长时间, 于是索性就在故障发生前先拉起来;
但你又不知道啥具体时候会发生, 于是只能一直启动着, 等故障发生后, 再切换流量到备用节点。优点: 故障检测和转移做的好的话, 可以控制在几秒内;
缺点: 资源利用率降低一半, 还有故障检测和切换动作需要触发,有些时候也比较复杂 -
负载均衡
简单说就是起N个节点, 前端负载均衡器将流量依次分发给各节点;如果检测到某节点故障,那就暂时屏蔽此节点;优点: 相当成熟的方案, 很可靠;
缺点: 增加了负载均衡器本身的性能和可靠性要求 -
零影响
如何做到每一笔交易都不被故障影响?例如涉及到资金的业务时;其实也没什么好的办法, 只能是对每一笔请求都进行校验和补偿;
以 nginx 为例, 发给某节点的请求无响应时, 就再转给下一个节点继续处理;
这就引发出了新的问题, 原节点收到并正在处理请求, 只是网络丢失了响应包,nginx 又转发了一份给新节点, 就会造成重复处理。
所以对这种请求, 需要等幂性设计, 或者全局锁机制。
三、快速恢复故障
即良好的事件应急处理机制;
主备节点是可以避免一部分故障, 但要是主备节点一起挂了呢?或者是机房级别的故障呢?
所以还是得有完善的应急处置办法;
核心要素: 应急方案 和 应急演练
应急方案覆盖面
- 基础设施: 或者说是自身不可控的内容; 例如运营商断网, 机房UPS炸了等
- 数据安全: 只要数据还在一切都可以重来
- 核心业务线:
- 人员安全: 某人参与不了应急时
应急方案常见的错误
- 没有关注核心事件:
即对企业最有价值的节点可能的问题没有制定方案, 而是围绕一些边边角角做计划;
如同那个"核电站的自行车棚"的笑话; - 忽略了最容易出现的问题或最不容易出现的问题
- 方案陈旧: 使用的还是原始技术或步骤,耗时耗力, 没能持续优化;
- 太简单: 没有给出具体操作步骤
- 太复杂: 没有实际可操作性;
- 项目太多: 几百页,事无大小都有记录;光翻目录都找半个小时;
- 缺少实操: 长期不操作就容易手生, 关键时候就手哆嗦, 更容易误操作。
附录: 可靠的架构设计时关注的内容
- 单点问题: 单服务多节点, 多机房, 多异地数据中心;
- 服务降级: 在资源不足的情况能保核心业务运行
- 自愈能力: 简单点就是服务故障重启脚本, 或者是 k8s 的新副本拉起方式
- 重试: 对请求需要校验, 如果不成功需要重试;对节点健康检查,异常重启和上报;
- 隔离: 对异常的请求发起方进行隔离, 对异常的服务节点进行隔离
- 无状态设计: 是指多数服务无状态化, 从而方便快速重启和扩容, 而有状态的应用使用更可靠的存储。
- 超时: 尽早确认当前请求能否继续, 然后进入重试或限流或熔断逻辑中去;
- 限流: 对恶意流量或资源不足时的请求限流
- 异步: 例如业务繁忙而注册失败, 就可以先告知用户已经登记, 后续内部完成注册后再邮件和短信告知;
剥离非核心业务线对主要业务的影响。 - 服务解耦: 拆分核心服务和辅助应用
- 监控: 可靠的监控措施
- 避免供应商锁定: 核心数据还是要自主可控
- 脑裂: 只要有多个节点, 就需要考虑这个问题
- 数据可靠性: 备份, 备份校验, 恢复测试, 异地多介质存储, 数据组件性能要求;
例如某在线事务数据, 如果需要几天才能做到恢复, 就等于无效备份; - 可回退: 对任何变更都要有回退措施;
例如改错了数据库字段名, 是再改回来, 还是使用备份文件恢复, 又或者干脆将错就错等等,行动之前需要有个后手准备。 - 一致性: 多节点操作同一份数据时, 或者一份数据存储在了多个节点时需要考虑。