Eureka-服务注册,服务发现
在远程调用的时候,我们写的url是写死的。
String url = \"\"+ orderInfo.getProductId();
当换个机器,或者新增个机器,导致ip变换,从而使得 url 发生了变化,接着就需要去通知所有的相关业务也跟着去改变,这就导致后期非常麻烦。
解决思路:
使用注册中心
什么是注册中心
注册中心是分布式系统/微服务架构中的核心基础设施,它扮演着服务治理的\"电话簿\"角色,他能维护一个服务列表,哪个机器上线了,哪个机器宕机了,这些信息都会自动更新到服务列表上,客户端拿到这个列表,直接进行服务调用即可。这个就是注册中心。 注册中心主要有三个角色:
- **服务提供者(Server):**一次业务中,被其他微服务调用的服务,也就是提供接口给其他微服务。
- **服务消费者(Client):**一次业务中,调用其他微服务的服务,也就是调用其他微服务提供的接口。
- **服务注册中心(Register):**用于保存Server的注册信息,当Server节点发生变更时,Register会同步变更。服务和注册中心使用一定的通信机制,如果注册中心与某服务长时间无法通信,就会注销该实例。
注:服务提供者和服务消费者是相对的。
他们之间的关系及工作内容,可以通过两个概念来描述:
- **服务注册:**服务提供者在启动时,向Register注册自身服务,并向Register定期发送心跳汇报存活状态。
- **服务发现:**服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口,服务发现的一个重要作用就是提供给消费者一个可用的服务列表。
CAP理论:分布式系统的基石
CAP 理论是分布式系统设计的核心定理,由计算机科学家 Eric Brewer 于 2000 年提出,揭示了分布式系统必然面临的三元悖论。其核心内容可概括为:
任何分布式系统最多只能同时满足以下三项中的两项:
Consistency(一致性)
Availability(可用性)
Partition tolerance(分区容错性)
注:一致性分为强一致性(主库和从库,不论何时,对外提供的服务都是一致的)和弱一致性(随着时间的推移,最终达到了一致性),这里指的是强一致性。
比如说我有一个数据库集群,客户端向数据库集群发送了一个数据修改的请求,数据库集群需要向客户端进行响应,响应的时机分为以下两种:
- 主库接收到请求,并处理成功,此时数据库还未完全同步到从库,随着时间的推移,主库和从库的数据,最终会达到一个一致性。
- 主库接收到请求,并且所有数据库同步成功时,才返回响应。
CAP三要素:
CAP理论告诉我们:一个分布式系统不可能同时满足数据一致性,服务可用性和分区容错性这是三个基本需求,最多只能同时满足其中的两个。
在分布式系统中,系统间的网络不能100%保证健康,服务又必须对外保证服务,因此PartitionTolerance不可避免,那就只能在C和A中选择一个,也就是CP或者AP架构。
正常情况:
异常情况:
CP架构:为了保证分布式系统对外的数据一致性,于是选择不返回任何数据。
AP架构:为了保证分布式系统的可用性,节点2返回V0版本的数据(即使这个数据不正确)
更多参考:一文看懂|分布式系统之CAP理论-腾讯云开发者社区-腾讯云
常见的注册中心有:
- Zookeeper(CP)
- nacos(CP或AP,默认是AP)
- eureka(AP)
Eureka介绍
Eureka是Netflix OSS套件中关于服务注册和发现的解决⽅案. Spring Cloud对Eureka进⾏了集成, 并
作为优先推荐⽅案进⾏宣传, 虽然⽬前Eureka 2.0已经停⽌维护, 新的微服务架构设计中, 也不再建议使
⽤, 但是⽬前依然有⼤量公司的微服务系统使⽤Eureka作为注册中⼼。
官方文档:https://github.com/Netflix/eureka/wiki
Eureka主要分为两个部分:
- Eureka Server:作为注册中心Server端,向微服务应用程序提供服务注册,发现健康检查等能力。
- Eureka Client:服务提供者,服务启动时,会向Eureka Server 注册自己的信息(IP,端口,服务信息等),Eureka Server会存储这些信息。
搭建注册中心
1.创建项目
2.pom加入Eureka的环境
org.springframework.cloud spring-cloud-starter-netflix-eureka-server
项目构建插件
org.springframework.boot spring-boot-maven-plugin
3.配置文件,增加Eureka相关的配置
server: port: 10010spring: application: name: eureka-servereureka: 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: {eureka.instance.hostname}:${server.port}/eureka/logging: pattern: console: \'%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n\'
4.启动类,开启Eureka的功能
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@EnableEurekaServer@SpringBootApplicationpublic class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class,args); }}
5.启动测试
启动服务,访问注册中心:http://127.0.0.1:10010/
可以看到能正常访问注册中心了。
服务注册
我们的需求是订单查询订单信息的时候,根据订单里的产品ID,获取产品的详细信息,也就是需要order-service远程调用product-service,也就是说product-service是服务提供者,就需要把product-sevrice服务注册到注册中心里去。
1.加入Eureka的依赖
org.springframework.cloud spring-cloud-starter-netflix-eureka-client
2.完善配置信息
#服务名称spring: application: name: product-service#eureka地址eureka: client: service-url: defaultZone: #日志logging: pattern: console: \'%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n\'
3.启动测试
可以看到product-service已经成功注册到eureka-service上了。
服务发现
order-service是服务消费者,在远程调用时候,会从eureka-server拉取product-service的服务信息,实现服务发现。
1.加入Eureka依赖
org.springframework.cloud spring-cloud-starter-netflix-eureka-client
2.完善配置信息
spring: application: name: order-serviceeureka: client: service-url: defaultZone: logging: pattern: console: \'%d{MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n\'
3.修改远程调用的代码
public OrderInfo selectOrderById(Integer orderId){ OrderInfo orderInfo = orderMapper.selectOrderById(orderId); //String url = \"\" + orderInfo.getProductId(); //从Eureka中获取服务列表 List instances = discoveryClient.getInstances(\"product-service\"); //http://127.0.0.1:9090 //instances.get(0):服务可能有多个,这里只获取第一个 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; }
4.启动测试
可以看到order-service已经注册到eureka上了。
访问接口:http://127.0.0.1:8080/order/1
也可以看到,远程调用成功了。
Eureka 和Zookeeper区别(不发)
Eureka和Zookeeper都是⽤于服务注册和发现的⼯具,区别如下:
- Eureka是Netflix开源的项⽬, ⽽Zookeeper是Apache开源的项⽬.
- Eureka 基于AP原则, 保证⾼可⽤, Zookeeper基于CP原则, 保证数据⼀致性.
- Eureka 每个节点 都是均等的, Zookeeper的节点区分Leader 和Follower 或 Observer, 也正因为这 个原因, 如果Zookeeper的Leader发⽣故障时, 需要重新选举, 选举过程集群会有短暂时间的不可⽤.