Spring Cloud 核心组件 Eureka
- 作者:DecaMinCow
- 博客:http://blog.csdn.net/m0_37567301
- 邮箱:decamincow#gmail.com (#->@)
什么是 Eureka
注册中心,方便多实例弹性扩缩容
主流注册中心对比
- Zookeeper
Zookeeper它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布 式应 用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式 应用配置项的管理等。
简单来说zookeeper本质=存储+监听通知。 znode
Zookeeper 用来做服务注册中心,主要是因为它具有节点变更通知功能,只要客户端监听相关服 务节点,服务节点的所有变更,都能及时的通知到监听客户端,这样作为调用方只要使用 Zookeeper 的客户端就能实现服务节点的订阅和变更通知功能了,非常方便。另外,Zookeeper 可用性也可以,因为只要半数以上的选举节点存活,整个集群就是可用的。
- Eureka
由Netflix开源,并被Pivatal集成到SpringCloud体系中,它是基于 RestfulAPI ⻛格开发的服务注册 与发现组件。
- Consul
Consul是由HashiCorp基于Go语言开发的支持多数据中心分布式高可用的服务发布和注册服务软 件, 采用Raft算法保证服务的一致性,且支持健康检查。
- Nacos
Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。简单来说 Nacos 就是 注册中心 + 配置中心的组合,帮助我们解决微服务开发必会涉及到的服务注册 与发现,服务 配置,服务管理等问题。Nacos 是 Spring Cloud Alibaba 核心组件之一,负责服务注册与发现, 还有配置。
组件名 | 语言 | CAP | 对外暴露接口 |
---|---|---|---|
Eureka | Java | AP | HTTP |
Consul | Go | CP | HTTP/DNS |
Zookeeper | Java | CP | 客户端 |
Nacos | Java | 支持 AP/CP 切换 | HTTP |
Eureka 客户端
provider:每隔30秒会向注册中心续约;租约在90秒没有响应则剔除
consumer:每隔30秒拉取服务列表,缓存到本地
Eureka 服务端
服务下线:当服务正常关闭操作时,会发送服务下线的REST请求给EurekaServer;服务中心接受到请求后,将该服务置为下线状态
失效剔除:一定时间内没有收到心跳,则会注销此实例
自我保护:服务端与客户端通信有问题,但是 provider 和 consumer 网络没有问题的情况,防止有误删除客户端机器的情形
自己练习的 DEMO 核心部分
先配置本地 host 解析
127.0.0.1 EurekaServerA
127.0.0.1 EurekaServerB
1. EurekaServer 部分
eureka server pom 依赖
<dependencies>
<!--Eureka server依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
eureka server1 启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApp8761 {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApp8761.class, args);
}
}
eureka server1 配置文件
#Eureka server服务端口
server:
port: 8761
spring:
application:
name: eureka-server # 应用名称,会在Eureka中作为服务的id标识(serviceId)
eureka:
instance:
hostname: EurekaServerA
client:
service-url: # 客户端与EurekaServer交互的地址,如果是集群,也需要写其它Server的地址
defaultZone: http://EurekaServerB:8762/eureka/
register-with-eureka: true
fetch-registry: true #自己就是服务不需要从Eureka Server获取服务信息,默认为true,置为false
eureka server2 启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApp8762 {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApp8762.class, args);
}
}
eureka server2 配置文件
#Eureka server服务端口
server:
port: 8762
spring:
application:
name: eureka-server # 应用名称,会在Eureka中作为服务的id标识(serviceId)
eureka:
instance:
hostname: EurekaServerB
client:
service-url: # 客户端与EurekaServer交互的地址,如果是集群,也需要写其它Server的地址
defaultZone: http://EurekaServerA:8761/eureka/
register-with-eureka: true
fetch-registry: true #自己就是服务不需要从Eureka Server获取服务信息,默认为true,置为false
2. EurekaClient 部分
provider 启动类
@SpringBootApplication
@EntityScan("com.decamincow.learning.springcloud.model")
@EnableDiscoveryClient // 开启注册中心客户端
public class ResumeApplication {
public static void main(String[] args) {
SpringApplication.run(ResumeApplication.class, args);
}
}
provider controller 类
@RestController
@RequestMapping("/resume")
public class ResumeController {
@Autowired
private ResumeService resumeService;
// /resume/openstate/1545132
@GetMapping("/openstate/{userId}")
public Integer findDefaultResumeState(@PathVariable Long userId) {
return resumeService.findDefaultResumeByUserId(userId).getIsOpenResume();
}
}
provider 配置文件
server:
port: 8080
spring:
application:
name: resume
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=yes&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
database: MySQL
show-sql: true
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl #避免将驼峰 命名转换为下划线命名
eureka:
client:
serviceUrl: # eureka server的路径
defaultZone: http://EurekaServerA:8761/eureka/,http://EurekaServerB:8762/eureka/ #把 eureka 集群中的所有 url 都填写了进来,也可以只写一台,因为各个 eureka server 可以同步注册表
instance:
#使用ip注册,否则会使用主机名注册了(此处考虑到对老版本的兼容,新版本经过实验都是ip)
prefer-ip-address: true #自定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
metadata-map:
# 自定义元数据(kv自定义)
cluster: cl1
region: rn1
# 租约续约间隔时间,默认30秒
lease-renewal-interval-in-seconds: 30
# 租约到期,服务时效时间,默认值90秒,服务超过90秒没有发生心跳,EurekaServer会将服务从列表移除
lease-expiration-duration-in-seconds: 90
consumer 启动类
@SpringBootApplication
@EnableDiscoveryClient
public class AutodeliverApplcation {
public static void main(String[] args) {
SpringApplication.run(AutodeliverApplcation.class, args);
}
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
consumer controller 类
@RestController
@RequestMapping("/autodeliver")
public class AutodeliverController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
// /autodeliver/checkState/1545132
@GetMapping("/checkState/{userId}")
public Integer findResumeOpenState(@PathVariable Long userId) {
// 1, 获取 Eureka 实例列表
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("resume");
// 2, 选择一个实例,这是负载均衡的过程
ServiceInstance serviceInstance = serviceInstances.get(0);
// 3, 从元数据取 host port
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
String url = "http://"+ host +":"+ port +"/resume/openstate/" + userId;
Integer forObject = restTemplate.getForObject(url, Integer.class);
System.out.println("======>>从 Eureka 获取的 url:" + url);
return forObject;
}
@GetMapping("/instances")
public List<ServiceInstance> showInfo() {
return this.discoveryClient.getInstances("resume");
}
}
consumer 配置文件
server:
port: 8090
spring:
application:
name: autodeliver
eureka:
client:
serviceUrl: # eureka server的路径
defaultZone: http://EurekaServerA:8761/eureka/,http://EurekaServerB:8762/eureka/ #把 eureka 集群中的所有 url 都填写了进来,也可以只写一台,因为各个 eureka server 可以同步注册表
# 每隔多久拉取一次服务列表
registry-fetch-interval-seconds: 30
instance:
#使用ip注册,否则会使用主机名注册了(此处考虑到对老版本的兼容,新版本经过实验都是ip)
prefer-ip-address: true #自定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
3. 父工程依赖文件
<?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.decamincow.learning.springcloud</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>common</module>
<module>resume</module>
<module>autodeliver</module>
<module>eureka-8761</module>
<module>eureka-8762</module>
</modules>
<packaging>pom</packaging>
<!--spring boot 父启动器依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<dependencies>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--日志依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok工具-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<!-- Actuator可以帮助你监控和管理Spring Boot应用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!--引入Jaxb,开始-->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.2.10-b140310.1920</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!--引入Jaxb,结束-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!--编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<!--打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>