📝 学技术、更要掌握学习的方法,一起学习,让进步发生
👩🏻 作者:一只IT攻城狮 。
💐学习建议:1、养成习惯,学习java的任何一个技术,都可以先去官网先看看,更准确、更专业。
💐学习建议:2、然后记住每个技术最关键的特性(通常一句话或者几个字),从主线入手,由浅入深学习。
❤️ 《SpringCloud入门实战系列》解锁SpringCloud主流组件入门应用及关键特性。带你了解SpringCloud主流组件,是如何一战解决微服务诸多难题的。项目demo:源码地址
项目demo源码地址:https://gitlab.com/springcloud5521407
文章目录
一、Eureka
Eureka是Netflix开发的服务发现框架
1、Eureka组件
包含两个组件:Eureka Server和Eureka Client。
Eureka Server
提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client
是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器
。
2、Eureka核心功能点:
-
服务注册(register)
:
Client会发送一次Rest请求给Server端来实现注册,Server接受到请求会将服务信息存储起来,并将注册信息给同集群其他Server。 -
服务续约(renew)
:
Client启动的时候,会开启一个定时任务(心跳)周期性发送一次服务续约地Rest请求,证明服务处于可用状态,防止Server剔除掉该可用服务。Eureka Client在默认的情况下会每隔30秒
发送一次心跳来进行服务续约。 -
服务同步(replicate)
Eureka Server之间会互相进行注册,构建Eureka Server集群,不同Eureka Server之间会进行服务信息同步,用来保证服务信息的一致性。 -
获取服务(get registry)
:
Client启动的时候,会开启一个定时任务周期性发送一次获取服务的Rest请求,获取服务信息,然后整合到Client的本地缓存中。Eureka Client在默认的情况下会每隔30秒获取一次Server端服务信息。 -
服务调用
:
服务消费者在获取到服务清单后,可以根据清单中的服务信息,进行远程调用。 -
服务下线(cancel)
当Eureka Client需要关闭或重启时,就会发送Rest请求给Server,Server端收到请求会更改实例状态并实例信息剔除掉,同时同步该服务下线消息给其他Server。 -
服务剔除(evict)
:
有时候,服务实例可能会因为网络故障等原因导致不能提供服务,而此时该实例也没有发送请求给 Server来进行服务下线,所以,还需要有服务剔除的机制。Eureka Server在启动的时候会创建一个定时任务,每隔一段时间(默认30秒),从当前服务清单中把超时没有续约(默认90秒, eureka.instance.leaseExpirationDurationInSeconds)的服务剔除。
自我保护机制:
既然Eureka Server会定时剔除超时没有续约的服务,那就有可能出现一种场景,网络一段时间内发生了异常,所有的服务都没能够进行续约,Eureka Server就把所有的服务都剔除了,这样显然不太合理。所以,就有了 自我保护机制,当短时间内,统计续约失败的比例,如果达到一定阈值,则会触发自我保护的机制,在该机制下, Eureka Server不会剔除任何的微服务,等到服务恢复正常后,再退出自我保护机制。自我保护开关(eureka.server.enable- self-preservation: false)。
综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
小结:
Zookeeper保障的CP
,zk中master有问题会进行选举时时不能对外提供服务的
Eureka 保障的是AP
,Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,节点是平等的,且有自我保护机制,不会立即剔除服务。
二、集成Eureka
1、单机版集成Eureka
上边提到过Eureka有两部分Server和Client,那么我们编写Server端,将两个微服务项目,服务提供者、服务消费者(创建order工程、payment工程)作为Client注册进Eureka,由注册中心进行管理。
1)编写Eureka Server
还是服务开发的基本步骤:新建module(cloud-eureka-server)->改pom(将order工程的pom粘贴进来),同时引入新的Eureka server的依赖->创建yml文件->主启动类:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>3.1.2</version>
</dependency>
application.yml:
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka 服务端的实例名称
client:
register-with-eureka: false #false 表示不想注册中心注册自己
fetch-registry: false #false 表示自己端就是注册中心,维护实例服务,不需要检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
主启动类EurekaApplication.java,记得加上注解@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class);
}
}
2)修改两个微服务项目的配置(我们创建的order工程、payment工程),将两个Client注册进Eureka
第一步:分别在两个项目的pom中添加client相关依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.2</version>
</dependency>
第二步:主启动类加上注解@EnableEurekaClient
第三步:修改yml文件,添加eureka内容
server:
port: 8001
spring:
application:
name: clould-payment #微服务应用的名字
eureka:
client:
register-with-eureka: true #向注册中心注册自己
fetch-registry: true #从EurekaServer抓取已有的注册信息,集群必须设置成true,才能配合ribbon负载均衡
service-url:
defaultZone: http://localhost:7001/eureka/
server:
port: 80
spring:
application:
name: clould-order #微服务应用的名字
eureka:
client:
register-with-eureka: true #向注册中心注册自己
fetch-registry: true #从EurekaServer抓取已有的注册信息,集群必须设置成true,才能配合ribbon负载均衡
service-url:
defaultZone: http://localhost:7001/eureka/
第四步:验证
分别启动注册中心服务和其他服务,浏览器访问:http://localhost:7001/可以看到已经成功注册进来两个服务(我们的order和payment应用),且application的名称就是我们yml文件中配置的spring-application-name的名字。
而出现的红色字即自我保护机制。
至此单机版Eureka已经集成完毕。
2、集群版Eureka集成
避免单点故障,我们知道实际应用时注册中心,应用一般都是集群部署。集群版Eureka就是相互注册、互相守望。
1)改host
tip:模拟集群几台服务就添加几个,接下来我们已两台为例
2)和上边编写Eureka Server一样,我们模拟Eureka集群两台服务,编写Eureka Server2,建module->改pom->主启动类->改yml:
分别调整Server和Server2两个工程各自yml中的hostname,都用localhost区分不清,将各自工程中yml的defaultZone地址改为对方地址(相互注册)
浏览器访问http://localhost:7002/ 可以看到7001成功注入,访问http://localhost:7001/ 可以看到7002成功注入,初步搭建完成。
3)将order、payment服务注册到刚搭建好的Eureka集群
修改两个工程yml文件中注入地址:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
4)启动服务验证:
可以看到我们的订单服务、支付服务已经成功注册到Eureka7001和7002,也就是成功注册到我们的集群中来了。
3、Client集群版Eureka集成
1)创建集群服务payment2
刚我们将注册中心改为集群模式,接下来将Client服务提供者改为集群模式,参照payment工程,创建一样的payment2工程,相应文件可以粘贴过来,注意修改端口号,另外修改payment、payment2两个工程中Controller添加相应的日志,用于验证后续的负载均衡,启动服务:
验证将payment集群(payment->8001,payment2–>8002)成功注册到eureka集群中:
2)修改服务调用者order工程
第一步:将OrderController类中调用payment的地址由单机的地址改为集群服务名(对应Eureka界面中显示的名字)
第二步:在配置类中添加@LoadBalanced
注解,赋予RESTTemplate负载均衡的能力,因为现在我们的支付payment服务已经是集群,order不知道调用哪个,所以开启默认的负载均衡
3)验证
多次调用相同查询接口,可看到是走了默认的负载均衡,对8001、8002轮训进行访问的。
至此实现了订单调用支付服务集群,Client注册到eureka集群的效果:
Ribbon和Eureka整合后Consumer可以直接调用服务而不用关心地址和端口号,且能实现负载均衡。
4)修改主机名和显示ip
为了使用和查看方便可以修改主机名和ip,在yml文件中与client同级添加如下内容:
在回到控制台查看名称已变成我们自定义的,放上去显示ip等信息,如果没有变,检查yml文件是否写错或者空格,或者重启一下服务。
三、Discovery服务发现
对于注册进Eureka里面的微服务,可以通过服务发现来获取服务的信息。
已payment8001为例,修改controller,添加如下两段代码:
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value ="/discovery")
public Object discovery(){
List<String> list=discoveryClient.getServices();
for(String str:list){
//对应eureka界面中application应用名
log.info("====application==={}",str);
}
List<ServiceInstance> lt= discoveryClient.getInstances("CLOULD-PAYMENT");
for(ServiceInstance instance:lt){
//对应eureka界面中
log.info("====instance====="+instance.getHost()+"\t"+instance.getServiceId()+"\t"+instance.getPort());
}
return this.discoveryClient;
}
主启动类将注解@EnableEurekaClient
替换成@EnableDiscoveryClient
,访问测试:
@EnableEurekaClient与@EnableDiscoveryClient区别:
首先从Spring Cloud 1.0.0.RC1版本开始,就已经不推荐使用EnableEurekaClient和EnableHystrix了;
spring容器在查询spring.factories的过程中,如果找到了EnableDiscoveryClient的配置,就会实例化该配置对应的服务注册发现:例如eureka、consul、zookeeper等;
@EnableEurekaClient只能作用于Eureka
四、自我保护机制
上面提到过Eureka的自我保护机制,这里主要提一下配置方面:
如何关闭自我保护
默认是开启自我保护,也就是服务由于网略等等不可用,不会立马剔除,可通过修改Eureka Server 工程yml文件参数enable-self-preservation: false
进行关闭,然后手动将payment系统停掉模拟服务不可用,可看见Eureka页面立马剔除该服务。
测试模拟时可将Eureka Client端参数设置小点,服务模拟不可用方便(死得快点):