【SpringCloud】微服务 墨蓝 2022-11-26 09:57 157阅读 0赞 # 一、分布式微服务框架 # ## 1.1 微服务 ## 微服务架构是一种架构风格,它提倡将单一的应用划分为一组小的服务,每个服务都围绕着具体的业务进行构建,服务之间互相协调、互相配合,为用户提供最终价值。每个微服务都运行在其独立的进程中,服务与服务之间采用轻量级的通信机制互相协作。 ## 1.2 分布式 ## 将项目拆分,并部署在不同的服务器上 # 二、什么是 SpringCloud # ## 2.1 SpringCloud 的概念 ## SpringCloud 是分布式微服务架构的一站式解决方案,是多种微服务架构落地技术的几何体,即微服务全家桶 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70][] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 1][] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 2][] ## 2.2 SpringCloud 和 SpringBoot 版本配合选型 ## SpringCloud 的版本号是使用 伦敦地铁站 的方式,即ABCDE.... 的方式,每升级一个版本号,就升级一阶符号 [https://spring.io/projects/spring-cloud\#overview][https_spring.io_projects_spring-cloud_overview] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 3][] 选型提示:[https://start.spring.io/actuator/info][https_start.spring.io_actuator_info] json 工具: [https://tool.lu/][https_tool.lu] ![20200811230107503.png][] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 4][] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 5][] ![20200811230533290.png][] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 6][] # 三、注册中心 # ## 3.1 什么是服务治理 ## SpringCloud 封装了 Eureka 实现服务治理 在传统的 rpc 远程调用框架中,管理每个服务与服务之间的依赖关系比较复杂,故而需要使用到服务治理,即统一管理服务与服务之间的依赖调用关系,可以实现服务调用、负载均衡、容错等,完成服务的发现与注册。 ## 3.2 什么是服务注册与发现 ## ### 3.2.1 Eureka 的角色 ### Eureka 采用了 CS 的设计架构,Eureka Server 作为服务注册功能的服务器,是服务注册中心。而系统中其他的微服务,使用 Eureka 客户端连接到 Eureka Server 并维持心跳连接,这样就实现了系统中各个微服务运行状态的监控。 ### 3.2.2 注册与发现的流程 ### ● **服务注册** Eureka Server 作为一个服务注册中心,当每一个 Eureka 客户端启动后,会将当前自己服务器的信息,如服务地址、通讯地址等以别名的方式(如 cloud-user-order)注册到注册中心上。 ● **服务发现** 服务消费者会以别名方式将自己注册到注册中心上,并去注册中心上获取到实际要调用的服务通讯地址,再通过 rpc 方式远程调用到对应的服务 ● 流程图 * 服务提供者会将自己的服务器信息、地址等以别名注册方式注册到 Eureka Server * 服务消费者会以别名方式,从服务器获取需要调用服务的 RPC 远程调用地址 * 服务消费者服务获取到服务地址后,会缓存在本地 jvm 中,默认每隔 30s 更新一次服务调用地址。通过 rpc 框架,调用服务提供者 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 7][] ### 3.2.3 Eureka 组件 ### **● Eureka Server ** Eureka Server 主要提供服务注册功能,在各个微服务节点启动会,会在 Eureka Server 中注册,Eureka Server 的服务注册表中将存储所有可用服务节点的信息 **● Eureka Client** Eureka Client 是一个 Java 客户端,主要用于与 Eureka Server 交互。同时客户端内置了一个负载均衡器,负责支持负载均衡。同时,在应用启动后,Eureka Client 会给 Eureka Server 发送心跳(默认30s),若 Eureka Server 在多个心跳周期内没有收到某个节点的心跳,则 Eureka Server 会将其中从服务注册表中移除(默认90s) ### 3.2.4 Eureka 高可用 ### Eureka 高可用是通过搭建 Eureka 集群,实现负载均衡、故障容错,来达到高可用的。 Eureka 集群中的节点,互相注册,互相监控,实现集群 ## 3.3 Eureka 集群搭建 ## ### 3.3.1 Eureka Server 集群搭建 ### 增加 maven 配置 <!-- eureka 服务端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> 增加配置文件 application.yml server: port: 7001 eureka: instance: hostname: eureka7001 client: # false 即不像注册中心注册自己 register-with-eureka: false # false 表示自己就是注册中心,不用去检索服务 fetch-registry: false service-url: # 设置与 eureka server 交互的地址,查询服务和注册服务都需要依赖这个地址 # 若是单机版,则配置自己的地址 # 若是集群版,则配置其他 eureka 服务的访问地址 defaultZone: http://eureka7002.com:7002/eureka/ server: port: 7002 eureka: instance: hostname: eureka7002 client: # false 即不向注册中心注册自己 register-with-eureka: false # false 表示自己就是注册中心,不用去检索服务 fetch-registry: false service-url: # 设置与 eureka server 交互的地址,查询服务和注册服务都需要依赖这个地址 # 若是单机版,则配置自己的地址 # 若是集群版,则配置其他 eureka 服务的访问地址 defaultZone: http://eureka7001.com:7001/eureka/ 修改启动类,使用注解 @EnableEurekaServer @SpringBootApplication @EnableEurekaServer public class Eureka02Applicaiton { public static void main(String[] args) { SpringApplication.run(Eureka02Applicaiton.class, args); } } 访问查看(配置了两个,7001 和 7002): [http://eureka7001.com:7001/][http_eureka7001.com_7001] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 8][] [http://eureka7002.com:7002/][http_eureka7002.com_7002] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 9][] ### 3.3.2 Eureka Client 连接集群 ### 添加 maven 配置 <!-- eureka 客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> 修改配置文件 application.yml eureka: client: #表示是否将自己注册进EurekaServer默认为true。 register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka instance: instance-id: consumer9001 修改启动类,添加注解 @EnableEurekaClient @SpringBootApplication @EnableEurekaClient public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } } 进入 Eureka Sever 查看 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 10][] ### 3.3.3 Eureka 负载均衡 ### ● **服务提供者设置集群** 服务提供者要集群,只需要指定相同的服务名即可 spring: application: name: cloud-payment-service ![20200816154833859.png][] ● **服务消费者,使用负载均衡** 当要调用的对应服务也是集群,Eureka Client 本身支持了使用负载均衡方式请求 将原本的调用请求改为调用服务,服务名需要与 Eureka 上显示的相同: public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"; 使用 @LoadBalanced 注解 @Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } } ## 3.4 服务发现 ## 服务发现即消费者能够通过 Eureka Server,获取到对应的服务信息 package com.tom.controller; import com.tom.entity.CommonResult; import com.tom.entity.Payment; import com.tom.service.PaymentService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/pay") @Slf4j public class PaymentController { @Autowired private PaymentService paymentService; @Value("${server.port}") private String serverPort; @Resource private DiscoveryClient discoveryClient; @GetMapping("/discovery") public Object discovery() { List<String> services = discoveryClient.getServices(); for(String service : services) { log.info(" service : "+ service); } List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); for (ServiceInstance instance : instances) { log.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri()); } return this.discoveryClient; } } @SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient public class PayApplication { public static void main(String[] args) { SpringApplication.run(PayApplication.class, args); } } ## 3.5 保护模式 ## ### 3.5.1 概念 ### 保护模式即某时刻某一个微服务不可用了,Eureka 不会立刻清理,依旧会保存该微服务的信息 ![20200816164919292.png][] 一旦进入保护模式,Eureka Server 会尝试保护服务注册表中的信息,不再删除服务注册表中的数据,即不会注销任何服务 ### 3.5.2 作用 ### 防止 EurekaClient 是正常运行,但与 EurekaServer 网络不通,EurekaServer 不会立刻将 EurekaClient 剔除。 ### 3.5.3 关闭保护模式 ### 通过关闭保护模式,Eureka Server 会在一定时间内没有收到服务心跳,就将这个服务从服务注册表中删除 **Eureka Server 配置:** eureka: ...... server: # 关闭自我保护机制,保证不可用服务被及时剔除 enable-self-preservation: false # 设置等待时间,超过等待时间没有收到心跳,则会清除 eviction-interval-timer-in-ms: 2000 ![20200816170153876.png][] **注意!!!** 若是关闭了保护模式,且修改了等待时间,需要对应修改客户端发送心跳包的时间,否则可能存在客户端被误删的情况。**生产环境下不建议关闭保护模式!** **Eureka Client 配置:** eureka: ...... instance: instance-id: payment18001 prefer-ip-address: true # 显示ip地址 # Eureka 客户端想服务器发送心跳的间隔时间,单位为秒(默认是30秒) lease-renewal-interval-in-seconds: 1 # Eureka 服务器在收到最后一次心跳后等待的时间上限,单位为秒(默认是90秒),超时将剔除服务 lease-expiration-duration-in-seconds: 2 ## 3.6 Zookeeper 作为注册中心 ## 由于 Eureka 已经停更,故可以改为 Zookeeper 作为注册中心 ### 3.6.1 配置 zookeeper 项目 ### 增加引入的 pom 依赖: <!-- zookeeper 服务 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency> 修改启动类,使用 @EnableDiscoveryClient @SpringBootApplication @EnableDiscoveryClient public class CloudPaymentZoo { public static void main(String[] args) { SpringApplication.run(CloudPaymentZoo.class, args); } } ### 3.6.2 测试 ### 注册成功后,进入 zkCli.sh ./opt/zookeeper/bin/zkCli.sh 获取节点 ls / ![20200821212437641.png][] 可以看到 services 节点,查看这个节点 ls /services ![20200821212527187.png][] 可以看到服务已经注册到 zookeeper 上了,查看 cloud-payment-zookeeper 节点上存储了什么 ![20200821212624276.png][] ### 3.6.3 使用 ### http://CLOUD-PAYMENT-SERVICE + restapi ## 3.7 Consul 作为注册中心 ## ### 3.7.1 概念 ### Consul 是一个服务网格(即各个微服务间的 TCP/IP,负责服务之间的网络调用、限流、熔断和监控)解决方案,作为注册中心被使用。 ### 3.7.2 特点 ### **● 服务发现(Service Discovery)** Consul 允许通过 dns 或 http 接口的方式来注册服务和发现服务,一些外部的服务能够通过 Consul 很容易找到注册了的服务 **● 健康检查(Health Checking)** Consul 的 Client 可以提供任意数量的健康检查,可以与特定的服务或是本地节点相关联并查看状态,操作员可以通过这些来监视集群的健康状况,服务发现组件可以使用这些信息将不健康的主机路由出去 **● KV存储** 提供了易用的键值存储,结合其他工具可以实现动态配置、功能标记、Leader 选举等 **● 安全服务通信** Consul 可以为服务生成和分发 TLS 证书,以建立相互的 TSL 连接。意图是用于定义允许那些服务通信,服务分割可以很容易地进行管理,目的是可以实时更改,而不是使用复杂的网络拓扑和静态防火墙规则 **● 多数据中心** Consul 支持开箱即用的多数据中心 ### 3.7.3 安装和测试 ### 下载安装包:[https://www.springcloud.cc/spring-cloud-consul.html][https_www.springcloud.cc_spring-cloud-consul.html] # 解压安装包 unzip consul_1.8.3_linux_amd64.zip # 查看命令 ./consul # 查看版本 ./consul --version 运行 @ 运行,并允许任意远端地址访问 ./consul agent -dev --client 0.0.0.0 访问控制台页面 http://xxxxx:8500 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 11][] ### 3.7.4 服务配置 ### 引入 pom 依赖 <!-- consul 服务 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency> 修改配置文件 server: port: 18003 spring: application: name: cloud-payment-consul cloud: consul: host: www.xxxx.com port: 8500 discovery: server-name: ${spring.application.name} 修改启动类 @SpringBootApplication @EnableDiscoveryClient public class CloudPaymentConsul { public static void main(String[] args) { SpringApplication.run(CloudPaymentConsul.class, args); } } ## 3.8 Eureka、Zookeeper、Consul 的区别 ## ### 3.8.1 区别 ### <table> <tbody> <tr> <td style="width:115px;"><strong>组件名</strong></td> <td style="width:85px;"><strong>语言</strong></td> <td style="width:104px;"><strong>CAP</strong></td> <td style="width:139px;"><strong>服务健康检查</strong></td> <td style="width:205px;"><strong>对外暴露接口</strong></td> <td style="width:238px;"><strong>Spring Cloud 集成</strong></td> </tr> <tr> <td style="width:115px;">Eureka</td> <td style="width:85px;">Java</td> <td style="width:104px;">AP</td> <td style="width:139px;">可配置支持</td> <td style="width:205px;">HTTP</td> <td style="width:238px;">已集成</td> </tr> <tr> <td style="width:115px;">Zookeeper</td> <td style="width:85px;">Java</td> <td style="width:104px;">CP</td> <td style="width:139px;">支持</td> <td style="width:205px;">客户端</td> <td style="width:238px;">已集成</td> </tr> <tr> <td style="width:115px;">Consul</td> <td style="width:85px;">Go</td> <td style="width:104px;">CP</td> <td style="width:139px;">支持</td> <td style="width:205px;">HTTP/DNS</td> <td style="width:238px;">已集成</td> </tr> </tbody> </table> ### 3.8.2 CAP ### 一个分布式系统不可能同时满足 CAP,但其中 P 必须满足,故只有 CP 或 AP。其中 AP 的有 Eureka,而 CP 的是 Zookeeper 和 Consul **C:** Consistency 强一致性 必须让数据必须一致,放弃 C 的情况如点赞数等 **A:** Availability 系统可用性 **P:** Partition tolerance 分区容错性 **CP:** 强调必须保证一致性,若服务出现故障,就会拒接请求,但这时候就违背了系统可用性 **AP:**强调系统的高可用性,即允许数据不是强一致的,而是通过其他方式保证数据的最终一致性 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 12][] # 四、Ribbon 负载均衡服务 # ## 4.1 概念 ## Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡和服务调用的工具。Ribbon 客户端组件提供一系列完善的配置项,如连接超时、重试等。简单地说,就是在配合文件中列出参与负载均衡的所有机器,Ribbon 会自动依据负载均衡规则(如简单轮询、随机连接等)去连接这些机器,也支持自定义负载均衡算法。 ## 4.2 Ribbon 工作流程 ## 先选择 EurekaServer,优先选择在同一个区域内负载较少的 server 根据用户指定的负载均衡策略,在从 server 渠道的服务注册列表中选择一个地址进行请求 ## 4.3 Ribbon 本地负载均衡 和 Nginx 负载均衡的区别 ## Nginx 是服务器负载均衡,客户端所有请求都会交给 Nginx,然后由 Nginx 实现转发请求 Ribbon 是本地负载均衡,在调用微服务接口的时候,会在注册中心上获取微服务列表之后缓存到 本地 jvm 中,从而实现本地 RPC 远程服务调用技术 即 Nginx 这一类处理的请求是十分笼统的,而 Ribbon 这是可以精细到某个具体的服务 ## 4.4 配置 Ribbon ## <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> 在 spring-cloud-starter-netflix-eureka-client 中自带了 spring-cloud-starter-ribbon 的引用 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 13][] 也可以自己单独配置 ribbon <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> ## 4.5 核心组件 IRule ## 根据特定算法中从服务列表中选取一个要访问的服务 ### 4.5.1 负载均衡算法 ### <table> <tbody> <tr> <td><strong>类名</strong></td> <td><strong>策略</strong></td> <td style="width:505px;"><strong>描述</strong></td> </tr> <tr> <td>RoundRobinRule</td> <td>轮询</td> <td style="width:505px;">逐一选择地址列表中的路径进行请求</td> </tr> <tr> <td>RandomRule</td> <td>随机</td> <td style="width:505px;">从地址列表中随机选择一个路径进行请求</td> </tr> <tr> <td>RetryRule</td> <td>轮询+重试</td> <td style="width:505px;">先采用轮询策略获取服务,若请求失败则会在指定时间内重试</td> </tr> <tr> <td>WeightedResponseTimeRule</td> <td>权重</td> <td style="width:505px;">对轮询策略的扩展,响应速度越快的实例选择权重越大,越容易被选择到</td> </tr> <tr> <td>BestAvailableRule</td> <td>最可用</td> <td style="width:505px;">先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务</td> </tr> <tr> <td>AvailabilityFilteringRule</td> <td>选择并发量最小</td> <td style="width:505px;">先过滤掉故障实例,再选择并发量较小的实例</td> </tr> <tr> <td>ZoneAvoidanceRule</td> <td>默认规则</td> <td style="width:505px;">复合判断 server 所在区域的性能和 server 的可用性选择服务器</td> </tr> </tbody> </table> ### 4.5.2 修改负载均衡算法 ### 定义使用的负载均衡算法的配置类,不能放置在 @ComponentScan 能够扫到的包下,否则会被所有 Ribbon 客户端共享 新建一个包,放在启动类所属的包外面,如 MyRule.java ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 14][] @Configuration public class MyRule { @Bean public IRule mRule() { return new RandomRule(); // 定义为随机策略 } } 修改主启动类: @SpringBootApplication @EnableEurekaClient // name: 指定哪个服务,configuration: 用哪种策略 @RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyRule.class) public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } } ### 4.5.6 手写轮询负载算法 ### 结构目录,创建了 LoadBalancer 是自己写的负载均衡类,MyLB 则是他的实现类 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 15][] **LoadBalancer.java:** public interface LoadBalancer { ServiceInstance instances(List<ServiceInstance> serviceInstances); } **MyLB.java:** @Component public class MyLB implements LoadBalancer { private AtomicInteger atomicInteger = new AtomicInteger(0); /** * 得到再增加 * do..while 中,使用了自旋锁的方式,即 AtomicInteger,实现设置取值和设置值 * 设置值在 compareAndSet 中实现,使用 cas 算法 * @return */ public final int getAndIncrement() { int current; int next; // 当设置值失败时,不断重新获取,并尝试设置值 do { current = this.atomicInteger.get(); next = current > 2147483647 ? 0 : current+1; }while (!this.atomicInteger.compareAndSet(current, next)); System.out.println("**** next = " + next); return next; } /** * 选出干活的那个服务地址 * @param serviceInstances * @return */ @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { // 获取余数 int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } } **使用:** @RestController public class OrderController { @Resource private RestTemplate restTemplate; @Resource private LoadBalancer loadBalancer; @Resource private DiscoveryClient discoveryClient; @GetMapping("/consumer/payment/lb") public String getPaymentLB() { List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); // 若是无效服务,则返回 if (instances == null || instances.size() <= 0) { return null; } // 若服务有效,则选择出实际要调用的服务实例 ServiceInstance serviceInstance = loadBalancer.instances(instances); URI uri = serviceInstance.getUri(); return restTemplate.getForObject(uri + "/pay/lb", String.class); } } # 五、OpenFeign # ## 5.1 概念 ## OpenFeign 是一个声明式的 webservice 客户端,通过定义一个服务接口,然后在上面添加注解实现服务之间的调用。可以与 Eureka 和 Ribbon(OpenFeign 已内置) 组合使用以支持负载均衡。 ## 5.2 Feign 和 OpenFeign 的区别 ## <table> <tbody> <tr> <td style="width:96px;"> </td> <td style="width:395px;"><strong>Feign</strong></td> <td style="width:416px;"><strong>OpenFeign</strong></td> </tr> <tr> <td style="width:96px;"><strong>描述</strong></td> <td style="width:395px;">Feign 是 SpringCloud 组件中的一个轻量级的 RESTful 的 HTTP 服务客户端,内置了 Ribbon。</td> <td style="width:416px;">Open Feign 是 SpringCloud 在 Feign 的基础上又支持了 SpringMVC 的注解,如 @RequestMapping 等,通过 OpenFeign 的 @FeignClient 解析 @RequestMapping 注解下的接口,并使用动态代理的方式产生实现类,在实现类中做负载均衡并调用其他服务</td> </tr> <tr> <td style="width:96px;"><strong>使用方式</strong></td> <td style="width:395px;">使用 Feign 的注解定义接口,调用这个接口就可以调用服务注册中心的服务</td> <td style="width:416px;">与 Feign 相同</td> </tr> <tr> <td style="width:96px;"><strong>maven 依赖</strong></td> <td style="width:395px;"> <pre><code><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feigh</artifactId> </dependency></code></pre> </td> <td style="width:416px;"> <pre><code><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency></code></pre> </td> </tr> </tbody> </table> ## 5.3 使用 ## ### 5.3.1 示例 ### OpenFeign 是用在消费方的,相比较 RestTemplate + Ribbon 的组合,OpenFeign 的接口对接口的方式无疑更适合程序员使用和理解。 当 Feign 调用的服务是集群的情况下,默认使用轮询策略 先添加 maven 依赖 <!-- eureka 客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- openfeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 修改启动类,加上 @EnableFeignClients @SpringBootApplication @EnableFeignClients public class OrderFeignMain { public static void main(String[] args) { SpringApplication.run(OrderFeignMain.class, args); } } 根据需求,创建对应的 FeignService,使用 @FeignClient 指定要调用 Eureka 上注册的哪个微服务 @Component @FeignClient("CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @RequestMapping("/pay/find/{id}") public CommonResult<Payment> findById(@PathVariable("id") Long id); } 配置文件 application.yml server: port: 9004 spring: application: name: cloud-consumer-order-feign eureka: client: register-with-eureka: false service-url: # 设置与 eureka server 交互的地址,查询服务和注册服务都需要依赖这个地址 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka ### 5.3.2 超时处理和设置 ### 由于 OpenFeign 默认等待一秒钟,若有长业务,则需要在客户端中进行设置 由于 OpenFeign 整合了 Ribbon,故在主配置文件中对 Ribbon 进行设置超时时间 server: port: 9004 spring: application: name: cloud-consumer-order-feign eureka: client: register-with-eureka: false service-url: # 设置与 eureka server 交互的地址,查询服务和注册服务都需要依赖这个地址 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka ribbon: # 建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 ConnectTimeout: 5000 # 建建连接后,从服务器读取到可用资源所用的时间 ReadTimeout: 5000 ## 5.4 日志打印 ## ### 5.4.1 日志级别 ### <table> <tbody> <tr> <td><strong>级别</strong></td> <td style="width:629px;"><strong>描述</strong></td> </tr> <tr> <td><strong>NONE</strong></td> <td style="width:629px;">默认,不显示任何日志</td> </tr> <tr> <td><strong>BASIC</strong></td> <td style="width:629px;">仅记录请求方法、URL、响应状态码及执行时间</td> </tr> <tr> <td><strong>HEADERS</strong></td> <td style="width:629px;">除了 BASIC 中定义的信息,还有请求和响应的头信息</td> </tr> <tr> <td><strong>FULL</strong></td> <td style="width:629px;">在 HEADERS 的基础上,还增加了请求和响应的正文及元数据</td> </tr> </tbody> </table> ### 5.4.2 配置 ### 修改主启动类,增加日志配置 logging: level: # 定义 feign 日志以书面级别监控哪个接口 com.tom.feign.PaymentFeignService: debug 编写配置类 @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } } # 六、服务降级、服务断路 # ## 6.1 概念 ## ### 6.1.1 什么是 Hystrix ### Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,它能够保证在一个依赖调用出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式的弹性 ### 6.1.2 Hystrix 的作用 ### 主要作用是 服务降级、服务熔断以及接近实时的监控 ### 6.1.3 断路器 ### 断路器类似于一种开关装置,当某个服务单元发生故障后,通过断路器的故障监控,向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间地等待或是抛出调用方无法处理的异常。通过这样的方式能够保证服务调用者的线程不会被长时间、不必要地占用,从而避免系统发生更多级联故障,甚至服务雪崩的发生。 ### 6.1.4 服务雪崩 ### 在复杂的分布式体系结构中,应用程序间可能有数十个依赖,每个依赖在某些时候都有可能会失败 多个微服务之间调用的时候,如服务A调用服务B和服务C,服务B和服务C又调用了其他服务,这就称为“扇出”。 若扇出的链路上某个微服务的调用响应时间过长或不可用,则对服务A的调用就会占用越来越多的系统资源,从而引起系统崩溃。 可能造成的影响有: * 服务之间的延迟增加 * 备份队列、线程和其他系统资源紧张 * 导致系统发生更多级联故障 故需要对故障和延迟进行隔离和管理,使得单个依赖关系的失败,不会对系统有巨大的影响 ## ## ### 6.1.5 服务降级(fallback) ### 服务降级即当服务出现故障时,至少有一个保底的处理方案,如给客户端返回友好提示等 发送服务降级的情况: * 程序运行异常 * 超时 * 服务熔断触发服务降级 * 线程池/信号量打满 ### 6.1.6 服务熔断(break) ### 当访问量达到极限值时,直接拒绝访问,然后使用服务降级的方式进行后续处理 ### 6.1.7 服务限流(flow limit) ### 限制通过的请求,一定时间内仅允许指定数量的请求通过,待处理的请求可能等待或是拒绝 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70]: /images/20221124/74f85986010e49929c9450e4e5ed2742.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 1]: /images/20221124/3d93f7ddb0ec4f7caca196419fa93843.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 2]: /images/20221124/05ccb039fc844298bf59d56703c72970.png [https_spring.io_projects_spring-cloud_overview]: https://spring.io/projects/spring-cloud#overview [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 3]: /images/20221124/68e0cb6e00a84ab4843768cbd79c3ac1.png [https_start.spring.io_actuator_info]: https://start.spring.io/actuator/info [https_tool.lu]: https://tool.lu/ [20200811230107503.png]: /images/20221124/1a6b46e65d84456f98c5a4dca7859cdf.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 4]: /images/20221124/0afd013e86424e98acc4f63f4f44cd86.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 5]: /images/20221124/94d38a8f5e8d4fc1a6198541aaae364b.png [20200811230533290.png]: /images/20221124/6cfff818c8104286b9b7f6f4661dd692.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 6]: /images/20221124/264daa71f37e4cf0a10b055c93a28338.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 7]: /images/20221124/e7604ed19cdd4809bd8d205febb33d19.png [http_eureka7001.com_7001]: http://eureka7001.com:7001/ [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 8]: /images/20221124/bdc4b1412ce84dd68de7c5cbe9677fc1.png [http_eureka7002.com_7002]: http://eureka7002.com:7002/ [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 9]: /images/20221124/971743994ca14ce1b3e2d3123325bc69.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 10]: /images/20221124/64e38e4af5814289b80947feec8c220f.png [20200816154833859.png]: /images/20221124/674f219c7cf1496a979e1cab75528072.png [20200816164919292.png]: /images/20221124/77d69de704dc46c895a2c7da5832e90a.png [20200816170153876.png]: /images/20221124/08471f5990d34e4ea1d687cc5fa227db.png [20200821212437641.png]: /images/20221124/15bc550546854d68bce921de80fd3b2e.png [20200821212527187.png]: /images/20221124/ffdd4a47b53446ee99fddda8bdb1fa2f.png [20200821212624276.png]: /images/20221124/27218af0caa64866ba2609f5f627b0a8.png [https_www.springcloud.cc_spring-cloud-consul.html]: https://www.springcloud.cc/spring-cloud-consul.html [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 11]: /images/20221124/cfa02b09b44648a59e113c41750d5482.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 12]: /images/20221124/11220e8f65a94f50a6824e8f2457a4f2.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 13]: /images/20221124/a99acba3d24f4a6a9fffb7bb894a1fc8.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 14]: /images/20221124/b3428b5eb70e46f087c58aa9a742d21f.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NDE2MzMx_size_16_color_FFFFFF_t_70 15]: /images/20221124/fca298fb194d457c8a654694e1de3510.png
还没有评论,来说两句吧...