承接上文:SpringCloud概述和基本工程搭建
1.服务注册/服务发现
1.1问题描述
从上篇文章的例子中可以看到,在远程调用的时候,我们的URL是写死的
String url ="http://127.0.0.1:9090/product/"+orderInfo.getProductId();
当更换机器,或者新增机器时,这个URL就需要跟着变更,就需要去通知所有的相关服务去修改.随之而来的就是各个项目的配置文件反复更新,各个项目的频繁部署
1.2解决思路
试想生活中的场景:
我们生活中,避免不了和各个机构(医院,学校,政府部门等)打交道,就需要保存各个机构的电话号码.如果机构换了电话号码,就需要通知各个使用方,但是这些机构的使用方群体是巨大的,没办法做到——通知,怎么处理呢?
机构电话如果发生变化,通知114.用户需要联系机构时,先打114查询电话,然后再联系各个机构.
114查号台的作用主要有两个:
号码注册:服务方把电话上报给114
号码查询:使用方通过114可以查到对应的号码
同样的,微服务开发时,也可以采用类似的方案.
服务启动/变更时,向注册中心报道.注册中心记录应用和IP的关系。
调用方调用时,先去注册中心获取服务方的IP,再去服务方进行调用.
1.3什么是注册中心
在最初的架构体系中,集群的概念还不那么流行,机器数量也比较少,此时直接使用DNS+Nginx就可以满足几乎所有服务的发现.相关的注册信息直接配置在Nginx.但是随着微服务的流行与流量的激增, 机器规模逐渐变大,并且机器会有频繁的上下线行为,这种时候需要运维手动地去维护这个配置信息是 一个很麻烦的操作.
所以开发者们开始希望有这么一个东西,它能维护一个服务列表,哪个机器上线了,哪个机器宕机了,这些信息都会自动更新到服务列表上,客户端拿到这个列表,直接进行服务调用即可. 这个就是注册中心
注册中心主要有三种角色:
- 服务提供者(Server): 一次业务中,被其它微服务调用的服务,也就是**提供接口给其它微服务. **
- 服务消费者(Client): 一次业务中,调用其它微服务的服务.也就是调用其它微服务提供的接口.
- 服务注册中心(Registry): 用于保存Server的注册信息,当Server节点发生变更时,Registry会同步变更.服务与注册中心使用一定机制通信,如果注册中心与某服务长时间无法通信,就会注销该实例。
他们之间的关系以及工作内容,可以通过两个概念来描述:
- 服务注册:服务提供者在启动时,向Registry注册自身服务,并向Registry定期发送心跳汇报存活状态.
- 服务发现:服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口,服务发现的一个重要作用就是提供给服务消费者一个可用的服务列表.
1.4CAP理论
谈到注册中心,就避不开CAP理论.
CAP理论是分布式系统设计中最基础,也是最为关键的理论.
- 一致性(Consistency)CAP理论中的一致性,指的是强一致性.所有节点在同一时间具有相同的数据
- 可用性(Availability)保证每个请求都有响应(响应结果可能不对)
- 分区容错性(Partition Tolerance)当出现网络分区后,系统仍然能够对外提供服务
一个部门全国各地都有岗位,这时候,总部下发了一个通知,由于通知需要开会周知全员,当有客户咨询时:
1.所有成员对客户的回应结果都是一致的(一致性)
2.客户咨询时,一定有回应(可用性)
3.当其中一个成员休假时,这个部门的其他成员也可以对客户提供咨询服务(分区容错性)
CAP理论告诉我们:一个分布式系统不可能同时满足数据一致性,服务可用性和分区容错性这三个基本需求,最多只能同时满足其中的两个.
在分布式系统中,系统间的网络不能100%保证健康,服务又必须对外保证服务.因此Partition Tolerance不可避免.那就只能在C和A中选择一个.也就是CP或者AP架构
正常情况:
网络异常情况:
** CP架构:为了保证分布式系统对外的数据一致性,于是选择不返回任何数据
AP架构:为了保证分布式系统的可用性,节点2返回V0版本的数据(即使这个数据不正确)**
更多参考:一文看懂|分布式系统之CAP理论-腾讯云开发者社区-腾讯云
1.5常见的注册中心
Zookeeper
Zookeeper的官方并没有说它是一个注册中心,但是国内Java体系,大部分的集群环境都是依赖 Zookeeper来完成注册中心的功能.
Eureka
Eureka是Netflix开发的基于REST的服务发现框架,主要用于服务注册,管理,负载均衡和服务故障 转移.
官方声明在Eureka2.0版本停止维护,不建议使用.但是Eureka是SpringCloud服务注册/发现的默认 实现,所以目前还是有很多公司在使用.
Nacos
Nacos是SpringCloud Alibaba架构中重要的组件,除了服务注册,服务发现功能之外,Nacos还支持 配置管理,流量管理,DNS,动态DNS等多种特性.
CAP理论对比:
在分布式环境中,即使拿到一个错误的数据,也胜过无法提供实例信息而造成请求失败要好(比如淘宝11.11,京东618都是谨遵AP原则)
2.Eureka介绍
Eureka是Netflix OSS套件中关于服务注册和发现的解决方案.SpringCloud对Eureka进行了集成,并作为优先推荐方案进行宣传,虽然目前Eureka 2.0已经停止维护,新的微服务架构设计中,也不再建议使用,但是目前依然有大量公司的微服务系统使用Eureka作为注册中心.
官方文档:https://github.com/Netflix/eureka/wiki
Eureka主要分为两个部分:
**Eureka Server:**作为注册中心Server端,向微服务应用程序提供服务注册,发现,健康检查等能力
Eureka Client:服务提供者,服务启动时,会向Eureka Server注册自己的信息(IP,端口,服务信息 等),Eureka Server会存储这些信息
关于Eureka的学习,主要包含以下三个部分:
- 搭建Eureka Server
- 将order-service,product-service都注册到Eureka
- order-service远程调用时,从Eureka中获取product-service的服务列表,然后进行交互
3.搭建Eureka Server
Eureka Server是一个独立的微服务
3.1创建Eureka-server子模块
3.2引入eureka-server依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3.3引入项目构建插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
3.4完善启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
3.5编写配置文件
server:
port: 10010
spring:
application:
name: eureka-server
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/
3.6启动服务
启动服务, 访问注册中心: http://127.0.0.1:10010/
可以看到eureka-server已经启动成功
4.服务注册
接下来我们把product-service 注册到eureka-server中
4.1引入eureka-client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
4.2完善配置文件、
添加服务名称和eureka地址
spring:
application:
name: product-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10010/eureka/
4.3启动服务
刷新注册中心: http://127.0.0.1:10010/
可以看到product-service已经注册到 eureka上了
5.服务发现
接下来我们修改order-service,在远程调用时,从eureka-server拉取product-service的服务信息,实现服务发现
5.1引入依赖
服务注册和服务发现都封装在eureka-client依赖中, 所以服务发现时, 也是引入eureka-client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
5.2完善配置文件
服务发现也需要知道eureka地址,因此配置内容依然与服务注册一致,都是配置eureka信息
spring:
application:
name: product-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10010/eureka/
5.3远程调用
远程调用时, 我们需要从eureka-server中获取product-service的列表(可能存在多个服务), 并选择其中⼀个进行调用
import com.example.orderservice.mapper.OrderMapper;
import com.example.orderservice.model.OrderInfo;
import com.example.orderservice.model.ProductInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@Slf4j
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
public OrderInfo selectOrderById(Integer orderId){
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
// 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();
String url = uri+"/product/"+orderInfo.getProductId();
log.info("远程调用url:{}", url);
ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
}
5.4启动服务
刷新注册中心: http://127.0.0.1:10010/
可以看到order-service已经注册到 eureka上了
访问接口http://127.0.0.1:8080/order/1
可以看到,远程调用也成功了
6.Eureka和Zookeeper区别
Eureka和Zookeeper都是用于服务注册和发现的工具,区别如下:
- 1.Eureka是Netflix开源的项目,而Zookeeper是Apache开源的项目。
- 2.Eureka基于AP原则,保证高可用,Zookeeper基于CP原则,保证数据一致性.
- 3.Eureka每个节点都是均等的,Zookeeper的节点区分Leader和Follower或Observer,也正因为这 个原因,如果Zookeeper的Leader发生故障时,需要重新选举,选举过程集群会有短暂时间的不可用.
版权归原作者 Romised. 所有, 如有侵权,请联系我们删除。