本篇是在微服务的服务调用者和服务提供者的基础上进行更改,可以参考之前的博客。SpringCloud微服务项目创建流程-CSDN博客
简介
从一个单独的微服务项目会发现,user-service对外提供服务,需要对外暴露自己的地址。而consumer(调用者)需要记录服务提供者的地址,若是地址发生变更,还需要及时更新。当服务较多的时候会是一件麻烦的事情,对于开发测试上线都是一个问题。
而Eureka的出现则解决了这个问题,Eureka只负责管理、记录服务提供者的信息,服务调用者无需自己寻找服务,而是把需求告诉Eureka,然后Eureka会把符合你需求的服务告诉你。
同时,服务提供方与Eureka之间通过“心跳”机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服务列表中提出。
这就实现了服务的自动注册、发现、状态监控。
Eureka架构中的三个核心角色:
- 服务注册中心
Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的eureka-server - 服务提供者
提供服务的应用,可以是Spring Boot应用,也可以是其它任意技术实现,只要对外提供的是REST 风格服务即可。本例中就是我们实现的user-service - 服务消费者
消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。本例中 就是我们实现的consumer-demo
1、编写EurekaServer
创建一个新模块EurekaServer,正常的maven项目。
Eureka是服务注册中心,只做服务注册;自身不提供服务也不消费服务。可以搭建Web工程实用Eureka,可以实用Springboot方式搭建。
1.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>
<parent>
<groupId>com.AE</groupId>
<artifactId>SpringCloud01</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>eureka-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
1.2 启动类
//声明当前应用时Eureka服务
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
1.3 编写配置文件
application.yml,定义端口号,定义application.name。
配置Eureka,规定当前服务的地址。因为当前只是作为服务注册,所以不注册自己,不拉去服务。
# 端口号
server:
port: 9003
spring:
application:
name: eureka-server
eureka:
client:
service-url:
# eureka 服务的地址:如果做集群,需要指定其他eureka地址
defaultZone: http://127.0.0.1:9003/eureka
# 不注册自己
register-with-eureka: false
# 不拉取服务
fetch-registry: false
1.4 启动服务
访问:localhost:9003即可,本地的对应端口号。
类似如下:
2、服务注册
在服务提供工程上添加Eureka客户端依赖,自动将服务注册到Eureka服务地址列表。
2.1 添加依赖
pom.xml
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.2 启动类上开启客户端功能
@MapperScan("com.AE.user.mapper")
@SpringBootApplication
@EnableDiscoveryClient // Eureka客户端发现功能
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
2.3 编写配置
application.yml
注意:这里的defaultZone 指向的是Eureka注册服务的ip+端口+eureka,这里我们添加了spring.application.name属性来指定应用名称,将来会作为应用的id使用。 不用指定register-with-eureka和fetch-registry,因为默认是true
# 端口号
server:
port: 9002
# 连接池
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
username: root
password: 123456
application:
name: user-service
mybatis:
type-aliases-package: com.AE.user.pojo # 别名扫描
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:9003/eureka
2.4 测试
重启项目,访问Eureka监控页面查看,会发现如下所示,表示user-service服务已经注册成功了
3、服务发现
3.1 添加依赖
服务消费工程也属于Eureka客户端,需要加上Eureka客户端依赖。可以实用工具类DiscoveryClient根据服务名称获取对应的服务地址列表。
pom.xml
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.2 启动类添加注解
开启服务的Eureka服务发现的注解。
@SpringBootApplication
@EnableDiscoveryClient // 开启Eureka客户端发现注解
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3.3 修改配置
application.yml
与服务提供者是相似的
spring:
application:
name: consumer-demo
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:9003/eureka
3.4 修改Controller层
注意这里导入的DiscoveryClient是一个接口,如果导错了,是没有类似方法的。
通过DiscoveryClient获取user-service对应的信息,获取ip以及对应的端口号,进行访问服务获取数据信息。
注意这里有一个问题,你可以通过调试会发现,这里获取的getHost获取的时计算机名而不是ip,如果希望使用IP,则需要进行配置,在最后配置的内容里面会说。
@RestController
@RequestMapping("consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("{id}")
public User query(@PathVariable("id") Long id) {
String url;
List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
ServiceInstance serviceInstance = instances.get(0);
url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;
return restTemplate.getForObject(url, User.class);
}
}
3.5 测试
重启之后重新访问Eureka监控服务,会发现consumer-demo服务注册完成,如图所示。
然后通过浏览器的url访问consumer中的url获取相关数据,正常情况下是可以正常获取信息的。
至此
已经可以正常实用Eureka注册中心了,还有一些配置可以参考。
4、高可用的Eureka Server
Eureka Server即服务的注册中心,在刚才的案例中,我们只有一个EurekaServer,事实上 EurekaServer也可以是一个集群,形成高可用的Eureka中心 。 Eureka Server是一个web应用,可以启动多个实例(配置不同端口)保证Eureka Server的高可用。
服务同步
多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中某个节点时,不同节点之间会进行信息同步,从而实现数据同步。
而作为客户端,需要把信息注册到每个Eureka中。
例如:9004.9005.9006三个Eureka Server 则
9004注册到9005、9006中,9005注册到9004、9006中,9006注册到9005、9004中.
4.1 修改EurekaServer配置
application.yml
这里的${port}和${defaultZone}是两个变量。为了在本地跑两个当前服务,需要在启动的时候动态修改配置,如果有参数就用参数变量中的值,没有就使用默认的,也就是冒号右边的。
# 端口号
server:
port: ${port:9003}
spring:
application:
name: eureka-server
eureka:
client:
service-url:
# eureka 服务的地址:如果做集群,需要指定其他eureka地址
defaultZone: ${defaultZone:http://127.0.0.1:9003/eureka}
# 不注册自己
# register-with-eureka: false
# 不拉取服务
# fetch-registry: false
4.2 客户端配置修改
application.yml
向两个Eureka注册中心都传递信息。
eureka:
client:
service-url: # EurekaServer 地址 多个地址之间以 ‘,’ 隔开
defaultZone: http://127.0.0.1:9003/eureka, http://127.0.0.1:9004/eureka
然后就行了。
4.3 测试
在启动的时候因为要启动两个EurekaServer,所以需要修改配置文件。
首先复制出一份新的启动项,然后重命名,最好可以区分对应的端口号。
在-D后面填写参数port和defaultZone
然后确定后就可以直接启动了。
5、Eureka客户端和服务端配置
5.1 getHost获取ip
在服务发现里面如果直接使用DiscoveryClient 里面的getHost,默认获取的时计算机用户名,而不是ip,如果希望用的是ip,则需要在服务提供者user-server的application.yml配置中添加以下配置。
eureka:
instance:
ip-address: 127.0.0.1 # ip地址
prefer-ip-address: true # 更倾向于使用ip,而不是host名
5.2 服务续约,心跳请求
在完成注册完成后,服务者会维持一个心跳,即定时向EurekaServer发起Rest请求,告诉EurekaServer:“我还活着”.这个我们称之为续约。
有两个参数可以修改服务续约的行为;可以在user-service中添加如下配置:
eureka:
instance:
lease-expiration-duration-in-seconds: 90 # 服务续约间隔,默认为30s
lease-renewal-interval-in-seconds: 30 # 服务失效时间,默认值为90s
5.3 获取服务列表
当服务消费者启动时,会检测 eureka.client.fetch-registry=true 参数的值,如果为true,则会从 Eureka Server服务的列表拉取只读备份,然后缓存在本地。并且 每隔30秒 会重新拉取并更新数据。可 以在 consumer-demo 项目中通过下面的参数来修改:
eureka:
client:
registry-fetch-interval-seconds: 30
5.4 失效剔除和自我保护
开发阶段大部分都会关闭自我保护模式。
失效剔除:有时我们的服务可能由于内存溢出或网络故障等原因使得服务不能正常的工作,而服务注册中心并未收 到“服务下线”的请求。相对于服务提供者的“服务续约”操作,服务注册中心在启动时会创建一个定时任 务,默认每隔一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除,这个操 作被称为失效剔除。 可以通过 eureka.server.eviction-interval-timer-in-ms 参数对其进行修改,单位是毫秒。
在EurekaServer的application.yml配置中添加如下代码:
eureka:
server:
enable-self-preservation: false # 关闭自我保护模式(缺省为打开)
eviction-interval-timer-in-ms: 1000 # 扫描失效服务的间隔时间(缺省为60*1000ms)