高可用并非一套总体解决方案,而是由诸多环节组成,一环扣一环,鬼知道为了这些串联起来的环节,我得出多少张牌去应对,才能最终组成一个整个系统的高可用落地方案。前端
在定义什么是高可用,能够先定义下什么是不可用,一个网站的内容最终呈如今用户面前须要通过若干个环节,而其中只要任何一个环节出现了故障,均可能致使网站页面不可访问,这个也就是网站不可用的状况。java
参考维基百科,看看维基怎么定义高可用mysql
系统无中断地执行其功能的能力,表明系统的可用性程度,是进行系统设计时的准则之一。nginx
这个难点或是重点在于“无中断”,要作到 7 x 24 小时无中断无异常的服务提供。redis
一套对外提供服务的系统是须要硬件,软件相结合,可是咱们的软件会有bug,硬件会慢慢老化,网络老是不稳定,软件会愈来愈复杂和庞大,除了硬件软件在本质上没法作到“无中断”,外部环境也可能致使服务的中断,例如断电,地震,火灾,光纤被挖掘机挖断,这些影响的程度可能更大。算法
在业界有一套比较出名的评定网站可用性的指标,经常使用N个9来量化可用性,能够直接映射到网站正常运行时间的百分比上sql
描述 | N个9 | 可用性级别 | 年度停机时间 |
---|---|---|---|
基本可用 | 2个9 | 99% | 87.6小时 |
较高可用 | 3个9 | 99% | 8.8小时 |
具有故障自动恢复能力可用 | 4个9 | 99.99% | 53分钟 |
极高可用 | 5个9 | 99.999% | 5分钟 |
以前就任的一家互联网公司也是按照这个指标去界定可用性,不过在执行的过程当中也碰到了一些问题,例如,有一些服务的升级或数据迁移明明能够在深夜停机或停服务进行,然而考虑到之后的报告要显示出咱们的系统达到了多少个9的高可用,而放弃停服务这种简单的解决方案,例如停机2个小时,就永远也达不到4个9。然而在一些高并发的场合,例如在秒杀或拼团,虽然服务中止了几分钟,可是这个对整个公司业务的影响多是很是重大的,分分钟丢失的订单多是一个庞大的数量。因此N个9来量化可用性其实也得考虑业务的状况。docker
高可用是一个比较复杂的命题,基本上在全部的处理中都会涉及到高可用,全部在设计高可用方案也涉及到了方方面面,这中间将会出现的细节是多种多样的,因此咱们须要对这样一个微服务高可用方案进行一个顶层的设计,围绕服务高可用,先检查下咱们手里有多少张牌。数据库
每个访问可能都会有多个服务组成而成,每一个机器每一个服务均可能出现问题,因此第一个考虑到的就是每一个服务必须不止一份能够是多份,所谓多份一致的服务就是服务的冗余,这里说的服务泛指了机器的服务,容器的服务,还有微服务自己的服务。后端
在机器服务层面须要考虑,各个机器间的冗余是否有在物理空间进行隔离冗余 ,例如是否全部机器是否有分别部署在不一样机房,若是在同一个机房是否作到了部署在不一样的机柜,若是是docker容器是否部署在分别不一样的物理机上面。 采起的策略其实也仍是根据服务的业务而定,因此须要对服务进行分级评分,从而采起不一样的策略,不一样的策略安全程度不一样,伴随这的成本也是不一样,安全等级更高的服务可能还不止考虑不一样机房,还须要把各个机房所处的区域考虑进行,例如,两个机房不要处在同一个地震带上等等
服务的冗余会要求咱们能够随时对服务进行扩容或者缩容,有可能咱们会从2台机器变成3台机器,想要对服务进行随时随地的扩缩容,就要求咱们的服务是一个无状态化,所谓无状态化就是每一个服务的服务内容和数据都是一致的。
例如,从咱们的微服务架构来看,咱们总共分水平划分了好几个层,正由于咱们每一个层都作到了无状态,因此在这个水平架构的扩张是很是的简单。
假设,咱们须要对网关进行扩容,咱们只须要增长服务就能够,而不须要去考虑网关是否存储了一个额外的数据。
网关不保存任何的session数据,不提供会形成一致性的服务,将不一致的数据进行几种存储,借助更加擅长数据同步的中间件来完成。
这个是目前主流的方案,服务自己尽量提供逻辑的服务,将数据的一致性保证集中式处理,这样就能够把“状态”抽取出来,让网关保持一个“无状态”
这里仅仅是举了网关的例子,在微服务只基本全部的服务,都应该按照这种思路去作,若是服务中有状态,就应该把状态抽取出来,让更加擅长处理数据的组件来处理,而不是在微服务中去兼容有数据的状态。
以前上面说的服务冗余,能够简单的理解为计算的高可用,计算高可用只须要作到无状态既可简单的扩容缩容,可是对于须要存储数据的系统来讲,数据自己就是有状态。
跟存储与计算相比,有一个本质的差异:
将数据从一台机器搬到另外一台机器,须要通过线路进行传输
网络是不稳定的,特别是跨机房的网络,ping的延时多是几十几百毫秒,虽然毫秒对于人来讲几乎没有什么感受,可是对于高可用系统来讲,就是本质上的不一样,这意味着整个系统在某个时间点上,数据确定是不一致的。按照“数据+逻辑=业务”的公式来看,数据不一致,逻辑一致,最后的业务表现也会不一致。举个例子
不管是正常状况下的传输延时,仍是异常状况下的传输中断,都会致使系统的数据在某个时间点出现不一致,而数据的不一致又会致使业务出现问题,可是若是数据不作冗余,系统的高可用没法保证
因此,存储高可用的难点不在于怎么备份数据,而在于如何减小或者规避数据不一致对业务形成的影响
分布式领域中有一个著名的CAP定理,从理论上论证了存储高可用的复杂度,也就是说,存储高可用不可能同时知足“一致性,可用性,分区容错性”,最多只能知足2个,其中分区容错在分布式中是必须的,就意味着,咱们在作架构设计时必须结合业务对一致性和可用性进行取舍。
存储高可用方案的本质是将数据复制到多个存储设备中,经过数据冗余的方式来现实高可用,其复杂度主要呈如今数据复制的延迟或中断致使数据的不一致性,咱们在设计存储架构时必须考虑到一下几个方面:
主从复制是最多见的也是最简单的存储高可用方案,例如Mysql,redis等等
其架构的优势就是简单,主机复制写和读,而从机只负责读操做,在读并发高时候可用扩张从库的数量减低压力,主机出现故障,读操做也能够保证读业务的顺利进行。
缺点就是客户端必须感知主从关系的存在,将不一样的操做发送给不一样的机器进行处理,并且主从复制中,从机器负责读操做,可能由于主从复制时延大,出现数据不一致性的问题。
刚说了主从切换存在两个问题: 1.主机故障写操做没法进行 2.须要人工将其中一台从机器升级为主机
为了解决这个两个问题,咱们能够设计一套主从自动切换的方案,其中设计到对主机的状态检测,切换的决策,数据丢失和冲突的问题。
1.主机状态检测
须要多个检查点来检测主机的机器是否正常,进程是否存在,是否出现超时,是否写操做不可执行,读操做是否不可执行,将其进行汇总,交给切换决策
2.切换决策
肯定切换的时间决策,什么状况下从机就应该升级为主机,是进程不存在,是写操做不可这行,连续检测多少失败次就进行切换。应该选择哪个从节点升级为主节点,通常来讲或应该选同步步骤最大的从节点来进行升级。切换是自动切换仍是半自动切换,经过报警方式,让人工作一次确认。
3.数据丢失和数据冲突 数据写到主机,尚未复制到从机主机就挂了,这个时候怎么处理,这个也得考虑业务的方式,是要确保CP或AP
还要考虑一个数据冲突的问题,这个问题在mysql中大部分是由自增主键引发,就算不考虑自增主键会引发数据冲突的问题,其实自增主键还要引发不少的问题,这里不细说,避免使用自增主键。
上述的数据冗余能够经过数据的复制来进行解决,可是数据的扩张须要经过数据的分片来进行解决(若是在关系型数据库是分表)。
HDFS , mongoDB 的sharding 模式也基本是基于这种分片的模式去实现,咱们在设计分片主要考虑到的点是:
在每一次调用,时间越长存在超时的风险就越大,逻辑越复杂执行的步骤越多存在失败的风险也就越大,若是在业务容许的状况下,用户调用只给用户必需要的结果,而不是须要同步的结果能够放在另外的地方异步去操做,这就减小了超时的风险也把复杂业务进行拆分减低复杂度。
固然异步化的好处是很是多,例如削封解耦等等,这里只是从可用的角度出发。
异步化大体有这三种的实现方式:
什么是柔性化,想象一个场景,咱们的系统会给每一个下单的用户增长他们下单金额对应的积分,当一个用户下单完毕后,咱们给他增长积分的服务出现了问题,这个时候,咱们是要取消掉这个订单仍是先让订单经过,积分的问题经过从新或者报警来处理呢?
所谓的柔性化,就是在咱们业务中容许的状况下,作不到给予用户百分百可用的经过降级的手段给到用户尽量多的服务,而不是非得每次都交出去要么100分或0分的答卷。
怎么去作柔性化,更多实际上是对业务的理解和判断,柔性化更可能是一种思惟,须要对业务场景有深刻的了解。
在电商订单的场景中,下单,扣库存,支付是必定要执行的步骤,若是失败则订单失败,可是加积分,发货,售后是能够柔性处理,就算出错也能够经过日志报警让人工去检查,不必为加积分损失整个下单的可用性
兜底是可能咱们常常谈论的是一种降级的方案,方案是用来实施,可是这里兜底可能更可能是一种思想,更多的是一种预案,每一个操做均可以犯错,咱们也能够接受犯错,可是每一个犯错咱们都必须有一个兜底的预案,这个兜底的预案其实就是咱们的容错或者说最大程度避免更大伤害的措施,实际上也是一个不断降级的过程。
举个例子:
例如咱们首页请求的用户个性化推荐商品的接口,发现推荐系统出错,咱们不该该去扩大(直接把异常抛给用户)或保持调用接口的错误,而是应该兼容调用接口的错误,作到更加柔性化,这时候能够选择获取以前没有失败接口的缓存数据,若是没有则能够获取通用商品不用个性化推荐,若是也没有能够读取一些静态文字进行展现。
因为咱们架构进行了分层,分红APP,网关,业务逻辑层,数据访问层等等,在组织结构也进行了划分,与之对应的是前端组,后端业务逻辑组,甚至有中台组等等。既然有代码和人员架构的划分层级,那么每一层都必须有这样的思想:包容下一层的错误,为上一层提供尽量无措的服务。
举个例子:
商品的美圆售价假设要用商品人民币售价/汇率,这个时候错误发生在低层的数据层,上一层若是直接进行除,确定就抛出 java.lang.ArithmeticException: / by zero,本着咱们对任何一层调用服务都不可信的原则,应该对其进行容错处理,不能让异常扩散,更要保证咱们这一层对上一次尽量的做出最大努力肯定的服务。
相信负载均衡这个话题基本已经深刻每一个作微服务开发或设计者的人心,负载均衡的实现有硬件和软件,硬件有F5,A10等机器,软件有LVS,nginx,HAProxy等等,负载均衡的算法有 random , RoundRobin , ConsistentHash等等。
nginx 根据给定好的负载均衡算法进行调度,当请求到tomcat1,nginx发现tomcat1出现链接错误(节点失效),nginx会根据必定的机制将tomcat1从调用的负载列表中清除,在下一次请求,nginx不会分配请求到有问题的tomcat1上面,会将请求转移到其余的tomcat之上。
nginx默认判断节点失效是以connect refuse和timeout为标准,在对某个节点进行fails累加,当fails大于max_fails时,该节点失效。
当某个节点失败的次数大于max_fails时,但不超过fail_timeout,nginx将不在对该节点进行探测,直到超过失效时间或者全部的节点都失效,nginx会对节点进行从新探测。
在使用ZK做为注册中心时,故障的发现是由Zk去进行发现,业务逻辑层经过watch的心跳机制将本身注册到zk上,网关对zk进行订阅就能够知道有多少能够调用的列表。当业务逻辑层在重启或者被关闭时就会跟zk断了心跳,zk会更新可调用列表。
使用zk做为负载均衡的协调器,最大的问题是zk对于服务是否可用是基于pingpong的方式,只要服务心跳存在,zk就认为服务是处在于可用状态,可是服务若是处在于假死的状态,zk是无从得知的。这个时候,业务逻辑服务是否真正可用只可以由网关知道。
为什么会牵出幂等设计的问题,主要是由于负载均衡的failover策略,就是对失败的服务会进行重试,通常来讲,若是是读操做的服务,重复执行也不会出问题,但想象一下,若是是一个建立订单减库存的操做,第一次调用也tomcat1超时,再从新调用了tomcat2,这个时候咱们都不能确认超时调用的tomcat1是否真的被调用,有可能根本就调用不成功,有可能已经调用成功可是由于某些缘由返回超时而已,因此,很大程度这个接口会被调用2次。若是咱们没有保证幂等性,就有可能一个订单致使了减小2次的库存。
所谓的幂等性,就是得保证在同一个业务中,一个接口被调用了屡次,其致使的结果都是同样的。
先来说讲微服务中限流/熔断的目的是什么,微服务后,系统分布式部署,系统之间经过rpc框架通讯,整个系统发生故障的几率随着系统规模的增加而增加,一个小的故障通过链路的传递放大,有可能会形成更大的故障。
限流跟高可用的关系是什么,假定咱们的系统最多只能承受500我的的并发访问,但整个时候忽然增长到1000我的进来,一会儿就把整个系统给压垮了,原本还有500我的能享受到咱们系统的服务,忽然间变成了全部人都没法获得服务,与其让1000人都不法获得服务,不如就让500我的获得服务,拒绝掉另外500我的。限流是对访问的隔离,是保证了部门系统承受范围内用户的可用性。
熔断跟高可用的关系是什么,上面说了微服务是一个错综复杂的调用链关系,假设 模块A 调用 模块B , 模块B 又调用了 模块C , 模块C 调用了 模块D,这个时候,模块D 出了问题出现严重的时延,这个时候,整个调用链就会被 模块D 给拖垮,A 等B,B等C,C等D,并且A B C D的资源被锁死得不到释放,若是流量大的话还容易引发雪崩。熔断,主动丢弃 模块D 的调用,并在功能上做出一些降级才能保证到咱们系统的健壮性。 熔断是对模块的隔离,是保证了最大功能的可用性。
服务模块与服务模块之间有着千丝万缕的关系,但服务模块在业务中各有权重,例如订单模块多是一家电商公司的重中之重,若是出问题将会直接影响整个公司的营收,而一个后台的查询服务模块可能也重要,但它的重要等级绝对是没有像订单这么重要。因此,在作服务治理时,必须明确各个服务模块的重要等级,这样才能更好的作好监控,分配好资源。这个在各个公司有各个公司的一个标准,例如在电商公司,肯定服务的级别可能会更加倾向对用用户请求数和营收相关的做为指标。
服务级别 | 服务模块 |
---|---|
一级服务 | 支付系统 订单服务 商品服务 用户服务 发布系统 ... |
二级服务 | 消息服务 权限系统 CRM系统 积分系统 BI系统 评论系统 ... |
三级服务 | 后台日志系统 |
可能真正的划分要比这个更为复杂,必须根据具体业务去定,这个能够从平时服务模块的访问量和流量去预估,每每更重要的模块也会提供更多的资源,因此不只要对技术架构了如指掌,还要对公司各类业务形态了然于心才能够。
服务分级不只仅在故障界定起到重要主要,并且决定了服务监控的力度,服务监控在高可用中起到了一个保障的做用,它不只能够保留服务奔溃的现场以等待往后复盘,更重要的是它能够起到一个先知,先行判断的角色,不少时候能够预先判断危险,防范于未然。
服务监控是微服务治理的一个重要环节,监控系统的完善程度直接影响到咱们微服务质量的好坏,咱们的微服务在线上运行的时候有没有一套完善的监控体系能去了解到它的健康状况,对整个系统的可靠性和稳定性是很是重要,可靠性和稳定性是高可用的一个前提保证。
服务的监控更可能是对于风险的预判,在出现不可用之间就提早的发现问题,若是系统获取监控报警系统能自我修复则能够将错误消灭在无形,若是系统发现报警没法自我修复则能够通知人员提前进行接入。
一个比较完善的微服务监控体系须要涉及到哪些层次,以下图,大体能够划分为五个层次的监控
例如网络,交换机,路由器等低层设备,这些设备的可靠性稳定性就直接影响到上层服务应用的稳定性,因此须要对网络的流量,丢包状况,错包状况,链接数等等这些基础设施的核心指标进行监控。
涵盖了物理机,虚拟机,操做系统这些都是属于系统级别监控的方面,对几个核心指标监控,如cpu使用率,内存占用率,磁盘IO和网络带宽状况
例如对url访问的性能,访问的调用数,访问的延迟,还有对服务提供性能进行监控,服务的错误率,对sql也须要进行监控,查看是否有慢sql,对与cache来讲,须要监控缓存的命中率和性能,每一个服务的响应时间和qps等等
比方说一个电商网站,须要关注它的用户登陆状况,注册状况,下单状况,支付状况,这些直接影响到实际触发的业务交易状况,这个监控能够提供给运营和公司高管他们需须要关注的数据,直接可能对公司战略产生影响。
用户经过浏览器,客户端打开练到到咱们的服务,那么在用户端用户的体验是怎么样,用户端的性能是怎么样,有没有产生错误,这些信息也是须要进行监控并记录下来,若是没有监控,有可能用户的由于某些缘由出错或者性能问题形成体验很是的差,而咱们并无感知,这里面包括了,监控用户端的使用性能,返回码,在哪些城市地区他们的使用状况是怎么样,还有运营商的状况,包括电信,联通用户的链接状况。咱们须要进一步去知道是否有哪些渠道哪些用户接入的时候存在着问题,包括咱们还须要知道客户端使用的操做系统浏览器的版本。
出了那么多张牌,出牌只是术,真正的道仍是得静下心来看看整个服务高可用的本质是什么,随着微服务架构的相互调用愈来愈复杂,环节只会愈来愈多,只有创建清晰的架构和层次才能理清楚每一个环节高可用的保障,保持简单。
从手段看高可用:主要使用的技术手段是服务和数据的冗余备份和失效转移,一组服务或一组数据都能在多节点上,之间相互备份,当一台机器宕机或出现问题的时候,能够从当前的服务切换到其余可用的服务,不影响系统的可用性,也不会致使数据丢失。
从架构看高可用:保持简单的架构,目前多数网站采用的是比较经典的分层架构,应用层,服务层,数据层。应用层是处理一些业务逻辑,服务层提供一些数据和业务紧密相关服务,数据层负责对数据进行读写,简单的架构可使应用层,服务层能够保持无状态化进行水平扩展,这个属于计算高可用,相比计算高可用,在数据层思考的高可用则属于数据高可用,数据高可用相比计算高可用须要考虑到数据的一致性问题会更加的复杂,这个时候CAP理论在里面会发挥关键的做用,到底是选择AP或CP,这个得根据业务去选择模型。
从硬件看高可用:首先得确认硬件老是可能坏的,网络老是不稳定的。解决它的方法也是一个服务器不够就来多几个,一个机柜不够就来几个,一个机房不够就来几个。
从软件看高可用:软件的开发不严谨,发布不规范也是致使各类不可用出现,经过控制软件开发过程质量监控,经过测试,预发布,灰度发布等手段也是减小不可用的措施。
从治理看高可用:一个系统在线上跑的好好的,但咱们也不能确保它在下一秒会不会出现不可用状态,将服务规范化,事前作好服务分割,作好服务监控,预判不可用的出现,在不可用出现以前发现问题,解决问题。
【注:文章部份内容参考 李云华《从0开始学架构》杨波老师《微服务》】