SpringCloud常用组件对比
Eurka和Nacos
Nacos和Eureka都是服务注册和发现的开源项目,用于构建分布式系统和微服务架构。它们的主要区别如下:
服务注册和发现机制:
- Nacos:Nacos提供了基于实例的服务注册和发现机制。服务提供者在启动时向Nacos注册自己的服务实例,并定期发送心跳来保持注册。服务消费者通过向Nacos查询服务列表来发现可用的服务实例。
- Eureka:Eureka采用了基于中心化的服务注册和发现模式。服务提供者在启动时向Eureka注册自己的服务实例,并周期性地发送心跳来保持注册。服务消费者通过向Eureka服务器获取服务注册表来发现可用的服务实例。
- Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式临时实例心跳不正常会被剔除,非临时实例则不会被剔除。另外Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
容错性和高可用性:
- Nacos:Nacos支持多节点的集群部署,具有高可用性和容错性。它使用Raft算法来保证数据的一致性和可用性,并支持自动的主从切换和故障恢复。
- Eureka:Eureka的设计目标是在AWS云平台上实现高可用性。它使用了主从架构,其中一个Eureka服务器作为主服务器,其他服务器作为从服务器。当主服务器失效时,会触发Eureka客户端的自我保护机制,但这可能导致注册信息的延迟和不一致。
- Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式。Eureka只有AP模式
配置管理:
- Nacos:Nacos提供了功能强大的配置管理功能。它支持动态配置的发布、监听和刷新,可以动态地修改配置参数而无需重启服务。Nacos还提供了命名空间、配置组和配置版本等概念,可以对配置进行灵活的管理和隔离。
- Eureka:Eureka本身并没有内置的配置管理功能。如果需要配置管理,可以结合其他的配置中心(如Spring Cloud Config)与Eureka一起使用。
自我保护机制
相同点: 保护阈值都是个比例,0-1 范围,表示健康的 instance 占全部instance 的比例。
不同点:
(1)保护方式不同
Eureka保护方式:当在短时间内,统计续约失败的比例,如果达到一定阈值,则会触发自我保护的机制,在该机制下Eureka Server不会别除任何的微服务,等到正常后,再退出自我保护机制。自我保护开关(eureka.server.enable-self.preservation. false)
Nacos保护方式: 当域名健康实例 (nstance) 占总服务实例(nstance)的比例小于阈值时,无论实例(Instance) 是否健康,都会将这个实例 (instance)返回给客户端。这样做虽然损失了一部分流量,但是保证了集群的剩余健康实例(Instance)能正常工作。
(2)范围不同
Nacos 的阈值是针对某个具体 Service 的,而不是针对所有服务的。但 Eureka的自我保护阈值是针对所有服务的.
社区支持和集成:
- Nacos:Nacos由阿里巴巴开源,得到了广泛的社区支持。它与Spring Cloud紧密集成,并提供了丰富的文档和示例来帮助开发者使用。
- Eureka:Eureka最初由Netflix开发,虽然已经开源并得到了一定的社区支持,但相比Nacos而言,社区支持相对较少。然而,Eureka与Netflix的开源项目(如Ribbon和Hystrix)紧密集成,并在Netflix的生态系统中被广泛应用。
Hystrix和Sentinel
Sentinel和Hystrix都是用于实现服务容错和熔断的开源项目。 Hystrix 的关注点在于以 隔离 和 熔断 为主的容错机制,超时或被熔断的调用将会快速失败,并可以提供 fallback 机制。而 Sentinel 的侧重点在于:多样化的流量控制、熔断降级、系统负载保护、实时监控和控制台。
资源模型和执行模型上的对比
Hystrix 的资源模型设计上采用了命令模式,将对外部资源的调用和 fallback 逻辑封装成一个命令对象(HystrixCommand
/ HystrixObservableCommand
),其底层的执行是基于 RxJava 实现的。每个 Command 创建时都要指定 commandKey 和 groupKey(用于区分资源)以及对应的隔离策略(线程池隔离 or 信号量隔离)。线程池隔离模式下需要配置线程池对应的参数(线程池名称、容量、排队超时等),然后 Command 就会在指定的线程池按照指定的容错策略执行;信号量隔离模式下需要配置最大并发数,执行 Command 时 Hystrix 就会限制其并发调用。
Sentinel 的设计则更为简单。相比 Hystrix Command 强依赖隔离规则,Sentinel 的资源定义与规则配置的耦合度更低。Hystrix 的 Command 强依赖于隔离规则配置的原因是隔离规则会直接影响 Command 的执行。在执行的时候 Hystrix 会解析 Command 的隔离规则来创建 RxJava Scheduler 并在其上调度执行,若是线程池模式则 Scheduler 底层的线程池为配置的线程池,若是信号量模式则简单包装成当前线程执行的 Scheduler。而 Sentinel 并不指定执行模型,也不关注应用是如何执行的。Sentinel 的原则非常简单:根据对应资源配置的规则来为资源执行相应的限流/降级/负载保护策略。在 Sentinel 中资源定义和规则配置是分离的。用户先通过 Sentinel API 给对应的业务逻辑定义资源(埋点),然后可以在需要的时候配置规则。埋点方式有两种:
- try-catch 方式(通过
SphU.entry(...)
),用户在 catch 块中执行异常处理 / fallback - if-else 方式(通过
SphO.entry(...)
),当返回 false 时执行异常处理 / fallback
Sentinel 还支持基于注解的资源定义方式,可以通过 @SentinelResource
注解参数指定异常处理函数和 fallback 函数。
隔离设计上的对比
隔离是 Hystrix 的核心功能之一。Hystrix 提供两种隔离策略:线程池隔离(Bulkhead Pattern)和信号量隔离,其中最推荐也是最常用的是线程池隔离。Hystrix 的线程池隔离针对不同的资源分别创建不同的线程池,不同服务调用都发生在不同的线程池中,在线程池排队、超时等阻塞情况时可以快速失败,并可以提供 fallback 机制。线程池隔离的好处是隔离度比较高,可以针对某个资源的线程池去进行处理而不影响其它资源,但是代价就是线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。
但是,实际情况下,线程池隔离并没有带来非常多的好处。首先就是过多的线程池会非常影响性能。考虑这样一个场景,在 Tomcat 之类的 Servlet 容器使用 Hystrix,本身 Tomcat 自身的线程数目就非常多了(可能到几十或一百多),如果加上 Hystrix 为各个资源创建的线程池,总共线程数目会非常多(几百个线程),这样上下文切换会有非常大的损耗。另外,线程池模式比较彻底的隔离性使得 Hystrix 可以针对不同资源线程池的排队、超时情况分别进行处理,但这其实是超时熔断和流量控制要解决的问题,如果组件具备了超时熔断和流量控制的能力,线程池隔离就显得没有那么必要了。
Hystrix 的信号量隔离限制对某个资源调用的并发数。这样的隔离非常轻量级,仅限制对某个资源调用的并发数,而不是显式地去创建线程池,所以 overhead 比较小,但是效果不错,也支持超时失败。Sentinel 可以通过并发线程数模式的流量控制来提供信号量隔离的功能。并且结合基于响应时间的熔断降级模式,可以在不稳定资源的平均响应时间比较高的时候自动降级,防止过多的慢调用占满并发数,影响整个系统。
熔断降级对比
Sentinel 和 Hystrix 的熔断降级功能本质上都是基于熔断器模式(Circuit Breaker Pattern)。Sentinel 与 Hystrix 都支持基于失败比率(异常比率)的熔断降级,在调用达到一定量级并且失败比率达到设定的阈值时自动进行熔断,此时所有对该资源的调用都会被 block,直到过了指定的时间窗口后才启发性地恢复。上面提到过,Sentinel 还支持基于平均响应时间的熔断降级,可以在服务响应时间持续飙高的时候自动熔断,拒绝掉更多的请求,直到一段时间后才恢复。这样可以防止调用非常慢造成级联阻塞的情况。
实时指标统计实现对比
Hystrix 和 Sentinel 的实时指标数据统计实现都是基于滑动窗口的。Hystrix 1.5 之前的版本是通过环形数组实现的滑动窗口,通过锁配合 CAS 的操作对每个桶的统计信息进行更新。Hystrix 1.5 开始对实时指标统计的实现进行了重构,将指标统计数据结构抽象成了响应式流(reactive stream)的形式,方便消费者去利用指标信息。同时底层改造成了基于 RxJava 的事件驱动模式,在服务调用成功/失败/超时的时候发布相应的事件,通过一系列的变换和聚合最终得到实时的指标统计数据流,可以被熔断器或 Dashboard 消费。
Sentinel 目前抽象出了 Metric 指标统计接口,底层可以有不同的实现,目前默认的实现是基于 LeapArray
的高性能滑动窗口,后续根据需要可能会引入 reactive stream 等实现。
总结
Sentinel | Hystrix | |
---|---|---|
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于慢调用比例或异常比例 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于 RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持慢启动、匀速排队模式 | 不支持 |
系统自适应保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |