Files
Knowledge/4 方案/高可用/可用性和高可用概念.md

415 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
### [高可用性](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7&zhida_source=entity):从理论到实践,打造坚如磐石的系统
### 什么是可用性?
可用性,简单来说就是系统能正常干活的时间比例。它是一个可以量化的指标,计算公式是这样的:
**可用性 = (总运行时间 - 宕机时间) / 总运行时间**
行业内通常用“几个9”来衡量可用性水平:
- **99.9%(三个9)**:年宕机时间不超过8.76小时。
- **99.99%(四个9)**:年宕机时间不超过52.6分钟。
- **99.999%(五个9)**:年宕机时间不超过5.26分钟。
对于大多数系统来说,**99.99%(四个9)**是起步要求,只有达到这个水平,才能勉强算得上高可用。
### 什么是高可用?
高可用(High Availability,HA),说白了就是系统能**无中断地提供服务**的能力。它是系统设计的核心准则之一,目标是尽量减少宕机时间,确保服务在任何情况下都能稳定运行。
但要注意,**100%可用是不可能的**!无论你设计得多完美,硬件故障、网络波动、人为失误等问题总是难以避免。所以,高可用的核心思想是:**尽最大可能提高系统的可用性,让服务在绝大多数情况下都能对外正常提供服务**。
### 高可用的本质
用一句话概括高可用的本质:**高可用就是让系统在任何情况下都能“扛得住、稳得住、恢复得快”**。
- **扛得住**:面对突发流量、硬件故障等异常情况,系统能稳定运行。
- **稳得住**:在日常运行中,系统能长期保持稳定,不出现性能波动。
- **恢复得快**:即使出现问题,系统也能快速恢复,将影响降到最低。
### 为什么高可用如此重要?
在当今的互联网时代,用户对系统的稳定性要求越来越高。一次小小的宕机,可能导致:
- 用户体验下降,用户流失。
- 业务损失,尤其是电商、金融等对实时性要求高的行业。
- 品牌信誉受损,甚至引发公关危机。
> 还记得2025年1月16日下午,支付宝出现了“**政府补贴**”错误提示,导致部分用户在支付时享受了不应有的折扣。支付宝官方确认了此事,并表示不会向用户追款。造成了严重的资金损失。
所以,高可用不仅是一个技术问题,更是一个业务问题。只有把高可用做到位,才能让系统真正成为业务的坚实后盾。
> _**最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,**_[[7701页的BAT大佬写的刷题笔记,让我offer拿到手软]](https://link.zhihu.com/?target=https%3A//cxykk.com/%23zhuanlan)
## 高可用系统设计思想
高可用系统的设计,需要有一套比较科学的工程管理套路,要从产品、开发、运维、基建等全方位去考量和设计,高可用系统的设计思想包括但不限于:
![](https://pica.zhimg.com/v2-77f30fc61558891fa151c6e6d3e1a44c_1440w.jpg)
> **做好研发规范**,系统都是研发人员设计和编码写出来的,因此首先要对研发层面有一个规范和标准
> **做好容量规划和评估**,主要是让开发人员对系统要抗住的量级有一个基本认知,方便进行合理的架 构设计和演进。
> **做好服务层面的高可用**,主要是[负载均衡](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1&zhida_source=entity)、[弹性扩缩容](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E5%BC%B9%E6%80%A7%E6%89%A9%E7%BC%A9%E5%AE%B9&zhida_source=entity)、异步解耦、故障容错、过载保护等。
> **做好存储层面的高可用**,主要是冗余备份(热备、冷备)、失效转移(确认,转移,恢复)等。
> **做好运维层面的高可用**,主要是发布测试、[监控告警](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E7%9B%91%E6%8E%A7%E5%91%8A%E8%AD%A6&zhida_source=entity)、容灾、[故障演练](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E6%95%85%E9%9A%9C%E6%BC%94%E7%BB%83&zhida_source=entity)等。
> **做好产品层面的高可用**,主要是兜底策略。
> **做好应急预案**,主要是在出现问题后怎么快速恢复,不至于让我们的异常事态扩大。
## 二、研发规范层面
## 方案设计和编码规范
研发规范层面这个是大家容易忽视的一个点,但是,我们所有的设计,都是研发人员来完成的,包括从设计文档到编码到发布上线,因此,研发层面也是有一个规范流程和套路,来让我们更好的去研发和维护一个高可用的系统:
### 设计阶段
> 方案设计后一定要进行评审,在我们团队中,新项目一定要评审,重构项目一定要评审,大 的系统优化或者升级一定要评审,其他的一般研发工作量超过一周的建议要评审的。
### 编码阶段
> 不要随便打日志 要接入远程日志 要能够分布式链路追踪
> 代码编写完需要有一定的单测来保证代码的健壮性,同时也能保障我们后续调整逻辑或者优化的时候可以保证代码的稳定 包括增量覆盖率、全量覆盖率,具体的覆盖率要达到多少可以根据团队内部的实际情况来定,在我们团队,定的规则是 50% 的覆盖率。
> 工程的 layout 目录结构规范,团队内部保持统一,尽量简洁 遵循团队内部的代码规范,一般公司都有对应语言的规范,如果没有则参考官方的规范,代 码规范可以大大减少 bug 并且提高可用性。
> 执行代码规范 单测覆盖率 日志规范
> 发布上线阶段,参考下面运维部署层面那一章节的灰度发布和接口测试相关说明
## 容量规划和评估
### 容量评估
**容量评估**,是指我们需要评估好,我们这个系统,是为了应对一个什么体量的业务,这个业务请求量的平均值、高峰的峰值大概都在一个什么级别。
如果是新系统,那么就需要根据产品和运营同学对业务有一个大体的预估,然后开发同学根据产品给的数据再进行详细的评估。如果是老系统,那么就可以根据历史数据来评估。评估的时候,要从一个整体角度来看全局的量级,然后再细化到每个子业务模块要承载的量级。
例如常用的二八法则估算
![](https://pic2.zhimg.com/v2-04c00b6635ec36beafdd417f1a846339_1440w.jpg)
### 容量规划
**容量规划**,简单说就是我们在设计系统的时候,就要大概知道系统能承受多少流量,是十万、百万,还是更多。
不同的流量量级,系统架构的设计差别可大了,尤其是到了千万、亿级别的流量,架构设计就得考虑的更多。
不过,别误会,并不是说一开始就得做个能承受几亿请求的系统——没必要。你得根据自己业务的真实流量来做,合适的才是最好的。
容量规划还得考虑我们系统上下游的各个模块,比如你依赖的存储、三方服务等,它们各自需要多少资源,这些数据得能量化出来。
最重要的是,容量规划更多是靠经验,团队的经验。比如,得了解你用的**日志系统的性能**、**Redis的性能**、**RPC接口的性能**、**服务化框架的性能**等,通过这些组件的性能数据,综合评估系统整体能承受多少流量。
做完容量评估和规划后,下一步就是进行性能压测,最好是全链路压测。性能压测的目的是为了验证容量规划到底准不准。
比如,你规划的系统能抗千万级别的请求,实际上能不能真的承受得住?这就得靠性能压测来给出准确答案。
经验固然重要,但一定得有实际的数据来支撑,才能确保系统上线不会出问题。
性能压测时,要关注的指标其实很多,但最关键的两个:一个是**QPS(每秒请求量)**,另一个是**响应时间**。确保压测的结果符合你的预期才行。
至于怎么压测,最好是先分模块逐个压测,如果有条件,能做全链路压测更好。这样才能真正知道,系统在大流量压力下的表现如何。
**QPS 预估(漏斗型)**,其实就是从一个真实请求进来后,依次经过系统的各个层级和模块。每一层级的 QPS(每秒请求量)都会有不同的量级,通常来说,越往下走,QPS的量级会逐步减少,因为每通过一个层级,都有可能会过滤掉一些请求。
举个例子,就像用户从活动页进入,查看商品详情,再到下单的过程。最开始,所有用户进入活动页时,都会有请求进入系统;接着,有部分用户会去查询商品详情;然后,在查看商品详情的用户中,又只有一部分最终会下单。所以,你会看到从活动页到下单的这个过程,就像一个漏斗,层级越往下,流量就会越来越少。
![](https://pic1.zhimg.com/v2-3aa58811dd9656694b65baedc9928f68_1440w.jpg)
> _**最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,**_[[7701页的BAT大佬写的刷题笔记,让我offer拿到手软]](https://link.zhihu.com/?target=https%3A//cxykk.com/%23zhuanlan)
## 三、应用服务层面
## 无状态和负载均衡设计
为了让我们的系统保持高可用,通常会设计成**无状态**的应用服务。
> 这是什么意思呢?
就是我们可以把服务拆成多个实例来提高可用性。多个实例的流量分配,靠的就是负载均衡。
![](https://picx.zhimg.com/v2-80817cfc1258b6afb33c2b11241888b9_1440w.jpg)
无状态服务加上负载均衡,不仅能提升系统的并发能力,还能让系统在面对故障时更加稳健。
如果我们用的是微服务框架来开发的,那大概率框架内部自带了服务发现和负载均衡的功能。
也就是说,有一整套流程:服务注册、服务发现、负载均衡、健康检查、自动剔除。当某个服务实例出了问题,系统会自动把它剔除,新增的服务实例会自动加入,继续提供服务。这样一来,整个系统就更加灵活、可靠。
但如果我们没有用微服务框架开发,而是用传统架构,那么就得依赖一些代理服务来做负载均衡了,比如**LVS** 或者 **Nginx**。这些工具会帮我们处理流量分配,保证系统的可用性和稳定性。
## 弹性扩缩容设计
弹性扩缩容是应对突发流量的绝招,也是保证我们服务能一直在线、可用的必要手段。它的核心是**无状态的应用服务**,因为服务是无状态的,所以我们可以根据实际的流量来随时进行扩容或缩容。流量猛增时,扩容来处理更多请求;流量下降时,缩容,节省资源,减少浪费。
那我们到底怎么实现弹性扩缩容呢?现在是云原生时代,很多公司都采用容器化部署,像是**K8s**(Kubernetes)这样的平台。对于这种架构,弹性扩缩容就变得特别简单。只需要在K8s中配置好弹性扩缩容的条件,比如设置CPU使用率的阈值,K8s就能自动监控、自动调整,保证系统始终处于最佳状态。
举个例子,假设你有一个电商系统在双十一期间,流量激增。K8s可以根据CPU使用情况,自动增加容器实例来应对大量并发请求。如果在流量低谷时,K8s又会根据预设条件自动减少实例数,节约资源。
![](https://pic4.zhimg.com/v2-8e15b791a80699d2cddd0869a84b2a97_1440w.jpg)
但如果你没有用容器化,而是传统的物理机部署,那要实现弹性扩缩容就没那么简单了。你得有强大的内部基础设施支持,通过运营平台实时监控服务的CPU使用率或者QPS。一旦这些指标超过某个阈值,系统就会自动触发扩缩容操作。虽然实现起来没有K8s那么自动化,但原理是一样的:根据需求动态调整资源。
无论是容器化还是物理机,弹性扩缩容的目标都是一样的:让服务在流量波动中保持高可用,同时也避免资源浪费。
## [消息队列](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97&zhida_source=entity):异步解耦 + 削峰的秘密武器
想让系统扛得住高并发、稳如老狗?架构设计上就得学会“切蛋糕”——分层分模块。
但光分开了还不够,还得让模块之间“各干各的”,这时候就要靠消息队列(比如**Kafka**、**RocketMQ**)的异步解耦和削峰能力了。这两招能让你的系统从“一碰就碎”变成“韧性十足”。
![](https://pic2.zhimg.com/v2-9fe3f31193d4c99a39dfaea10eb6a6e7_1440w.jpg)
---
### 异步解耦
想象一下,A模块要调B模块,如果每次都要等B模块回复才能继续干活。但用了消息队列,A模块只需要把消息往队列里一扔(比如订单数据写到Kafka),就可以转身继续处理其他请求。B模块(比如支付系统)什么时候有空了,再去队列里慢慢取消息处理。
![](https://picx.zhimg.com/v2-ed82a323a2265b060d185068595ed953_1440w.jpg)
**例如**: 电商平台用**RocketMQ**处理订单。用户下单后,订单服务直接把消息丢进队列,不用等库存服务、支付服务挨个处理完才给用户反馈。哪怕库存服务突然宕机了,订单数据还在队列里存着,恢复后继续扣库存,用户完全感知不到。
![](https://pic4.zhimg.com/v2-b21065b4c191e01a9cf991e186de3427_1440w.jpg)
---
### 消息队列选型小贴士
- **Kafka**:吞吐量怪兽,适合日志处理、大数据场景(比如用户行为分析)
- **RocketMQ**:业务消息专家,事务消息、顺序消息一把梭(比如电商订单、金融交易)
- **RabbitMQ**:轻量灵活,适合中小规模业务(比如通知提醒)
## 故障和容错设计
高可用设计的核心不是追求100%不出错(这不可能),而是出错时怎么让用户觉得“问题不大”,甚至无感知。因此业界来评价可用性 SLA都是说多少个 9,比如 4 个 9(99.99%)的可用性。
### 过载保护设计(限流、熔断、降级)
---
### 第一板斧:限流
想象一下双十一零点,每秒百万请求冲进来,服务器眼看要挂。这时候就得学地铁站——限流!比如:
- **接口限流**:只允许每秒处理1万次下单请求,超出的直接返回“稍后再试”
- **用户限流**:单个用户1秒内最多点5次“抢购”,防止机器人刷单
- **服务限流**:支付服务最多承受5万QPS,超了就让部分用户走备用通道
例如前端时间,华哥演唱会开票时,10万人同时开抢,系统只放前1万请求进核心流程,后面的直接展示“排队中”。虽然有人骂,但至少系统没崩,比全员404强多了。
---
### 第二板斧:熔断
当你发现依赖的服务开始抽风(比如数据库响应从50ms变成5秒),千万别头铁继续调用!这时候要像家里电路跳闸一样,直接切断连接。比如:
1. 监控到下游服务错误率超过50% → 触发熔断
2. 后续请求直接走本地缓存/默认值
3. 每隔30秒试探性放一个请求,确认下游恢复后关闭熔断
---
### 第三板斧:降级
系统快扛不住时,得学会“丢车保帅”。比如:
- 关闭商品详情页的“猜你喜欢”推荐
- 停用积分兑换功能
- 订单页隐藏非必填字段
**真实案例**:微博社交App在明星官宣离婚时,立刻降级非核心功能:
1. 关闭动态页的“热门评论”计算
2. 停用消息页的未读红点推送
3. 保留核心的发布/浏览功能 虽然用户体验打了折扣,但至少没崩盘上热搜。
---
### 容错设计心法
1. **Fail Fast原则**:就像发现煤气泄漏,第一时间关总闸而不是找漏气点
2. **分层防御**:前端限流 → 网关熔断 → 服务降级,层层设防
3. **监控告警**:给每个熔断降级动作加告警(比如企业微信/钉钉通知)
系统出问题不可怕,可怕的是雪崩时没有应急预案。设计系统时,不妨多想一步——如果这个服务挂了,用户能不能至少完成核心操作?
**四、存储层面的高可用**
现在的互联网应用大部分都是无状态的,所以保证应用服务的高可用其实挺简单的。但是要保证数据存储的高可用就复杂多了,因为数据是有状态的。
> **那我们到底该怎么保证数据存储的高可用呢?**
数据存储高可用的本质就是通过“冗余”来确保数据的可靠性,简单来说,就是把数据复制到多个地方。
这样不仅能避免数据丢失,还能提升并发能力。因为数据本身是有状态的,所以数据存储的高可用比应用服务的高可用复杂多了。
**主要体现在以下几个方面:**
- 数据该怎么复制?各个节点分别负责什么?
- 复制过程中的延迟咋办?
- 复制中断了,怎么办?
其实解决这些问题的常见方法就是两种:[集群存储](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E9%9B%86%E7%BE%A4%E5%AD%98%E5%82%A8&zhida_source=entity)和[分布式存储](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E5%88%86%E5%B8%83%E5%BC%8F%E5%AD%98%E5%82%A8&zhida_source=entity)。
业界大多数方案其实都是围绕这两种方式进行的,或者对它们做了一些衍生和扩展。
**集群存储(集中式存储)**
所谓集群,其实就是一群逻辑上在做同一个任务的机器。它们可以在同一个机房,也可以分布在不同的机房。集群存储就是把这些机器上的存储资源合在一起,呈现给外部一个统一的存储系统。
集群存储其实适用于那些业务存储量规模不算特别大的场景。对于一般的业务数据存储,集群方式就足够用了。比如现在大家用的Redis、MySQL等,都是采用集群存储方式。对于中大型互联网公司来说,默认就是这么做的。
集群存储的工作方式是:1主多备或者1主多从。数据写入通过主机,读取一般由从机来承担。集群存储要解决的关键问题就是:
- 主机怎么把数据复制到备机(从机)上?
- 这里的数据同步就是主机负责的,把数据复制到备机(从机)。不过得注意,主备之间的数据同步有可能会有延迟。
- 备机(从机)怎么监控主机状态?
- 如果主机故障,备机(从机)怎么接管主机的角色,变成新的主机?
简而言之,在主从架构中,一旦主机挂掉,备机(从机)就可以直接接管,继续提供服务。这也是集群存储的基本思想。
> _**最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,**_[[7701页的BAT大佬写的刷题笔记,让我offer拿到手软]](https://link.zhihu.com/?target=https%3A//cxykk.com/%23zhuanlan)
**1. 主备复制**
主备复制是最常见、最简单的存储高可用方案了。几乎所有的存储系统都能提供这种功能,比如 MySQL、Redis、MongoDB 这些大家熟悉的工具,都是这么做的。
在主备架构里,所谓“备机”主要是用来做备份的,并不会参与实际的读写操作。如果想要让备机变成主机,那就得手动干预了。所以,这种架构一般用于后台管理系统,或者一些不需要高实时性的场景。
![](https://picx.zhimg.com/v2-b6a08a8fd5fd753d9c66614e9c9e9471_1440w.jpg)
**2. 主从复制**
主从复制和主备复制听起来差不多,但其实是两种不同的设计思路。简单来说,“从”就是听命的意思,“备”是备份的意思。主从复制的“从机”是要真的干活的,它会处理数据的“读”操作,而“主机”负责“写”和“读”操作。
所以,主从架构里,主机负责数据的读写,而从机只负责数据的读取。写操作不会由从机来承担。
![](https://pic4.zhimg.com/v2-34300eb69504ea9e104949d8dec1c803_1440w.jpg)
**3. 主从切换**
主备复制和主从复制这两种方案,虽然挺常见,但都有个问题:主机故障后,系统就不能继续写数据了。如果主机坏了,还得人工去指定一个新的主机。
为了解决这两个问题,就出现了主从切换(有时候叫主备切换)。这就是在原有架构上加了一点“智能”,也就是当主机异常时,系统会自动检测并把备机或者从机切换成主机。这个方案在实际应用中非常常见,因为它能保证主机挂掉后,从机能自动顶上,保证业务不出问题。
**4. 主主复制**
主主复制就是两台机器都当“主机”,它们互相将数据复制给对方。客户端可以随便选择一台机器进行读写操作,没啥限制。但主主复制的一个大挑战是:两台机器之间的数据必须能双向同步。所以,这种架构的实现要求相对较高,需要更强的数据一致性保证。
![](https://pic3.zhimg.com/v2-47555d2b60e7d88e937a66958bcef972_1440w.jpg)
**分布式存储**
集群和分布式听起来有点像,但其实不一样。集群是把几台服务器集中在一起,做同一个业务,而分布式就是把不同的业务分散到不同的地方,形成一个整体。在分布式系统里,每一个节点都有可能是一个小集群。
分布式存储就是通过网络,把企业每台机器的磁盘空间给用上,将这些零散的存储资源整合成一个虚拟的存储设备。数据就像散落在各个角落一样,分布在不同的地方。分布式存储的每台服务器都能处理读写请求,不像集群存储那样只有一个主机负责写数据。可是,虽然没有主机这种角色,还是得有一个“指挥官”来负责数据分配算法,这个“指挥官”可以是独立的服务器,也可以是集群中选举出来的某台机器。
这种分布式存储特别适合海量数据存储,尤其是那些数据量特别大的业务场景。常见的分布式存储系统有Hadoop(HDFS)、HBase、Elasticsearch等。
**五、产品层面的高可用**
在产品层面上,高可用架构主要是指我们的“兜底”策略,也就是当系统出现问题时,能保证用户体验不至于崩溃。降级和限流策略更多是从后端架构的角度来考虑,而产品层的兜底策略就是从用户的角度,确保即使出现问题,用户也能感知到的是友好的提醒,而不是系统崩塌。
举个例子,假如我们的页面获取不到数据或者不能访问时,我们该如何友好地通知用户呢?像“稍后重试”这种提示就很有用。
再比如,当真实页面无法访问时,产品应该提供一个默认页面。如果后端获取不到真实数据,直接给用户渲染默认的页面,而不是让他们一直等。
再比如,服务器需要停机维护时,产品应该给出一个停机页面,所有用户看到的就是这个页面,不会再请求后端服务,避免系统负担过重。
还有一种情况,比如抽奖活动,万一后台数据出问题,给一个默认的兜底商品,至少能让用户看到一个结果,而不是一片空白。
> _**最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,**_[[7701页的BAT大佬写的刷题笔记,让我offer拿到手软]](https://link.zhihu.com/?target=https%3A//cxykk.com/%23zhuanlan)
**六、运维部署层面**
**开发阶段——灰度发布、接口测试设计**
说到灰度发布和接口测试,很多人都会觉得这两者是个常见的流程,尤其是在大公司里,基本都会涉及到这些环节。灰度发布是啥?就是服务上线的时候,不是一次性把所有实例都发布出去,而是先发布1-2个实例,然后慢慢放量,看看效果如何。如果没问题,再继续发布,直到所有实例都上线。
接口测试呢,就是每次服务发布前,要先跑一遍接口测试用例,确保接口没有问题,避免上线后出现麻烦。接口测试能让我们在发布前知道,接口是不是能正常工作。
这两项工作,尤其在大公司中,基本都由专门的DevOps团队来负责,确保每次发布都安全、稳定。
**开发阶段——监控告警设计**
监控告警的设计,听起来可能有点复杂,但在大公司里这通常不是问题。公司会有一群专门的人来搭建这个基础设施,配套的系统也会有,开发同学只需要配置好、使用好就行了。
但如果你在的公司没有这样的基础设施,那就得自己动手了,得接入一些监控系统来保证服务的稳定性。
**监控系统**
说到监控系统,现在有几个开源的解决方案特别流行,可以帮助我们快速搭建自己的监控体系:
> **ELK (Elasticsearch、Logstash、Kibana)** :日志收集和分析。 由于微服务化后,日志分布在各个机器上,不能都存在本地,这时候ELK就是不二选择。它能将日志收集起来,做集中管理和分析。
>
> **Prometheus**:监控数据收集。 它可以帮助我们监控各种系统指标,甚至自定义一些业务指标。
>
> **OpenTracing**:分布式全链路追踪。 这意味着,你可以追踪一个请求从开始到结束的整个流程,查看涉及到的每一个服务,精准找到问题。
>
> **OpenTelemetry**:可观测系统标准。 这是个新标准,能结合追踪数据、指标数据和日志数据来观察分布式系统的状态,简化了很多监控的工作。
这些监控工具都是用来帮我们搭建一个全方位的监控体系。监控的指标会包括以下几个层面:
> **基础设施层监控**:主要是监控网络、交换机、路由器等底层设备。如果这些设备出现问题,那我们的业务服务肯定也会受影响。常见的监控指标包括网络流量(进和出)、丢包情况、连接数等。
>
> **操作系统层监控**:包括物理机和容器的监控,主要监控CPU使用率、内存占用、磁盘IO和网络带宽等。
>
> **应用服务层监控**:这个层面就比较复杂了,涉及到很多指标,比如主调请求量、被调请求量、接口成功率、失败率、响应时间(包括P99、P95等)等。
>
> **业务自定义监控**:每个业务服务都有自己独特的监控指标。例如电商系统里可能需要监控浏览量、支付成功率、发货情况等。
>
> **端用户层监控**:这一层关注的是用户实际体验,比如用户访问页面时的耗时、数据获取的耗时等。这个通常是前端或者客户端需要进行统计的。
这些监控系统和指标的设计,最终目的是为了让我们在服务出现问题时能尽早发现,并且能迅速定位到问题所在,确保系统始终稳定运行。
**告警系统**
虽然我们通过监控系统已经把所有可能出现的问题都统计清楚了,但如果没有一个实时告警系统,问题出现时我们就无法及时反应,系统出问题后,可能就会错失最佳处理时机,最终导致大规模的故障或者灾难。所以,除了监控,还得有一个能即时报警的系统。
告警系统的设计要做到:
- **实时性**:要做到秒级监控,问题一出现就能发现。
- **全面性**:要覆盖公司所有的系统和业务,确保没有遗漏。
- **实用性**:告警要分级,轻微问题和严重问题要有不同的预警级别,监控人员可以根据严重程度做出准确的决策。
- **多样性**:告警方式要多样,除了常规的短信和邮件,还要有可视化界面,方便监控人员随时发现问题。
**开发阶段——安全性、防攻击设计**
防刷、防黑产、防黑客攻击这些防御措施,就是为了保护我们的系统不被外部恶意攻击。通常有几种常见策略:
- 在公司级的流量入口上做好统一的防刷和鉴权能力,比如统一接入层的封装。
- 在业务服务内部,要做好细致的业务鉴权,比如登录状态的管理,或者加入更多业务层的鉴权逻辑,确保每一步都安全。
**部署阶段——多机房部署(容灾设计)**
我们通常会设计高可用策略,确保一个机房内的服务稳定运行,但万一整个机房出问题怎么办?比如地震、火灾,或者光纤被挖断了,那可就麻烦了。这时候就需要有容灾设计,常见的做法就是多机房部署。
- **服务的多机房部署**:这一点相对容易,因为服务大多数是无状态的,只要名字服务能发现不同机房的服务,调用就能顺利进行。但要注意,名字服务或者负载均衡服务需要有就近访问的能力。
- **存储的多机房部署**:这就比较难搞了,因为存储是有状态的,部署到不同机房就意味着要考虑存储的同步和复制问题,这要求要更高。
如果条件有限,至少保证多机房部署业务服务就好,毕竟存储的多机房部署相对复杂。
**线上运行阶段——故障演练([混沌实验](https://zhida.zhihu.com/search?content_id=716292842&content_type=Answer&match_order=1&q=%E6%B7%B7%E6%B2%8C%E5%AE%9E%E9%AA%8C&zhida_source=entity))**
故障演练在大公司里是常见手段,尤其是像Netflix这种大公司,早在2010年就推出了混沌实验工具——Chaos Monkey。这个“混沌实验”对提升复杂分布式系统的健壮性和可靠性非常有效。
![](https://pic1.zhimg.com/v2-d4bcc0528a3f1b12e6c5b45f31c0772e_1440w.jpg)
故障演练其实挺简单,就是模拟一些极端场景,比如机房断电、网络断开、服务挂掉,看看我们的系统能不能正常运行。这其实是个大工程,得按照混沌实验的框架来规划和设计,但一旦实施,效果非常好。不过,这需要大量人力来做基础设施的开发和支撑。
**线上运行阶段——接口拨测设计**
接口拨测,说白了就像是巡检。服务上线后,我们需要定时(比如每隔5秒)调用后端的各种接口,检查它们是否正常。如果发现接口异常,就立即报警。
接口拨测通常会有一些配套的工具来支持实现这个功能。如果没有这样的工具,那我们就只能自己开发一个接口拨测(巡检)服务,定期检查那些重要的接口,确保它们随时正常。
**七、异常应急层面**
虽然前面做了各种保障措施,但毕竟线上服务总会遇到一些不可预见的异常。服务出现问题、无法正常提供服务时,我们还得有一套应急预案,把损失降到最低。
应急预案的核心就是:在业务系统出现问题时,我们需要有明确的恢复步骤,知道第一时间该怎么应对。我们要事先制定好相关的规则和流程,一旦异常情况发生,就能按流程执行,避免手忙脚乱,导致问题扩大。
没有一个完备的应急预案,你的业务在遇到重大故障时,基本上就会瘫痪,完全失去控制。所以,做好预案,时刻保持应急准备,才是线上服务的“救命稻草”。