Spring Cloud学习笔记1——服务治理(Eureka)

1、搭建服务注册中心

1)新建一个Spring Boot项目,取名为EurekaServer,代码见码云:https://gitee.com/wudiyong/EurekaServer.git,然后在pom.xml文件中加入依赖:

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

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>	
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka-server</artifactId>
		</dependency>	
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Camden.SR6</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

2)在入口类处加上@EnableEurekaServer注解,用于开启服务注册中心,如下:

@EnableEurekaServer
@SpringBootApplication
public class ErukaServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(ErukaServerApplication.class, args);
	}
}

3)配置application.properties

server.port=8761
eureka.instance.hostname=localhost#当前实例的主机名称
eureka.client.register-with-eureka=false#false代表不向注册中心注册自己(因为本身就是注册中心),默认是true,如果不设为false,启动会报找不到注册中心的错误
eureka.client.fetch-registry=false#注册中心用于维护服务实例,无需检索服务,故设为false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

eureka.client.serviceUrl.defaultZone与eureka.client.service-url.defaultZone有什么区别?

“eureka.client.service-url.”指定服务注册中心地址,类型为 HashMap,并设置有一组默认值,默认的Key为 defaultZone;默认的Value为http://localhost:8761/eureka ,如果服务注册中心为高可用集群时,多个注册中心地址以逗号分隔。

如果服务注册中心加入了安全验证,这里配置的地址格式为: http://<username>:<password>@localhost:8761/eureka 其中 <username> 为安全校验的用户名;<password> 为该用户的密码

至此,注册中心搭建完成,访问http://localhost:8761/可看到注册中心信息,如系统状态、已注册的服务列表等。

可以看到页面中的environment的值是test,可以通过eureka.environment=dev来改变该值。

2、服务提供者到注册中心注册服务(服务注册)

新建一个项目,取名为userInfoService,代码见码云:https://gitee.com/wudiyong/userInfoService.git

1)pom.xml文件与注册中心类似

2)入口类加上注解@EnableEurekaClient,开启eureka客户端,可以注册服务及发现调用服务,与注册中心的@EnableEurekaServer刚好相反。

@EnableDiscoveryClient也能起到该作用,@EnableDiscoveryClient与@EnableEurekaClient的关系如下:

SpringCloud中的“Discovery Service”有多种实现,比如:eureka, consul, zookeeper,可见eruka只是其中的一种。

@EnableDiscoveryClient注解是基于spring-cloud-commons依赖,并且在classpath中实现(根据导入的jar包有关);
@EnableEurekaClient注解是基于spring-cloud-netflix依赖,只能为eureka作用;

如果你的classpath中添加了eureka,则它们的作用是一样的。

3)编写controller类,对外提供服务,如:

@RestController
public class UserInfoController {
	//@RequestBody告诉从body里取值,请求方的Content-Type要设置为application/json,否则报415错误
	//@RequestBody好像不能用多个,如@RequestBody String name,@RequestBody int age
	@RequestMapping(value="/addUserInfo",method=RequestMethod.POST)
	public String addUserInfo(@RequestBody UserInfo userInfo){
		return userInfo.getName() + ":" + userInfo.getAge();
	}
	//@RequestParam告诉从url里取值
	@RequestMapping(value="/userInfo",method=RequestMethod.GET)
	public String userInfo(@RequestParam String name,@RequestParam String age){
		return name + ":" + age;
	}
}

4)配置application.properties

spring.application.name=userInfo-service
server.port=1001
#指向注册中心,http://${eureka.instance.hostname}:${server.port}/eureka/
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

5)测试

启动服务注册中心和服务提供者程序,再访问http://localhost:8761/,可以看到如下信息,说明服务已经注册到注册中心了:

Instances currently registered with Eureka

ApplicationAMIsAvailability ZonesStatus
USERINFO-SERVICEn/a (1)(1)UP (1) - 80245675-OAPC.itc.cmbchina.cn:userInfo-service:1001

可以在浏览器输入http://www.localhost:1001/userInfo?name=吴帝永&age=12来访问提供的服务,但这种方式并不涉及到eureka,仅仅是普通的url访问,并不是通过eureka客户端进行服务发现和调用。

可以修改端口号,启动多个userInfo-service服务,这时可以看到

ApplicationAMIsAvailability ZonesStatus
USERINFO-SERVICEn/a (2)(2)UP (2) - 192.168.1.106:userInfo-service :1002 , 192.168.1.106:userInfo-service :1001

3、服务发现及调用

服务的调用者若想调用某个服务,首先向注册中心发起咨询服务请求,获取服务实例清单,可以有多个服务名相同的服务提供者,即有多个服务实例,当调用者发起调用时,会以某种轮询策略,选择其中一个实例进行调用,这涉及到客户端(Eureka Client)负载均衡。

首先新建一个项目,取名为userInfoService,代码见码云:https://gitee.com/wudiyong/ribbonConsumer.git

1)配置pom.xml,如下:

<?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</groupId>
	<artifactId>ribbonConsumer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>ribbonConsumer</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.8.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>
		<spring-cloud.version>Camden.SR6</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

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

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</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)入口类加上注解@EnableEurekaClient,同时,在该类中创建RestTemplate实例,并通过@LoadBalanced注解开启客户端负载均衡

@EnableEurekaClient
@SpringBootApplication
public class RibbonConsumerApplication {
	@Bean
	@LoadBalanced
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
	public static void main(String[] args) {
		SpringApplication.run(RibbonConsumerApplication.class, args);
	}
}

3)配置application.properties

spring.application.name=ribbon-consumer
server.port=9000
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

4)编写调用服务的类

@RestController
public class ConsumerController {
	@Autowired
	RestTemplate restTemplate;
	@RequestMapping(value="/userInfo", method = RequestMethod.GET)
	public String userInfo(@RequestParam String name, @RequestParam String age) {
		//如果是post请求,可以用postForEntity
		Map<String , Object> params = new HashMap<String , Object>();
		params.put("name", name);
		params.put("age", age);
		return restTemplate.getForEntity("http://USERINFO-SERVICE/userInfo?name={name}&age={age}", 
				String.class,params).getBody();
	}
}

分别启动EurekaServer、userInfoService和userInfoService,其中userInfoService可以修改端口号来启动多个,打开http://localhost:8761/,可看到:

ApplicationAMIsAvailability ZonesStatus
RIBBON-CONSUMERn/a (1)(1)UP (1) - 192.168.1.106:ribbon-consumer:9000
USERINFO-SERVICEn/a (2)(2)UP (2) - 192.168.1.106:userInfo-service :1001 , 192.168.1.106:userInfo-service :1002

4)测试,访问:http://www.localhost:9000/userInfo?name=杀杀杀&age=326
如果有多个USERINFO-SERVICE服务,则请求会轮询被分配到某一个服务。

服务提供者本身也可以作为服务调用者,可以调用其它的服务,也就是说,提供者与调用者是相对的,一个系统可以既是服务提供者又是服务调用者,这一点很重要,因为服务提供者之间会互相调用。


4、高可用注册中心

前面我们只使用一个注册中心,当该注册中心不可用时,所有的服务都不可用,解决方案是,采用多个注册中心,注册中心之间互相注册,前面的注册中心我们通过设置下面两个参数让注册中心不要注册自己:

eureka.client.register-with-eureka=false

eureka.client.fetch-registry=false

现在需要把这两行删掉。

由于除了application.properties之外,其它代码都一样,所以采用spring.profiles.active来控制加载不同的配置文件。

假设有两个注册中心,则分别创建两个配置文件:

application-peer1.properties:

server.port=1111
spring.application.name=eureka-server
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://localhost:1112/eureka/

application-peer2.properties:

server.port=1112
spring.application.name=eureka-server
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

上面的例子中,都是通过eureka.instance.hostname设置主机名来定义实例地址的,这里的localhost只是一个特殊的情况,系统会自动转换为127.0.0.1,我们也可以设置为

eureka.instance.hostname=peer1

eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/

eureka.instance.hostname=peer2

eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/

然后在C:\Windows\System32\drivers\etc\hosts或/etc/hosts中加入如下信息:

127.0.0.1 peer1

127.0.0.1 peer2

