任何普通服务都运行在Netflix的大规模集群(上万台机器)中。如果不做特殊处理,就会出现各种问题。以电影推荐服务的实现为例。传统方案:在传统方案中,你会使用固定的DNS域名解析服务,将一组固定的IP放在负载均衡列表中。服务注册和发现写在配置文件中。一旦该服务宕机,其他依赖该服务的服务都会受到影响。传统的方法只能启动一个新的服务器,然后更改其他机器的配置文件,并重启相关服务。这种方式在小型集群中可能还可以忍受,但是在几万台服务器的集群中管理500多个服务时,情况就会变得非常复杂。Netflix通过多年的实践贡献了很多开源项目。例如:Eureka、Hystrix、Feign、Ribbon等,解决大规模集群中的服务管理问题。使用Eureka作为服务发现工具什么是Eureka?Eureka是Netflix贡献的开源中间层负载均衡和服务发现工具。Eureka是基于Java实现的,在Spring应用中声明Server和Client进行服务注册非常方便。Eureka解决的问题Eureka服务器是服务的注册中心,可以提高大规模集群环境下服务发现的容错性和可用性。并且可以解决数据中心之间的服务注册和发现问题。Netflix推荐在每个Region搭建一个Eureka集群,每个Region的可用区至少有一个EurekaServer,这样可以保证任何一个可用区的服务注册信息都会复制到每个可用区,实现服务信息的高可用。任何可用性区域中的客户端都可以访问该服务的注册信息。客户端访问服务器后,会在本地缓存服务的信息,并定期(30秒)刷新服务的状态。如果集群出现大规模网络故障(例如交换机故障导致子网无法互通),Eureka会进入自我保护模式,各个Eureka节点会继续对外提供服务(注:ZooKeeperwillnot):接收新的服务注册并提供给下游的服务发现请求。这样新发布的服务仍然可以在同一个子网(Samesideofpartition)内被发现和访问。在EurekaV1.0版本中,Eureka之间的数据同步是全量同步,每个客户端都有Eureka集群中所有服务的信息。在V2.0版本中,将支持同步客户端偏好的服务信息。同时也会增强Eureka的读写分离和高可用。有了Eureka,Netflix是怎么做红黑版的?Netflix的发行方式是红黑发行。如果线上部署的服务出现问题,传统方式回滚一个服务需要5-15分钟。Netflix使用Eureka来动态离线/在线服务。有两种类型的服务:REST服务和非REST服务。如果离线服务是REST服务,那么情况比较简单,通过Eureka实时实现离线和在线服务。如果服务是非REST服务,比如执行Batching任务或者快速服务Transaction等,不能简单的将服务标记为下线。借助Spring提供的EventListener(事件监听器),Eureka可以通过EurekaStatusChangeEvent事件来帮助开发者在这个事件监听器中,对应的服务下线。Netflix在实现红黑发布时,会先动态下线一些服务。如果这些服务有一些Batching任务,它们会通过事件监听器停止这些任务。为什么Netflix没有选择使用ZooKeeper来进行服务发现?因为当ZooKeeper在处理上千个节点时,它可能能够应付失败次数少的情况。在大型集群中,集群故障时有发生。如果每次重选的成本都太高,Eureka会采用基于CAP理论中AP策略的最终一致性方案。其次,Eureka提供了REST端点支持服务的注册,可以解决Non-Java服务的注册问题。用于服务降级的HystrixHystrix是Netflix的一个开源组件,可以帮助服务之间调用超时,报错时,防止问题扩散,避免雪崩。服务在用户不知情的情况下降级。示例:当你尝试为你的用户推荐电影时,服务调用由于某种原因没有返回(可能是依赖的User服务宕机),Hystrix可以定义多种策略来判断服务是否健康。例如:为Hystrix预设了一个超时时间。如果服务调用的返回结果超过这个时间,Hystrix会决定触发熔断机制,暂时中止服务的调用,并返回一个通用的电影列表作为推荐,而不是让用户无休止地等待下去,从而改善用户体验。当然,超时时间只是Hystrix做出熔断决定的一个条件。Hystrix可以设置多个条件来判断一个服务调用是否正常。比如服务的corePoolSize、maximumPoolSize和keepAliveTime都可以作为Hystrix的熔断策略。Hystrix提供了CircuitBreak来检测服务的健康状态。CircuitBreak解决了以下问题:检查服务的状态。支持线程隔离和资源访问。当服务的并发访问量特别大时(每秒数百个连接),CircuitBreak会隔离线程或限制资源访问,以保证服务的可用性。下图是CircuitBreakOpen/Close的决策过程:如果服务调用的错误率高于预设的错误率。Circuit-breaker的状态将从CLOSED变为OPEN(熔断器状态)。当断路器状态为OPEN时,所有传入请求都将被阻止。过一段时间,会有一些个别的请求进来(Half-Open)。如果服务调用仍然失败,Circuit-breaker将再次进入OPEN状态。如果请求成功,Circuit-breaker状态会变为CLOSED,重新进入第一步。目前Hystrix正在优化跨服务的事务处理。Ribbon作为负载均衡器Ribbon是NetflixOSS贡献的一个软负载均衡器,用于处理RPC调用。除了传统负载均衡的能力外,它还可以解决以下问题:当监控到集群中有9台服务器提供相同的服务,且其中3台响应明显有问题时,Ribbon可以暂时将这三台服务器从负载均衡中移除。剔除,直到三台机器恢复正常响应。可以对响应最快的服务器进行加权,从而为响应最快的节点带来更多流量。支持同时启用多种负载均衡策略,负载均衡效果可调试到极致。自定义设置重试机制。虽然Ribbon项目正在维护中,但是其实现思路还是值得借鉴的。总结本文主要介绍NetflixOSS贡献的Eureka、Hystrix和Ribbon。限于篇幅,其他组件将在后续文章中介绍。这些开源组件与SpringBoot/SpringCloud很好的结合,通过注解Properties文件进行配合,可以解决在管理大型服务时遇到的常见问题。本文旨在解读Netflix在实现大规模扩张过程中遇到的问题,分析他们的解决方案,并为未来的问题提供一些思路。想法和愿景有时比工具本身更重要。参考资料:作者简介:王青,JFrog中国区高级架构师,曾在IBM、爱奇艺、新浪、VIPKID从事架构研发工作,目前专注于DevOps和微服务的落地。
