分享

高可用服务设计概述[1]

 xujin3 2017-12-16

1. 负载均衡与反向代理


当我们的应用单实例不能支撑用户请求时,就需要扩容,从一天服务器扩容到两台、几十台、几百台。然而用户访问时是通过如http://www.jd.com的方式访问,在请求时,浏览器首先会查询DNS服务器获取对应的IP,然后通过此IP访问对应的服务。


对于负载均衡需要关心的几个方面如下:


  • 上游服务器配置:使用upstream server配置上游服务器。

  • 负载均衡算法:配置多个上游服务器时的负载均衡机制。

  • 失败重试机制:配置当超时或上游服务器不存活时,是否需要重试其他上游服务器。

  • 服务器心跳检查:上游服务器的健康检查/心跳检查。


Nginx提供的负载均衡机制可以实现服务器的负载均衡、故障转移、失败重试、容错、健康检查等,当某些上游服务器出现问题时可以将请求转到其他上游服务器以保障高可用,并通过OpenResty实现更智能的负载均衡,如将热点与非热点流量分离、正常流量与爬虫流量分离等。Nginx负载均衡器本身也是一台反向代理服务器,将用户请求通过Ningx代理到内网中的某台上游服务器处理,反向代理服务器可以对响应结果进行缓存、压缩等处理以提升性能。


负载均衡算法


负载均衡算法用来解决用户请求到来时如何选择upstream server进行处理,默认采用的是round-robin(轮询),同时支持其他几种算法。


  • round-robin:轮询,默认负载均衡算法,即以轮询的方式将请求转发到上游服务器,通过配合weight配置可以实现基于权重的轮询。

  • ip-hash:根据客户IP进行负载均衡,即相同的IP将负载均衡到同一个upstream server。

  • hash key [consistent]:对某一个key进行哈希或者使用一致性哈希算法进行负载均衡。使用Hash算法那存在的问题是,当添加/删除一台服务器时,将导致很多key被重新负载均衡到不同的服务器(从而导致后端肯可能出现问题);因此,建议考虑使用一致性hash算法,这样当添加/删除一台服务器时,只有少数key将被重新负载均衡到不同的服务器。

  • 哈希算法:此处是根据请求uri进行负载均衡,可以使用Nginx变量,因此可以实现复杂的算法。


失败重试


当fail_timeout时间内失败了max_fails次请求,则认为该上游服务器不可用/不存活,然后将摘掉该上游服务器,fail_timeout时间后会再次将该服务器加入到存活上游服务器列表进行重试。


健康检查


Nginx对上游服务器的健康检查默认采用的是惰性策略,Nginx商业版提供了health_check进行主动健康检查。也可以集成nginx_upstream_check_module模块进行主动健康检查,它支持TCP心跳和HTTP心跳来实现健康检查。


HTTP动态负载均衡


Consul是一款开源的分布式服务注册与发现系统,通过HTTP API可以使得服务注册、发现实现起来非常简单,它支持以下特性:


  • 服务注册:服务注册者可以通过HTTP API或DNS方式,将服务注册到Consul。

  • 服务发现:服务消费者可以通过HTTP API或DNS方式,从Consul获取服务的IP和PORT。

  • 故障检测:支持如TCP、HTTP等方式的健康检查机制,从而当服务有故障时自动摘除。

  • K/V存储:使用K/V存储实现动态配置中心,其使用HTTP长轮询方式实现变更触发和配置更改。

  • 多数据中心:支持多数据中心,可以按照数据中心注册和发现服务,即支持只消费本地机房服务,使用多数据中心集群还可以避免单数据中心的单点故障。

  • Raft算法:Consul使用Raft算法实现集群数据一致性。


2. 隔离术


隔离是指将系统或资源分隔开。系统隔离是为了在系统发生故障时能限定传播范围和影响范围,即发生故障后不会出现滚雪球效应,从而保证只有出问题的服务不可用,其他服务还是可用的。资源隔离是通过隔离来减少资源竞争,保障服务间的相互不影响和可用性。


线程隔离


线程隔离主要是指线程池隔离,在实际使用时,我们会把请求分类,然后交给不同的线程池处理。当一种业务的请求处理发生问题时,不会将故障扩散到其他线程池,从而保证其他服务可用。


进程隔离


在公司发展初期,一般是先进行从零到一,不会一上来就进行系统拆分,这样就会开发出一些大而全的系统,系统中的一个模块/功能出现问题,整个系统就不可用了。首先想到的解决方案是通过部署多个实例,通过负载均衡进行路由转发。但是这种情况无法避免某个模块因为BUG而出现如OOM导致整个系统不可用的风险。因此这种解决方案只能是一个过渡,较好的解决方案是通过将系统拆分为多个子系统来实现物理隔离。通过进程隔离使得某一个子系统出现问题时不会影响到其他子系统。


集群隔离


随着系统的发展,单实例服务无法满足需求,此时需要服务化技术,通过部署多个服务形成服务集群,以提升系统容量。

随着调用方的增多,当秒杀服务被刷会影响到其他服务的稳定性时,应该考虑为秒杀提供单独的服务集群,即为服务分组,这样当某一个分组出现问题时,不会影响到其他分组,从而实现了故障隔离。

机房隔离


随着对系统可用性的要求,会进行多机房部署,每个机房的服务都有自己的服务分组,本机房的服务应该只调用本机房的服务,不进行跨机房调用。其中,一个机房服务发生问题时,可以通过DNS/负载均衡将请求全部切到另一个机房,或者考虑服务能自动重试其他机房的服务,从而提供系统可用性。

读写隔离


通过主从模式将读和写集群隔离,读服务只从Rdis集群获取数据,当主Redis集群出现问题时,从Redis集群还是可用的,从而不影响用户访问。而当从集群出现问题时,可以进行其他集群的重试。

动静隔离


当用户访问如结算页时,如果JS/CSS等静态资源也在结算页系统中,很可能因为访问量太大导致带宽被打满,从而导致服务不可用。因此,应该将动态内容和静态资源分离,一般应该将静态资源放在CDN上。


爬虫隔离


通过负载均衡将爬虫路由到单独集群,从而保证正常流量可用,爬虫流量尽量可用。


热点隔离


秒杀、抢购属于非常合适的热点例子,对于这种热点,是能提前知道的,所以可以将秒杀和抢购做成独立系统或服务进行隔离,从而保证秒杀/抢购流程出现问题时不影响主流程。


资源隔离


如磁盘、CPU、网络等的隔离。


还有一些其他类似的隔离术,如环境隔离(测试环境、预发布环境/灰度环境、正式环境)、压测隔离(真实数据、压测数据隔离)、AB测试(为不同的用户提供不同版本的服务)、缓存隔离(有些系统混用缓存,而有些系统会扔大字节值到Redis,造成Redis慢查询)、查询隔离(简单、批量、复杂查询条件分别路由到不同的集群)等。通过隔离,可以将风险降到最低,将性能提升至最优。


使用Hystrix实现隔离


Hystrix是Netflix开源的一款针对分布式系统的延迟和容错库,目的是用来隔离分布式服务故障。它提供线程隔离信号量隔离,以减少不同服务之间资源竞争带来的相互影响;提供优雅降级机制;提供熔断机制使得服务可以快速失败,而不是一直阻塞等待服务响应,从能从中快速恢复。Hystrix通过这些机制来阻止级联失败并保证系统弹性、可用。


参考来源:  [1] 亿级流量网站架构核心技术.张开涛著

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多