• [技术干货] Spring Cloud Hystrix 降级机制是如何实现的
    Spring Cloud Hystrix的降级机制主要通过以下几个方面来实现:一、服务降级的概念服务降级是指在某些情况下(如系统负载过高、服务不可用或调用超时等),为了保证系统的整体稳定性和可用性,主动降低某些非核心服务的调用级别,通过返回一个预设的默认值或执行备用逻辑来处理请求。这样,即使部分服务出现故障,也不会影响到整个系统的运行。二、降级机制的实现方式注解方式:使用@HystrixCommand注解:在需要降级的服务方法上添加@HystrixCommand注解,并指定fallbackMethod属性为降级处理的方法。当服务调用失败或超时等异常情况发生时,会自动调用指定的降级方法。使用@DefaultProperties注解(结合@HystrixCommand):如果某个类中有多个方法需要降级处理,并且希望它们共享同一个降级方法,可以使用@DefaultProperties注解来指定一个默认的降级方法。然后,在每个需要降级的方法上使用@HystrixCommand注解,但不指定fallbackMethod属性,这样它们就会使用默认的降级方法。配置文件方式:在Spring Cloud的配置文件中,可以通过设置相关属性来配置Hystrix的降级策略。例如,可以设置服务调用的超时时间、熔断器的打开条件等。当服务调用满足这些条件时,Hystrix会自动触发降级机制。编程方式:通过编程方式动态地配置Hystrix的降级策略。例如,可以在代码中根据系统的当前状态或负载情况动态地调整服务调用的超时时间、熔断器的阈值等参数。这样,可以根据实际情况灵活地调整降级策略,以提高系统的适应性和稳定性。三、降级逻辑的实现降级逻辑是指当服务调用失败或触发降级条件时,系统执行的备用逻辑。降级逻辑可以是返回一个预设的默认值、执行其他备用服务或执行一些补偿操作等。具体的降级逻辑需要根据业务需求和系统实际情况来设计和实现。在实现降级逻辑时,需要注意以下几点:降级逻辑应该简单、快速且可靠,以避免对系统造成额外的负担。降级逻辑应该能够处理各种异常情况,包括服务不可用、调用超时、网络异常等。降级逻辑应该能够与系统的其他部分协同工作,以确保系统的整体稳定性和可用性。四、监控与告警Hystrix提供了近实时监控功能,可以实时监控服务的调用情况、失败率等指标。当服务的调用情况出现异常时,Hystrix可以触发告警通知开发人员或运维人员进行处理。通过监控和告警功能,可以及时发现和处理服务调用中的异常情况,从而避免降级机制被频繁触发对用户体验和系统稳定性造成不良影响。综上所述,Spring Cloud Hystrix的降级机制通过注解方式、配置文件方式和编程方式等多种方式来实现。在实现降级机制时,需要根据业务需求和系统实际情况来设计和实现降级逻辑,并注意监控与告警功能的配置和使用。
  • [技术干货] Spring Cloud 服务的隔离及断路器-Hystrix
    Spring Cloud中的服务隔离和断路器Hystrix是两个关键概念,它们共同作用于提高分布式系统的弹性和稳定性。以下是对这两个概念的详细解释:一、服务隔离服务隔离是指在微服务架构中,通过某种方式将不同的服务相互隔离开来,以防止一个服务的故障影响到其他服务。服务隔离可以通过多种方式实现,包括但不限于:线程池隔离:Hystrix为每个依赖的服务调用创建一个独立的线程池。这样,当某个服务出现故障时,其对应的线程池被耗尽或阻塞时,不会影响其他服务的调用。例如,服务A调用服务B、C和D时,Hystrix会为这三个服务调用分别创建线程池。这样,服务B的故障就不会影响到服务A对服务C和D的调用。信号量隔离:信号量隔离是一种轻量级的并发控制机制,它不会创建新的线程,而是在同一线程内对并发请求进行限制。Hystrix可以为每个服务调用设置一个信号量的数量,当超过这个数量时,后续的请求会被拒绝,从而实现了服务调用的隔离。进程隔离:在某些情况下,可以通过将不同的服务部署在不同的进程或容器中来实现隔离。这种方法虽然有效,但相对较重,需要更多的资源和管理开销。API网关隔离:使用API网关作为所有外部请求的入口点,并在网关层实现路由、限流、熔断等功能,也可以起到服务隔离的作用。二、断路器Hystrix断路器Hystrix是Netflix开源的一个用于处理分布式系统延迟和容错的库。它通过“断路器”模式来防止一个服务的故障导致整个系统的崩溃。以下是Hystrix的主要功能和特点:熔断机制:当某个服务的调用失败率达到一定的阈值时,Hystrix会自动熔断该服务的调用,直接返回一个预设的默认值或执行降级逻辑。熔断器有三种状态:关闭(Closed)、打开(Open)和半开(Half-Open)。在正常情况下,熔断器处于关闭状态;当服务调用失败率达到阈值时,熔断器切换到打开状态;在一段时间后,熔断器会进入半开状态,允许少量的请求通过以试探服务是否已恢复正常。降级逻辑:开发人员可以为每个服务调用定义一个降级方法,当服务不可用或调用失败时,执行降级逻辑以返回一个备选响应。降级逻辑可以是返回一个缓存中的数据、一个默认的响应值或执行其他备用逻辑。隔离与限流:通过线程池隔离和信号量隔离机制,Hystrix能够限制某个服务的调用对系统资源的影响。同时,Hystrix还支持限流功能,可以根据系统的负载情况动态调整对某个服务的调用频率。实时监控与告警:Hystrix提供了近实时监控功能,可以实时监控服务的调用情况、失败率等指标。当服务的调用情况出现异常时,Hystrix可以触发告警通知开发人员或运维人员进行处理。三、Hystrix的使用场景与配置Hystrix适用于具有以下特点的场景:微服务架构中的服务调用链较长,一个服务的故障容易引发连锁反应。服务之间的依赖关系复杂,需要实现故障隔离和容错处理。系统需要高可用性和稳定性,能够容忍部分服务的暂时不可用。在使用Hystrix时,需要进行以下配置:线程池大小:根据服务的调用频率和资源消耗情况,合理配置线程池大小以防止资源耗尽。熔断阈值:设置服务调用的失败率阈值,当超过该阈值时触发熔断机制。降级逻辑:为每个服务调用定义合理的降级逻辑,确保在服务不可用时能够返回备选响应。监控与告警:配置监控和告警功能,以便及时发现和处理服务调用中的异常情况。综上所述,服务隔离和断路器Hystrix是Spring Cloud中提高分布式系统弹性和稳定性的重要手段。通过合理的配置和使用,它们可以有效地防止一个服务的故障对整个系统造成灾难性的影响。
  • [技术干货] Spring Cloud Robbin支持的负载均衡策略,及配置方式
    在Spring Cloud中,Ribbon(注意:原文中的“Robbin”应为拼写错误,正确为“Ribbon”)是一个客户端负载均衡器,它提供了多种负载均衡策略来分发请求到多个服务实例。以下是Ribbon支持的负载均衡策略及其配置方式:一、Ribbon支持的负载均衡策略轮询(RoundRobinRule):按照顺序将请求依次分配给每个服务器。当请求到达时,负载均衡器会选择下一个服务器,直到所有服务器都被遍历。适用于服务器性能相近的情况。随机(RandomRule):将请求随机分配给服务器,不考虑服务器的性能或负载情况。这种方法简单且易于实现,适用于服务器数量较少且性能相近的情况。加权响应时间(WeightedResponseTimeRule):根据服务器的响应时间进行负载均衡。权重是根据服务器的响应时间来分配的,响应时间较短的服务器将获得更高的权重,从而获得更多的请求。适用于服务器性能存在差异的情况。最少活跃数(LeastActiveRule):将请求分配给当前活跃连接数最少的服务器。这种策略旨在平衡服务器负载,确保高可用性。适用于服务器性能存在差异的情况,但注意这不是Ribbon官方直接提供的策略,可能需要自定义或借助其他扩展实现。最少连接数(BestAvailableRule):与最少活跃数策略类似,但考虑的是每个服务器的连接数,而不是总的活跃连接数。实际上,在Ribbon的某些版本中,BestAvailableRule可能表现为选择请求数最少的健康实例。一致性哈希(ConsistentHashRule):使用哈希算法将请求映射到特定的服务器节点。当添加或删除节点时,只有相邻的节点才会受到影响,从而最小化负载波动。适用于需要稳定和均匀的负载分布的情况。但注意,这不是Ribbon官方直接提供的标准策略,可能需要自定义或借助其他扩展实现。动态权重(DynamicWeightRule,非官方标准策略):根据服务器的性能和负载情况动态调整权重。权重较高的服务器将获得更多的请求,而权重较低的服务器将获得较少的请求。这种方法可以根据实际情况动态调整负载均衡,提高系统的可用性和性能。但同样,这不是Ribbon官方直接提供的策略,可能需要自定义或借助其他扩展实现。二、配置方式引入依赖:在Spring Boot项目的pom.xml文件中添加Ribbon和Eureka Client的依赖(如果Eureka作为服务注册中心)。配置文件:在application.yml或application.properties配置文件中,配置Eureka服务注册中心的地址和Ribbon的相关参数。例如,要指定负载均衡策略为随机策略,可以在application.yml中配置如下内容:eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRuleJava配置:在Spring Boot的启动类或配置类中,通过Java代码配置Ribbon的负载均衡策略(虽然通常通过配置文件更常见)。例如,可以创建一个配置类,并在该类中通过@Bean注解定义一个自定义的负载均衡策略Bean。但请注意,对于标准的Ribbon策略,通常不需要这样做,因为可以直接在配置文件中指定。自定义负载均衡策略:如果需要自定义负载均衡策略,可以实现com.netflix.loadbalancer.IRule接口,并在配置类中将其注册为Bean。然后,在配置文件中指定自定义负载均衡策略的名称(即Bean的名称)。三、注意事项Ribbon在新版Spring Cloud中已被Spring Cloud LoadBalancer所替代。对于新项目,建议使用Spring Cloud LoadBalancer来实现负载均衡功能。在使用Ribbon时,请确保已正确配置Eureka或其他服务注册中心,以便Ribbon能够获取到可用的服务实例列表。负载均衡策略的选择应根据具体的业务场景和需求来决定。例如,对于需要稳定和均匀的负载分布的应用,一致性哈希可能是更好的选择;而对于服务器性能存在差异的情况,加权响应时间或动态权重可能更适合。综上所述,Ribbon在Spring Cloud中提供了多种负载均衡策略来分发请求到多个服务实例。通过正确的配置和选择合适的负载均衡策略,可以提高系统的性能和稳定性。
  • [技术干货] Spring Cloud 服务间的负载均衡-Robbin
    在Spring Cloud中,Ribbon是实现服务间负载均衡的一个重要工具。以下是对Spring Cloud中Ribbon负载均衡的详细解释:一、Ribbon简介Ribbon是Netflix开源的一个客户端负载均衡工具,它能够与Spring Cloud深度集成,为微服务架构中的服务调用提供负载均衡支持。通过Ribbon,客户端可以在多个服务实例之间智能地分发请求,从而提高系统的性能和稳定性。二、Ribbon的工作原理服务注册与发现:Ribbon依赖于服务注册中心(如Eureka)来获取服务实例的列表。服务提供者启动后,会将自己的信息注册到服务注册中心。服务消费者通过服务注册中心获取可用服务实例的列表。负载均衡策略:Ribbon提供了多种负载均衡策略,如轮询(RoundRobinRule)、随机(RandomRule)、权重(WeightedResponseTimeRule)等。默认情况下,Ribbon使用轮询策略,即按照服务实例列表的顺序依次分发请求。开发者可以根据实际需求选择合适的负载均衡策略,或者自定义负载均衡规则。请求分发:当服务消费者发起请求时,Ribbon会根据选定的负载均衡策略,从服务实例列表中选择一个目标实例。然后,Ribbon将请求转发到选定的目标实例上,由该实例处理请求。三、Ribbon的配置与使用引入依赖:在Spring Boot项目的pom.xml文件中添加Ribbon和Eureka Client的依赖。配置文件:在application.yml或application.properties配置文件中,配置Eureka服务注册中心的地址和Ribbon的相关参数。启用负载均衡:在服务消费者的启动类上添加@EnableEurekaClient注解,以启用Eureka客户端功能。创建一个配置类,并在该类中定义一个带有@LoadBalanced注解的RestTemplate Bean。这样,RestTemplate在发起请求时就会使用Ribbon进行负载均衡。自定义负载均衡策略:如果需要自定义负载均衡策略,可以实现IRule接口,并在配置类中将其注册为Bean。然后,在application.yml或application.properties配置文件中,指定自定义负载均衡策略的名称。四、Ribbon的优缺点优点:Ribbon与Spring Cloud深度集成,易于使用。提供了多种负载均衡策略,满足不同的业务需求。支持动态更新服务实例列表,能够自动感知服务实例的上下线。缺点:Ribbon在新版Spring Cloud中已被弃用,建议使用Spring Cloud LoadBalancer作为替代方案。Ribbon的负载均衡策略相对简单,可能无法满足一些复杂的业务需求。五、Spring Cloud LoadBalancer与Ribbon的对比Spring Cloud LoadBalancer是Spring Cloud官方提供的负载均衡实现,从Spring Cloud 2020版本开始推荐使用。它提供了更丰富的负载均衡策略和更灵活的配置方式。Ribbon虽然功能强大且易于使用,但已在新版Spring Cloud中被弃用。对于正在使用Ribbon的项目,建议逐步迁移到Spring Cloud LoadBalancer。综上所述,Ribbon是Spring Cloud中实现服务间负载均衡的一个重要工具。它通过与服务注册中心集成,为微服务架构中的服务调用提供了智能的请求分发功能。然而,随着Spring Cloud的发展,Ribbon已被Spring Cloud LoadBalancer所替代。因此,在新项目中建议使用Spring Cloud LoadBalancer来实现负载均衡功能。
  • [技术干货] Spring Cloud 中的 Eureka 如何保证其安全性
    在Spring Cloud中,Eureka作为服务注册与发现的核心组件,其安全性至关重要。为了保证Eureka的安全性,可以采取以下几种措施:一、添加安全依赖与配置添加Spring Security依赖:在Eureka Server的pom.xml文件中添加Spring Security的依赖,以便为Eureka Server提供基本的安全认证功能。配置安全认证信息:在Eureka Server的配置文件中(如application.yml或application.properties),配置安全认证的用户名和密码。这样,当客户端尝试访问Eureka Server时,需要进行基本的身份验证。二、修改访问集群节点的URL在Eureka Server的配置文件中,设置服务注册中心地址时,可以将用户名和密码包含在URL中。这样,当Eureka Client向Eureka Server注册或发现服务时,会自动带上这些认证信息。三、配置CSRF防御机制Eureka会自动配置CSRF(跨站请求伪造)防御机制。由于Eureka控制台和某些API端点可能面临CSRF攻击的风险,因此需要采取适当的防御措施。可以通过配置一个WebSecurityConfigurerAdapter类,并重写configure方法,来忽略/eureka/**的所有请求的CSRF检查。但请注意,这种做法可能会降低安全性,因此在实际应用中需要权衡利弊。四、使用HTTPS为了保证数据传输的安全性,建议使用HTTPS协议来加密Eureka Server与客户端之间的通信。这样可以防止数据在传输过程中被窃听或篡改。五、网络隔离与访问控制将Eureka Server部署在安全的网络环境中,通过防火墙、VPN等网络安全设备来限制对Eureka Server的访问。使用网络访问控制列表(ACL)来允许或拒绝特定IP地址或网段的访问。六、定期审计与监控定期对Eureka Server进行安全审计,检查配置的正确性和安全性。使用监控工具来实时监控Eureka Server的运行状态和访问日志,以便及时发现并响应潜在的安全威胁。综上所述,通过添加安全依赖与配置、修改访问集群节点的URL、配置CSRF防御机制、使用HTTPS、网络隔离与访问控制以及定期审计与监控等措施,可以有效地提高Spring Cloud中Eureka的安全性。这些措施共同构成了一个多层次的安全防护体系,为微服务架构中的服务注册与发现提供了有力的保障。
  • [技术干货] Spring cloud 服务的注册与发现-Eureka
    Eureka是Spring Cloud中的一个核心组件,主要负责服务的注册与发现。以下是对Eureka的详细介绍:一、Eureka的背景与定义Eureka最早由Netflix开源,后成为Spring Cloud生态系统中的一个重要组件。它是一个基于REST的服务,主要用于解决分布式系统中服务注册和发现的问题,使得服务能够动态地加入和离开集群,并能够自动地进行负载均衡和服务降级。Eureka的设计目标是提供一个高可用的服务注册与发现系统,可以自动化地管理和监控微服务应用的状态和位置。二、Eureka的架构与组件Eureka采用C-S(客户端-服务器)架构,主要包括Eureka Server和Eureka Client两个组件:Eureka Server:作为服务注册中心,接收来自服务提供方的注册请求,并维护所有注册的服务实例信息。同时,Eureka Server也作为服务发现中心,允许服务消费方查询和发现其他服务的地址信息。Eureka Client:用于服务注册和发现,它与Eureka Server进行通信,将自己的服务信息注册到Eureka Server中,并从Eureka Server获取其他服务的信息。Eureka Client是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询负载算法的负载均衡器。三、Eureka的工作原理Eureka的工作原理主要包括以下几个步骤:Eureka Server启动:首先启动Eureka Server作为服务注册中心,等待来自微服务应用的注册请求。服务注册:微服务应用(服务提供者)启动后,通过Eureka Client将自己的基本信息(如服务名称、网络地址等)发送给Eureka Server进行注册。Eureka Server接收到注册请求后,将微服务应用的信息存储在注册表中。心跳检测:注册成功的服务会定期向Eureka Server发送心跳请求,以更新自身状态信息。Eureka Server通过心跳检测来保持与服务实例的连接,并及时更新服务的状态。如果Eureka Server在多个心跳周期内没有收到某个服务的心跳,会将其从服务注册表中移除。服务发现:服务消费方通过Eureka Client向Eureka Server发送查询请求,获取可用服务的列表。然后,根据负载均衡策略选择合适的服务实例进行调用。四、Eureka的特性与优势高可用性:Eureka采用了主从架构,多个Eureka Server可以组成一个集群,实现高可用性。当Eureka Server集群中的某个节点宕机时,客户端仍然可以通过其他可用的节点进行服务发现和注册。弹性和容错:Eureka基于CAP原理(一致性、可用性、分区容忍性),将可用性放在首位。在网络分区故障的情况下,Eureka能够保护服务注册表的可用性,防止故障扩散到其他服务实例。自我保护机制:Eureka引入了自我保护机制,当Eureka Server节点在短时间内丢失过多的心跳时,它将进入自我保护模式,不再剔除因为心跳丢失而被视为下线的服务。这有助于防止因网络波动等原因导致的误剔除。负载均衡:Eureka提供了几种负载均衡的策略来选择使用哪个服务实例。这有助于优化资源利用和提高系统性能。五、Eureka与其他Spring Cloud组件的集成Eureka不仅可以单独使用,还可以与其他Spring Cloud组件配合使用,提供更全面的微服务架构支持。例如:Ribbon:Eureka与Ribbon结合可以实现客户端负载均衡,让微服务应用能够根据一定的策略选择合适的服务进行调用。Feign:Eureka与Feign结合可以实现声明式REST客户端,简化微服务之间的调用与交互。Hystrix:Eureka与Hystrix结合可以实现服务的容错和熔断,保证系统的可靠性和稳定性。综上所述,Eureka作为Spring Cloud中的服务注册与发现组件,具有高可用性、弹性和容错性、自我保护机制以及与其他Spring Cloud组件的良好集成等特性与优势。它能够帮助开发人员构建基于微服务架构的分布式系统,实现服务的高效注册与发现。
  • [技术干货] 【微服务】【微服务】SpringClound常用注解以及示例-转载
    引言 Spring Cloud 作为一套完整的微服务解决方案,提供了丰富的工具和功能,帮助开发者轻松实现服务注册、负载均衡、服务调用、配置管理等核心需求。  在这篇文章中,我们将介绍 Spring Cloud 中常用的注解,帮助您更好地理解和应用这些注解,以简化微服务开发过程。  常用注解 Spring Cloud 是一个微服务框架,提供了许多用于构建分布式系统的工具。以下是 Spring Cloud 中一些常用的注解:  1. @EnableEurekaServer 作用: 开启 Eureka 服务端,用于服务注册和发现。 使用场景: 当需要搭建服务注册中心时,在启动类上加此注解。 @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication {     public static void main(String[] args) {         SpringApplication.run(EurekaServerApplication.class, args);     } } 2. @EnableEurekaClient 作用: 开启 Eureka 客户端,自动将服务注册到 Eureka Server 中。 使用场景: 当需要将服务注册到 Eureka 中时,使用此注解。 @SpringBootApplication @EnableEurekaClient public class EurekaClientApplication {     public static void main(String[] args) {         SpringApplication.run(EurekaClientApplication.class, args);     } } 3. @EnableDiscoveryClient 作用: 启用服务发现功能。与 @EnableEurekaClient 类似,但更通用,支持多种服务发现机制(如 Consul、Zookeeper 等)。 使用场景: 在需要服务发现的场景中使用。 @SpringBootApplication @EnableDiscoveryClient public class DiscoveryClientApplication {     public static void main(String[] args) {         SpringApplication.run(DiscoveryClientApplication.class, args);     } } 4. @LoadBalanced 作用: 用于配置 RestTemplate 的负载均衡。 使用场景: 在微服务调用其他服务时,可以使用带有 @LoadBalanced 注解的 RestTemplate 来实现客户端负载均衡。 @Bean @LoadBalanced public RestTemplate restTemplate() {     return new RestTemplate(); } 5. @EnableFeignClients 作用: 开启 Feign 客户端。Feign 是一个声明式的 HTTP 客户端,可以更简洁地调用远程服务。 使用场景: 需要使用 Feign 进行服务调用时。 @SpringBootApplication @EnableFeignClients public class FeignClientApplication {     public static void main(String[] args) {         SpringApplication.run(FeignClientApplication.class, args);     } } 6. @FeignClient 作用: 声明一个 Feign 客户端,用于调用远程服务。 使用场景: 在调用其他微服务时,通过接口与该注解配置远程调用。 @FeignClient(name = "service-name") public interface ServiceClient {     @GetMapping("/api/service-endpoint")     String getServiceResponse(); } 7. @HystrixCommand 作用: 用于配置 Hystrix 命令,实现断路器、服务降级、超时等功能。 使用场景: 需要对远程服务调用进行容错处理时。 @HystrixCommand(fallbackMethod = "fallbackMethod") public String callRemoteService() {     return restTemplate.getForObject("http://remote-service/api", String.class); }  public String fallbackMethod() {     return "Fallback response"; } 8. @EnableHystrix 作用: 开启 Hystrix 断路器支持。 使用场景: 当需要使用 Hystrix 进行容错处理时。 @SpringBootApplication @EnableHystrix public class HystrixApplication {     public static void main(String[] args) {         SpringApplication.run(HystrixApplication.class, args);     } } 9. @EnableZuulProxy 作用: 开启 Zuul 网关功能。 使用场景: 构建 API 网关时,通过 Zuul 实现路由和过滤功能。 @SpringBootApplication @EnableZuulProxy public class ZuulApplication {     public static void main(String[] args) {         SpringApplication.run(ZuulApplication.class, args);     } } 10. @EnableConfigServer 作用: 开启 Spring Cloud Config Server,用于集中管理配置。 使用场景: 当需要集中管理多个微服务的配置时。 @SpringBootApplication @EnableConfigServer public class ConfigServerApplication {     public static void main(String[] args) {         SpringApplication.run(ConfigServerApplication.class, args);     } } 这些注解是 Spring Cloud 框架中常用的注解,可以帮助开发者快速构建微服务架构。不同注解提供了不同的功能,如服务注册、负载均衡、服务调用、断路器等。  引用的包 在使用 Spring Cloud 的常用注解时,您需要在项目中引入相应的依赖包。以下是一些常用的 Spring Cloud 组件和相关依赖包的示例:  1. Eureka (服务注册与发现) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> 2. Feign (声明式服务调用) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 3. Hystrix (断路器) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> 4. Zuul (API 网关) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> 5. Spring Cloud Config (配置管理) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-config-server</artifactId> </dependency>  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-config</artifactId> </dependency> 6. Ribbon (客户端负载均衡) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> 7. Spring Cloud Commons (通用服务发现) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter</artifactId> </dependency> 8. Consul (服务注册与发现,Consul 方案) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> 9. Zookeeper (服务注册与发现,Zookeeper 方案) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency> 10. Sleuth (分布式链路追踪) Maven 依赖:  <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> 版本管理 Maven 依赖版本管理: 为了保证依赖版本的一致性,通常在 pom.xml 中加入 Spring Cloud 的版本管理配置。例如:  <dependencyManagement>     <dependencies>         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-dependencies</artifactId>             <version>Hoxton.SR12</version>             <type>pom</type>             <scope>import</scope>         </dependency>     </dependencies> </dependencyManagement> 结束语 Spring Cloud 为开发分布式系统提供了强大的支持,通过灵活使用其提供的注解,我们可以显著提升微服务开发的效率和可靠性。  这些注解不仅简化了服务的注册、发现和调用,还增强了系统的容错能力和可维护性。  掌握这些常用注解,将为您构建稳定、高效的微服务架构奠定坚实的基础。  希望通过本文的介绍,您能更好地应用 Spring Cloud,打造高质量的分布式系统。 ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/jinxinxin1314/article/details/141336869 
  • [技术干货] spring boot3登录开发-2(1图形验证码接口实现) -转载
     前置条件 本文衔接上文,请从上文开始  spring boot3x登录开发-上(整合jwt)-CSDN博客 https://blog.csdn.net/qq_62262918/article/details/135964626?spm=1001.2014.3001.5502  内容简介 上文我们已经整合好了jwt,本文我们开始实现图形验证码接口的实现。  通过糊涂工具包的图形验证码工具完成获取验证码接口 通过redis缓存key(验证码id)-value(验证码内容) 图形验证码接口实现 导入糊涂工具依赖 pom.xml:  <dependency>     <groupId>cn.hutool</groupId>     <artifactId>hutool-all</artifactId>     <version>5.8.25</version> </dependency> 接口分析 前端的登录表单有个验证码id字段,第一次打开登录页面默认会请求验证码接口,那么后端验证码接口将返回验证码图片的base64编码和验证码id,前端需要将验证码id保存到表单对象的验证码id字段,同时把验证码图片显示。用户填写账密、验证码点击登录,表单对象将携带账密和验证码id和用户键入的验证码内容提交到后端,后端需要根据此验证码id去查redis跟用户提交的比对。  分析完我们就可以知道怎样设计这个接口了。  接口接收一个验证码id参数,判断这个参数如果是null则生成一个验证码id,不为null则直接拿它去生成redis缓存验证码内容的key,接着将验证码图片同id返回给前端。   首先定义验证码接口数据对象  import lombok.Builder; import lombok.Data;   /**  * @author mijiupro  */ @Data @Builder public class CaptchaVO {     //验证码id     private  String captchaId;     //验证码图片base64编码     private  String captchaImage; } 编写验证码接口 这里用到了redis,需要整合好:  Spring Boot3整合Redis-CSDN博客 https://blog.csdn.net/qq_62262918/article/details/136067550?spm=1001.2014.3001.5501  import cn.hutool.captcha.CaptchaUtil; import cn.hutool.captcha.CircleCaptcha; import com.mijiu.commom.model.vo.CaptchaVO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;   import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit;   /**  * @author mijiupro  */ @RestController @RequestMapping("/Captcha") @Tag(name = "验证码接口", description = "验证码接口相关操作") public class CaptchaController {     private final StringRedisTemplate stringRedisTemplate;       public CaptchaController(StringRedisTemplate stringRedisTemplate) {         this.stringRedisTemplate = stringRedisTemplate;     }          @GetMapping("/graph-captcha")     @Operation(summary = "获取验证码")     public CaptchaVO getCaptcha(String captchaId) {         // 创建一个图像验证码宽度为130,高度为48,包含4个字符,干扰线10个         CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(130, 48, 4, 10);         // 获取验证码的文本         String captchaText = circleCaptcha.getCode();         // 获取验证码图片的Base64编码         String captchaImageBase64Data = circleCaptcha.getImageBase64Data();         // 如果没有传入captchaId,则生成一个随机字符串作为captchaId         captchaId = Optional.ofNullable(captchaId).orElseGet(() -> UUID.randomUUID().toString());         // 保存验证码文本到Redis中,有效期30秒         stringRedisTemplate.opsForValue().set("captcha:" + captchaId, captchaText, 30, TimeUnit.SECONDS);           return CaptchaVO.builder()                 .captchaId(captchaId)                 .captchaImage(captchaImageBase64Data)                 .build();     }   }  测试验证码接口 这里使用Knife4jConfig(swigger3)测试,也可以用浏览器地址栏、Postman等测试  Spring Boot3整合knife4j(swagger3)_springboot3 knife4j-CSDN博客 https://blog.csdn.net/qq_62262918/article/details/135761392?spm=1001.2014.3001.5502                            原文链接:https://blog.csdn.net/qq_62262918/article/details/136064820 
  • [技术干货] 【监控】spring actuator源码速读-转载
     1.前言 版本:spring-boot-starter-actuator  2.6.3  阅读源码一定要带着疑问去阅读,这个疑问就是你阅读的主线,不然在浩如烟海的源码里面很容易迷路。我们当前的疑问是什么?之前我们已经聊过spring actuator的使用了:  Spring Boot 监控_springboot 监控-CSDN博客  本文要搞清楚的两个问题在于:  EndPoint是怎么被注入IOC又怎么暴露出去能通过HTTP访问到的?  EndPoint是怎么实现监控能力的?  2.先搂一眼EndPoint 首先我们找一个EndPoint来看看,此处以HealthEndPoint为例。点看源码我们可以看到这个EndPoint被@EndPoint注解所注释,id为health。然后其中的2个方法被@ReadOperation所注释:   这里其实猜都能猜到被@EndPoint注解,然后被注解的类被归类为EndPoint,然后被集中暴露出去,变成可访问的。  3.EndPoint如何被注入 我们是通过stater来引入actuator的,Spring Boot体系内如何注入stater的?那肯定是通过autoConfiguration来的撒。点进actuator的配置文件也可以看到:   于是我们来到spring-boot-starter-actuator来看看,看看它的spring.factories里面注入了些什么:  见名知意了,这些众多的XXXautoConfiguration是拿来做什么的就不必多说了吧,health、metrics......分门别类,各种EndPoint的autoConfiguration。   我们来看看HealthEndpointAutoConfiguration里面做了什么:  其实就是加载了HealthEndpointConfiguration、ReactiveHealthEndpointConfiguration、HealthEndpointWebExtensionConfiguration、HealthEndpointReactiveWebExtensionConfiguration这几个类  @Configuration(     proxyBeanMethods = false ) @ConditionalOnAvailableEndpoint(     endpoint = HealthEndpoint.class ) @EnableConfigurationProperties({HealthEndpointProperties.class}) @Import({HealthEndpointConfiguration.class, ReactiveHealthEndpointConfiguration.class, HealthEndpointWebExtensionConfiguration.class, HealthEndpointReactiveWebExtensionConfiguration.class}) public class HealthEndpointAutoConfiguration {     public HealthEndpointAutoConfiguration() {     } } 我们先看HealthEndpointConfiguration,它里面向IOC中注入了health的Registry,HealthContributorRegistry中注册了HealthContributor类型的实体。   我们随便打开一个health的EndPoint,发现它都继承同一个父类:   而这个父类实现了HealthContributor接口:   所以其实就是在将注册器注入IOC的时候,就将所有属于该类型的EndPoint注册到注册器中了。  4.EndPoint如何被暴露 4.1.如何通过http暴露 在SpringBoot体系中,谁来负责http请求?那当然是SpringMVC的DispatcherServlet。把path和对应处理的类注册到DispatcherServlet中就行了。spring actuator就是这样对外通过HTTP的方式暴露EndPoint的。  回到spring.factories,找ManagementContextAutoConfiguration,这个类中完成了通过HTTP的方式来暴露EndPoint的过程:   这个类的代码并不多,我们去掉不要的部分,把和对外暴露EndPoint相关的代码保留,来读一下:  @ManagementContextConfiguration(     proxyBeanMethods = false ) @ConditionalOnWebApplication(     type = Type.SERVLET )//只能在Web环境中生效 public class ServletEndpointManagementContextConfiguration {     public ServletEndpointManagementContextConfiguration() {     } ​     @Configuration(         proxyBeanMethods = false     )     @ConditionalOnClass({DispatcherServlet.class})//当SpringMVC存在时向IOC中注入     public static class WebMvcServletEndpointManagementContextConfiguration {         public WebMvcServletEndpointManagementContextConfiguration() {         }         @Bean         public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties, ServletEndpointsSupplier servletEndpointsSupplier, DispatcherServletPath dispatcherServletPath) {             return new ServletEndpointRegistrar(dispatcherServletPath.getRelativePath(properties.getBasePath()), servletEndpointsSupplier.getEndpoints());//核心的一步,将EndPoint和对于的Path注册给DispatcherServlet         }     } }  最后就是开头我们看见的在HealthEndPoint被@ReadOperation注解的方法,就相当于@RequetMapping,拿来处理读请求的。  4.2.如何通过jmx暴露 jmx的对外暴露更简单。直接找JmxEndpointAutoConfiguration:   进去整个逻辑一目了然,去扫Jmx的EndPoint然后注册进mBeanServer里:   5.EndPoint是怎么实现监控能力的 spring actuator获取各种监控的值是怎么获取到的?  内置指标获取: Spring Boot 提供了一些内置的监控指标获取器,用于获取常见的监控数据,比如 JVM 内存使用情况、系统负载、数据库连接池状态等。这些指标获取器会周期性地获取数据,并将其暴露为 Actuator 端点,以便外部系统或者工具可以通过相应的接口来获取。例如,MemoryHealthIndicator 获取 JVM 内存使用情况,DataSourceHealthIndicator 获取数据库连接池状态等。  自定义指标获取: 除了内置的指标获取器外,开发者还可以通过实现 HealthIndicator 接口来自定义监控指标获取器,用于获取应用程序特定的监控数据。HealthIndicator 接口定义了一个 health() 方法,用于返回健康状态信息。开发者可以在 health() 方法中编写自定义的监控逻辑,比如检查某个依赖服务的可用性、计算某个指标的值等。  JMX 获取: Spring Actuator 还可以通过 Java Management Extensions (JMX) API 来获取一些系统级的监控数据,比如 JVM 运行时信息、操作系统信息等。Spring Actuator 中的一些监控指标获取器会使用 JMX API 来获取数据,然后将其暴露为 Actuator 端点。例如,JvmInfoContributor 使用 JMX API 来获取 JVM 运行时信息。  系统调用获取: 有些监控数据可能需要通过系统调用来获取,比如获取操作系统的 CPU 使用率、磁盘使用情况等。Spring Actuator 中的一些监控指标获取器会使用系统调用来获取这些数据,然后将其暴露为 Actuator 端点。  6.知道这些的意义是什么 本文是作者java监控系列文章的第三篇,之前两篇文章我们着重讲了java监控的基石——JMX。  【JMX】JAVA监控的基石-CSDN博客  详解tomcat中的jmx监控-CSDN博客  在spring actuator里面我们知道了目前市面上一个成熟的框架是如何通过http、JMX等不同方式来对外暴露监控能力的。基本上走到这里我们就已经对JAVA整个的监控技术体系最核心的部分有了认识了。作为监控框架来说核心点有哪些?无非是:  获取数据  对外暴露口子  监控的核心肯定是怎么获取数据以及如何将获取的数据暴露出去,只要这两点搞定了,后面的对接各种可视化平台就很好办了。所有知道为啥这篇文章为啥要关心spring actuator这些地方了吧,主要是看看实现思想。 ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/Joker_ZJN/article/details/136154345 
  • [技术干货] Spring Cloud与Spring的区别
    前言随着微服务架构的兴起,Spring Cloud逐渐崭露头角,成为了构建分布式系统的重要工具。对于很多初次接触Spring Cloud的开发者来说,可能不太清楚它与传统的Spring框架有何区别。本文旨在探讨Spring Cloud与Spring之间的主要差异。一、Spring框架简介Spring是一个开源的Java平台,它提供了一套全面的编程和配置模型,用于构建企业级应用程序。Spring的核心特性包括依赖注入(DI)、面向切面编程(AOP)、数据访问抽象等。通过Spring,开发者可以更加高效、简洁地开发应用程序。二、Spring Cloud简介Spring Cloud是基于Spring Boot的一套微服务工具集,它提供了一整套微服务解决方案,包括服务发现、配置管理、熔断器、负载均衡等。Spring Cloud的目标是让微服务架构的搭建变得更加简单、快速和可靠。三、Spring Cloud与Spring的主要区别关注点不同:Spring框架主要关注的是应用程序的本身,提供了一系列的基础功能,如依赖注入、事务管理等。而Spring Cloud则更加关注微服务架构中的各个组件和服务之间的通信与协作,为构建分布式系统提供了丰富的工具和解决方案。组件和服务的集成:Spring Cloud集成了许多优秀的开源项目,如Netflix的Eureka、Hystrix、Zuul等,这些组件共同构成了微服务架构的核心部分。而Spring本身并不包含这些组件,需要开发者自行集成。服务治理:Spring Cloud提供了强大的服务治理功能,包括服务发现、配置管理、熔断器、负载均衡等。这些功能使得微服务架构更加健壮、可靠和易于维护。相比之下,Spring本身并不提供这些服务治理功能。部署和扩展性:Spring Cloud的设计初衷就是为了支持快速部署和横向扩展,它允许开发者将应用程序拆分成多个独立的服务,每个服务都可以独立部署和扩展。而传统的Spring应用程序通常需要整体部署,扩展性相对较差。与Spring Boot的整合:Spring Cloud是建立在Spring Boot基础之上的,因此它充分利用了Spring Boot的优点,如自动配置、快速启动等。这使得开发者在构建微服务应用程序时,可以更加高效、简洁地开发、部署和维护。四、总结综上所述,Spring Cloud与Spring的主要区别在于它们的关注点、组件和服务的集成、服务治理、部署和扩展性以及与Spring Boot的整合。Spring Cloud作为一套微服务工具集,为构建分布式系统提供了丰富的解决方案,使得开发者可以更加轻松地应对复杂的业务需求。然而,在使用Spring Cloud时,也需要关注其复杂性、学习曲线和潜在的兼容性问题。因此,在选择使用Spring Cloud还是传统的Spring框架时,需要根据项目的具体需求和团队的实际情况进行权衡。
  • [技术干货] Spring Cloud定位问题思路
    一般来说,问题都不是Spring Cloud 本身的Bug导致的。因此,读者排查问题的思路不妨按照以下步骤展开。 1. 排查配置问题 首先排查配置有无问题,举几个简单的例子。·YAML缩进是否正确 曾经有朋友发现Spring Cloud应用程序无法正常启动,或配置无法正常加载。经笔者协助,发现仅仅是YAML配置文件缩进不正确。类似问题应在编码的过程中严格规避。 配置属性是否正确 配置的属性编写错误,也是一个非常常见的问题。尽管该问题很低级,但从笔者的观察来看,不少初学者都会遇到这类问题。 在很多场景下,这类问题可借助IDE的提示功能来排查--当IDE给出警告或没有自动提示时,应格外注意。·配置属性的位置是否正确 配置属性位置不正确可能会导致应用的不正常。举几个常见的例子。 -应当配置在EurekaClient项目上的属性,配置在了Eureka Server项目上。 -应当写在bootstrap.yml 中的属性,写在了application.yml中,例如:spring: cloud: config: uri: http://localhost:8080/该属性应当存放在bootstrap.yml 中。 -应当写在application.yml的属性,写在了bootstrap.yml中,例如: cureka.client.healthcheck.enabled=true 2排查环境问题 若确认配置无误,即可考虑运行环境是否存在问题。举几个例子:.环境变量 例如Java 环境变量、Maven环境变量以及Docker容器环境变量等。当应用无法正常工作时,应该确保环境变量配置正确。.依赖下载是否完整 曾经有朋友遇到应用无法正常启动的问题,最终发现仅仅是依赖没有下载完整所致。因此,建议在启动应用前,使用以下命令打包,从而确认依赖的完整性。 mvn clean package.网络问题 微服务之间通过网络保持通信,因此,网络常常是排查问题的关键。当问题发生时,可优先排查网络问题。 3.排查代码问题 若经过以上步骤,依然没有定位到Spring Cloud的问题,那么可能是编写的代码出了问题。很多时候,常常因为少了某个注解,或是依赖缺失,而导致了各种异常。在许多场景下,设置合理的日志级别,会对问题的定位有奇效。 4.排查 Spring Cloud自身的问题 若确定不是自身代码问题,就可Debug一下Spring Cloud的代码了。同时,可在 GitHub等平台给Spring Cloud项目组提交Issue,然后参考官方回复,尝试规避相应问题。若问题无法规避,就需要对Spring Cloud进行扩展,或者修复Spring Cloud 的 Bug,从而满足需求。此时,请不要忘记在Spring Cloud的GitHub上Pull Request,协助官方改进Spring Cloud,让Spring Cloud更加完善、稳定。
  • 使用Spring Cloud Bus自动刷新配置
    使用/refresh端点手动刷新配置,但如果所有微服务节点的配置都需要手动去刷新,工作量可想而知。不仅如此、随着系统的不断扩张,会越来越难以维护。因此、实现配置的自动刷新是很有必要的、本节将使用SpringCloud Bus实现配置的自动刷新。 Spring Cloud Bus使用轻量级的消息代理(例如RabbitMQ、Kafka等)连接分布式系统的节点,这样就可以广播传播状态的更改(例如配置的更新)或者其他的管理指令。可将 Spring Cloud Bus想象成一个分布式的Spring Boot Actuator。微服务A的所有实例都通过消息总线连接到了一起,每个实例都会订阅配置更新事件。当其中一个微服务节点的/bus/refresh端点被请求时,该实例就会向消息总线发送一个配置更新事件,其他实例获得该事件后也会更新配置。接下来为项目整合SpringCloud Bus并实现自动刷新。 1.复制项目microservice-config-client-refresh,将ArtifactId修改为microservice-config -client-refresh-cloud-bus。 2.为项目添加spring-cloud-starter-bus-amqp的依赖。 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId></dependency> 3.在bootstrap.yml中添加以下内容: spring:    rabbitmq:    9.9     port: 5672    host: localhost         username: guest        password: guest这样代码就改造完成了。测试:1.启动 microservice-config-server 如下的内容。    2启动 microservice-config-client-refresh-cloud-bus,可发现此时控制台会输出类似     [ main] o.s.b.a.e.mvc.EndpointHandlerMapping    :Mapped"{[/bus/     refresh],methods=[POST]}" onto public void org.springframework.cloud.bus.endpoint.RefreshBusEndpoint.refresh( java.lang.String)由结果可知,此时项目有一个/bus/refresh端点。 3.将 microservice-config-client-refresh-cloud-bus的端口改为8082,再启动一个节点。 4.访问http://localhost:8081/profile,可获得结果:dev-1.0。 5.将Git 仓库中的 microservice-foo-dev.properties 文件内容修改为如下内容。 profile=dev-1.0-bus 6.发送 POST 请求到其中一个Config Client实例的/bus/refresh端点,例如: curl-X POST http://localhost:8081/bus/refresh 7.访问两个ConfgClient节点的/profle端点,发现两个节点都会返回dev-1.8-bus,说明配置内容已被刷新。 借助Git 仓库的 WebHooks,即可轻松实现配置的自动刷新,
  • [技术干货] spring cloud config统一管理微服务配置
    为什么要统一管理微服务配置 对于传统的单体应用,常使用配置文件管理所有配置。例如一个Spring Boot开发的单体应用,可将配置内容放在application.yml文件中。如果需要切换环境,可设置多个Profile,并在启动应用时指定spring.profiles.active={profile}。当然也可借助Maven的 Profile实现环境切换。 然而,在微服务架构中,微服务的配置管理一般有以下需求: ·集中管理配置。一个使用微服务架构的应用系统可能会包含成百上千个微服务,因此集中管理配置是非常有必要的。 .不同环境,不同配置。例如,数据源配置在不同的环境(开发、测试、预发布、生产等)中是不同的。 ·运行期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连接池大小或熔断阈值,并且在调整配置时不停止微服务。.配置修改后可自动更新。如配置内容发生变化,微服务能够自动更新配置。 综上所述,对于微服务架构而言、一个通用的配置管理机制是必不可少的,常见做法是使用配置服务器管理配置。 Spring Cloud Config为分布式系统外部化配置提供了服务器端和客户端的支持,它包括Config Server和Config Client两部分。由于Config Server和Config Client 都实现了对 Spring Environment和PropertySource抽象的映射,因此,SpringCloud Config非常适合 Spring应用程序,当然也可与任何其他语言编写的应用程序配合使用。 Config Server是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用Git存储配置内容(也可使用Subversion、本地文件系统或Vault存储配置,限于篇幅,本书不作讨论),因此可以很方便地实现对配置的版本控制与内容审计。 Config Client是Config Server的客户端,用于操作存储在Config Server中的配置属性。各个微服务在启动时,会请求Config Server 以获取所需要的配置属性,然后缓存这些属性以提高性能。 
  • [技术干货] 【SpringCloud】这一次终于使用MQ解决了Eureka服务下线延迟感知问题-转载
     前言 其实,“通过Redis手动更新Ribbon缓存来解决Eureka微服务架构中服务下线感知的问题”是一种解,但不是最优解  1.痛点 上一篇文章的标题是: 通过Redis手动更新Ribbon缓存来解决Eureka微服务架构中服务下线感知的问题 当时在文章的末尾就指出,使用Redis+AOP的方式有很多漏洞,只有在服务调用方发送调用请求的情况下才会触发切面中更新Ribbon缓存的逻辑。如果每次在发布Eureka新服务的场景下,告警的接口都能准确定位到,那将这些接口方法通过切面去针对性的加上更新Ribbon缓存的前置操作完全是没问题的。但是如果告警接口数量众多,并且无法定位,上述方法就有些不够看了。  2.解决方案 于是,基于此种困境,我想到了用mq的事件驱动模式来推进Ribbon缓存更新(“下线”这一事件驱动,而不是“发送跨服务调用请求”这一事件),具体如下:  即,当服务被调用方中调用了下线接口下线了指定服务,会生产消息到MQ里,服务被调用方会监听这个队列去消费消息,并通过消费消息这一事件(消费下线服务端口信息)去驱动更新Ribbon缓存。 说明: 在以前我觉得用MQ不能做下线,压测了很多次也没成功,这本质还是没搞懂Eureka-Server,Eureka-Client,Ribbon三者的关系和之间的动作,其实这个体系里有两个非常关键的点(在配置文件中设置),可以直接影响无感知下线的结果,需要动态调整:那就是要关闭Eureka-server的三级缓存useReadOnlyResponseCache: false,并且缩短Eureka-Client端向Eureka-server端拉取服务列表的时间registry-fetch-interval-seconds: 3。可能这里大家看到去改配置有点鸡肋并且在实际场景中也不太现实,但别急,暂时先往下看,后面我会专门写一篇文章来解决这一问题  3.具体实现 3.1配置RabbitMQ 1.配置RabbitMQ(安装这些大家可以去看看平台比较成熟的文章)这里就不写了,我是直接在服务器上用docker容器化运行的:  在调用方与被调用方都配好MQ  3.2生产下线消息 首先声明一个队列:  @Configuration @EnableRabbit public class RabbitMqConfig {     @Bean     public Queue theQueue() {         return new Queue("SERVER_LIST");     } } 服务下线接口处,生产下线消息到MQ,向这接口/service-down-list发送GET请求,传递指定的下线服务实例信息即可下线服务,即http://localhost:8081/control/service-down-list?portParams=8083就下线了8083服务实例      @Value("${eureka-server.ipAddress}")     private String ipAddress;     @Value("${eureka-server.appName}")     private String appName;     @Value("${DIY_QUEUE.VALUE}")     private String queueName;     @GetMapping(value = "/service-down-list")     public String offLine(@RequestParam List<Integer> portParams) {         List<Integer> successList = new ArrayList<>();         //得到服务信息         List<InstanceInfo> instances = eurekaClient.getInstancesByVipAddress(appName, false);         List<Integer> servicePorts = instances.stream().map(InstanceInfo::getPort).collect(Collectors.toList());          //去服务列表里挨个下线         OkHttpClient client = new OkHttpClient();         log.error("开始时间:{}", System.currentTimeMillis());         portParams.parallelStream().forEach(temp -> {             if (servicePorts.contains(temp)) {                 String url = "http://" + ipAddress + ":" + temp + "/control/service-down";                 try {                     Response response = client.newCall(new Request.Builder().url(url).build()).execute();                     if (response.code() == 200) {                         log.debug(temp + "服务下线成功");                         successList.add(temp);                     } else {                         log.debug(temp + "服务下线失败");                     }                 } catch (IOException e) {                     log.error(e.toString());                 }             }         });         //todo MQ通知         HashMap<String, List<Integer>> portInfo = new HashMap<>();         portInfo.put(appName,successList);         rabbitTemplate.convertAndSend(queueName,portInfo);         return successList + "优雅下线成功";     } 这里向MQ的队列里传递了下线的服务实例端口信息  3.3更新Ribbon缓存 服务调用方通过“下线“这一事件驱动Ribbon缓存更新  /**  * 消费者  */ @Slf4j @Component public class Consumer {      @Resource     SpringClientFactory springClientFactory;     @Resource     ClearRibbonCacheBean clearRibbonCacheBean;      @RabbitListener(queues = "SERVER_LIST")     public void listenWorkQueue1(HashMap<String, List<Integer>> message) {         log.debug("消费者1接收到消息——" + message + "时间为:" + LocalTime.now());         for (String key : message.keySet()) {             List<Integer> value = message.get(key);             log.debug("Key: " + key);             log.debug("Value: " + value);             if (ObjectUtils.isNotEmpty(value)) {                 clearRibbonCacheBean.clearRibbonCache(springClientFactory, value.toString(), key);             }             log.debug("现在的所有服务列表:{}", springClientFactory.getLoadBalancer(key).getAllServers());         }     } } 清理Ribbon缓存的Bean:  /**  * 手动清除Ribbon缓存  */ @Configuration @Slf4j public class ClearRibbonCacheBean {     /**      * 削减      */     public static boolean cutDown(List<Integer> ports, Server index) {         return ports.contains(index.getPort());     }      public void clearRibbonCache(SpringClientFactory clientFactory, String portParams,String appName) {         // 获取指定服务的负载均衡器         ILoadBalancer loadBalancer = clientFactory.getLoadBalancer(appName);         //在主动拉取可用列表,而不是走拦截器被动的方式——这里为什么获取可用的之后还要过滤,就是因为所谓的可用不是实时的可用而是缓存中的可用         List<Server> reachableServers = loadBalancer.getReachableServers();//这里从客户端获取,会等待客户端同步三级缓存         //过滤掉已经下线的端口,符合条件端口的服务过滤出来         List<Integer> portList = StringChange.stringToList(portParams);         List<Server> ableServers = reachableServers.stream().filter(temp -> !cutDown(portList, temp)).collect(Collectors.toList());         log.debug("可用服务列表:{}", ableServers);         // 在某个时机需要清除Ribbon缓存         ((BaseLoadBalancer) loadBalancer).setServersList(ableServers); // 清除Ribbon负载均衡器的缓存     } 3.4压测 运行项目,调用下线接口并压测来模拟一下线上场景: 此时我们调用下线接口,下线8083服务实例:  压测结果,均无异常: 观察服务实例的日志输出: 未下线的8081,8084  下线的8083  这说明,Eureka服务下线感知的延迟已经完全被消除  4.优化 以上的MQ还是采用简单队列的模式,即生产者生产一条消息到队列中,该消息也只能被一个消费者消费到。在微服务架构中,用户微服务肯定不只是被单方面调用,而是会被多方调用。那这就要求我们不能单纯只将消息生产到队列里,应该通过广播的模式进行消息的分发。为了更方便交换机与队列的灵活绑定,以及方便扩展,采用Topic话题的模型进行消息的广播:  声明一个新队列:      @Bean     public Queue theQueue() {         return new Queue("USER-QUEUE");     } 将生产消息的地方改为携带一个routingkey并发送到交换机中:    //todo MQ通知   HashMap<String, List<Integer>> portInfo = new HashMap<>();   portInfo.put(appName,successList);   rabbitTemplate.convertAndSend(exchangeName,"USER.SERVICE-DOWN",portInfo);// 这个队列以后可能会发USER话题下的很多信息 1 2 3 4 将消费者端的消息监听器进行改造,变为监听指定话题的消息:   @RabbitListener(bindings = @QueueBinding(             value = @Queue(name = "USER-QUEUE"),             exchange = @Exchange(name = "USER-TOPIC", type = ExchangeTypes.TOPIC),             key = "USER.SERVICE-DOWN")     )     public void listenWorkQueue1(HashMap<String, List<Integer>> message) {         log.debug("消费者1接收到消息——" + message + "时间为:" + LocalTime.now());         for (String key : message.keySet()) {             List<Integer> value = message.get(key);             log.debug("Key: " + key);             log.debug("Value: " + value);             if (ObjectUtils.isNotEmpty(value)) {                 clearRibbonCacheBean.clearRibbonCache(springClientFactory, value.toString(), key);             }             log.debug("现在的所有服务列表:{}", springClientFactory.getLoadBalancer(key).getAllServers());         }     }  ————————————————                              @CSDN-懒羊羊.java的原创                          原文链接:https://blog.csdn.net/weixin_57535055/article/details/135560050 
  • [技术干货] 【SpringCloud Nacos】 微服务治理介绍及Nacos引入初体验 -转载
     前言 在开始今天的学习之前,大家先来思考一个问题:  通过上一章的操作,我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址(ip,端口)等硬编码到了代码中,这种做法存在许多问题:  一旦服务提供者地址变化,就需要手工修改代码; 一旦是多个服务提供者,无法实现负载均衡功能; 一旦服务变得越来越多,人工维护调用关系困难; 那么应该怎么解决呢,这时候就需要通过注册中心动态的实现服务治理。  服务治理介绍 什么是服务治理 服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的自动化注册与发现。  服务注册:在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供服务的详细信息。并在注册中心形成一张服务的清单,服务注册中心需要以心跳的方式去监测清单中的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。 服务发现:服务调用方向服务注册中心咨询服务,并获取所有服务的实例清单,实现对具体服务实例的访问。  通过上面的调用图你会发现,除了微服务,还有一个组件是服务注册中心,它是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者的一个作用。注册中心一般包含如下几个功能:  1、服务发现 服务注册:保存服务提供者和服务调用者的信息; 服务订阅:服务调用者订阅服务提供者的信息,注册中心向订阅者推送提供者的信息; 2、服务配置 配置订阅:服务提供者和服务调用者订阅微服务相关的配置; 配置下发:主动将配置推送给服务提供者和服务调用者; 3、服务健康检测 检测服务提供者的健康情况,如果发现异常,执行服务剔除。 常见的注册中心 Zookeeper Zookeeper 是一个分布式服务框架,是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。  Eureka Eureka 是 SpringCloud Netflix 中的重要组件,主要作用就是做服务注册和发现,但是现在已经闭源。  Consul Consul 是基于GO语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现和配置管理的功能。Consul 的功能都很实用,其中包括:服务注册/发现、健康检查、Key/Value 存储、多数据中心和分布式一致性保证等特性。  Consul 本身只是一个二进制的可执行文件,所以安装和部署都非常简单,只需要从官网下载后,在执行对应的启动脚本即可。  Nacos Nacos 是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它是 SpringCloud Alibaba 组件之一,负责服务注册发现和服务配置,可以这样认为 nacos=eureka+config  Nacos 简介 Nacos 致力于帮助我们发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助我们快速实现动态服务发现、服务配置、服务元数据及流量管理。  从上面的介绍就可以看出, nacos 的作用就是一个注册中心,用来管理注册上来的各个微服务。  Nacos 实战入门 接下来,我们就在现有的环境中加入nacos,并将我们的两个微服务注册上去。  搭建nacos环境 1、安装nacos 下载地址: https://github.com/alibaba/nacos/releases  下载zip格式的安装包,然后进行解压缩操作,下载不下来的可以直接联系阿Q:qingqing-4132  2、配置nacos 将 conf 下的 nacos-mysql.sql 导入数据库   修改 conf 下的 application.properties,添加数据库配置  spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=nacos db.password.0=nacos 1 2 3 4 5 修改bin目录下的 startup.cmd文件,将 set MODE=“cluster” 改为 set MODE=“standalone”  然后在 bin 下启动 nacos,访问地址127.0.0.0:8848/nacos,默认用户名密码nacos,可以在里边创建配置列表  3、访问nacos 打开浏览器输入http://127.0.0.1:8848/nacos/index.html,即可访问服务,默认密码是 nacos/nacos   将商品微服务注册到 nacos 接下来开始修改 shop-product 模块的代码,将其注册到 nacos 服务上  1、在 pom. xml 中添加 nacos 的依赖 <!--nacos客户端--> <dependency>      <groupId>com.alibaba.cloud</groupId>      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>      <version>2.1.0.RELEASE</version> </dependency> 1 2 3 4 5 6 2、在主类上添加 @EnableDiscoveryClient 注解 3、在 application. yml 中添加 nacos 服务的地址 spring:     cloud:         nacos:             discovery:                 server-addr: 127.0.0.1:8848 1 2 3 4 5 4、启动服务, 观察 nacos 的控制面板中是否有注册上来的商品微服务   将订单微服务注册到 nacos 接下来开始修改 shop-order 模块的代码,将其注册到 nacos 服务上,前三个步骤和商品微服务完全相同,此处直接省略。  启动之后如下   实现微服务调用 OrderController 中将请求路径写死变为从nacos中获取,代码如下:  ServiceInstance serviceInstance = discoveryClient.getInstances("shop-product").get(0); String url = serviceInstance.getHost()+":"+serviceInstance.getPort(); //通过restTemplate调用商品微服务 ShopProduct shopProduct = restTemplate.getForObject("http://"+url+"/product/"+pid, ShopProduct.class); Integer count = restTemplate.postForObject("http://"+url+"/product/reduceStock", productReduceDTO, Integer.class); 1 2 3 4 5 DiscoveryClient 是专门负责服务注册和发现的,我们可以通过它获取到注册到注册中心的所有服务。  改好之后再次重启服务,请求地址127.0.0.1:8091/order/2,查看数据库   总结 到这儿,我们的 nacos 入门案例就结束了。下一篇将为大家带来基于nacos的负载均衡和基于feign实现微服务调用的文章,敬请期待吧!  后续的文章,我们将继续完善我们的微服务系统,集成更多的Alibaba组件。想要了解更多JAVA后端知识,请点击文末名片与我交流吧。留下您的一键三连,让我们在这个寒冷的东西互相温暖吧! ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/Qingai521/article/details/135866526