一、注册中心出现的背景
单体应用经过拆分之后变成多个微服务,每个服务独立部署,架构也由当初的一台Nginx负载多个tomcat。例如:现在有2个微服务分别为服务A和服务B,
服务A调用服务B。服务B部署了3个实例,要将A的请求转发到服务B的3个实例中有2个方案。
方案1:A服务部署一个nginx维护服务B三个实例的IP地址,如果服务B的实例增加或减少需要通知服务A修改服务B实例的IP。
方案2:服务B自己部署一个Nginx服务维护3个微服务实例的IP地址,如果服务B的实例需要增加或者修改则只需自己修改nginx中的配置就可以,不需要通知服务A去修改Nginx。
二、Eureka-Server注册中心
注册中心的出现解决了微服务实例维护困难的问题,所有的微服务将自己的IP和端口地址及相关的信息发送到注册中心,由注册中心来维护微服务实例。
CAP理论
在一个分布式系统中,当涉及读写操作时,只能保证一致性(Consistency)、可用性(Availability)、分区容忍性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。
1.一致性(Consistency)
对于某个指定的客户端来说,读操作保证能够返回最新的写操作结果。
2.可用性(Availability)
非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)
3.分区容忍性(Partition Tolerance)
当出现网络分区后,系统能够继续提供服务。
Eureka-Server 的复制策略
Eureka-Server 采用的是P2P(对等复制)模式,但是它不保证复制操作一定能成功,因此它提供的是一个最终一致性的服务实例视图。Client端在Server端的注册信息有个带期限的租约,一旦Server端在指定的时间没有收到Client端发送的心跳,则Server端认为Client端的服务是不可用的,定时任务会将其从注册表中删除。
1.创建spring-cloud-demo
2.创建父模块spring-cloud-parent
在父模块中引入相关的依赖
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>5.2</version>
</dependency>
</dependencies>
3.创建Eureka-Server
pom.xml指定parent并引入eureka-server依赖
<parent>
<artifactId>spring-cloud-parent</artifactId>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../spring-cloud-parent/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>${spring-cloud-eureka-server.version}</version>
</dependency>
</dependencies>
配置application.yml
server:
port: 8762
eureka:
instance:
hostname: localhost
# 指定Eureka Client 间隔多久需要向Eureka-Server发送心跳来告知Eureka-Server该实例还存活 默认90
lease-expiration-duration-in-seconds: 10
# 优先使用IP地址
prefer-ip-address: true
client:
# 是否应该将实例注册到Eureka-Server 默认为true
register-with-eureka: false
fetch-registry: true
service-url:
defaultZone: http://localhost:8762/eureka/
server:
wait-time-in-ms-when-sync-empty: 0
enable-self-preservation: false
spring:
application:
name: eureka-server
4.创建Eureka-Client 模块(spring-cloud-service-provide)
配置pom.xml,指定parent并引入eureka-client等相关依赖
<parent>
<artifactId>spring-cloud-parent</artifactId>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../spring-cloud-parent/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${spring-cloud-starter-openfeign.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<!--<version>${spring-cloud-eureka-client.version}</version>-->
</dependency>
</dependencies>
配置application.yml,将服务注册到Eureka-Server
server:
port: 8086
spring:
application:
name: cloud-service-provide
eureka:
instance:
hostname: localhost
prefer-ip-address: true
lease-expiration-duration-in-seconds: 10
client:
serviceUrl:
# 注册到Eureka-Server
defaultZone: http://localhost:8762/eureka/
分别启动Eureka-Server和Eureka-Client,通过浏览器访问注册中心http://localhost:8762,可以看到cloud-serivce-provide已经注册到Eureka-Server
三、Eureka-Server rest api
操作 | 请求类型 | URL | 描述 |
---|---|---|---|
注册服务实例 | POST | /eureka/apps/{appId} | 可以输入json或xml格式的body数据,成功返回204 |
注销应用实例 | DELETE | /eureka/apps/{appId}/{instanceId} | 成功返回200 |
应用实例发送心跳 | PUT | /eureka/apps/{appId}/{instanceId} | 成功返回200,如果instanceId不存在返回404 |
查询所有实例 | GET | /eureka/apps | 成功返回200,输出json或xml格式数据 |
查询指定appId的实例 | GET | /eureka/apps/{appId} | 成功返回200,输出json或xml格式数据 |
根据appId和instanceId查询 | GET | /eureka/apps/{appId}/{instanceId} | 成功返回200,输出json或xml格式 |
根据指定instanceId查询 | GET | /eureka/instances/{instanceId} | 成功返回200,输出json或xml格式 |
暂停应用实例 | PUT | /eureka/apps/{appId}/{instanceId}/status?value=OUT_OF_SERVER | 成功返回200,失败返回500 |
恢复应用实例 | DELETE | /eureka/apps/{appId}/{instanceId}/status?value=UP | 成功返回200,失败返回500 |
更新元数据 | PUT | /eureka/apps/{appId}/{instanceId}/metadata?key=value | 成返回200,失败返回500 |
根据vip地址查询 | GET | /eureka/vips/{vipAddress} | 成返回200,输出json或xml |
根据svip地址查询 | GET | /eureka/svips/{svipAddress} | 成功返回200,输出json或xml格式数据 |