【Day3-Spring Cloud】之Eureka--服务治理机制

【首先】本SpringCloud知识来自阅读【翟永超】《SpringCloud微服务实战》一书

一.注册中心

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.syf.study</groupId>
	<artifactId>eureka-server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>eureka-server</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.14.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka-server</artifactId>
			<version>1.4.3.RELEASE</version>
		</dependency>
	</dependencies>
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

	<!--springcloud-->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.RC1</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>


	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

2.配置文件:

application-peer1.properties

spring.application.name=eureka-server
server.port=1001

eureka.instance.hostname=peer1
eureka.client.service-url.defaultZone=http://peer2:1002/eureka/

application-peer2.properties

spring.application.name=eureka-server
server.port=1002

eureka.instance.hostname=peer2
eureka.client.service-url.defaultZone=http://peer1:1001/eureka/

3.启动项

package com.syf.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaServerApplication.class, args);
	}
}

4.启动注册中心【高可用注册中心】

java -jar eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1
java -jar eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2

5.查看注册中心是否启动成功

二、服务提供者

1.导包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.syf.study</groupId>
	<artifactId>eureka-client-1</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>eureka-client-1</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.14.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<!--全栈开发模式,包含嵌入Tomcaat和SpringMVC-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!--包含JUnite,Hamcrest,Mockito-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!--依赖模块 可不写-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!--springcloud-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
			<version>1.4.3.RELEASE</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

	<!--springcloud-->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.RC1</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
</project>

2.配置文件

application-pro1.properties

### 高可用配置
spring.application.name=eureka-client-1
server.port=2001

eureka.client.service-url.defaultZone=http://localhost:1001/eureka/

### 原先配置 ,http://localhost:1002/eureka/
#spring.application.name=eureka-client-2
#
#eureka.client.service-url.defaultZone=http://peer1:1001/eureka/
#
####以下为application.yml配置
##spring:
##  application:
##    name: eureka-client-1
##eureka:
##  client:
##    serviceUrl:
##      defaultZone: http://127.0.0.1:1111/eureka/
##
#

application-pro2.properties

### 高可用配置
spring.application.name=eureka-client-1
server.port=2002

eureka.client.service-url.defaultZone=http://localhost:1002/eureka/

### 原先配置 ,http://localhost:1002/eureka/
#spring.application.name=eureka-client-2
#
#eureka.client.service-url.defaultZone=http://peer1:1001/eureka/
#
####以下为application.yml配置
##spring:
##  application:
##    name: eureka-client-1
##eureka:
##  client:
##    serviceUrl:
##      defaultZone: http://127.0.0.1:1111/eureka/
##
#

3.启动类

package com.syf.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class EurekaClient1Application {

	public static void main(String[] args) {
		SpringApplication.run(EurekaClient1Application.class, args);
	}
}

4.启动

java -jar eureka-client-1-0.0.1-SNAPSHOT.jar --spring.profiles.active=pro1
java -jar eureka-client-1-0.0.1-SNAPSHOT.jar --spring.profiles.active=pro2

5.先看一下是否成功注册到注册中心上

三、消费者

1.导包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.syf.study</groupId>
	<artifactId>ribbon-consumer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>ribbon-consumer</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.15.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka-server</artifactId>
			<version>1.4.3.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
			<version>1.4.3.RELEASE</version>
		</dependency>
	</dependencies>
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

	<!--springcloud-->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.RC1</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

2.配置文件

application-rib1.properties

### 高可用配置
spring.application.name=ribbon-consumer
server.port=3001

eureka.client.service-url.defaultZone=http://localhost:1001/eureka/

application-rib2.properties

### 高可用配置
spring.application.name=ribbon-consumer
server.port=3002

eureka.client.service-url.defaultZone=http://localhost:1002/eureka/

3.启动类

package com.syf.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient //开启注册中心客户端注解
public class RibbonConsumerApplication {

	public static void main(String[] args) {
		SpringApplication.run(RibbonConsumerApplication.class, args);
	}

	@Bean
	@LoadBalanced
	RestTemplate restTemplate(){
		return new RestTemplate();
	}
}

4.负载均衡实现接口

package com.syf.study;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping("/findHelloInServer")
    public String findHelloInServer(){
        System.out.println("客户端调用...");
        ResponseEntity<String> forEntity = restTemplate.getForEntity("http://EUREKA-CLIENT-1/hello", String.class);
        String body = forEntity.getBody();
        System.out.println("访问对象:"+forEntity.toString());
        System.out.println("负载均衡调用结果得到:"+body);
        return body;
    }
}

5.启动

java -jar ribbon-consumer-0.0.1-SNAPSHOT.jar --spring.profiles.active=rib1
java -jar ribbon-consumer-0.0.1-SNAPSHOT.jar --spring.profiles.active=rib2

6.查看是否成功注册到注册中心上

 

 7.Postman调用接口

http://localhost:3001/findHelloInServer

第一次调用:

 

 第二次调用【蓝色框为第二次调用】:

四、总结:

1【服务提供者】

1.1.“服务注册中心peer1”和“服务注册中心peer2”,它们相互注册组成了高可用集群。

