SpringCloud Netflix-springcloudnetflix(一)https://developer.aliyun.com/article/1469568
Eureka服务注册与发现
什么是服务治理
springcloud 封装了netflix的Eureka模块实现服务治理
在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂所以需要有一个东西去治理他,管理服务与服务之间的依赖关系,负载均衡,容错等 实现服务发现与注册
这个是有人要问了:什么时服务的注册与发现呢???
问得好,
答案:
Eureka采用了CS也就是服务器和客户端的架构模式,Eureka Server作为服务注册中心,来管理微服务,也可以理解成用springboot来开发的一个个微服务,他们在Eureka的位置就是Eureka client,他们用心跳来告诉服务端自己是可以用的
我们可以用Eureka server就可以监控各个微服务的状态,同时也有一系列的保证机制,比如心跳检测,
我们的服务提供者和消费者的例子就是这样的,
服务提供者:在启动后将把自己当前的信息,通讯地址等以别名的方式注册到注册中心也就是Eureka server中
消费者:用别名的的形式,去获取服务的信息和通讯地址,之后实现本地调用RPC调用框架的设计思想
注册中心负责管理服务之间的依赖关系(服务治理),在任何的远程RPC中都会有一个注册中心,通过注册中心来获取服务的信息和接口地址
下图是脑图中对于Eureka两大组件的作用和功能介绍
- Eureka server
- Eureka client
单项目Eurekademo
老步骤:
- 建模块
- 添加依赖pom
- yml配置文件
- 主启动类
- 业务编码
创建cloud-eureka-server7001模块
之后导入我们要用到的依赖
<dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies>
这里Eureka的服务端新老版本也有变化
之后就是配置了yml
server: port: 7001 eureka: instance: hostname: localhost #eureka服务端的实例名字 client: register-with-eureka: false #表识不向注册中心注册自己 fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
之后的主启动类的编写
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class,args); } }
@EnableEurekaServer
加上个注解就是Eureka的服务端了,我们并不需要写什么业务员,启动之后访问
7001端口就可以看道Eureka的注册中心啦
服务的注册
cloud-provider-payment8001我们的目光回到服务提供者
Eurekashi1 C/S架构
所以我们想要将服务提供者注册道服务中心,还需要导入一个依赖,就是Eureka client的依赖抱
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBh2RWke-1648908821908)(https://cdn.jsdelivr.net/gh/Doomwatcher2004/my-image-host@master/ img /image-20210819230600170.png)]
之后就是配置文件了
eureka: client: register-with-eureka: true fetchRegistry: true service-url: defaultZone: http://localhost:7001/eureka
配置解读:
register-with-eureka:true
表示自己会被注册到服务中心fetchRegistry:true
表示自己不是服务中心,需要检索服务defaultZone
要注册的服务中心的地址
主启动类
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @EnableEurekaClient @SpringBootApplication public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); } }
@EnableEurekaClient
表示自己的客户端,
之后就是测试了
- 先启动注册中心
- 之后启动需要注册的注册中心
- 访问注册中心即可
微服务名称配置
Eureka的自我保护机制
当Eureka一定时间内没有检测到服务的心跳或者短时间内丢失了多个服务,那么服务端就会认为是网络故障或者是一系列i意外的发生
此时不应该注销任何的服务。同时新的服务也可以继续进来,
设计哲学
好死不如赖活着
Eureka宁可保护错误的服务信息,也不会去轻易的注销服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KVWJjlqP-1648908821910)(https://cdn.jsdelivr.net/gh/Doomwatcher2004/my-image-host@master/ img /image-20210819233339779.png)]
Eureka集群原理
Eureka集群原理说明:
搭建注册中心集群
参考我们的注册中心7001,搭建一个一模一样的注册中心
在搭建之前请去修改一下映射文件,
找到C:\Windows\System32\drivers\etc路径下的hosts文件,修改
因为我们之前使用都是一个单机的项目,我们要集群那么不能使用 localhost,他会被识别成一样的路径
我们修改一些映射
如:
- 127.0.0.1 eureka7001.com
- 127.0.0.1 eureka7002.com
本质还是localhost但是却是两个不一样的映射
导入和7001相同的依赖
之后分别修改
7001配置文件
server: port: 7001 eureka: instance: hostname: eureka7001.com #eureka服务端的实例名字 client: register-with-eureka: false #表识不向注册中心注册自己 fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 service-url: defaultZone: http://eureka7002.com:7002/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
7002
server: port: 7002 eureka: instance: hostname: eureka7002.com #eureka服务端的实例名字 client: register-with-eureka: false #表识不向注册中心注册自己 fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 service-url: defaultZone: http://eureka7001.com:7001/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
集群其实就是一句话:相互守望,
之后我们还要修改一下 服务提供者 8001的注册地址,他现在同时需要注册到两个注册中心去
service-url: defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
测试:
- 先要启动EurekaServer,7001/7002服务
- 再要启动服务提供者provider,8001服务
- 再要启动消费者,80
- http://localhost/consumer/payment/get/1
查看结果即可
支付服务提供者8001集群环境构建
同上搭建一个除了端口号和8001一抹一样的模块
cloud-provider-payment8002
Ribbon 负载均衡
现在的RIbbon已经进入维护模式了
现有他的代替解决方案是
LB(负载均衡)
负载均衡分类
集中式LB
即在服务的消费方和提供方之间使用独立的LB设施,(可以是硬件,如f5,也可以是软件,如nginx),由该设施负责把访问请求通过某种请求策略转发至服务的提供方;
进程内LB
将L B逻辑集成在消费方,消费方从服务注册中心获取那些地址可用,让后自己再从这些地址选择出一个合适的服务器.
Ribbon 就是属于进程内LB,他只是一个类库,集成于消费房的进程,消费房通过他来获取到服务器的提供方地址
Ribbon能够做些什么
就是在消费者中对服务提供者进行负载均衡操作,
默认是轮询的方式,
1 2 3 再来一遍 1 2 3
负载均衡+RestTemplate调用架构说明
总结:
Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。
我们之前导入的 Netflix-Eureka的jar包中包含了 ribbon 新版本不包含,
现在的最新版本 h12 Ribbon 以被上图提到的 lb给代替了(之前全部最新版的时候踩到的坑)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s1Y5cCOF-1648908821913)(https://cdn.jsdelivr.net/gh/Doomwatcher2004/my-image-host@master/ img /image-20210831160552808.png)]
再次复习RestTemplate 的使用
getForObject方法/getForEntity方法
postForObject/postForEntity
开启负载均衡
默认的开启负载均衡操作就一个注解
在你的消费者config中的restTemoplate上添加一个注解
@Configuration public class orderConfig { @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
这样就开启的Ribbon的默认轮询的负载均衡
IRule:根据特定算法从服务列表中选取一个要访问的服务,用哪一种方式做负载均衡
我们首先要强调一下配置细节
如果我们想改变默认的负载均衡算法我们需要在 这样建立一个新包
主启动类在cloud的中,所以他会扫描cloud下所有的子包
接下来是自定义负载均衡的规则编写(使用起来越方便的,他的底层就越精妙)
@SpringBootApplication @EnableEurekaClient @RibbonClient(value = "CLOUD-PAYMENT-SERVICE",configuration = Myselgrule.class ) public class orderMain { public static void main(String[] args) { SpringApplication.run(orderMain.class,args); } }
添加了这个之后我们要使用自己设置的规则我们需要使用到注解@RibbonClient
在主启动类上添加这个注解 ,并且设置两个参数
value:需要负载均衡的服务名
configuration : 要使用的规则类 Myselgrule.class
即可
Ribbon负载均衡算法(这里由于算法实在不是咱的擅长就跳过了手写算法那个一节课)
轮询算法原理
openFeign
链接:https://github.com/spring-cloud/spring-cloud-openfeign
Feign是什么?
Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可.
Feign能干什么?
使用Feign可以让我们在编写java HTTP客户端的时候变得更加的容易
我们在之前的项目中使用的是Ribbon + Resttemplate的时候,利用Resttemplate对请求的封装处理,形成了一套模版话的调用方法,但是实际开发中,由于对服务的依赖调用可能不止一处,往往一个接口要被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装.这个依赖服务的调用.所以,Feign在此基础上,做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义.在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置他(以前是dao接口上面标注mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用spring cloud ribbon 时候,自动封装服务调用客户端的开发量
同时Feign集成了Ribbon
利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡.而与Ribbon不同的是.通过feign只需要定义服务绑定的接口且以声明式的方法,简单的实现了服务的调用
这个时候有人要提问了
我们学习openFeign和Feign有什么区别嘛,
区别如下
也就是说,我们要使用openFeign需要使用
接口+注解的方式来开发:微服务调用接口+@FeignClient
使用之前强调一点,也是官方文档说的,fegin 在消费端使用
前置知识强调完之后我们开始编码吧!
老规矩,新建一个模块: cloud-consumer-feign-order80
导入相关的依赖
<!--openfeign--> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
底下的依赖是平常的使用的,主要是第一个依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
之后编写配置文件:编写端口和Eureka的相关配置
server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
我们可以学习的时候就发现,我们每次接触到新的组件,主启动类就会多一个新的注解@EnableFeignClients
@SpringBootApplication @EnableFeignClients public class feignOrder80Main { public static void main(String[] args) { SpringApplication.run(feignOrder80Main.class,args); } }
之后就编写业务类就可以了
业务逻辑接口+@FeignClient配置调用provider服务
新建服务层接口
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping("/payment/get/{id}") public CommonResult getPaymentByid(@PathVariable("id") long id); @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout(); }
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
这里是我们需要使用fegin来调用的服务提供者的,服务名称
编写控制层之后测试
@RestController public class openFeginController { @Resource private PaymentFeignService paymentFeignService; @GetMapping("/consumer/payment/get/{id}") public CommonResult getPaymentByid(@PathVariable("id") long id){ System.out.println(id); return paymentFeignService.getPaymentByid(id); } @GetMapping(value = "/consumer/payment/feign/timeout") public String paymentFeignTimeout(){ return paymentFeignService.paymentFeignTimeout(); } }
测试
- 先启动2个eureka集群7001/7002
- 再启动2个微服务8001/8002
- 启动OpenFeign启动
- http://localhost/consumer/payment/get/1
- Feign自带负载均衡配置项
这里是调用的服务名称的对应和服务调用的地址
OpenFeign超时控制
场景演示
超时设置,故意设置超时演示出错情况
服务提供方8001故意写暂停程序
@GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout(){ try { TimeUnit.SECONDS.sleep(3); }catch (Exception e) {e.printStackTrace();} return serverPort; }
服务消费方80添加超时方法PaymentFeignService
@GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout();
服务消费方80添加超时方法OrderFeignController
@GetMapping(value = "/consumer/payment/feign/timeout") public String paymentFeignTimeout(){ return paymentFeignService.paymentFeignTimeout(); }
测试方法
访问延时方法:http://localhost/consumer/payment/feign/timeout
错误页面:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7cjtDIAK-1648908821916)(https://cdn.jsdelivr.net/gh/Doomwatcher2004/my-image-host@master/ img /image-20210905153649722.png)]
OpenFeign默认等待一秒钟,超过后报错,因为集成了ribbon,默认超过一秒钟就会超时
怎么配置呢 ? :我们在yml中配置ribbon的超时即可
ribbon: ReadTimeout: 5000 ConnectTimeout: 5000
OpenFeign日志打印功能
feign支持日志打印功能
我们可以通过日志来获取到feign的http请求中的细节
对使用了feign的接口调用情况监控和输出
opnefeign的日志级别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jm7bL43A-1648908821917)(https://cdn.jsdelivr.net/gh/Doomwatcher2004/my-image-host@master/ img /image-20210905154015536.png)]
要使用opnefeign的日志
我们需要去配置config
package com.atguigu.springcloud.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
之后在yml配置日志的级别
logging: level: com.hyc.springcloud.service.PaymentFeignService: debug
之后查看日志内容
SpringCloud Netflix-springcloudnetflix(三)https://developer.aliyun.com/article/1469570