SpringCloud之服务注册中心
1.Eureka
源码:https://github.com/zhongyushi-git/cloud-eureka-demo.git。
说明:本文是创建maven父子模块,然后把子模块转为SpringBoot项目进行开发的,也可以直接单独创建SpringBoot项目开发,大同小异。
1.1定义
官网:https://github.com/Netflix/eureka/wiki。目前2.0版本已经停止维护,只能使用1.0版本。
它是一个基于REST的服务,用于定位服务,以实现云端中间层发现和故障转移。简单来说就是服务注册与发现,只要使用服务的标识就可以访问到服务。
它采用cs架构,Eureka Server作为服务注册的服务器,是注册中心;
Eureka Client是客户端,需要注册的服务使用客户端连接到服务器并维持心跳,可以通过服务器来监测各个微服务是否正常运行。
1.2原理图
服务提供者把服务注册到Eureka,而服务消费者也把服务注册到Eureka。服务消费者想要调用服务提供者,就通过服务名去Eureka注册中心查询,服务提供者即可提供服务。
1.3基础环境搭建
1)创建一个maven工程名为cloud-eureka-demo,作为父工程,删除src目录
2)在pom中导入依赖,对SpringBoot和SpringCloud版本进行锁定
<properties> <spring.boot.version>2.2.2.RELEASE</spring.boot.version> <spring.cloud.version>Hoxton.SR1</spring.cloud.version> </properties> <!-- 依赖管理,父工程锁定版本--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
1.4搭建Eureka的服务注册中心
所谓服务中心,也就是Eureka Server。服务中心需要在启动类上添加注解@EnableEurekaServer表示这是一个Eureka的服务中心
1)创建maven的工程名为eureka-demo-server7001,作为子工程,下同。在pom中导入依赖
<dependencies> <!--eureka server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
2)创建包com.zys.cloud,在包下新建启动类EurekaMain7001
package com.zys.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class, args); } }
3)在资源目录下创建配置文件application.yml
server: port: 7001 eureka: instance: #eureka服务端的实例名称 hostname: localhost client: #false表示不向注册中心注册自己 register-with-eureka: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4)运行测试
启动主启动类,在浏览器输入http://127.0.0.1:7001测试server是否搭建成功,看到下图说明已搭建成功。
1.5创建服务提供者
1)创建maven的工程名为eureka-demo-provider,在pom中导入依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
引入的actuator作用是健康检查,故每个项目都导入了此坐标。
2)新建启动类ProviderMain8001
package com.zys; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
3)创建TestController类
package com.zys.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class TestController { @Value("${server.port}") private String port; @GetMapping("/get") public String get() { return "我是服务提供者,端口:" + port; } }
4)在资源目录下创建配置文件application.yml
server: port: 8001
1.6将服务提供者注册到Eureka
1)在eureka-demo-provider的pom中添加eureka客户端的依赖
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2)在eureka-demo-provider的yml文件中添加eureka客户端的配置
spring:
application:
name: cloud-eureka-demo-provider
#把客户端注册到服务列表中
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
instance:
#设置入驻的服务的名称,是唯一的,最好和应用名称一致
instance-id: cloud-eureka-demo-provider
#访问路径显示ip
prefer-ip-address: true
需要注意的是,必须要设置应用名称,否则在eureka中会显示UNKNOW。
3)在eureka-demo-provider的启动类上添加eureka客户端的注解@EnableEurekaClient
@SpringBootApplication @EnableEurekaClient public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
4)运行测试
先运行eureka服务,再运行服务提供者,在浏览器输入http://127.0.0.1:7001,看到有一个服务,说明注册成功。
1.7Eureka自我保护机制
在刚刚启动的时候,并没有出现下面红色的部分,但是过一会再次刷新,就会出现下面的红色文字。也就是说是eureka的自我保护机制发挥的作用。简单来说,就是某一时刻,某个服务不使用了,但eureka并不会立即清除掉,而是依旧保持此微服务的信息。当它收到的心跳数重新恢复到阈值以上时该服务节点会自动退出保护模式,是一种应对网络异常的安全保护措施。
有时候就想某个服务不用了或者死掉了,就直接清理,如何操作呢?也是可以配置的。
在动服务注册中心7001的yml设置server.enable-self-preservation为false,配置如下
eureka:
#关闭自我保护 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000
在eureka-demo-provider的yml设置连接的时间
eureka: instance: #eureka服务端在接受到最后一次心跳后等待的时间,默认90s,超时剔除服务 lease-expiration-duration-in-seconds: 2 #eureka客户端向服务端发送心跳的时间,默认30s lease-renewal-interval-in-seconds: 1
然后启动服务注册中心7001和服务提供者eureka-demo-provider,刷新eureka页面,出现下图说明关闭成功:
悄悄的关闭服务提供者eureka-demo-provider,刷新页面,发现8001的服务不在了。
1.8Eureka集群搭建
如果eureka服务注册中心只有一台,当服务器宕机时,就不能正常提供服务了,因此集群也是很重要的。这里就由三个服务器组成一个集群。
1)新建maven工程eureka-demo-server7002和eureka-demo-server7003。后面就简称7002和7003
2)分别把eureka-demo-server7001的pom依赖复制到7002和7003中
3)参照7001创建7002和7003的启动类
4)修改域名映射文件C:\Windows\System32\drivers\etc\hosts, 在最后添加
127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 127.0.0.1 eureka7003.com
5)修改配置文件yml,将eureka单机版服务改为集群服务
7001的yml
server: port: 7001 eureka: #关闭自我保护 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000 instance: #eureka服务端的实例名称 #单机版 # hostname: localhost #集群 hostname: eureka7001.com client: #false表示不向注册中心注册自己 register-with-eureka: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址 #单机版 # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #集群 defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/
7002的yml
server: port: 7002 eureka: #关闭自我保护 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000 instance: #eureka服务端的实例名称 #单机版 # hostname: localhost #集群 hostname: eureka7002.com client: #false表示不向注册中心注册自己 register-with-eureka: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址 #单机版 # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #集群 defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7003.com:7003/eureka/
7003的yml
server: port: 7003 eureka: #关闭自我保护 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000 instance: #eureka服务端的实例名称 #单机版 # hostname: localhost #集群 hostname: eureka7003.com client: #false表示不向注册中心注册自己 register-with-eureka: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址 #单机版 # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #集群 defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/
6)修改eureka-demo-provider的yml,服务url设置为集群
defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/
7)启动测试
依次启动7001、7002、7003、服务提供者eureka-demo-provider,然后在浏览器分别访问eureka7001.com:7001,eureka7002.com:7002,eureka7003.com:7003。会发现他们都和另外两个服务器连接着。如访问7003的:
1.9Eureka服务发现Discovery
它的功能就是获取注册进eureka中的微服务的信息。
1)修改eureka-demo-provider模块的controller,在里面添加获取服务信息的方法
@Autowired private DiscoveryClient discoveryClient; @GetMapping("/discovery") public Object discovery() { //获取注册的服务列表信息 List<String> services = discoveryClient.getServices(); //根据服务名称获取实例列表信息 String serviceId = "CLOUD-EUREKA-DEMO-PROVIDER"; List<ServiceInstance> instances = discoveryClient.getInstances(serviceId); Map<String, Object> map = new HashMap<>(); map.put("服务列表", services); map.put("实例列表", instances); return map; }
2)在启动类上添加注解@EnableDiscoveryClient
@SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
3)启动测试
先启动eureka集群,然后启动8001,在浏览器输入即可看到服务的相关信息,包括服务列表,实例列表,主机ip等。
2.Zookeeper
zookeeper也可以做注册中心。这里默认已经在linux上安装好了Zookeeper服务并允许外部访问。
源代码:https://github.com/zhongyushi-git/cloud-zookeeper-demo.git
2.1项目搭建
1)创建一个maven工程名为cloud-zookeeper-demo,作为父工程,删除src目录
2)在pom中导入依赖,对SpringBoot和SpringCloud版本进行锁定
<dependencies> <!--eureka server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
2.2服务提供者注册
1)创建子模块cloud-zk-provider,导入依赖
<dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency <!--springboot整合zookeeper客户端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <!--先排除自带的zookeeper3.5.3--> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> <!--添加zookeeper3.4.14版本--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.14</version> <exclusions> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
2)配置application.yml
server: port: 8001 spring: application: name: cloud-provider #配置zookeeper cloud: zookeeper: connect-string: 192.168.0.22:2181
3)创建controller
package com.zys.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class TestController { @Value("${server.port}") private String port; @GetMapping("/get") public String get() { return "我是服务提供者,端口:" + port; } }
4)创建启动类并添加注解@EnableDiscoveryClient
package com.zys; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
@EnableDiscoveryClient用于Zookeeper作为注册中心时注册服务
5)启动测试
启动服务后,在浏览器输入http://127.0.0.1:8001/user/get/1,数据可以正常访问。打开连接linux的软件,启动Zookeeper客户端。
查看注册的服务
ls /
查看注册的具体服务
ls /services ls /services/cloud-provider
获取服务的具体信息
ls /services/cloud-provider/d619cc0e-d460-454a-8238-5ac87c0dd3f8
需要注意的是cloud-provider是注册的时候的服务名称,后面的字符串是生成的服务的id。这个服务节点是临时节点。至此服务提供者已注册到Zookeeper中。
3.Consul
源码:https://github.com/zhongyushi-git/cloud-consul-demo.git
3.1定义
是一套开源的分布式服务发现和配置管理系统,提供了服务治理、配置中心、控制总线等功能。它拥有一个web的可视化界面。
3.2下载与安装
1)下载网址:https://www.consul.io/downloads.html 下载对应的版本即可
2)解压,在当前目录打开cmd,输入命令来以开发者模式启动
consul agent -dev
3)在浏览器输入localhost:8500看到consul控制界面,说明安装成功。
3.3基本环境搭建
1)创建一个maven工程名为cloud-consul-demo,作为父工程,删除src目录
2)在pom中导入依赖,对SpringBoot和SpringCloud版本进行锁定
<properties> <spring.boot.version>2.2.2.RELEASE</spring.boot.version> <spring.cloud.version>Hoxton.SR1</spring.cloud.version> </properties> <!-- 依赖管理,父工程锁定版本--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
3.4服务提供者注册
1)新建maven的子工程cloud-consul-provider8001,导入依赖
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
2)配置application.yml
server: port: 8001 spring: application: name: cloud-consul-provider cloud: consul: host: localhost port: 8500 discovery: service-name: ${spring.application.name}
3)创建启动类并加@EnableDiscoveryClient注解
package com.zxh.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ConsulProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ConsulProviderMain8001.class,args); } }
4)创建controller接口
package com.zxh.cloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class TestController { @Value("${server.port}") private String port; @GetMapping("/get") public String get() { return "我是服务提供者,端口:" + port; } }
5)启动测试
先启动consul服务,然后启动8001,在浏览器输入http://localhost:8500/可以看到提供者服务注册进来了。
3.5CAP定理
在一个分布式系统中,一致性、可用性、分区容错这三个特性,不可能同时满足,而是必须有所舍弃,只能同时满足其中的两个。表示含义如下:
简写 | 全称 | 说明 |
C | Consistency | 一致性。各节点的数据在同一时刻保持一致 |
A | Availability | 可用性。每次向未崩溃的节点发送请求,总能保证收到响应数据(允许不是最新数据) |
P | Partition tolerance | 分区容错性。容许节点间传递消息出现延迟或丢失,而不影响系统继续运行 |
3.6Eureka、Zookeeper与Consul的异同
组件名 | 所用语言 | CAP | 对外暴露接口 |
Eureka | java | AP | HTTP |
Zookeeper | java | CP | 客户端 |
Consul | go | CP | HTTP/DNS |