1.2.“服务提供者”启动类连个实例,一个注册到“服务注册中心peer1”上,另一个注册到“服务注册中心peer2”上。

1.3.两个“服务消费者”它们也都分各别指向了一个注册中心

如图所示:

1)服务注册:在服务注册时,要确认一下eureka.client.register-with-eureka=true是否正确【默认是true】,若设置为false将不会启动注册操作。

如下图【示例】:

2)服务同步:如图,这里的两个入伍提供者分别注册到了连个不同的服务注册中心上,也就是说他们的信息分别被两个服务注册中心维护。此时,由于服务注册中心之间因互相注册为服务,当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发给集群中相连的其他注册中心,从而实现注册中心之间的服务同步。通过服务同步,两个服务提供者的服务信息就可以通过这两台服务注册中心中的任意一台获取到。

3)服务续约:在注册完服务之后,服务提供者会维护一个心跳用来告诉Eureka Server:“我还活着”,以放着Eureka Server 的“剔除任务”将该服务实例从服务列表中排出出去,我们称该操作为服务续约,关于服务续约有两个重要属性,我们可以关注并根据需要来进行调整:

eureka.instance.lease-renewal-interval-in-seconds=30用于定义服务续约任务的调用时间间隔,默认30秒

eureka.instance.lease-expiration-duration-in-seconds=90参数用于定义服务失效的时间,默认90秒

2【服务消费者】

2.1获取服务

到这里,在服务注册中心已经注册了一个服务,并且该服务有连个实例,当我们启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取项目注册的服务清单。为了性能考虑,Eureka Server会维护一份制度的服务清单来返回给客户端,同事该缓存清单会每隔30秒更新一次。

获取服务是服务消费者的基础,所以必须确保eureka.client.fetch-registry=true参数没有被修改成false,该值默认为true

如果为false将无法获取服务.

。若希望修改缓存清单的更新时间,可以通过eureka.client.registry-fetch-interval-seconds=30参数进行修改,默认30秒。

如下图【示例】:

调用:http://localhost:3001/findHelloInServer

调用:http://localhost:3002/findHelloInServer

2.2服务调用

服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息,因为有这些服务实例的详细信息,所以客户端可以根据自己的需求决定具体调用那个实例,在ribbon中会more采用轮询的方式进行调用,从事实现客户端的服务均衡。

对于访问实例的选择,Eureka中有Region和Zone的概念,一个Regionzhong keyi baohan duoge Zone.每个服务客户端需要被注册到一个Zone中,所以每个客户端对应一个Region和一个Zone.在进行服务调用的时候,优先访问同一个Zone中的服务提供方,若访问不到就访问其他的Zone,更多相关Region和Zone的知识,以后会提到。

2.3服务下线

在系统运行过程中必然会棉铃关闭或重启服务的某个实例的情况,在服务关闭期间我们自然不希望客户端会继续电泳关闭了的实例,所以在客户端程序中,当服务实例进行正常的关闭操作时,他会出发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线了”,服务端会在接收到请求之后将该服务状态置为下线(DOWN),并把该下线的时间传播出去。

3.【服务注册中心】

3.1失效剔除

有些时候,我们的服务实例并不一定会正常下线,可能由于内存溢出、网络故障等原因使得服务不能正常工作,二服务注册中心并未收到“服务下线”的请求,未来从服务列表中将这些无法提供服务的实例剔除,Eureka Server在启动的时候回创建一个定时任务,默认每隔一段时间(默认是60秒)将当前清单中超市(默认为90秒)没有续约的服务剔除出去。

客户端服务提供者下线时提示:

 客户端下线时注册中心提示:

客户端消费者下线提示(其实和服务提供者一样都是注册中心客户端):

注册中心:

3.2自我保护
当我们再本地调试基于Eureka的程序时,基本上都会碰到这样一个问题,在服务注册中心的信息面板中出现类似下面的红色警告信息:

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

实际上,该警告就是出发了Eureka Server的自我保护机制,之前我们介绍过,服务注册到Eureka Server之后,会维护一个心跳连接,告诉Eureka Server自己还活着。Eureka Server在运行期间会统计心跳失败的比例在15分钟之内是否低于58%,如果出现低于的情况(在单机调试的时候很容易满足,实际生产环境上通常是由于往网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,让这些实例不会过期,尽可能保护这些注册信息,但是,在这段保护期间内实例若出现问题,那么客户端很容易拿到实际不存在的服务实例,会出现调用失败的情况,所以客户端必须要有容错机制,比如可以使用请求重试、断路器等机制。

下图为:先停止服务提供者后停止服务消费者导致报错(此操作为非正常服务下线),并且导致注册中心无法接收到消费者的下线请求,因此没有将该服务状态置为下线(DOWN)

由于本地调试很容易出发注册中心的保护机制,这 会使得注册中心维护的服务实例不难准确,所以,我们再本地进行开发的时候,可以使用eureka.server.enable-self-preservation=false参数来关闭保护机制,以确保注册中心可以将不可用的实例正确剔除。

如下图【示例】:

1.已关闭保护机制:

2.未关闭保护机制:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值