Eureka 介绍
整体介绍
- 背景:在传统应用中,组件之间的调用,通过有规范的约束的接口来实现,从而实现不同模块间良好的协作。但是被拆分成微服务后,每个微服务实例的网络地址都可能动态变化,数量也会变化,使得原来硬编码的地址失去了作用。需要一个中心化的组件来进行服务的登记和管理。
- 概念:实现服务治理,即管理所有的服务信息和状态。
注册中心相当于买票乘车,只看有没有票(有没有服务),有就去买票(获取注册列表),然后乘车(调用)。不必关心有多少火车在运行。
-
注册中心好处:不用关心有多少提供方。
-
注册中心有哪些:Eureka,Nacos,Consul,Zookeeper等。
-
服务注册与发现包括两部分,一个是服务器端,另一个是客户端。
Server是一个公共服务,为Client提供服务注册和发现的功能,维护注册到自身的Client的相关信息,同时提供接口给Client获取注册表中其他服务的信息,使得动态变化的Client能够进行服务间的相互调用。
Client将自己的服务信息通过一定的方式登记到Server上,并在正常范围内维护自己信息一致性,方便其他服务发现自己,同时可以通过Server获取到自己依赖的其他服务信息,完成服务调用,还内置了负载均衡器,用来进行基本的负载均衡。
-
我们课程的Spring Cloud是用Eureka作为服务注册中心。
-
Eureka:是一个RESTful风格的服务,是一个用于服务发现和注册的基础组件,是搭建Spring Cloud微服务的前提之一,它屏蔽了Server和client的交互细节,使得开发者将精力放到业务上。
-
serverA从serverB同步信息,则serverB是serverA的peer。
-
上面例子中如果service-url为空,且register-with-eureka,fetch-registry为true,则会报错,Cannot execute request on any known server,因为server同时也是一个client,他会尝试注册自己,所以要有一个注册中心url去注册。
-
Netflix开源的组件。包括server和client两部分。
https://github.com/Netflix/Eureka
注册中心和微服务间的关系
client功能
- 注册:每个微服务启动时,将自己的网络地址等信息注册到注册中心,注册中心会存储(内存中)这些信息。
- 获取服务注册表:服务消费者从注册中心,查询服务提供者的网络地址,并使用该地址调用服务提供者,为了避免每次都查注册表信息,所以client会定时去server拉取注册表信息到缓存到client本地。
- 心跳:各个微服务与注册中心通过某种机制(心跳)通信,若注册中心长时间和服务间没有通信,就会注销该实例。
- 调用:实际的服务调用,通过注册表,解析服务名和具体地址的对应关系,找到具体服务的地址,进行实际调用。
server注册中心功能
-
服务注册表:记录各个微服务信息,例如服务名称,ip,端口等。
注册表提供 查询API(查询可用的微服务实例)和管理API(用于服务的注册和注销)。
-
服务注册与发现:注册:将微服务信息注册到注册中心。发现:查询可用微服务列表及其网络地址。
-
服务检查:定时检测已注册的服务,如发现某实例长时间无法访问,就从注册表中移除。
组件:Eureka , Consul , ZooKeeper,nacos等。
Eureka环境搭建
(在一台机器上模拟多服务)
Eureka高可用
- 首先修改本机的hosts文件(C盘–>windows–>system32–>drivers–>etc–>hosts),模拟出两台机器(域名),分别为euk1.com和euk2.com分别指向本机的localhost,如果有两台服务器或者机器的,可以跳过这个步骤。
- 在创建项目时,勾选Eureka-server或者导入下面的starter。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- 开启Eureka服务的注解
- 配置properties配置文件
euk1.com上的配置
#是否将自己注册到Eureka Server,默认为true,由于当前就是server,故而设置成false,表明该服务不会向eureka注册自己的信息
eureka.client.register-with-eureka=true
#是否从eureka server获取注册信息,由于单节点,不需要同步其他节点数据,用false
eureka.client.fetch-registry=true
#设置服务注册中心的URL,把euk1.com 注册到euk2.com节点上
eureka.client.service-url.defaultZone=http://euk2.com:7902/eureka/
#每个服务的主机名
eureka.instance.hostname=euk1.com
#项目的项目名,主要用来区分是否是同一个服务,一个服务可以部署在多台机器上,用此名称进行分组
#如果euk1和euk2的name相同,表示这两个服务为同一组服务,那么不同表示为不同的服务
spring.application.name=eureka-server
##必须本服务注册url的端口保持一致http://euk1.com:7901/eureka/
server.port=7901
euk2.con配置
#是否将自己注册到Eureka Server,默认为true,由于当前就是server,故而设置成false,表明该服务不会向eureka注册自己的信息
eureka.client.register-with-eureka=true
#是否从eureka server获取注册信息,由于单节点,不需要同步其他节点数据,用false
eureka.client.fetch-registry=true
#设置服务注册中心的URL,把euk2注册到euk1上
eureka.client.service-url.defaultZone=http://euk1.com:7901/eureka/
#当前服务的名称
eureka.instance.hostname=euk2.com
#项目名或者服务所属组名,用于进行服务分组
spring.application.name=eureka-server
#必须本服务注册url的端口保持一致http://euk2.com:7902/eureka/
server.port=7902
- 启动两台节点
远程服务调用–精简版示例
注册中心配置
#是否将自己注册到Eureka Server,默认为true,由于当前就是server,故而设置成false,表明该服务不会向eureka注册自己的信息
eureka.client.register-with-eureka=false
#是否从eureka server获取注册信息,由于单节点,不需要同步其他节点数据,用false
eureka.client.fetch-registry=false
#设置服务注册中心的URL,把euk1.com 注册到euk2.com节点上
eureka.client.service-url.defaultZone=http://euk1.com:7901/eureka/
#每个服务的主机名
eureka.instance.hostname=euk1.com
#eureka服务的端口号
server.port=7901
服务提供者配置
application.propertise
spring.profiles.active=privideXX
spring.application.name=sayHi
application-privide01.propertise
eureka.instance.hostname=privide01.com
eureka.client.service-url.defaultZone=http://euk1.com:7901/eureka/
server.port=8081
application-privide02.propertise
eureka.instance.hostname=privide02.com
eureka.client.service-url.defaultZone=http://euk1.com:7901/eureka/
server.port=8082
application-privide03.propertise
eureka.instance.hostname=privide03.com
eureka.client.service-url.defaultZone=http://euk1.com:7901/eureka/
server.port=8083
controller
@RestController
public class SayHiController {
@RequestMapping("/sayHi")
public String sayHi(){
return "你好,大帅哥!";
}
}
服务调用方
eureka.client.service-url.defaultZone=http://euk1.com:7901/eureka/
spring.application.name=eureka-consumer
server.port=8080
controller层
@RestController
public class ConsController {
//eureka 实现的客户端接口
@Autowired
EurekaClient client;
//实现服务调用的负载均衡接口
@Autowired
LoadBalancerClient loadBalancer;
/**
* 简单的远程服务调用
* @return
*/
@RequestMapping("/consayhi")
public String consSayHi(){
String result = "";
List<InstanceInfo> instanceInfos = client.getInstancesByVipAddress("sayHi", false);
for (InstanceInfo ins:instanceInfos){
System.out.println(ToStringBuilder.reflectionToString(ins));
}
if (instanceInfos.size()>0){
InstanceInfo instanceInfo = instanceInfos.get(0);
if (instanceInfo.getStatus() == InstanceInfo.InstanceStatus.UP){
String url = "http://"+instanceInfo.getHostName()+":"+instanceInfo.getPort()+"/sayHi";
RestTemplate restTemplate = new RestTemplate();
result = restTemplate.getForObject(url, String.class);
}
}
return result;
}
/**
* 带服务调用负载均衡的远程服务调用
* @return
*/
@RequestMapping("/consayhi1")
public String consSayHi1(){
String result = "";
//通过loadBalance的负载均衡算法,返回多个服务中的一个服务
ServiceInstance instance = loadBalancer.choose("sayHi");
String url = "http://"+instance.getHost()+":"+instance.getPort()+"/sayHi";
RestTemplate restTemplate = new RestTemplate();
result = restTemplate.getForObject(url,String.class);
return result;
}
}
测试
注册中心服务注册详情:
服务调用方调用 服务