当前位置: 首页 > 科技观察

互联网架构的“高可用”到底是什么

时间:2023-03-12 22:59:45 科技观察

1、什么是高可用?高可用性(HA)是分布式系统架构设计中必须考虑的因素之一。提供的服务时间。假设系统已经能够提供服务,我们说系统的可用性是100%。如果系统每运行100个时间单位,就会有1个时间单位不能提供服务,我们说系统的可用性是99%。很多公司的高可用目标是4个9,也就是99.99%,也就是说系统每年宕机时间是8.76小时。百度的搜索首页是业界公认的高可用保障优秀的系统。人们甚至通过能否访问www.baidu.com来判断“网络连通性”。百度的高可用服务让人留下“网络畅通”,百度能访问”,“百度打不开,应该是网络连不上”的印象,这其实是对百度HA***的褒奖。2.如何保证系统的高可用我们都知道单点是系统高可用的大敌,单点往往是系统高可用的风险和大敌,我们在系统设计的过程中要尽量避免单点。从方法论上来说,高可用保证的原则是“集群”,或者说“冗余”:只有一个单点,一旦失效就会影响服务;如果有冗余备份,还有其他备份可以发生故障接管。为了保证系统的高可用,架构设计的核心原则是:冗余。光有冗余是不够的。每次发生故障,都需要人工干预来恢复系统,这不可避免增加系统的无用实践。因此,系统的高可用性往往是通过“自动故障转移”来实现的。接下来我们看看在典型的互联网架构下,如何通过冗余+故障自动切换来保证系统的高可用。3.常见的互联网分层架构常见的互联网分布式架构如上,分为:(1)客户端层:典型的调用者是浏览器浏览器或手机应用APP(2)反向代理层:系统入口,反向代理(3)站点应用层:实现核心应用逻辑,返回html或json(4)服务层:如果实现了服务,就会有这一层(5)数据-缓存层:缓存加速访问存储(6)数据-数据库层:整个系统的高可用性是通过各层的冗余和自动故障转移来实现的。四、分层高可用架构实践【客户端层->反向代理层】高可用【客户端层】到【反向代理层】高可用,是通过反向代理层的冗余来实现的。以nginx为例:nginx有两台,一台提供在线服务,一台冗余保证高可用。常见的做法是keepalived存活检测,同一个虚拟IP提供服务。自动故障转移:当nginx宕机时,keepalived可以检测到,会自动进行故障转移,自动将流量迁移到shadow-nginx。由于使用的是同一个虚拟IP,这个切换过程对调用者来说是透明的。【反向代理层->站点层】的高可用【反向代理层】到【站点层】的高可用是通过站点层的冗余实现的。假设反向代理层是nginx,可以在nginx.conf中配置多个web后端,nginx可以检测多个后端的生存能力。自动故障转移:当网络服务器宕机时,nginx可以检测到它,并自动进行故障转移,并自动将流量迁移到其他网络服务器。整个过程由nginx自动完成,对调用者透明。【站点层->服务层】高可用【站点层】到【服务层】高可用是通过服务层的冗余实现的。“服务连接池”会与下游服务建立多个连接,每个请求都会“随机”选择连接访问下游服务。自动故障转移:当服务宕机时,service-connection-pool可以检测到,自动故障转移,自动将流量迁移到其他服务。整个过程由连接池自动完成,对调用者是透明的(所以RPC-client中的服务连接池是一个非常重要的基础组件)。【服务层>缓存层】高可用【服务层】到【缓存层】高可用是通过缓存数据的冗余来实现的。缓存层的数据冗余有几种方式:第一种是利用客户端的封装,服务端对缓存进行双读或双写。缓存层也可以通过支持主从同步缓存集群来解决缓存层的高可用问题。以redis为例,redis天然支持主从同步,redis官方有sentinel哨兵机制检测redis的生存能力。自动故障转移:Sentinel可以检测到redismaster何时宕机,并会通知调用者访问新的redis。整个过程由sentinel和rediscluster配合完成,对调用者是透明的。说完缓存的高可用,这里还要多说一点。业务不一定对缓存有“高可用”的需求。缓存的更多使用场景是用来“加速数据访问”:把一些数据放在缓存中这里,如果缓存宕机或者缓存不活跃,可以去后端数据库重新获取数据.对于这种允许“cachemiss”的业务场景,对于缓存架构的建议是:将kv缓存封装成一个服务集群,上游设置一个agent(agent可以使用集群冗余来保证高可用),agent的backend根据缓存访问serverkey级别分为若干个instance,每个instance的访问不具备高可用。缓存实例挂掉掩码:当一个水平拆分的实例挂掉时,代理层直接返回缓存未命中。此时缓存挂起对调用者也是透明的。key水平切分的实例减少,不建议做re-hash,容易导致缓存数据不一致。【服务层>数据库层】大部分互联网技术的高可用,数据库层采用“主从同步,读写分离”的架构,所以数据库层的高可用分为“读数据库高可用”和“写库高可用性”类别。【服务层>数据库层“读取”】【服务层】的高可用到【数据库读取】的高可用是通过读库的冗余来实现的。由于读库冗余,一般来说,从库至少有2个。“数据库连接池”会与阅览库建立多个连接,每个请求都会路由到这些阅览库。自动故障转移:当读库宕机时,db-connection-pool可以检测到,会自动进行故障转移,自动将流量迁移到其他读库。整个过程由连接池自动完成,调用者是透明的(所以DAO中的数据库连接池是一个非常重要的基础组件)。【服务层>数据库层“写”】【服务层】的高可用到【数据库写】的高可用,是通过写库的冗余来实现的。以mysql为例,可以设置两台mysql双主同步,一台提供在线服务,一台冗余保证高可用。常见的做法是keepalived存活检测,同一个虚拟IP提供服务。自动故障转移:当写库宕机时,keepalived可以检测到,会自动进行故障转移,自动将流量迁移到shadow-db-master。由于使用同一个虚拟IP,这个切换过程对调用方没有影响是透明的。五、小结高可用性HA(HighAvailability)是分布式系统架构设计中必须考虑的因素之一。通常是指通过设计减少系统不能提供服务的时间。从方法上讲,高可用性是通过冗余+自动故障转移来实现的。整个互联网分层系统架构的高可用是通过每一层的冗余+自动故障转移来全面实现的,具体来说:(1)从【客户端层】到【反向代理层】的高可用,是通过反向的冗余来实现的代理层。常见的做法是keepalived+虚拟IP自动failover。(2)从【反向代理层】到【站点层】的高可用是通过站点层的冗余来实现的。常见的做法是nginx和web-server之间的生存性检测和自动故障转移(3)通过服务层的冗余实现从[站点层]到[服务层]的高可用性。通常的做法是通过service-connection-pool来确保自动故障转移(4)通过缓存数据的冗余来实现从[服务层]到[缓存层]的高可用性。常见的做法是双读双写缓存客户端,或者使用缓存集群Master-slave数据同步和sentinelkeep-alive和自动failover;更多的业务场景,对缓存没有高可用要求,可以使用缓存服务来屏蔽调用者的底层复杂性(5)【服务层】到【数据库】的高可用,通过冗余实现读库。常见的做法是通过db-connection-pool来保证自动故障转移。(6)[服务层]到[数据库“写”]的高可用是通过写库的冗余来实现的。做法是keepalived+虚拟IP自动切换,前段时间受@谢工邀请,首发GitChat平台《究竟啥才是互联网架构“高可用”》,12月1日周四晚8点30分,讨论本文话题是在微信群里进行的,以下是主持人@赫阳整理的问题精华,记录了我和各位读者关于高可用架构的问答花絮,问答中的所有文章都可以直接点击跳转。问题:缓存层的rehash过程中肯定有脏数据。Consistenthashing实际上只能降低rehash的代价,并不能消除脏数据。有什么办法可以避免这种脏数据吗?答:在《究竟啥才是互联网架构“高可用”》一文中提到,如果没有高可用需求,一个缓存挂了,不适合做rehash会产生脏数据。这时候缓存未命中可以直接返回挂起缓存的key。问:从你后面的回答来看,这其实是一种“降级”。这样以后是不是直接把请求发给后端数据库呢?还是直接丢弃请求?如果出现雪崩效应,miss请求会越来越多,如果所有miss都开库,则库会立即挂掉。老师可以就这个话题展开吗?答:命中数据库时,缓存簇的副本数与数据库能抵抗多少读有关。理论上,如果1-2个副本失效,数据库可以承受。58方法,有备份的mc集群,如果挂了可以补上,不建议rehash。高可用的代价是冗余,冗余有成本和复杂性,一致性问题缓存我文章中缓存服务的集群是一个更好的解决方案(有备份集群)。问题:从服务层到数据层,如果写是通过冗余写来保证高可用,那么按照CAP,一致性可能得不到保证。如何在基本一致的情况下保证数据层的高可用?答:根据CAP理论,一般来说,一致性和可用性都是选的,其实最终一致性就够了。为了确保高可用性,必须牺牲一些一致性。以主从数据库为例,在主从数据同步时间窗口内,可以从从数据库读取旧数据。问题:你在时间管理和自我实现方面有什么特别的经历吗?您也可以发布以前的文章。我想了解更多。答:时间管理个人体会,工作中关闭朋友圈、QQ、各种群、邮件提醒等是影响效率的主要矛盾。自我实现?仍在努力编码和写文章以实现自我。在百度的一段工作经历给我留下了深刻的印象。身边比我优秀的同事都比我努力,我也一直在努力向他们学习。Q:其实我说的***问题是,如果不允许cachemiss,怎么尽可能少的脏数据做rehash?答:如果不允许cachemiss,就做cachehighavailability,cachehighavailability也和文中一样,有几种实现方式。缓存一致性,看?,这篇文章对你有帮助。问:我见过很多大型网站的架构演变,从一体机到面向服务的系统。既然前人开路了,我们的后人已经知道了最终的架构,是否可以一步到位这个面向服务的系统呢?很多人给出的理由是,从一开始就搭建这样的架构成本太高,必须先发展业务再管理。但是在我看来,很多东西是可以自动化的,几行命令就可以搭建起一整套基础设施,比如jenkins自动化集成+部署,大数据分析平台kafka+spark+zookeeper+Hadoop等等,rest就是在上面写业务应用,根据具体的业务情况调整参数。正因如此,我不太认同“高成本”的观点。请问,是否可以一步到最后的面向服务的系统,跳到中间的演进过程?为什么?可能有人会说,合适的架构才是好的架构。如果你现在的业务量还达不到,就没必要淘宝,58架构。我想说,如果建一个和他们类似的架构成本很低,那我为什么不建呢?简单的说,问题就是:能不能跳过大部分公司的架构演化过程,直接搭建最终的架构?答:有很多建筑设计如果你回到10年前的58,在同一个城市创业,估计结构还是和以前一样,和现在不一样。不建议跳过演进,架构是支撑业务的,不同阶段业务需求不同,架构不同,架构演进最好。建筑师之路公众号这篇文章《好架构是进化来的》或许对您有所帮助。Q:服务层读到数据库的高可用和服务层写到数据库的高可用需要注意哪些问题?想请沉老师给我一些感悟,看看是否给我同样的思考?答:《DB主从一致性架构优化4种方法》这篇文章有详细的介绍。Q:服务挂掉后rpcclient转server时,如何避免集群中的shockinggroupeffect?答:我的理解是没有惊群。假设有5个服务10个连接,现在一个服务挂了,变成4个服务8个连接。只要负载分配策略是随机的,流量仍然是随机的。Q:58到家在灰度发布和A/B方面的实施计划是怎样的?答:灰度发布是APP的灰度发布吗?还是类似于推荐算法的AB测试,多个算法同时运行?还是服务升级的顺畅度?第一种,常用的方法有渠道包、越狱包。对于第二种,需要有推荐算法分流平台的支持。第三个,web/service升级,在间隔重启期间,必须断流,保证所有用户不受影响。以webserver的顺利重启为例。一般从nginx层断tomcat流量一天。本次升级站点重启,nginx流量再次切回。它是如此光滑。提问:58也建了一个分中心,是中心内部调用和中心调用rpc形式,还有哪些场景用到消息调用,那些用到rpc服务的,你怎么看,还有例子?:58没有做多机房架构,本文《从IDC到云端架构迁移之路》讲了在同城机房迁移过程中一段时间??多机房的一些经验。原则是:如果不能完全不跨机房,可以减少跨机房,“相连”的架构,具体可以看文章。问题:您如何看待内存计算?现在的redis功能太底层,内存计算必须同时读取缓存信息。是不是可以在内存计算中做缓存,或者说缓存只是缓存,只做这一件事情?答:我不确定问题是关于什么的。mc支持kv,redis支持一些数据结构,还有master-slave,也支持登陆(不推荐)。我觉得功能太强大了。缓存就是缓存。适当的,应该由业务服务层自己来计算。Q:缓存分库后重新分区后的数据迁移有什么好的解决方案吗?),可能有帮助。缓存的扩展可以加倍。如果像我文章中的proxy+cache集群架构,其实扩容对调用者是透明的。Q:您的文章介绍了各个层次和阶段的高可用方案和设计原则。我关心的是用这些方案和原理设计出来的东西怎么去测试,以及设计和测试方案的思路和原理?答:不是特别明白这个“怎么测”在高可用上线之前是完全可以测的。例如,nigix层是高可用的。做keepalived+vip后,kill一个,测试服务是否可以继续。问:我想知道在云环境下如何做数据库高可用?没有VIP怎么办?它们提供的负载在使用中受到限制。比如mha不能做vip漂移。答:云端有两种方式,以阿里云为例。一种是ECS+自建DB+购买阿里云的VIP类服务,一种是直接使用rds高可用数据。印象中阿里云只对主库提供了rds高可用,从库好像没有高可用(需要数据库连接池实现)。58到家目前用的是阿里云,两种方式都有用。Q:采用微服务方式后,如何保证某个服务的版本更新后,对其他服务的影响尽可能小?答:跟服务的粒度有关。粒度越粗,耦合度越高,一个地方的升级会影响其他服务。.粒径越细,影响越小。这篇文章《微服务架构多“微”才合适》可能对您有所帮助。Q:架构的高可用是架构师和运维人员的事吗?开发者有什么可以做和需要注意的吗?答:我的理解是,不适合专职架构师负责架构设计,开发人员负责编码。架构本身是由技术人员设计的,rd、dba、op等,高可用是大家的事情,只是说可能有稍微有点经验的R&D(暂且称architect)来牵头梳理和设计。Q:老师,有什么好的方法可以在分布式系统中生成全局唯一ID吗?答:请阅读这篇文章《细聊分布式ID生成方法》。Q:从高级工程师到架构师需要提升哪些能力?对于提高系统设计能力,您有什么建议?A:这个问题有点笼统,这篇文章可能会有帮助(非本人原创)《互联网架构师必备技能》。问题:如果我之前的5台机器可以支持10w个用户,突然一台机器断电,然后把流量分给另外4台机器,那么这4台机器都会超过最大值,挂掉,就是一个令人震惊的群体效应,是否实施拒绝策略,具体如何实施?答:1)如果流量能承受,直配是没问题的。2)如果流量超过剩余的系统负载,则需要降级。最简单的方法是丢弃请求,只为部分用户提供服务,而不是在负载超载时直接挂掉,这样就无法为所有用户提供服务=>服务本身需要做自我保护。Q:类似于支付宝的750积分,类似的操作可以配置策略控制不同的人。根据不同的策略,他们联系的服务类型是不同的。这种具体实现如何实现呢?答:这样的灰度是指不同的用户界面、功能、算法不同,需要系统支持(交换机、流量策略、导流、不同的实现方式)。《58同城推荐系统架构设计与实现》本文中的“分发”部分应该有所帮助。问题:请问web集群中的数据同步问题。如果涉及到跨机房,有什么最好的方法可以避免跨区域机房的数据同步和复制可靠性,或者其他更好的方法来避免跨机房的数据交互?是吗?答:这是多机房的问题,在多机房架构一文中会详细说明。多机房架构常见的解决方案有以下三种:1)冷备(强烈不推荐);2)伪多机房(跨机房读取主库数据);3)多机房多活(入口流量分段+双机房数据同步)。Q:58的服务如何降级?A:更不用说组合业务的降级(跳过非关键路径),以及通用系统级别的降级。一种常见的做法是设置队列并丢弃超出负载的请求。这个解决方案不好。当一个上游请求变大时,所有上游队列和丢弃的请求都会受到影响。58服务治理一般是这样做的:限制不同调用者的流量;如果有一个调用者超过限制,则只丢弃该调用者的请求,不影响其他调用者。最后希望文章思路清晰,希望大家对高可用的概念和实践有一个系统的认识,谢谢。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】