一、.Eureka简介?
在现在日益复杂 的互联网环境,一个项目肯定会拆分出十几,甚至数十个微服务。此时如果还人为管理地址,不仅开发困难,将来 测试、发布上线都会非常麻烦,这与DevOps的思想是背道而驰的。
Eureka负责管理、记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉 Eureka,然后Eureka会把符合你需求的服务告诉你。
同时,服务提供方与Eureka之间通过 “心跳” 机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服 务列表中剔除。
这就实现了服务的自动注册、发现、状态监控。
二、原理图
- Eureka:就是服务注册中心(可以是 一个集群),对外暴露自己的地址
- 提供者:启动后向Eureka注册自己信息(地址,提供什么服务)
- 消费者:向Eureka订阅服务,Eureka会将对应服务的所有提供者地址列表发送给消费者,并且定期更新
- 心跳(续约):提供者定期通过HTTP方式向Eureka刷新自己的状态
工作原理图解析:
1、将服务注册到eureka
2、记录服务
3、从eureka中获取服务列表
4、基于负载均衡算法从地址列表中选择一个服务地址调用服务
5、定期发送心跳
6、检查哪些没有定期发送心跳续约的服务,将其在一定时间内剔除服务列表
三、Eureka入门案例
我们会用到以下三个项目:
1.编写EurekaServer
Eureka是服务注册中心,只做服务注册;自身并不提供服务也不消费服务。可以搭建Web工程使用Eureka,可以 使用Spring Boot方式搭建。
创建eureka-server 项目后配置以下内容:
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">
<parent>
<artifactId>cloud1</artifactId>
<groupId>com.syq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
2. 编写启动类:
package com.syq;
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);
}
}
3. 编写配置:application.yml
server:
port: 10086
spring:
application:
name:eureka-server
eureka:
client:
service-url:
#eureka服务地址,如果做集群,需指定其他eureka地址
defaultZone: HTTP://127.0.0.1:10086/eureka
#不注册自己
register-with-eureka: false
#不拉取服务
fetch-registry: false
server:
#关闭自我保护
enable-self-preservation: false
4. 启动服务
2. 服务注册
再创建 user-service 项目:
1、pom文件如下:
<?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">
<parent>
<artifactId>cloud1</artifactId>
<groupId>com.syq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 通用Mapper启动器 -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>
2. 在启动类上开启Eureka客户端功能
通过添加 @EnableDiscoveryClient 来开启Eureka客户端功能。
package com.syq.user;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan("com.syq.user.mapper")
@EnableDiscoveryClient//开启eureka客户端发现功能
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
3. 编写配置文件:bootstrap.yml
server:
port: 9091
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud
username: root
password: root
application:
name: user-service
mybatis:
type-aliases-package: com.syq.user.pojo
eureka:
client:
service-url:
defaultZone: HTTP://127.0.0.1:10086/eureka
register-with-eureka: true
fetch-registry: true
instance:
#更倾向于使用ip地址
prefer-ip-address: true
ip-address: 127.0.0.1
#续约的间隔
lease-renewal-interval-in-seconds: 30
#服务失效时间
lease-expiration-duration-in-seconds: 90
注意:
这里我们添加了spring.application.name属性来指定应用名称,将来会作为应用的id使用。 不用指定register-with-eureka和fetch-registry,因为默认是true
4、重启项目,访问Eureka监控页面查看
我们发现user-service服务已经注册成功了
3、服务发现
在服务消费工程consumer-demo上添加Eureka客户端依赖;可以使用工具类DiscoveryClient根据服务名称获取对应的服务地址列表。
创建新项目 consumer-demo:
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">
<parent>
<artifactId>cloud1</artifactId>
<groupId>com.syq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>consumer-demo</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
2、在启动类添加开启Eureka客户端发现的注解
package com.syq.consumer;
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 // 开启Eureka客户端
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3、修改配置文件:application.yml
spring:
application:
name: consumer-demo
eureka:
client:
service-url:
defaultZone: HTTP://127.0.0.1:10086/eureka
#拉去服务列表时间
registry-fetch-interval-seconds: 30
4、用DiscoveryClient类的方法,根据服务名称,获取服务实例
@RestController
@RequestMapping("consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id){
String url = null;
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("user-service");
ServiceInstance serviceInstance = serviceInstances.get(0);
url = "http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/user/"+id;
return restTemplate.getForObject(url,User.class);
}
}
访问:http://localhost:8080/consumer/1
注意:需要先连接上数据库哦~
四、Eureka详解
1、基础架构
Eureka架构中的三个核心角色:
-
服务注册中心: Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的eureka-server
-
服务提供者:提供服务的应用,可以是Spring Boot应用,也可以是其它任意技术实现,只要对外提供的是REST风格服务即可。本例中就是我们实现的user-service
-
服务消费者: 消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。本例中就是我们 实现的consumer-demo
2、失效剔除和自我保护
如下的配置都是在Eureka Server服务端进行:
服务下线:当服务进行正常关闭操作时,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线 了”。服务中心接受到请求之后,将该服务置为下线状态
失效剔除:有时我们的服务可能由于内存溢出或网络故障等原因使得服务不能正常的工作,而服务注册中心并未收到“服务下 线”的请求。相对于服务提供者的“服务续约”操作,服务注册中心在启动时会创建一个定时任务,默认每隔一段时间 (默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除,这个操作被称为失效剔除。 可以通过 eureka.server.eviction-interval-timer-in-ms 参数对其进行修改,单位是毫秒。
自我保护:我们关停一个服务,就会在Eureka面板看到一条警告:
这是触发了Eureka的自我保护机制。当一个服务未按时进行心跳续约时,Eureka会统计最近15分钟心跳失败的服 务实例的比例是否超过了85%,当EurekaServer节点在短时间内丢失过多客户端(可能发生了网络分区故障)。在 生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因 为服务可能没有宕机。Eureka就会把当前实例的注册信息保护起来,不予剔除。生产环境下这很有效,保证了大多 数服务依然可用。
但是这给我们的开发带来了麻烦, 因此开发阶段我们都会关闭自我保护模式:
在eureka-server的配置文件中:
eureka:
server:
#关闭自我保护
enable-self-preservation: false #关闭自我保护模式(缺省为打开)
eviction-interval-timer-in-ms: 1000 # 扫描失效服务的间隔时间(缺省为60*1000ms)