# spring-cloud教程系列 **Repository Path**: xzm-gitee/spring-cloud-parent ## Basic Information - **Project Name**: spring-cloud教程系列 - **Description**: spring-cloud教程系列 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-08-10 - **Last Updated**: 2022-02-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # spring-cloud教程系列 前言, 版本选定 ``` org.springframework.boot spring-boot-dependencies 2.2.2.RELEASE pom import org.springframework.cloud spring-cloud-dependencies Hoxton.SR1 pom import ``` ## Eureka-服务注册与发现 ### Eureka简介 Spring Cloud Eureka是Spring Cloud Netflix 子项目的核心组件之一,主要用于微服务架构中的服务治理。 在微服务架构中往往会有一个注册中心,每个微服务都会向注册中心去注册自己的地址及端口信息,注册中心维护着服务名称与服务实例的对应关系。每个微服务都会定时从注册中心获取服务列表,同时汇报自己的运行情况, 这样当有的服务需要调用其他服务时,就可以从自己获取到的服务列表中获取实例地址进行调用,Eureka实现了这套服务注册与发现机制。 ### 搭建单机版Eureka注册中心 #### 引入Eureka依赖 ``` org.springframework.cloud spring-cloud-starter-netflix-eureka-server ``` #### 启用Euerka注册中心功能 在启动类上面加上```@EnableEurekaServer```注解 ``` @EnableEurekaServer @SpringBootApplication public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class); } } ``` #### 配置Eureka ``` server: port: 8001 spring: application: name: eureka-server eureka: instance: hostname: localhost client: fetch-registry: false register-with-eureka: false ``` - server.port: 指定eureka的端口号 - spring.application.name: 应用名称 - eureka.instance.hostname: 指定主机地址 - eureka.client.fetch-registry: 是否要从注册中心获取服务(注册中心不需要开启) - eureka.client.register-with-eureka: 是否要注册到注册中心(注册中心不需要开启) #### 查看Eureka的web界面 访问地址: http://localhost:8001 ### 搭建集群版的Eureka注册中心 由于所有服务都会注册到注册中心去,服务之间的调用都是通过从注册中心获取的服务列表来调用,注册中心一旦宕机,所有服务调用都会出现问题。所以我们需要多个注册中心组成集群来提供服务 #### 修改host文件 找到 C:\Windows\System32\drivers\etc\ 文件夹, 在文件 **host** 末尾添加如下两行代码 ``` 127.0.0.1 eureka1 127.0.0.1 eureka2 ``` #### eureka-node-1 配置文件 ``` server: port: 8001 spring: application: name: eureka-server-node1 eureka: instance: hostname: eureka1 client: fetch-registry: false register-with-eureka: false service-url: defaultZone: http://eureka2:8002/eureka/ ``` #### eureka-node-2 配置文件 ``` server: port: 8002 spring: application: name: eureka-server-node2 eureka: instance: hostname: eureka2 client: fetch-registry: false register-with-eureka: false service-url: defaultZone: http://eureka1:8001/eureka/ ``` #### 校验集群是否成功 节点1访问地址: http://localhost:8001/ 节点2访问地址: http://localhost:8002/ ### Eureka客户端搭建单节点注册 #### 导入Eureka客户端依赖 ``` org.springframework.cloud spring-cloud-starter-netflix-eureka-client ``` #### 启动Eureka客户端功能 在启动类上加上```@EnableDiscoveryClient```注解 ``` @EnableDiscoveryClient @SpringBootApplication public class ProducerApplication { public static void main(String[] args) { SpringApplication.run(ProducerApplication.class); } } ``` #### 编写单节点注册中心配置文件 ``` server: port: 9000 spring: application: name: producer-server eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8000/eureka/ ``` - eureka.client.register-with-eureka: 是否要从注册中心获取服务 - eureka.client.fetch-registry: 是否要注册到注册中心 - eureka.client.service-url.defaultZone: 注册中心地址 启动客户端之后可以在Eureka的web页面看到服务名就表示已经注册成功了 #### 编写多节点注册中心配置文件 ``` server: port: 9001 spring: application: name: producer-server-register-nodes eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka1:8001/eureka/,http://eureka2:8002/eureka/ ``` ## Ribbon-负载均衡的服务调用 ### Ribbon简介 在微服务架构中,很多服务都会部署多个,其他服务去调用该服务的时候,如何保证负载均衡是个不得不去考虑的问题。负载均衡可以增加系统的可用性和扩展性,当我们使用RestTemplate来调用其他服务时, Ribbon可以很方便的实现负载均衡功能。 ### 导入依赖 ``` org.springframework.cloud spring-cloud-starter-netflix-ribbon ``` ### 配置RestTemplate ``` @Configuration public class RibbonConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } } ``` ### Ribbon常用配置 ``` ribbon: ConnectTimeout: 1000 ReadTimeout: 3000 OkToRetryOnAllOperations: true MaxAutoRetriesNextServer: 1 MaxAutoRetries: 1 ``` - ribbon.ConnectTimeout: 服务请求连接超时时间(毫秒) - ribbon.ReadTimeout: 服务请求处理超时时间(毫秒) - ribbon.OkToRetryOnAllOperations: 对超时请求启用重试机制 - ribbon.MaxAutoRetriesNextServer: 切换重试实例的最大个数 - ribbon.MaxAutoRetries: 切换实例后重试最大次数 - ribbon.NFLoadBalancerRuleClassName: 修改负载均衡算法 ### Ribbon的负载均衡策略 - com.netflix.loadbalancer.RandomRule:从提供服务的实例中以随机的方式; - com.netflix.loadbalancer.RoundRobinRule:以线性轮询的方式,就是维护一个计数器,从提供服务的实例中按顺序选取,第一次选第一个,第二次选第二个,以此类推,到最后一个以后再从头来过; - com.netflix.loadbalancer.RetryRule:在RoundRobinRule的基础上添加重试机制,即在指定的重试时间内,反复使用线性轮询策略来选择可用实例; - com.netflix.loadbalancer.WeightedResponseTimeRule:对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择; - com.netflix.loadbalancer.BestAvailableRule:选择并发较小的实例; - com.netflix.loadbalancer.AvailabilityFilteringRule:先过滤掉故障实例,再选择并发较小的实例; - com.netflix.loadbalancer.ZoneAwareLoadBalancer:采用双重过滤,同时过滤不是同一区域的实例和故障实例,选择并发较小的实例。 ## Hystrix-服务容错保护 ### Hystrix 简介 在微服务架构中,服务与服务之间通过远程调用的方式进行通信,一旦某个被调用的服务发生了故障,其依赖服务也会发生故障,此时就会发生故障的蔓延,最终导致系统瘫痪。Hystrix实现了断路器模式, 当某个服务发生故障时,通过断路器的监控,给调用方返回一个错误响应,而不是长时间的等待,这样就不会使得调用方由于长时间得不到响应而占用线程,从而防止故障的蔓延。 Hystrix具备服务降级、服务熔断、线程隔离、请求缓存、请求合并及服务监控等强大功能。 ### 导入Hystrix依赖 ``` org.springframework.cloud spring-cloud-starter-netflix-hystrix ``` ### 开启服务容错 ```@EnableCircuitBreaker``` ``` @EnableCircuitBreaker @EnableDiscoveryClient @SpringBootApplication public class ProducerApplication { public static void main(String[] args) { SpringApplication.run(ProducerApplication.class); } } ``` ### 编写服务容错的方法 ``` public String handle() { return "服务出错, 已经降级处理"; } ``` ### 调用服务容错 ``` @GetMapping("/error") @HystrixCommand(fallbackMethod = "handle") public String error() { return "现在是【" + port + "】给您提供服务"; } ``` ### @HystrixCommand中的常用参数 - fallbackMethod:指定服务降级处理方法; - ignoreExceptions:忽略某些异常,不发生服务降级; - commandKey:命令名称,用于区分不同的命令; - groupKey:分组名称,Hystrix会根据不同的分组来统计命令的告警及仪表盘信息; - threadPoolKey:线程池名称,用于划分线程池。 ### Hystrix的请求缓存 当系统并发量越来越大时,我们需要使用缓存来优化系统,达到减轻并发请求线程数,提供响应速度的效果。 - @CacheResult:开启缓存,默认所有参数作为缓存的key,cacheKeyMethod可以通过返回String类型的方法指定key; - @CacheKey:指定缓存的key,可以指定参数或指定参数中的属性值为缓存key,cacheKeyMethod还可以通过返回String类型的方法指定; - @CacheRemove:移除缓存,需要指定commandKey。 ### Hystrix请求合并 微服务系统中的服务间通信,需要通过远程调用来实现,随着调用次数越来越多,占用线程资源也会越来越多。Hystrix中提供了@HystrixCollapser用于合并请求,从而达到减少通信消耗及线程数量的效果。 - batchMethod:用于设置请求合并的方法; - collapserProperties:请求合并属性,用于控制实例属性,有很多; - timerDelayInMilliseconds:collapserProperties中的属性,用于控制每隔多少时间合并一次请求; ### Hystrix的常用配置 ``` hystrix: command: default: execution: isolation: strategy: THREAD thread: timeoutInMilliseconds: 1000 interruptOnTimeout: true interruptOnCancel: true timeout: enabled: true semaphore: maxConcurrentRequests: 10 fallback: enabled: true ``` - timeoutInMilliseconds: 执行的超时时间,执行超过该时间会进行服务降级处理 - interruptOnTimeout: 执行超时的时候是否要中断 - interruptOnCancel: 执行被取消的时候是否要中断 - timeout.enable: 是否启用超时时间 - fallback.enabled: 是否启用服务降级 ## Hystrix Dashboard-断路器监控 ### Hystrix Dashboard简介 Hystrix提供了Hystrix Dashboard来实时监控HystrixCommand方法的执行情况。 Hystrix Dashboard可以有效地反映出每个Hystrix实例的运行情况,帮助我们快速发现系统中的问题,从而采取对应措施。 ### 搭建Hystrix Dashboard 导入依赖 ``` org.springframework.cloud spring-cloud-starter-netflix-hystrix-dashboard ``` 开启配置 ``` @EnableHystrixDashboard @EnableDiscoveryClient @SpringBootApplication public class HystrixApplication { public static void main(String[] args) { SpringApplication.run(HystrixApplication.class); } } ``` 访问监控地址: http://localhost:9200/hystrix/ ### Hystrix监控服务 导入依赖 ``` org.springframework.boot spring-boot-starter-actuator ``` 配置Hystrix ``` @Configuration public class HystrixConfig { @Bean public ServletRegistrationBean bean() { HystrixMetricsStreamServlet servlet = new HystrixMetricsStreamServlet(); ServletRegistrationBean bean = new ServletRegistrationBean(servlet); bean.setLoadOnStartup(1); bean.addUrlMappings("/hystrix.stream"); bean.setName("HystrixMetricsStreamServlet"); return bean; } } ``` 查看监控 http://localhost:9000/hystrix.stream ## OpenFeign-声明式服务调用 ### Feign简介 Feign是声明式的服务调用工具,我们只需创建一个接口并用注解的方式来配置它,就可以实现对某个服务接口的调用,简化了直接使用RestTemplate来调用服务接口的开发量。 ### 导入依赖 ``` org.springframework.cloud spring-cloud-starter-openfeign ``` ### 简单跨服务调用 启动类上开启feign的客户端功能: ```@EnableFeignClients``` ``` @EnableFeignClients @EnableDiscoveryClient @SpringBootApplication public class FeignApplication { public static void main(String[] args) { SpringApplication.run(FeignApplication.class); } } ``` 服务接口绑定 ``` @FeignClient(value = "producer-server") public interface ProducerFeign { @GetMapping("/get") public String get(); } ``` 服务调用 ``` @Autowired private ProducerFeign prodducerFeign; @GetMapping("/get") public String get() { return prodducerFeign.get(); } ``` ### feign的常用配置 #### 服务容错降级处理 ``` feign: hystrix: enabled: true ``` 编写一个类继承被绑定的服务接口, 然后在里面实现降级处理 ``` @Component public class ProducerFeignFallback implements ProducerFeign { @Override public String get() { return "系统繁忙, 请稍后再试"; } } ``` 在服务接口配置容错处理 ``` @FeignClient(value = "producer-server", fallback = ProducerFeignFallback.class) public interface ProducerFeign { @GetMapping("/get") public String get(); } ``` #### 超时配置 ``` hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 5000 ribbon: ConnectTimeout: 5000 ReadTimeout: 5000 ``` #### 日志配置 ``` logging: level: com.ming.feign.feign: debug ``` #### feign的拦截器 ``` @Bean public RequestInterceptor requestInterceptor() { return (template -> { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes != null) { HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); if (request != null) { String authorization = request.getHeader("Authorization"); if (authorization != null) { template.header("Authorization",authorization); } } } }); } ``` ## Zuul-服务网关 ### zuul简介 API网关为微服务架构中的服务提供了统一的访问入口,客户端通过API网关访问相关服务。API网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。 它实现了请求路由、负载均衡、校验过滤、服务容错、服务聚合等功能。 ### 导入依赖 ``` org.springframework.cloud spring-cloud-starter-netflix-zuul ``` ### API路由 #### 配置文件 ``` server: port: 80 spring: application: name: zuul-server eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8000/eureka/ ``` #### 开启api路由功能 ``` @EnableZuulProxy @EnableDiscoveryClient @SpringBootApplication public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class); } } ``` #### 配置路由 ``` zuul: routes: open-feign-server: path: /feign/** ``` - open-feign-server: 服务名 - path: 路由规则 ### 过滤器 #### 过滤器类型: zuul的过滤器类型都在```FilterConstants``类里面 - PRE_TYPE: 在请求被路由到目标服务前执行,比如权限校验、打印日志等功能; - ROUTE_TYPE: 在请求被路由到目标服务时执行,这是使用Apache HttpClient或Netflix Ribbon构建和发送原始HTTP请求的地方; - POST_TYPE: 在请求被路由到目标服务后执行,比如给目标服务的响应添加头信息,收集统计数据等功能; - ERROR_TYPE: 请求在其他阶段发生错误时执行。 #### 自定义过滤器 ``` @Component public class LoggerFilter extends ZuulFilter { private Logger logger = LoggerFactory.getLogger(LoggerFilter.class); @Override public String filterType() { return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { return 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); StringBuffer url = request.getRequestURL(); logger.info("url:{}", url); return null; } } ``` ### Ribbon和Hystrix的支持 由于Zuul自动集成了Ribbon和Hystrix,所以Zuul天生就有负载均衡和服务容错能力,我们可以通过Ribbon和Hystrix的配置来配置Zuul中的相应功能。 使用Hystrix的配置来设置路由转发时HystrixCommand的执行超时时间 ``` hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 1000 ``` 使用Ribbon的配置来设置路由转发时请求连接及处理的超时时间 ``` ribbon: ConnectTimeout: 1000 ReadTimeout: 3000 ``` ## Config-集中户配置 ## Bus-消息总线 ## Sleuth-链路追踪 ## Gateway-新一代API网关 ## Oauth2-微服务权限