# spring-cloud-parent **Repository Path**: itblog/spring-cloud-parent ## Basic Information - **Project Name**: spring-cloud-parent - **Description**: No description available - **Primary Language**: Unknown - **License**: Unlicense - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-03-21 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README dependencyManagement Maven 使用dependencyManagement元素来提供了一种管理依赖版本号的方式 通常会在一个组织或者项目的最顶层的父POM中看到dependencyManagement元素 使用pom.xml中的dependencyManagement元素能让所有在子项目中引用一个依赖而不用显示的列出版本号 Maven会沿着父子层向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用这个dependencyManagement元素中指定的版本号 建子模块步骤: 1.建module 2 改pom 3. 写yml 4.主启动 5. 业务类 Eureka服务端搭建步骤: 1.pom.xml org.springframework.cloud spring-cloud-starter-netflix-eureka-server 2.修改application.yml eureka: instance: hostname: localhost #eureka服务端的实例名称 client: #false表示不向注册中心注册自己 register-with-eureka: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: #设置与Eureka Serverqgx的地址查询服务和注册服务都需要依赖这个地址 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 3.启动类添加注解: @EnableEurekaServer 4.启动测试 Eureka客户端搭建步骤: 1.修改pom.xml文件: org.springframework.cloud spring-cloud-starter-netflix-eureka-client 2.修改application.yml: spring: application: name: cloud-order-service eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:7001/eureka 3.启动类添加注解: @EnableEurekaClient 4.启动测试 Eureka集群服务端搭建: 1.修改hosts映射文件: 127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 2.修改application.yml: hostname: eureka7001.com #集群 #hostname: localhost #eureka服务端的实例名称 单机 # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 单机 defaultZone: http://eureka7002.com:7002/eureka/ #集群 集群总结:相互关注,互相守望 Eureka集群客户端搭建: 修改application.yml文件: defaultZone: http://localhost:7001/eureka defaultZone: http://eureka7002.com:7002/eureka,http://eureka7001.com:7001/eureka 负载均衡报错: There was an unexpected error (type=Internal Server Error, status=500). I/O error on GET request for "http://CLOUD-PAYMENT-SERVICE/payment/get/22": CLOUD-PAYMENT-SERVICE; nested exception is java.net.UnknownHostException: CLOUD-PAYMENT-SERVICE 加注解: @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } actuator微服务信息完善 主机名的修改: 修改application.yml: instance: instance-id:payment8001 ip信息提示: prefer-ip-address: true 服务发现Discover ```java @GetMapping("/payment/discovery") public Object discovery(){ List services = discoveryClient.getServices(); for (String service : services) { logger.info("*****service:={}",service); } List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); for (ServiceInstance instance : instances) { logger.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri()); } return this.discoveryClient; } ``` Ribbon在工作时分成两步 第一步:先选择EurakerServer,它优先选择在同一个区域内负载较少的server 第二步:再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址 其中Ribbon提供了多种策略:比如轮询,随机和根据响应时间加权 @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } Ribbon核实组件IRule com.netflix.loadbalance.RoundRobinRule 轮询 com.netflix.loadbalance.Random 随机 com.netflix.loadbalance.RetryRule 重试 WeightedResponseTimeRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,如果获取服务失败,则在指定时间内会进行重试,获取可用的服务 BestAvilableRule 先过滤掉故障实例,再选择并发较小的实例 ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器 如何替换 启动类添加注解: @RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class) 新建类: ```java @Configuration public class MySelfRule { @Bean public IRule myRule(){ return new RandomRule(); //定义为随机 } } ``` 访问地址: http://localhost//consumer/payment/getForEntity/22 负载均衡算法:rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始 手写一个负载的算法: 1. @GetMapping("/payment/lb") public String getPaymentByLB(){ return serverPort; } 2.去掉@LoadBalanced 3.客户端: ```java @GetMapping("/consumer/payment/lb") public String getPaymentLB(){ List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); if(instances == null || instances.size()<0){ return null; } ServiceInstance instances1 = loadBalance.instances(instances); URI uri = instances1.getUri(); return restTemplate.getForObject(uri+"/payment/lb",String.class); } ``` Feign和OpenFeign的关系 Feign是一个声明式WebService客户端,使用Feign能让编写web service客户端更加简单 他的使用方法是定义一个服务接口然后在上面添加注解,Feign也支持可拨插式的编码器和解码器,Spring Cloud对Feign进行了封装 ,使其支持Spring MVC标准注解和HttpMessageConverters.Feign可以与Eureka和Ribbon组合使用以支持负载均衡 Feign能干什么 Feign旨在使编写Java Http客户端变得更容易 前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模板化的调用方法,但是在实际开发中 ,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务 的调用。所以,Feign在此基础上做了进一步封装,由于他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需要创建 一个接口并使用注解的方式来配置它(以前是Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成 对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量 Feign集成了Ribbon 利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明的方法 ,优雅而简单的实现了服务调用。 OpenFeign 接口加注解 1.修改 pom.xml org.springframework.cloud spring-cloud-starter-openfeign 2.主启动类添加注解: @EnableFeignClients 3.新建接口: ```java @Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id); } ``` 4.控制层Controller ```java @RestController @Slf4j public class OrderFeignController { // public static final Logger logger = LoggerFactory.getLogger(OrderFeignController.class); @Autowired private PaymentFeignService paymentFeignService; @GetMapping(value = "/consumer/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id){ return paymentFeignService.getPaymentById(id); } } 5.测试地址: http://localhost//consumer/payment/get/22 OpenFeign超时控制 ribbon: ReadTimeout: 5000 ConnectTimeout: 5000 OpenFeign的日志打印功能 Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节 说白了就是对Feign接口的调用情况进行监控和输出 Histrix是一个用于处理分布式系统的延迟和容错开源库,在分布式系统里,许多 依赖不可避免的会调用失败,比如超时,异常等 Hystrix能够保证在一个依赖出问题 的情况下,不会导致整体服务失败,避免级联故障监控(类似熔断保险丝),向调用方返回一个符合预期 的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法下得的异常,这样就保证了服务调用方的线程不会被长时间, 不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。 http://github.com/Netflix/Hystrix 1.服务降级:服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示:fallback 出现情况: 程序运行异常 超时 服务熔断触发服务降级 线程池/信号量打满会导致服务降级 2.服务熔断:类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法 就是保险丝 3.服务限流:秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒种N个,有序进行 添加插件: 1.修改pom.xml org.springframework.cloud spring-cloud-starter-netflix-hystrix 2. 解决:对方服务8001超时,宕机,调用都80自身出故障,必须有服务降级 ```java //服务熔断 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value="true"),//是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//请求次数 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),//时间窗口期 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value="60")//失败率达到多少后跳闸 }) public String paymentCircuitBreaker(@PathVariable("id") Integer id) ``` 涉及到断路器的三个重要参数:快照时间窗、请求总数阈值,错误百分阈值 1:快照时间窗口:断路器确定是否打开需要统计一结请深圳市和错误数据,而统计的时间是快照时间窗,默认为最近的10秒 2.请求总数阈值:在快照时间窗内,必须满足请求总数阈值才有资格熔断,默认为20,意味着在10秒内,如果该 hystrix命令的调用次数不足20次 即使所有的请求都超时或其他原因失败,断路器都不会打开 3.错误百分比阈值:当请求总数在快照时间窗内超过了阈值,比如发生了30次调用,如· 果在这30次调用 中有15次发生了超时异常,也就是超过了50%的错误百分比,在默认设定 GateWay Springcloud Gateway使用的是webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架 Spring Cloud Gateway具有如下特性: 基于Spring Framework 5,Project Reactor和Spring Boot 2.0进行构建 动态路由:能够匹配任何请求属性 可以对路由指定Predicate(断言)和Filter(过滤器) 集成Hystrix的断路器功能 集成Spring cloud服务发现功能 易于编写Predicate(断言)和Filter(过滤器) 请求限流功能 支持路径重写 配置中心客户端: application.yml 是用户级别的资源配置项 bootstrap.yml是系统级的,优先级更高 Spring Cloud会创建一个Bootstrap Context,作为Spring应用的Application Context的父上下文, 初始化的时候,BootStrap Context负责从外部源加载配置属性并解析配置。这两个上下文共享一个外部获取的Environment Bootstrap属性有高优先级,默认情况下,它们不会被本地配置覆盖。Bootstrap context他Application context有着不同的约定 所以新增了一个bootstrap.yml文件,保证Bootstrap Context和Application context配置的分离 要将Client模块下的application.yml文件改为bootstrap.yml,这是很关键的 因为bootstrap.yml是比application.yml先加载的,bootstrap.yml优先级高于application.yml 客户端动态刷新问题: linux运维修改github上的配置文件内容做调整 刷新3344,发现configServer配置中心立刻响应 刷新3355,发现configclient客户端没有任何响应 3355没有变化除非自己重启或者重新加载 难到每次运维修改配置文件,客户端要重启?噩梦 解决方案: 1.修改pom.xml org.springframework.boot spring-boot-starter-actuator 2.修改bootstrap.yml 暴露监控端点 management: endpoints: web: exposure: include: "*" 3.Controller增加@RefreshScope注解 4.运维人员刷新URL curl -X POST "http://localhost:3355/actuator/refresh" zipkin: http://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/ https://nacos.io/zh-cn/docs/nacos-spring.html Spring Cloud Alibaba(一) 如何使用nacos服务注册和发现 ````java Exception in thread "main" java.lang.UnsupportedClassVersionError: org/springfra mework/boot/loader/PropertiesLauncher : Unsupported major.minor version 52.0 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:800) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:14 2) at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) at java.net.URLClassLoader.access$100(URLClassLoader.java:71) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482) ```` 解决方案 配置java_home,增加jdk1.8环境变量,怎么添加环境变量需要自行百度,以下贴出我的java环境变量 ``` C:\Users\Administrator>set java_home JAVA_HOME=D:\Program Files\Java\jdk1.7.0_71 C:\Users\Administrator>set java8_home JAVA8_HOME=D:\Program Files\Java\jdk1.8.0_201 C:\Users\Administrator> ``` 调整startup.cmd脚本,使用java8_home变量,使它能正确调用jdk1.8而非jdk1.7,以下是调整部分代码 ``` if not exist "%JAVA8_HOME%\bin\java.exe" echo Please set the JAVA8_HOME variable in your environment, We need java(x64)! jdk8 or later is better! & EXIT /B 1 set "JAVA=%JAVA8_HOME%\bin\java.exe" ``` 这里只做个替换,把原来的JAVA_HOME规划成JAVA8_HOME,运行startup.cmd,此时能正确运行Nacos服务了 http://localhost:8848/nacos nacos集群和持久化配置(重要) 1. 执行nacos/conf/nacos-mysql.sql的SQL语句 2.修改application.properties配置文件: ``` #--------------------- #derby数据库切换到mysql数据库配置 spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true #db.url.1=jdbc:mysql://11.163.152.9:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true db.user=root db.password=123456 ``` 3.重启服务 集群配置: 1个nginx+3个nacos注册中心+1个mysql 最好linux做集群。 步骤: 1.修改cluster.conf.example 2.修改application.properties配置文件: 3.修改startup.sh 适应启动格式:startup.sh -p3355端口号形式 第57行: 修改前: export FUNCTION_MODE="all" while getopts ":m:f:s:" opt do 修改后: export FUNCTION_MODE="all" while getopts ":m:f:s:p:" opt do 65行 改前: s) SERVER=$OPTARG;; ?) 改后: s) SERVER=$OPTARG;; p) PORT=$OPTARG;; ?) 132行: 改前: nohup $JAVA ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 & 改后: nohup $JAVA -Dserver.port=${PORT} ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &