文章目录
1. Eureka介绍
Eureka是Netflix公司提供的一款服务注册中心,Eureka基于REST来实现服务的注册和发现。Spring Cloud中封装了Eureka,在Eureka的基础上,优化了一些配置并提供了可视化的界面,可以方便地查看服务的注册情况以及服务注册中心集群的运行情况。
Euraka由两部分组成:服务端和客户端。服务端就是注册中心,用来接收其他服务的注册;客户端分为服务提供者和服务消费者,是一个Java客户端。如下图所示:
2. Eureka搭建
Eureka本身使用Java来开发的,Spring Cloud使用Spring Boot技术对Eureka进行封装,在Spring Cloud中使用Eureka非常方便,只需要引入依赖:spring-cloud-starter-netflix-eureka-server
,就可以像启动一个普通Spring Boot项目那样启动了。
1.创建一个Spring Boot项目,添加Eureka依赖。
2.项目创建完成后,在启动类中添加注解@EnableEurekaServer标识该项目为Eureka Server。
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
3.在application.properties中添加基本配置信息:
#当前服务的名字
spring.application.name=eureka
#端口号(Eureka后台管理端端口)
server.port=1111
#默认情况下,Eureka Server也是一个普通的微服务,所以当它还是注册中心时,就有两层身份:
#1.注册中心;2.普通服务。默认当前eureka server自动把自己注册到注册中心中,
# 通过eureka.client.register-with-eureka=false设置不注册
eureka.client.register-with-eureka=false
#表示是否从Eureka Server上获取注册信息
eureka.client.fetch-registry=false
4.配置完成就可以启动项目,在浏览器中访问http://localhost:1111就可以查看Eureka后台管理页面了。
3. Eureka集群
在Spring Cloud架构中,如果注册中心只有一个,如果出故障了会导致整个服务环境不可用,所以我们需要搭建Eureka注册中心集群,实现负载均衡和故障容错。Eureka集群架构图示意图:
Eureka集群搭建原理是互相注册。在这个集群架构中,Eureka Server之间都进行数据同步,不区分主从节点,所有节点都是平等的。节点之间通过置顶serviceUrl来互相注册,形成集群,从而提高节点的可用性。
在Eureka服务器集群中,如果单个节点发生故障,Eureka客户端将自动切换到新的Eureka服务器。每个Eureka服务器节点彼此同步数据。Eureka服务器的连接方式可以是单线,连接方式为a->b->c,节点a的数据也将与c同步。但不建议这样写。当我们配置serviceUrl时,您可以指定多个注册地址,即a可以同时在b或c上注册。
4. Eureka架构
Eureka包含两个组件:Eureka Server和Eureka Client。
4.1 Eureka Server
Eureka Server主要有三个功能:
- 服务注册,所有的服务都注册到Eureka Server上。每个微服务节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表讲会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
- 提供注册表,注册表就是注册到Eureka Server上的服务列表。Eureka Client在调用服务时,需要获取这个注册表,一般来说,这个注册表会缓存下来,如果缓存失败,则直接获取最新的注册表。
- 同步状态,Eureka Client通过注册、心跳等机制,和Eureka Server同步当前注册中心的状态。
4.2 Eureka Client
Eureka Client主要用来简化每一个服务和Eureka Server之间的交互。Eureka Client会自动拉取更新以及缓存Eureka Server中的信息,这样即使Eureka Server所有节点都宕机,Eureka Client依然能够获得想要调用的服务。(但是地址可能不准确)。
Eureka Client提供了以下功能:
- 服务注册
服务提供者将自己注册到服务注册中心Eureka Server,所谓的服务提供者,只是一个业务上的划分,其本质上就是一个Eureka Client。Eureka Client向Eureka Server注册后会提供自身的元数据信息,例如IP地址、端口、名称、运行状态等等信息。
- 服务续约
Eureka Client注册到Eureka Server之后,==默认情况下,Eureka每隔30s就要向Eureka Server发送一条心跳消息,来告诉Eureka Server它还在运行。==如果Eureka Server连续90秒都没有收到Eureka Client的续约消息,Eureka Server会认为这个Eureka Client已经掉线,并将其从服务注册列表中剔除。
服务续约相关功能有两个相关的属性(一般不建议修改):
#服务续约时间,默认30s
eureka.instance.lease-renewal-interval-in-seconds=30
#未续约的服务失效时间,默认90s
eureka.instance.lease-expiration-duration-in-seconds=90
- 服务下线
当Eureka Client下线时,它会主动发送一条消息告诉Eureka Server,它要下线了。
- 获取注册表信息
Eureka Client从Eureka Server上获取服务的注册信息,并将其缓存在本地。本地客户端在需要调用远程服务时,会从该信息中查找远程服务所对应的IP地址、端口等信息。Eureka Client上缓存的服务注册信息会定期更新(30秒),如果Eureka Server返回的注册表信息与本地缓存的注册表信息不同的话,Eureka Client会自动处理。
涉及到的两个属性:
#是否获取注册表信息,默认为true
eureka.client.fetch-registry=true
#定期更新的时间间隔,默认为30秒
eureka.client.registry-fetch-interval-seconds=30
4.3 Eureka自我保护
默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会注销该微服务实例。但是当网络分区故障发生延时、卡顿、拥挤时,微服务与Eureka Server之间无法正常通信,但是因为微服务其实是健康的,此时不应该下线这个微服务实例。Eureka通过“自我保护模式”来解决这个问题----当Eureka Server节点在短时间内丢失过多客户端时,那么Eureka进入自我保护模式,Eureka Server不会立刻将Eureka Client服务下线。
5. 服务注册
服务注册就是将一个微服务注册到Eureka Server上,这样其他的服务想要调用该服务时,就只需要从Eureka Server上查询该服务的信息,然后完成服务调用。
要创建一个服务提供者provider,只需要在Spring Boot项目中添加以下两个依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
然后在application.properties中配置项目的注册地址,就可以将该服务提供者Provider注册到Eureka Server上:
#服务名
spring.application.name=provider
#服务端口号
server.port=1113
#注册中心url地址
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
然后,首先启动服务注册中心Eureka Server,待其启动完成后再启动服务提供者provider。等到两者启动成功后,在浏览器中输入http://localhost:1111
就可以查看当前服务注册中心中的注册信息。
6. 服务消费
首先在模块provider中提供一个接口:
@RestController
public class HelloController {
@Value("${server.port}")
Integer port;
@GetMapping("/hello")
public String hello(){
return "hello world port:"+port;
}
}
然后创建一个consumer模块,同样添加spring-boot-starter-web和spring-cloud-starter-netflix-eureka-client依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
创建完成后在application.properties中配置注册信息
#服务名称
spring.application.name=consumer
#端口号
server.port=1114
#注册中心的url地址
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
然后提供一个接口,消费服务提供者提供的接口,然后借助Eureka Client提供的DiscoveryClient工具,根据服务名从Eureka Server上查询到一个服务的详细信息,并使用RestTemplate工具类来发起请求。
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
RestTemplate restTemplate(){
return new RestTemplate();
}
}
@RestController
public class HelloController {
@Autowired
DiscoveryClient discoveryClient;
@Autowired
RestTemplate restTemplate;
@GetMapping("/hello2")
public String hello2(){
HttpURLConnection httpConnection=null;
//如果是集群部署会有多个
List<ServiceInstance> providerList = discoveryClient.getInstances("provider");
ServiceInstance provider=providerList.get(0);
String host = provider.getHost();
int port=provider.getPort();
StringBuffer providerUrl = new StringBuffer("http://").append(host)
.append(":")
.append(port)
.append("/hello");
//通过RestTemplate实现服务的调用
String result = restTemplate.getForObject(providerUrl.toString(), String.class);
return result;
}
}
配置RestTemplate的负载均衡功能,需要添加注解@LoadBalanced来开启
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
RestTemplate restTemplate(){
return new RestTemplate();
}
}
@Bean
@LoadBalanced
RestTemplate balancedRestTemplate(){
return new RestTemplate();
}