微服务原则上是应该有多个服务提供者的实例的,在一般状况下服务提供者的数量和分布每每是动态变化的,这样在传统的单体应用中的那种硬编码服务url进行远程调用的方式就不足取。服务注册中心就是为了解决服务之间的注册与发现而产生的。
服务注册中心本质上是为了解耦服务提供者和服务消费者。java
服务注册中心的通常原理:node
Zookeeper它是⼀个分布式服务框架,是Apache Hadoop 的⼀个⼦项⽬,它主要是⽤来解决分布式应⽤中常常遇到的⼀些数据管理问题,如:统⼀命名服务、状态同步服务、集群管理、分布式应⽤配置项的管理等。
简单来讲zookeeper本质=存储+监听通知。
Zookeeper ⽤来作服务注册中⼼,主要是由于它具备节点(znode)变动通知功能,只要客户端监听相关服务节点,服务节点的全部变动,都能及时的通知到监听客户端,这样做为调⽤⽅只要使⽤Zookeeper 的客户端就能实现服务节点的订阅和变动通知功能了,⾮常⽅便。另外,Zookeeper可⽤性也能够,由于只要半数以上的选举节点存活,整个集群就是可⽤的。git
由Netflix开源,并被Pivatal集成到SpringCloud体系中,它是基于 RestfulAPI ⻛格开发的服务注册与发现组件。web
Consul是由HashiCorp基于Go语⾔开发的⽀持多数据中⼼分布式⾼可⽤的服务发布和注册服务软件, 采⽤Raft算法保证服务的⼀致性,且⽀持健康检查。算法
Nacos是⼀个更易于构建云原⽣应⽤的动态服务发现、配置管理和服务管理平台。简单来讲 Nacos就是 注册中⼼ + 配置中⼼的组合,帮助咱们解决微服务开发必会涉及到的服务注册与发现,服务配置,服务管理等问题。 Nacos 是 Spring Cloud Alibaba 核⼼组件之⼀,负责服务注册与发现,还有配置。spring
CAP原理三者对比:
浏览器
Eureka 包含两个组件:Eureka Server 和 Eureka Client, Eureka Client是⼀个Java客户端,⽤于简化与Eureka Server的交互; Eureka Server提供服务发现的能⼒,各个微服务启动时,会经过Eureka Client向Eureka Server 进⾏注册⾃⼰的信息(例如⽹络信息),Eureka Server会存储该服务的信息;
详细流程以下:缓存
服务提供者向Eureka Server中注册服务, Eureka Server接受到注册事件会在集群和分区中进⾏数据同步,Application Client做为消费端(服务消费者)能够从Eureka Server中获取到服务注册信息,进⾏服务调⽤。微服务启动后,会周期性地向Eureka Server发送⼼跳(默认周期为30秒)以续约⾃⼰的信息服务器
Eureka Server在⼀定时间内没有接收到某个微服务节点的⼼跳, Eureka Server将会注销该微服务节点(默认90秒)架构
每一个Eureka Server同时也是Eureka Client,多个Eureka Server之间经过复制的⽅式完成服务注册列表的同步
Eureka Client会缓存Eureka Server中的信息。即便全部的Eureka Server节点都宕掉,服务消费者依然能够使⽤缓存中的信息找到服务提供者
下面咱们来分别进行Eureka单实例及集群环境的搭建及使用(仅列出部分关键代码,详细代码请看文末源码):
新建父工程lagou-parent,在pom.xml中统一规定springcloud的版本:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
新建一个子模块spring-cloud-eureka-server8761,
添加依赖
<!--Eureka server依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
在启动类上面添加@EnableEurekaServer注解,代表此工程为EurekaServer服务工程。
application.yml:
#eureka server服务端口 server: port: 8761 spring: application: name: lagou-cloud-eureka-server # 应用名称,应用名称会在Eureka中做为服务名称 # eureka 客户端配置(和Server交互),Eureka Server 其实也是一个Client eureka: instance: hostname: localhost # 当前eureka实例的主机名 client: service-url: # 配置客户端所交互的Eureka Server的地址(Eureka Server集群中每个Server其实相对于其它Server来讲都是Client) # 集群模式下,defaultZone应该指向其它Eureka Server,若是有更多其它Server实例,逗号拼接便可 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ register-with-eureka: false # ⾃⼰就是服务不须要注册⾃⼰ 集群模式下能够改为true fetch-registry: false # ⾃⼰就是服务不须要从Eureka Server获取服务信息,默认为true,集群模式下能够改为true
执行启动类,浏览器访问http://localhost:8761/,出现如下界面说明启动成功。
对界面上的信息进行说明:
至此,单个Eureka server搭建完成。
在上面单体Eureka server的基础上搭建Eureka集群。
为了模拟服务器集群的效果,修改本机hosts文件:C:\Windows\System32\drivers\etc\hosts
127.0.0.1 LagouCloudEurekaServerA 127.0.0.1 LagouCloudEurekaServerB
在原有工程上新建一个Eureka server模块,命名为spring-cloud-eureka-server8762,
spring-cloud-eureka-server8761和spring-cloud-eureka-server8762的application.yml文件以下:
8761:
#eureka server服务端口 server: port: 8761 spring: application: name: lagou-cloud-eureka-server # 应用名称,应用名称会在Eureka中做为服务名称 # eureka 客户端配置(和Server交互),Eureka Server 其实也是一个Client eureka: instance: hostname: LagouCloudEurekaServerA # 当前eureka实例的主机名 client: service-url: # 配置客户端所交互的Eureka Server的地址(Eureka Server集群中每个Server其实相对于其它Server来讲都是Client) # 集群模式下,defaultZone应该指向其它Eureka Server,若是有更多其它Server实例,逗号拼接便可 defaultZone: http://LagouCloudEurekaServerB:8762/eureka/ register-with-eureka: true # ⾃⼰就是服务不须要注册⾃⼰ 集群模式下能够改为true fetch-registry: true # ⾃⼰就是服务不须要从Eureka Server获取服务信息,默认为true,集群模式下能够改为true
8762:
#eureka server服务端口 server: port: 8762 spring: application: name: lagou-cloud-eureka-server eureka: instance: hostname: LagouCloudEurekaServerB client: service-url: defaultZone: http://LagouCloudEurekaServerA:8761/eureka/ register-with-eureka: true fetch-registry: true
浏览器中访问
http://LagouCloudEurekaServerA:8761/eureka/
及
http://LagouCloudEurekaServerB:8762/eureka/
效果以下:
8761:
8762:
父工程中引入
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-commons</artifactId> </dependency>
服务提供者微服务中引入
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
服务提供者微服务applicaion.yml:
# Eureka配置 eureka: client: service-url: defaultZone: http://LagouCloudEurekaServerA:8761/eureka/,http://LagouCloudEurekaServerB:8762/eureka/ #把 eureka 集群中的全部 url 都填写了进来,也能够只写⼀台,由于各个eureka server能够同步注册表 instance: prefer-ip-address: true #使⽤ip注册,不然会使⽤主机名注册了(此处考虑到对⽼版本的兼容,新版本通过实验都是ip) #⾃定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress instance-id: ${spring.cloud.client.ipaddress}:${spring.application.name}:${server.port}:@project.version@
服务提供者启动类添加注解 @EnableDiscoveryClient或@EnableEurekaClient。
说明:
1)从Spring Cloud Edgware版本开始, @EnableDiscoveryClient 或 EnableEurekaClient
可省略。只需加上相关依赖,并进⾏相应配置,便可将微服务注册到服务发现组件上。
2)@EnableDiscoveryClient和@EnableEurekaClient⼆者的功能是⼀样的。可是若是选⽤的是eureka服务器,那么就推荐@EnableEurekaClient,若是是其余的注册中⼼,那么推荐使⽤
@EnableDiscoveryClient,考虑到通⽤性,后期咱们能够使⽤@EnableDiscoveryClient
启动EurekaServer,能够看到服务提供者实例已经成功注册到EurekaServer上:
注册服务消费者和服务提供者相似,pom中添加依赖,在启动类添加@EnableDiscoveryClient,在application.yml中添加eureka的配置信息。
能够看到服务消费者信息成功注册到EurekaServer上:
package com.lagou.edu.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.List; @RestController public class AutoDeliverController { @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; @GetMapping("/checkState/{userId}") public Integer findResumeOpenState(@PathVariable Long userId) { List<ServiceInstance> serviceInstanceList = discoveryClient.getInstances("lagou-service-resume"); ServiceInstance serviceInstance = serviceInstanceList.get(0); String host = serviceInstance.getHost(); int port = serviceInstance.getPort(); String url="http://"+host+":"+port+"/resume/openstate/"+userId; Integer forObject =restTemplate.getForObject(url,Integer.class); System.out.println("======>>>从eureka server获取服务提供者实例:"+url); return forObject; } }
调用成功信息以下:
源码地址:eureka-demo 源码
欢迎访问个人博客:https://www.liuyj.top