目录
[CAP 理论](#CAP 理论)
[搭建 Eureka Server](#搭建 Eureka Server)
[引⼊ eureka-server 依赖](#引⼊ eureka-server 依赖)
[引⼊ eureka-client 依赖](#引⼊ eureka-client 依赖)
前言
在微服务开发中,一个服务通常由一个微服务集群提供,在代码中两个服务之间的服务器是不可能绑定死的,是 n 对 n 的关系,所以对微服务进行管理是很有必要的。
比如当订单服务需要用到商品信息时就需要发送请求给商品服务,我们要如何找到商品服务呢?可以通过 Eureka 来找到该服务。
在微服务开发中:
服务启动/变更时,向**注册中⼼**报道,注册中⼼记录应⽤和 IP 的关系.
调⽤⽅**调⽤时,先去注册中⼼**获取服务⽅的 IP ,再去服务⽅进⾏调⽤.
注册中心
在最初的架构体系中,集群的概念还不那么流⾏,且机器数量也⽐较少,此时直接使⽤DNS + Nginx 就可以满⾜⼏乎所有服务的发现.相关的注册信息直接配置在 Nginx.但是随着微服务的流⾏与流量的激增,机器规模逐渐变⼤,并且机器会有频繁的上下线⾏为,这种时候需要运维⼿动地去维护这个配置信息是 ⼀个很⿇烦的操作.
所以开发者们开始希望有这么⼀个东西,它能维护⼀个服务列表,哪个机器上线了,哪个机器宕机了,这些信息都会⾃动更新到服务列表上,客户端拿到这个列表,直接找到服务进⾏服务调⽤即可.这个就是注册中⼼.
注册中⼼主要有三种⻆⾊:
• 服务提供者(Server):⼀次业务中,被其它微服务调⽤的服务.也就是提供接给其它微服务.
• 服务消费者(Client):⼀次业务中,调⽤其它微服务的服务.也就是调⽤其它微服务提供的接⼝.
• 服务注册中⼼(Registry):⽤于保存 Server 的注册信息,当 Server节点发⽣变更时, Registry 会同步 变更.服务与注册中⼼使⽤⼀定机制通信,如果注册中⼼与某服务⻓时间⽆法通信,就会注销该实例.
他们之间的关系以及⼯作内容,可以通过两个概念来描述:
服务注册:服务提供者在启动时,向 Registry 注册⾃⾝服务,并向 Registry定期发送⼼跳汇报存活状态.
服务发现:服务消费者从注册中⼼查询服务提供者的地址,并通过该地址调⽤服务提供者的接⼝.服务发现的⼀个重要作⽤就是提供给服务消费者⼀个可⽤的服务列表.
CAP 理论
谈到注册中⼼,就避不开 CA P理论.CAP 理论是分布式系统设计中最基础,也是最为关键的理论.
• ⼀致性(Consistency) CAP 理论中的⼀致性,指的是强⼀致性.所有节点在同⼀时间具有相同的数据
• 可⽤性(Availability) 保证每个请求都有响应(响应结果可能不对)
• 分区容错性(Partition Tolerance) 当出现⽹络分区后,系统仍然能够对外提供服务
CAP 理论告诉我们:⼀个分布式系统不可能同时满⾜数据⼀致性,服务可⽤性和分区容错性这三个基本需求,最多只能同时满⾜其中的两个.
在分布式系统中,系统间的⽹络不能100%保证健康,服务⼜必须对外保证服务.因此 Partition Tolerance不可避免.那就只能在C和A中选择⼀个.也就是 CP 或者 AP 架构
正常情况:
⽹络异常:
CP 架构:为了保证分布式系统对外的数据⼀致性,于是选择不返回任何数据
AP 架构:为了保证分布式系统的可⽤性,节点2返回 V0 版本的数据(即使这个数据不正确)
常⻅的注册中心
- Zookeeper
Zookeeper的官⽅并没有说它是⼀个注册中⼼,但是国内 Java 体系,⼤部分的集群环境都是依赖 Zookeeper 来完成注册中⼼的功能.
- Eureka
Eureka是 Netflix 开发的基于 REST 的服务发现框架,主要⽤于服务注册,管理,负载均衡和服务故障转移.官⽅声明在Eureka2.0 版本停⽌维护,不建议使⽤.但是 Eureka 是 SpringCloud 服务注册/发现的默认实现(以前),所以⽬前还是有很多公司在使⽤.
- Nacos
Nacos 是 Spring Cloud Alibaba 架构中重要的组件,除了服务注册,服务发现功能之外,Nacos还⽀持配置管理,流量管理,DNS,动态 DNS 等多种特性.
CAP理论对比
在分布式环境中,即使拿到⼀个错误的数据,也胜过⽆法提供实例信息⽽造成请求失败要好(⽐如淘宝 11.11,京东 618 都是谨遵 AP 原则)
Eureka
Eureka 是 Netflix OSS 套件中关于服务注册和发现的解决⽅案.Spring Cloud 对 Eureka 进⾏了集成,并作为优先推荐⽅案进⾏宣传,虽然**⽬前 Eureka 2.0 已经停⽌维护,新的微服务架构设计中,也不再建议使⽤**,但是⽬前依然有⼤量公司的微服务系统使⽤ Eureka 作为注册中⼼.
Eureka 主要分为两个部分:
• Eureka Server: 作为注册中⼼ Server 端,向微服务应⽤程序提供服务注册,发现,健康检查等能⼒.
• Eureka Client: 服务提供者,服务启动时,会向 Eureka Server 注册⾃⼰的信息(IP,端⼝,服务信息 等),Eureka Server 会存储这些信息。服务请求者,会去 Eureka Server 拉取服务列表,知道服务位置后,去获取服务
搭建 Eureka Server
引⼊ eureka-server 依赖
java
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
完善启动类
java
//开启 Eureka 注册中心服务
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
编写配置⽂件
java
# Eureka相关配置
# Eureka 服务
server:
port: 10010
# Eureka 项目名称
spring:
application:
name: eureka-server
# Eureka 主机名称
eureka:
instance:
hostname: localhost
client:
fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为false
register-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.
service-url:
# 设置与Eureka Server的地址,查询服务和注册服务都需要依赖这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
启动服务
访问注册中⼼:http://127.0.0.1:10010
可以看到 eureka-server 已经启动成功了
服务注册
接下来我们把 product-service 注册到 eureka-server 中
引⼊ eureka-client 依赖
java
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
完善配置⽂件
添加服务名称和 eureka 地址
java
spring:
application:
name: product-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10010/eureka/
启动服务
刷新注册中⼼:http://127.0.0.1:10010
可以看到 product-service 已经注册到 eureka 上了
服务发现
引⼊依赖
服务注册和服务发现都封装在 eureka-client 依赖中,所以服务发现时,也是引⼊ eureka-client 依赖
java
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
完善配置⽂件
java
spring:
application:
name: order-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10010/eureka/
服务发现也需要知道 eureka 地址,因此配置内容依然与服务注册⼀致,都是配置 eureka 信息
远程调⽤
远程调⽤时,我们需要从 eureka-server 中获取 product-service 的列表(可能存在多个服务),并选择其中 ⼀个进⾏调⽤
核心代码:
java
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
//注入 DiscoveryClient 对象,来从注册中心拉取服务列表
@Autowired
private DiscoveryClient discoveryClient;
public OrderInfo selectOrderById(Integer orderId){
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
//从 eureka 注册中心获取服务列表
List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
//由于此时服务中心只有一个 product-service 服务,直接获取即可,获取到了 product-service 服务的 IP 地址和端口号
String uri = instances.get(0).getUri().toString();
String url=uri+"/product/info/"+orderInfo.getProductId();
//String url = "http://127.0.0.1:9090/product/info/"+orderInfo.getProductId();
//通过 restTemplate 发送 HTTP 请求到指定的接口,并将响应数据封装成对象
ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
}
启动服务
刷新注册中⼼:http://127.0.0.1:10010
可以看到服务的请求者和提供者都被记录到注册中心
访问订单服务接口,获取订单信息:
可以看到订单服务成功通过注册中心获得了订单服务的 IP 地址以及端口号,发送请求给了商品服务获得了商品信息。