首先我们先新建一个eureka-server的项目
这里要勾选Eureka Server这个组件
以上项目就初步创建好了,我们可以查看pom.xml文件,里面已经帮我们引入了eureka-server的相关依赖。
然后我们在项目的入口这加上一个注解@EnableEurekaServer
当然还有在properties文件里进行相关的配置,配置url之前,eureka内部有个多网卡绑定机制,所以先到C:\Windows\System32\drivers\etc\hosts文件中整两个主机名出来如下,保存好之后,手动ping一下,看是否设置成功
127.0.0.1 eureka1.com
127.0.0.1 eureka2.com
我们需要建两个项目(两个eureka服务),一个是eureka1.com,一个是eureka2.com ,他们仅仅是properties文件不一样,下面是eureka1.com的配置文件,defaultZone是1向2注册,所以另一个项目相反就ok啦!(我都贴出来吧),这里的hostname在生产环境下配实际的ip地址就好啦。
server.port= 7001
#是否将自己注册到Eureka Server,默认为true,高可用的话我们就需要eureka直接互相注册信息,所以默认true
#eureka.client.register-with-eureka=true
#是否从Eureka Server获取注册信息,默认为true,高可用的话我们就需要eureka直接互相拉取信息,所以默认true
#eureka.client.fetch-registry=true
#设置服务注册中心的URL,用于client和server端的通信,默认是8761端口,eureka会像这里的url去注册
eureka.client.service-url.defaultZone=http://eureka2.com:7002/eureka/
#查找主机地址
eureka.instance.hostname=eureka1.com
spring.application.name=EurekaServer
server.port= 7002
#是否将自己注册到Eureka Server,默认为true,高可用的话我们就需要eureka直接互相注册信息,所以默认true
#eureka.client.register-with-eureka=true
#是否从Eureka Server获取注册信息,默认为true,高可用的话我们就需要eureka直接互相拉取信息,所以默认true
#eureka.client.fetch-registry=true
#设置服务注册中心的URL,用于client和server端的通信,默认是8761端口,eureka会像这里的url去注册
eureka.client.service-url.defaultZone=http://eureka1.com:7001/eureka/
#查找主机地址
eureka.instance.hostname=eureka2.com
spring.application.name=EurekaServer
然后这个项目就可以成功跑起来了,我们设置tomcat端口号为7001和7002,所以我们可以到这http://eureka1.com:7001/和http://eureka2.com:7002/查看eureka的监控后台
到这就说明EurekaServer集群已经搭起来啦!!!接下来要搞个客户端
还是新建一个项目eurekaProvider,然后引入依赖,这里是引入eureka client!!!
在项目入口这加上@EnableEurekaClient,新版本是不需要加这个注解的
项目建好后还是去修改properties文件
server.port=80
spring.application.name=provider
#这里的地址是provider去寻找服务的地址和端口
eureka.client.service-url.defaultZone=http://eureka1.com:7001/eureka/
然后我们写个测试服务的controller。
@RestController
public class testController {
@GetMapping("/HelloWorld")
public String HelloWorld(){
return "HelloWorld-Provider";
}
}
我的provider跑起来后就会把自己注册到eureka1.com中
接下来再新建一个eurekaClient作为consumer和provider一样,这样我们就相当于有两个微服务,然后都注册到eureka1.
那我们两个微服务怎么调用呢,我们就可以注入DiscoveryClient接口,从这个接口可以获取到eureka内的信息,这个接口如下,就几个方法,可以从getInstances中获取到某个服务,getServices()可以获取注册到eurekaServer的服务列表
public interface DiscoveryClient extends Ordered {
int DEFAULT_ORDER = 0;
String description();
List<ServiceInstance> getInstances(String serviceId);
List<String> getServices();
default void probe() {
this.getServices();
}
default int getOrder() {
return 0;
}
}
@RestController
public class testController {
@Autowired
DiscoveryClient discoveryClient;
EurekaClient eurekaClient;
@GetMapping("/getServices")
public String getClient(){
List<String> services = discoveryClient.getServices();
for (String server: services){
System.out.println(server);
}
return "";
}
}
当我们调用/getServices,打印了这两个服务
然后调用/ServiceInstance,根据getServices返回的serviceId,作为参数,
这里我们就获得了provider的相关信息,这样就可以对provider进行远程调用
以上就是通过eureka服务器来拉去其他微服务的相关ip地址和端口号还有服务的状态。
然后我们就可以通过ip地址和端口号拼接来对provider进行远程调用。
@GetMapping("/ServiceInstance")
public String getServiceInstance(){
List<InstanceInfo> services = eurekaClient.getInstancesByVipAddress("provider",false);
if(services.size() > 0){
InstanceInfo instanceInfo = services.get(0);
//判断服务状态是否正常,不行是down
if(instanceInfo.getStatus() == InstanceInfo.InstanceStatus.UP){
//这里拼接好请求,调用provider的/HelloWorld
String url = "http://"+instanceInfo.getHostName()+":"+instanceInfo.getPort()+"/HelloWorld";
//用restTemplate去发起请求
RestTemplate restTemplate = new RestTemplate();
String respon = restTemplate.getForObject(url, String.class);
return respon;
}
}
return "false";
}
最后正确的返回了"HelloWorld-Provider",这就成功的使微服务直接能互相调用
Ribbon负载均衡
我们可以才需要调用其他微服务时,注入LoadBalancerClient对象,这是一个抽象接口,它可以自动的帮我们完成负载均衡并且过滤掉状态为down的服务
@Autowired
LoadBalancerClient loadBalancerClient;
@GetMapping("/LoadBalancedServiceInstance")
public String getLoadBalancedServiceInstance(){
//ribbon可以完成客户端的负载均衡,并且过滤掉down状态的服务
ServiceInstance serviceInstance = loadBalancerClient.choose("provider");
String url = "http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/HelloWorld";
RestTemplate restTemplate = new RestTemplate();
String respon = restTemplate.getForObject(url, String.class);
return respon;
}
看下图就调用成功啦,代码实现也简单了很多。
eureka自我保护机制
eureka在高可用的特性下,会遇到某些节点暂时失效,所以它就有一个自我保护机制来保证宁愿保留健康和不健康的服务,也不会盲目注销任何健康的服务,所以客户端每分钟发送心跳的数量小于客户端总数的85%时就会触发自我保护机制(默认30秒发送一次心跳)。这样做是使eureka的可用性更加强,但是一致性是无法保证的。但是如果我们的服务确实出问题了,eurekaServer因为开启了自我保护机制,也不会去把有问题的服务剔除,eurekaServer是无法知道每个微服务是否可用的,它不会主动去发心跳询问客户端,检测客户端是否可用。那所以我们如果想要在微服务中catch到错误后,主动把这个服务down掉,那么我们可以用Actuator监控每一个微服务。
Actuator监控
首先我们需要引入Actuator的依赖用来上报服务的信息
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
这里就说明引入成功啦!
里面_links下面目前只有health节点相关内容,如果想要增加所有的相关信息节点,我们就需要在properties里配置加上,然后信息就好多了很多了吧。感兴趣的可以再去查一查每一个信息节点相关内容。
management.endpoints.web.exposure.include=*
里面有一个特殊的节点shutdown,默认是没开的要单独配置一下,这样就会多了shutdown的信息节点,只要发post请求这个节点里的url,就可以远程关闭这个微服务。
#可以远程关闭微服务
management.endpoint.shutdown.enabled=true
配好之后,我们就可以实现自定义上下线服务了,什么意思呢?就是eureka服务一直觉得某个微服务是可以调通的,所以状态为up,但是实际上,这个微服务已经不能用了,需要人为的去catch某些异常,然后人为主动地去上传微服务的真是状态。
我们先配置客户端的配置,将服务自己的健康状态传播到server
#可以上班服务的真是状态
eureka.client.healthcheck.enabled=true
我们写个service,实现HealthIndicator接口
@Service
public class HealthStatusService implements HealthIndicator {
//当前服务状态
private Boolean status = true;
public void setStatus(Boolean status) {
this.status = status;
}
public String getStatus() {
return status.toString();
}
@Override
public Health health() {
//当状态为true,上报状态up
if (status){
return new Health.Builder().up().build();
}
//当状态为false,上报状态up
return new Health.Builder().down().build();
}
}
我们只有调下面这个接口,并传入状态,这样就可以手动上下线我们的服务啦!!!
@Autowired
HealthStatusService healthStatusService
@GetMapping("/health")
public String health(@RequestParam("status") Boolean status){
healthStatusService.setStatus(status);
return healthStatusService.getStatus();
}
这样就可以穿不同参数的时候,让服务上下线了啊!!!
以上是spring-cloud相关的基础组件,有什么错误希望大佬们给我指点一下,谢谢