《从零开始:Spring Cloud Eureka 配置与服务注册全流程》
关于Eureka的学习,主要学习如何搭建Eureka,将order-service和product-service都注册到Eureka。
1.为什么使用Eureka?
我在实现一个查询订单功能时,希望可以根据订单中productId去获取对应商品的详细信息,但是产品服务和订单服务是分布式的,所以如果要实现根据订单中的productId去获取商品的详细信息,就需要在订单服务中远程调用产品服务,如下图
但是这样有一个问题,就是远程调用产品服务时,这里的ip和端口号是写死的,如果ip地址发生变化,我们就需要修改对应的代码,而Eureka就是用解决这个问题的。
2.注册中心
Eureka是作为一个注册中心来解决这个问题的,当产品服务发生变更重新启动时,会先先向Eureka打报告,然后Eureka去记录服务和对应IP的关系,此时订单服务如果想远程调用产品服务,此时产品服务会先去Eureka获取产品服务的IP,然后再根据从Eureka中获取的IP去远程调用产品服务。
2.1 什么是注册中心?
在Spring Cloud Eureka中,注册中心是服务发现的核心组件,负责管理微服务的注册和发现。
2.2 注册中心的三种角色
注册中心主要有3中角色,分别是服务提供者(Server),服务消费者(Client)和服务注册中心(Registry)。
服务提供者(Server):一次业务中,被其他微服务调用的服务,也就是给其他微服务提供接口的微服务,如上面提到的产品服务就是服务提供者
服务消费者(Client):一次业务中,调用其他微服务的微服务,也就是调用其他微服务提供的接口的微服务,如上面提到的订单服务就是服务消费者
服务注册中心(Registry) :用于保存Server的注册信息,当Server节点发生更改时,Registry会同步变更。服务与注册中心使用一定机制通信,如果注册中心与某服务长时间无法通信,就会注销该实例。
三者之间的关系和工作内容,可以用两个概念来解释。
服务注册:服务提供者在启动时,向注册中心注册自身服务,并向注册中心定期发送心跳汇报存活状态。
服务发现: 服务消费者1从注册中心查询服务提供者的IP地址,并通过该IP地址远程调用服务提供者的接口。服务发现的一个重要作用就是提供给服务者一个可用的服务列表。
如下图
2.3 CAP理论
谈到注册中心,就避不开CAP理论,CAP理论是分布式系统设计中最基础,也是最为关键的理论。
一致性:CAP理论中的一致性,这里指的是强一致性,强一致性的意思是所有节点的对外提供的数据都是一致的。
可用性:保证每个请求都能有响应,响应的数据有可能是旧的数据。
分区容错性: 当出现网络分区后后,系统任然能够对外提供服务。
网络分区是指在分布式系统中,由于网络故障,导致分布式系统中部分节点无法进行通信,形成多个独立的子网络(即分区)
CAP理论告诉我们:一个分布式系统不可能同时满足数据一致性,服务可用性和分区容错性这三个基本需求,最多只能同时满足其中两个。
在分布式系统中,由于网络状态是不可预测的,我们即使出现网络分区的情况,我们的系统任然能够对外提供服务,所以我们一定保证分区容错性。
正常情况下
网络出现异常:
而一致性和可用性只能满足一个。
如果想要保证各个节点数据的强一致性,由于数据的同步更新是有一定时间延迟的,那么此时该节点的服务一定是有一段时间是停止对外提供服务的。
如果想要保证可用性,由于数据的同步更新是有一定时间延迟的,那么此时一定有一段时间一些节点的数据是来不及更新的,如果此时请求发送到给数据还没有同步更新的节点,那么得到的响应就是一个旧的数据。
所以,我们只能实现AP架构或者CP架构
AP架构:为了保证分布式系统对外的数据一致性,于是选择不返回任何数据
AP架构:为了保证分布式系统的可用性,即使该节点数据还没有关系,依旧会返回一个响应,这个响应中的数据是一个旧的数据。
y3.搭建Eureka Server
Eureka Server可以是一个单独的工程,也可以是一个子工程,下面的搭建Eureka Server是以子工程的方式搭建的。
第一步,创建一个子工程
第二步,在eureka-server工程中的pom文件引入eureka-server的依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>
第三步,在在eureka-server工程中的pom文件引入项目构建插件
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
第四步,完善启动类,注意在在启动类加上@EnableEurekaServer注解
第五步,在配置文件中添加一下配置信息
# Eureka相关配置
# Eureka 服务
server:port: 10010
spring:application:name: eureka-server
eureka:instance:hostname: localhostclient:fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为falseregister-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.service-url:# 设置Eureka Server的地址,查询服务和注册服务都需要依赖这个地址defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
第六步,启动服务
启动服务后,如果能通过127.0.0.1:10010访问,说明Eureka搭建成功了,如下图
4.服务注册
将product-service服务注册到eureka server中
第一步,在product-service的pom文件中引入下面的依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
第二步,完善product-service的配置文件
添加服务名称和eureka地址
#Eureka Client
eureka:client:service-url:defaultZone: http://127.0.0.1:10010/eureka/
第三部,启动product-service服务,启动之后,刷新注册中心界面,会发现注册中心中注册了product-service服务
5.服务发现
接下来我们修改orders-service,在远程调用时,从eureka-server拉去product-service的服务信息,实现服务发现。
第一步,在orders-service工程的pom文件中引入下面的依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
第二步,完善orders-service的配置文件,添加服务名称和eureka地址
添加的eureka地址的配置文件,添加服务名称根据自己工程的名字自己去添加即可。
#Eureka Client
eureka:client:service-url:defaultZone: http://127.0.0.1:10010/eureka/
第三步,实现订单服务远程调用产品服务,代码如下
修改原来的service层代码
如果要从Eureka中获取注册的服务列表,要用到一个spring中提供的DiscoveryClient,通过getInstances方法来获取服务列表,getInstances是通过服务的Id来Eureka中获取对应的服务列表,这里的id其实就是服务的名称。
由于是一个服务列表,我们要从服务列表中获取对应的服务,由于我在Eureka中注册的product-service服务只有一个,所以从服务列表中取第一个服务就行了。
@Slf4j
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;public OrderInfo selectByOrderId(Integer id){OrderInfo orderInfo = orderMapper.selectByOrderId(id);/*String url = "http://127.0.0.1:9090/product/"+orderInfo.getProductId();*///根据应用名从eureka中获取对应的服务列表List<ServiceInstance> instances = discoveryClient.getInstances("product-service");String uri = instances.get(0).getUri().toString();log.info("远程调用的uri:{}",uri);String url = uri+"/product/"+orderInfo.getProductId();ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}}
第四步,运行订单服务,启动orders-service服务,此时刷新Eureka页面,发现Eureka中也成功注册orders-service服务
远程调用product-service也成功了
注意:校验时,eureka-server,product-service和order-service都要启动