导读:在互联网公司中,业务迭代快,零碎变更频繁,初期都是刀耕火种。但随着零碎复杂度一直减少,零碎稳定性问题会凸显进去,当稳定性问题成为业务倒退的掣肘的时候,从新推倒重来所须要的代价可想而知,因而咱们的零碎架构须要继续优化和演进一直晋升稳定性,既要解决事不宜迟,又要防患未然。本文联合具体实际,对系统高可用建设的办法进行思考和总结。
全文 7986 字,预计浏览工夫 19 分钟。
一、背景介绍
百度商业托管:是百度为了实现营销新生态的建设,以高效连贯和投放优化为指标,为商业客户提供一站式的的经营阵地,连贯服务和消费者,是百度从流量经营到用户经营的重要转变。代表的产品有基木鱼、度小店等建站和电商平台。
随着托管页的业务一直倒退,零碎的规模和业务复杂度一直减少,零碎的可用性面临微小挑战,本文从可用性建设的办法到实际,深入分析稳定性建设的思路,从标准、监控、冗余、降级、预案等多方面实现零碎的高可用。
「可用性指标定义:」对于零碎而言,最现实的状况是零碎能提供 24 小时不间断的提供服务、但因为软件系统的复杂度高,尤其在分布式系统环境中常常会因为零碎 BUG、软硬件异样、容量有余等导致系统无奈提供 100% 的可用性,因而通常采纳 N 个 9 来评估零碎可用性,此指标也作为一些根底服务的 SLA 的规范。
二、可用性整体建设思路
零碎的高可用建设是一件宏大的工程、须要从不同维度去综合思考,整体建设思路能够围绕系统故障产生的工夫、范畴、频率,处理速度等方面来综合思考。
2.1 故障发现早
从故障的产生工夫来看,在用户或客户反馈问题之前,研发人员可能第一工夫发现问题是十分重要的,每一次故障产生之后咱们都会深刻思考一个问题,能不能更早的发现问题, 咱们有哪些罕用的伎俩和办法,上面就逐个介绍下。
2.1.1 故障发现早 - 规范化:
- 「日志规范化」规范化的核心思想是通过肯定束缚来保障整体零碎可能协调对立, 托管外部的服务是基于对立的微服务框架构建,但因为各个系统和模块的日志千差万别,在开发、测试和运维阶段带来较高的老本。日志标准次要是针对开发过程中要害业务信息的记录,高效的定位问题;在 QA 测试阶段进行问题排查;在数据统计分析提供无效领导手册。
- 「全局通用标准」:
- 全局上下文采纳对立的 MDC 实现,用中括号和空格宰割。
- 所有的 logger 均需设置 addtivity=false,禁止反复打印。
- msg 信息须要扼要、易懂。
- 相干日志禁止反复打印到 console.log 中。
- 打印日志应用 slf4j 门面。
「日志分级」:
- 「TRACE」调试详细信息,线上禁止开启。
- 「DEBUG」开发调试日志,线上禁止开启。
- 「WARN」正告日志 日志罕用来示意零碎模块产生问题,但并不影响零碎运行。
- 「INFO」信息记录 日志级别次要用于记录零碎运行状态等关联信息。
- 「ERROR」错误信息输入 此信息输入后,主体系统核心模块失常工作,须要修复能力失常工作。
「日志文件」
![图片](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/75533b7134ee435baa9b050a677035b1~tplv-k3u1fbpfcp-zoom-1.image)
- 「logPattern」
<property name="ENCODER_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.fff} [%thread] [%X{reqid}] [%X{ip}] [%X{baiduid}] [%X{cuid}] %-5level %logger{5}: %msg%n"/>
- 「要害日志的格局要求」此处波及的细则标准较多,不一一列举,次要波及到贯通日志的外围上下文,须要蕴含起源 ip, 申请门路, 状态码, 耗时等。
- 「报警规范化」报警规范化次要针对谬误日志的报警监控,做到报警的分级监控、定义了分级监控的监控项目名称的定义。针对不同级别的报警,采纳不同的采集工作和监控策略,并定义配套的跟进流程。
- 通用服务的性能监控报警。
- 强依赖的性能监控报警。
- 服务异样状态码监控报警。
- 第三方服务耗时监控报警。
- 「值班规范化」针对值班同学的通报、止损、定位、解决等外围标准和流程,保障线上的问题可能第一工夫解决和解决。
2.1.2 故障发现早 - 系统监控
系统监控次要是从问题感知到问题定位的全面能力的建设。后面提到的日志规范化整改是实现自动化问题感知的前提,当系统日志标准实现之后,咱们就能够通过一些自动化的形式来建设对立的监控。在问题感知层面次要蕴含业务指标、业务性能、零碎稳定性、数据的正确性、时效性等。
- 「问题感知:」业务指标是指零碎关注的外围业务指标,次要是通过实时数据采集的形式可能发现业务指标的变动,可能实时监控到零碎问题对业务的影响范畴。
业务性能是指针对外围的业务性能分场景的自动化测试和监控能力。
零碎稳定性会从多个维度去掂量。会从网关入口来掂量可用性、会从模块本身来看可用性、以及从依赖的第三方的稳定性来掂量零碎的稳定性。
数据一致性校验实质上是一种离线或近线的对账场景,对于分布式的微服务来说,绝大部分都是采纳弥补来实现最终一致性,因而数据的对账就显得尤为重要。 - 「问题定位:」问题定位次要是联合一些外围业务场景,建设一些异样指标的报警和监控,其中包含流量异样、平响异样、pvlost 等。在数据正确性和时效性下面来看,包含数据延时、数据不统一等。
2.1.3 故障发现早 - 容量评估
容量评估是提前发现零碎容量问题的无效伎俩,尤其是当有一些特定的业务场景的时候,须要工程师或者架构师进行零碎的容量评估来判断零碎是否须要扩容等操作,在这里须要咱们提前做很多筹备,常见的容量评估的形式有动态剖析和动静评估两种伎俩。
动态剖析是指通过剖析现有零碎的依赖拓扑,联合在以后流量的状况下,通过实践计算出零碎是否接受的最大流量的负载能力和零碎瓶颈。动态剖析只能提供一种预估的后果,不肯定主观和精确。动静评估是指针对线上的服务进行模仿压测,通过零碎的理论状况来评估容量状况,此种形式绝对主观精确,但线上的全链路压测会有肯定危险,而且容易对业务数据带来净化。因而理论在做容量评估的时候能够采纳动态剖析 + 动静评估两者联合的形式来进行。
- 「动静评估相干注意事项:」
- 尽量模仿线上实在的流量(流量回放)来进行线上压测,因为不同的分支逻辑可能带来的零碎负载不同,例如如果针对某一个雷同申请和参数进行压测,极可能命中 cache, 则会导致压测后果不相信。
- 动静评估之前须要通过动态剖析排查可能对业务带来的影响,须要减少相干的开关防止对用户带来烦扰,例如: 针对下单行为给用户或者商家发短信等。
- 动静评估可能会对线上零碎带来影响,因而要在流量低峰期进行,并且可能做到疾速启停。
- 动静评估须要业务零碎配合做数据打标和清理,防止脏数据对线上业务的影响。
2.2 故障范畴小
从故障的范畴来看,放大故障范畴的罕用办法和外围伎俩次要就是隔离,隔离强调的是将微服务架构体系中非核心服务导致的故障隔离进来,缩小非核心因素对业务外围的稳定性影响,隔离工作做好之后只须要思考外围服务的稳定性。艰深点讲鸡蛋不能放在同一个篮子里。具体有存储的隔离、服务的隔离、以及权限的隔离。
2.2.1 故障范畴小 - 存储隔离
零碎建设初期,为了晋升研发效率和节俭资源,很多业务都是共用存储的。随着业务的倒退,常常会呈现以下问题
- A 业务的慢 sql 导致整个集群变慢。影响了 B、C、D 业务。
- B 业务的大表的增加字段,导致主从延时,影响了 A、C、D 业务。
- C 业务线下离线统计分析导致从库 CPU100%,影响了 A、B、D 业务。
解决如下问题的次要办法就是物理集群拆分,防止业务共用底层存储相互影响, 晋升零碎整体稳定性。托管页零碎有建站和电商两大业务,因为共享 MYSQL 集群导致相互影响的线上 case 呈现的频率较高,个别依照业务域去迁徙物理集群,次要的拆分办法和步骤见下图:
其中新集群的容量评估、资源申请、以及切换过程中的双写同步都是十分重要的流程和步骤,双写后业务要及时校验数据的准确性。对于其余 redis 等其余的存储隔离的思路和办法与上述统一。
2.2.2 故障范畴小 - 服务隔离
- 「服务隔离」服务隔离一种形式是从业务视角去看的,此处波及到微服务的拆分的准则,个别办法和准则如下:
- 将容易变动的,频繁变更的局部隔离进去服务。
- 将高并发等级高的利用与低等级的利用隔离进去。
- 依照组织架构划分将服务进行拆分和隔离(康威定律 | 垂直拆分)。
- 积淀底层通用的根底信息和服务,保障通用性(程度拆分)。
另外一种隔离的形式是从冗余的视角去看的,从高可用的角度须要保障咱们的服务保障多机房多地区的冗余,保障在某个机房或者某个地区呈现故障时候,是否及时切换和止损。冗余解决的是外围服务面对各种环境变动时的稳定性应答,比方服务故障、交换机故障、网络故障、机房故障等,通过各种档次的冗余和流量调度机制,保障业务面对各种硬件和环境变动时依然能够通过冗余切换提供稳固的服务。
此处的冗余更多的是指接入层和服务的冗余,对于无状态的服务冗余是很容易实现的,然而对于有状态的根底组件和存储服务做多地区冗余老本是很高的,能够分场景去实现,例如对数据一致性要求不高的查问场景,能够采纳存储的多地区部署,然而对一致性要求很高的,须要思考 set 化来实现,具体可参考阿里的三地五核心架构。
- 「老旧服务清理」因为零碎一直变更和迭代,一直会有一些技术我的项目对现有的零碎进行重构或者重写,对于多个版本的接口或者零碎并存的状况在互联网公司并不常见。尤其是对一些底层的根底服务,此处须要程序员或者架构师有高度的敏感度和责任心,对于一些技术的尾巴要及时清理,来保证系统的高可用。
- 对于根底服务的提供方,波及到老旧版本的降级,须要及时推动上游零碎进行降级。
- 对于依赖一些无人保护的老旧服务,须要从新梳理服务依赖拓扑,进行优化代替。
- 对于依赖的根底组件、须要及时进行评估和更新上线,尤其波及到一些平安问题,性能问题等。
2.2.3 故障范畴小 - 权限隔离
系统故障大多数都是因为变更导致的,在变更管控上重要的一点就是要做到权限隔离,服务公布和上线的权限隔离,此处须要依靠于容器化治理平台的能力,然而团队外部须要及时清理相干权限。防止不相干人员误操作导致线上危险。
- 线上数据库的读写权限隔离,IP 受权的管控。
- 线上服务的公布和部署权限隔离,分级公布的审核人员名单管控。
- 代码库的权限隔离,保障 CR 的品质。
- 对于服务的入口层以及管理权限的隔离。
2.3 故障频率低
提到故障频率不得不提及另外一个概念,叫做 MTBF(均匀故障距离)
生效工夫是指上一次设施恢复正常状态(图中的 up time)起,到设施此次生效那一刻(图中的 down time)之间距离的工夫。能够将 MTBF 用如下的数学式表白:
咱们面临的是各种简单的网络环境,故障频率是掂量咱们零碎自我爱护能力的重要指标,接下来介绍下常见的办法和实际。
2.3.1 故障频率低 - 服务限流
每个零碎都有本人的最大承受能力,即在达到某个临界点之前,零碎都能够失常提供服务。为了保证系统在面临大量刹时流量的同时依然能够对外提供服务,咱们就须要采取流控。尤其是针对一些底层根底服务或者被较多利用依赖的业务服务。限流算法常见的有记数法 (固定窗口和滑动窗口) 令牌桶和漏桶算法。
- 「常见限流算法」
-
令牌桶算法: 在令牌桶算法中,存在一个桶,用来寄存固定数量的令牌。算法中存在一种机制,以肯定的速率往桶中放令牌。每次申请调用须要先获取令牌,只有拿到令牌,才有机会继续执行,否则抉择抉择期待可用的令牌、或者间接回绝。
-
漏桶算法: 漏桶算法这个名字就很形象,算法外部有一个容器,相似生存用到的漏斗,当申请进来时,相当于水倒入漏斗,而后从下端小口缓缓匀速的流出。不论下面流量多大,上面流出的速度始终保持不变。
- 「限流形式」:从托管页零碎来看,次要是两大类服务的限流,一种是间接面向用户的 web 服务或者 api, 这种通常状况下都会有网关层,例如百度有本人的 BFE 平台,能够很不便实现限流规定的配置。另一种是 RPC 服务,这种须要本人来实现限流,目前比拟风行的限流形式是 RateLimiter – resilience4j(基于令牌桶实现),可能跟 Springboot 很好的集成,具体实现和应用办法可参考 https://resilience4j.readme.i…
在配置和实现限流时须要留神以下几点:
- 限流的难点是如何评估正当的阈值,通常要联合线上的理论状况,和动静压测后果来精确评估。
- 因为咱们的服务会提供多个 API, 须要针对服务进行全局的限流配置以及外围重要 API 的限流配置,优先级是全局 > 部分。
- 为保障限流操作的及时性,零碎须要反对动静批改配置。
2.3.2 故障频率低 - 降级熔断
分布式系统的熔断就像家用电路的保险丝一样,当零碎超过承载的阈值时,会主动熔断,起到零碎爱护的作用。尤其在微服务倒退迅猛的明天,服务依赖的拓扑越来越简单,架构师都很难画进去所有的服务依赖拓扑,当呈现某一个服务不可用然而没有相应的熔断措施的话,极可能呈现雪崩,这种灾难性的故障须要咱们通过正当的熔断和降级来保障的。
- 「强弱依赖梳理」
要做好熔断降级的前提是要梳理好强弱依赖,此处的强弱依赖梳理次要从对业务的影响来评估,例如下单操作,对于商品的库存服务就是强依赖,因为要保证数据的一致性。此处不可降级。然而在商品详情页展现的价格依赖营销算价服务,此处能够定义成弱依赖,因为就算价格服务不可用,商品能够依照原价展现。降级一般来说对业务都有影响,咱们外围要做的是降级后预期是什么,会对哪些业务产生影响。 -
「框架抉择」熔断降级框架目前比拟罕用的是 https://resilience4j.readme.i…。这是一款轻量级的断路器框架(6w 行代码),应用简略。(Hystrix 进行更新,转入保护模式),同样比拟常见的是 Sentinel,网上比照文章较多,此处不再赘述。
与 Hystrix 雷同,Resilience4j 熔断器也存在三种状态,即敞开状态 (CLOSED)、半开启状态(HALF\_OPEN) 和开启状态 (OPEN), 但除此之外,Resilience4j 还有两个非凡的状态,不可用状态(DISABLED) 和强制开启状态(FORCED\_OPEN)
Resilience4j 应用 ring bit buffer 这种数据结构来存储被爱护办法的调用后果。一次胜利调用,存储 1,一次失败调用存储 0。ring bit buffer 是一个相似 bitset 的数据结构,其底层是一个 long 型的数组,仅需 16 个元素就能够存储 1024 次调用的后果。
2.3.3 故障频率低 - 超时设置
超时和重试设置的不合理同样会带来系统故障,托管零碎针对超时、容错、池化、等进行了全盘的梳理和整改。次要集中在如下方面
- 「正当的超时设置」
- RPC 依赖和 HTTP 依赖均应设置正当的超时工夫,可依据依赖服务线上 99 分位值,减少 30%-50% 的 buffer。
- 许多框架都有默认的超时工夫,须要酌情调整。例如 redis 连接池默认读写和连贯超时为 2000ms,okhttp 的连接池默认为 10s,hikari 连贯超时默认为 30s. 很多默认的超时连贯对于并发高的服务和利用都不太正当,须要联合业务场景综合思考。
- 「容错机制」
- 对于读操作能够抉择 failover 的容错策略,重试次数 <= 2 次。
- 对于写操作的重试须要酌情思考,要充分考虑上游服务是否能保障幂等性,为危险起见,对于上游无奈保障幂等性的状况能够抉择 failfast。
- 「池化设置」
线程池、连接池都是咱们在程序开发中常常会应用的形式,外围目标就是为了缩小频繁创立和销毁带来的零碎开销,晋升零碎的性能,然而不合理的池化配置同样会给零碎带来肯定的危险。
- 线程池不容许应用 Executors 去创立,而是通过 ThreadPoolExecutor 的形式。显示定义线程池外围参数。(阿里编码标准)。
- redis 和数据库连接池初始值须要思考集群规模 以及存储服务容许的最大连接数,不可配置过大,配置的不合理会呈现服务启动时就把存储服务打满的状况。
- 线程池和连接池须要设置有区分度的名称,以便于 monitor 和日志记录。
- 池化大小设置多少适合?要联合吞吐量战争响要求,倡议公式: 并发量(连接数、线程数)= 每秒申请数(QPS)* 解决工夫。也须要思考 CPU 核数,磁盘,内存等综合思考。倡议依据线上压测来理论评估。
2.4 故障解决快
故障解决要害是要疾速止损,很多程序员比拟爱钻牛角尖,非要定位出根本原因才去解决问题,但随着故障工夫的减少,对业务的影响会变得越来越大。因而每个程序员都须要有疾速止损的意识,第一工夫复原业务,故障深层次的起因待保留现场预先剖析和复盘解决。
- 「疾速扩缩容」
疾速扩缩容体现了服务和零碎的伸缩能力,这里要依赖于容器化的集群伸缩能力。因为历史问题,托管页零碎有一些是运行在物理机或者无人保护的老平台下面,对于突发流量的应答几乎大刀阔斧,因而 paas 化是亟待解决的事件,依靠于弱小的 paas 平台的疾速扩缩容的能力,可能做到疾速止损。 - 「惯例解决预案」
在平时多积攒惯例的预案是应答突发故障疾速解决的无效伎俩,故障疾速定位和止损绝对现实的形式是买通故障定位和预案,当呈现故障时,相干开发或者运维同学可能疾速判断出故障类型并及时执行预案,次要有攻打限流、机房切换、疾速扩容、惯例紧急 case 的解决流程等。
预案设计的一些教训 TIPS:
- 将历史呈现过的 case 进行复盘总结,分类归档到预案。
- 建设预案时尽量不便触发和执行。
- 上线或者变更引起的故障比拟常见,每次上线须要有相应的变更回滚的残缺计划。
- 对于流量和容量变动引起的故障,须要周期例行化的进行线上容量评估。
- 对于机房、网络、硬件等故障,要通过适当冗余和疾速的流量切换保障服务稳定性。
- 「数据备份」
当服务出问题咱们能够及时通过流量切换、重启、扩容解决,然而当数据出问题,例如删库,数据失落等问题,复原起来老本极高,因而平时咱们须要对外围数据进行备份,例如 MYSQL 集群的外围数据要做到天级备份,并且能够通过 binlog 实时回溯数据,个别须要业务方和 DBA 独特确认数据的备份以及疾速复原机制。
三、总结和思考
零碎稳定性是一个十分大的课题,本文联合商业托管页的稳定性建设的实际,从宏观层面分类论述了保障系统稳定性的常见办法。从故障发现、到故障影响,从故障频率到故障解决多个方面进行了总结。稳定性建设须要综合思考业务、研发、测试、运维多方面的因素,须要各个方面协同配合。因为笔者能力无限,编写仓促,文中难免会有不精确或未能详尽的中央,请读者多多斧正。
———- END ———-
百度 Geek 说
百度官网技术公众号上线啦!
技术干货 · 行业资讯 · 线上沙龙 · 行业大会
招聘信息 · 内推信息 · 技术书籍 · 百度周边
欢送各位同学关注