这样系统就会自动把peer1、peer2转换成ip地址。除了以上方式,还可以直接指定ip,eureka.instance.prefer-ip-address默认是false,需要把其设为true来开启,如果采用ip方式,则eureka.instance.hostname可以去掉,系统会自动为实例设置ip地址,如果要手动设置,可以通过eureka.instance.ip-address来设置。

注意:如果不显式地把eureka.instance.prefer-ip-address设为true,则服务会以域名的方式注册到eureka,其它服务会通过该服务的域名来调用,如果客户端无法将域名转换成ip,则会调不通。

实例主机名或实例ip地址不仅仅是用在注册中心,也能用于服务的提供者和调用者,因为三者本质上都是一个实例。

application.properties文件只要写spring.profiles.active=peer1或spring.profiles.active=peer2

分别启动这两个注册中心,打开http://localhost:1112/http://localhost:1111/,都能看到如下信息:

ApplicationAMIsAvailability ZonesStatus
EUREKA-SERVERn/a (2)(2)UP (2) - 80245675-OAPC.itc.cmbchina.cn:eureka-server:1111 , 80245675-OAPC.itc.cmbchina.cn:eureka-server:1112

至此,两个注册中心已互相注册成功。

服务提供者、服务调用者都需修改application.properties文件,使其都注册到这两个注册中心中,修改成如下:

eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/,http://localhost:1112/eureka/

5、进阶配置

服务续约

eureka.instance.lease-renewal-interval-in-seconds=30

该配置用于定义服务续约任务的调用间隔时间,默认为30秒

eureka.instance.lease-expiration-duration-in-seconds=90

该配置用于定义服务失效时间,默认为90秒

获取服务

eureka.client.registry-fetch-interval-seconds=30

获取服务列表的时间间隔,默认为30秒,

服务下线

在系统运行过程中,总会有停止或重启服务的时候,这时我们不希望别的服务调用到这个已经停掉的服务,所以在服务正常关闭关闭时,它会出发一个请求发给eureka server,告诉eureka server自己下线了,eureka server会把这个状态传播出去(似乎不是立刻的,可能是别的服务过来拉取的)。

失效剔除

失效剔除和服务下线不一样失效剔除是服务自己非正常下线,例如内存溢出导致应用crash,这时该服务没有继续往eureka server发续约心跳,eureka server在90秒后(默认90秒)还没有收到心跳,就认为该服务失效,然后把该服务从服务列表中删除,但eureka server不是每时每刻都在判断有没有达到90秒的阈值的,而是默认60秒会刷新一次,所以,极端情况下,服务失效后,有可能150秒才会被从服务列表中删除。

自我保护

看自我保护的文章,这里不详细说

6、手动修改服务状态

实例启动后,正常的状态是UP,Eureka Client从Eureka Server中拉取状态为UP的实例列表,服务间调用的请求也只会发给UP状态的实例。当某个实例不希望被别的实例调用时,可以把自己的状态设为DOWN或OUT_OF_SERVICE,比如,要更新某个实例的jar包时,如果直接更新,则由于该实例还在实例列表中保留一段时间,默认时120秒,这段时间如果有请求发给该实例的话,则会报错,因为实例实际上已经停掉了,只是别的实例不知道。我们可以把实例剔除然后再更新实例,或者单某个实力运行不正常时,也可以把有问题的实例踢除。

从Eureka Server中踢实例两种方式:
1、向要被踢的实例发送请求
curl -l -H "Content-type: application/json" -X POST -d 'OUT_OF_SERVICE' http://实例IP:端口号/service-registry/instance-status
2、向Eureka发请求,由Eureka把实例从实例列表中剔除
curl -l -H "Content-type: application/json" -X PUT http://Eureka的IP:端口号/eureka/apps/服务名/实例名/status?value=OUT_OF_SERVICE

服务名和实例名可以在Eureka中找到,分别是<app>和<instanceId>(app就是配置文件中的app-name,instanceId一般是"机器名:服务名:端口号")
可以在下面地址查看Eureka中所有实例的详细信息
http://Eureka的IP:端口号/eureka/apps

7、配置详解


 











评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值