文章目录
系列链接:
- GitHub:源码
- SpringCloud(1)–入门、版本、环境搭建
- SpringCloud(2)–服务注册与发现(Eureka、Zookeeper、Consul)
- SpringCloud(3)–服务调用(Ribbon、OpenFeign)
- SpringCloud(4)–服务降级(Hystrix、降级、熔断、监控)
- SpringCloud(5)–服务网关(GateWay)
- …
服务注册中心
在环境搭建中,我们实现了服务模块直接通过Http的方式进行调用。而当我们的服务越来越多时就会不方便管理(服务运行状态等等),所以将这些服务在某个地方注册并进行统一的管理,这个地方就是我们的服务注册中心。
前面我们说过的几种服务注册中心:
- Eureka
- Zookeeper
- Consul
Eureka
服务治理:
而SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理。
微服务使用 Eureka 的客服端与 Eureka 服务器端维持心跳连接,维护人员就可以在服务器端监控到各个微服务(服务器信息)是否正常。
Eureka包含了两个组件:
- Eureka Server:提供注册服务,各个微服务节点会在其中进行注册。
- Eureka Client:一个Java客户端,用于简化与Eureka Server 的交互,同时会定时向Eureka Server发送心跳,如果Eureka Server 在多个心跳周期内没有接收到某个节点的心跳则会将该节点移除。
单机版eureka
创建Module
-
创建名为cloud-eureka-server7001的模块
-
引入pom依赖
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 其他依赖 -->
- 配置文件
server:
port: 7001
eureka:
instance:
# eureka服务端的实例名称
hostname: localhost
client:
# 不注册自己
register-with-eureka: false
# 表示自己是注册中心,不用检索服务
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 主启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args){
SpringApplication.run(EurekaMain7001.class,args);
}
}
- 启动当前项目,访问http://localhost:7001就可以看到如下页面,可以看到当前没有服务注册进来
其他服务注册到eureka
比如此时pay模块加入eureka:
- 修改pom,引入依赖
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 主启动类上,加注解,表示当前是eureka客户端
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args){
SpringApplication.run(PaymentMain8001.class,args);
}
}
- 修改配置文件:
eureka:
client:
# 不注册自己
register-with-eureka: true
# 表示自己是注册中心,不用检索服务
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
-
先启动EurekaServer,然后启动pay模块,就注册到eureka中了
-
order模块的注册是一样的,不再赘述
集群版eureka
集群原理
- pay模块与order模块启动时,会注册自己并将自身信息也放入EurekaServer
- 当order模块调用pay模块时,会先从EurekaServer拿到pay模块的调用地址
- 底层通过HttpClient调用并且还会缓存一份到本地,每30秒更新一次
- 如果注册中心只有一个,出现故障就会导致整个微服务环境不可用
构建原理:
构建新erueka项目
-
新建名字cloud-eureka-server7002的Module
-
主启动类、pom文件复制7001中的
-
为了更好辨认,修改Host文件,添加如下:
127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com
-
修改之前的7001项目的配置文件
7002也是一样的,只不过端口和地址改一下,多台在defaultZone用逗号隔开
- 然后启动7001,7002即可
其他服务注册到eureka集群
- 只需要修改配置文件即可
- 两个模块都修改上面的都一样即可
将pay模块也配置为集群模式
-
新建名称为cloud-provider-payment8002的Module
-
主启动类、pom文件、mapper、service、controller复制8001的
-
配置文件复制8001的,端口修改一下,改为8002,服务名称不用改,用一样的
-
然后修改订单模块中的URL,使请求负载均衡到两个pay模块中
-
首先添加注解,使RestTemplate开启负载均衡
(可以指定负载均衡算法,默认轮询)
@Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
-
之后修改RestTemplate请求的URL地址为微服务名称
-
为了避免暴露信息以及方便管理,可以修改服务主机名和ip在eureka的web上显示,通过修改配置文件:
服务发现
对于注册进Eureka里面的微服务,可以通过服务发现来获取该服务的信息,此处以pay模块为例。
-
首先注入DiscoverClient服务发现客户端
@Resource private DiscoveryClient discoveryClient;
-
这里我们便携一个查询接口
@GetMapping("/discovery") public Object discovery(){ //获取服务列表 List<String> services = discoveryClient.getServices(); for(String element : services){ log.info("****element: "+element); } //获取具体服务下的实例列表 List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); for(ServiceInstance instance : instances){ log.info(instance.getServiceId()+"/t"+instance.getHost()+"/t"+instance.getPort()+"/t"+instance.getUri()); } return this.discoveryClient; }
-
在主启动类上添加一个注解
-
最后访问我们的接口
自我保护
为什么有自我保护机制
为了防止EurekaClient可以正常运行,但是与EurekaServer网络不同的情况下,将EurekaClient服务剔除。
**自我保护模式 **
正常情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,就会注销该实例。
而自我保护模式就是某时刻某个微服务不可用了,Eureka不会立即进行清理,依旧会对该微服务的信息进行保存,属于CAP里面的AP分支(下文补充)。当EurekaServer节点在短时间内丢失过多客户端时(网络故障),节点就会进入自我保护模式。
自我保护模式配置
默认自我保护模式是开启的,可以通过配置进行禁用:
也可以设置客户端接受心跳时间间隔
此时启动erueka和pay.此时如果直接关闭了pay,那么erueka会直接删除其注册信息
Zookeeper
linux上安装 Zookeeper
Zookeeper是一个分布式协调工具,可以实现注册中心功能,所以可以取代Eureka服务器,作为服务注册与发现中心。
为了方便我们接下来的测试,通过 Docker 方式在远程服务器上以单机形式安装 Zookeeper,并启动。
创建新的pay模块
-
创建名称为 cloud-provider-payment8004 的 Module
-
pom依赖,相比之前的pay模块,添加如下
<!--SpringBoot整合Zookeeper客户端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <exclusions> <!--先排除自带的zookeeper3.5.3--> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> <!--添加zookeeper3.6.1版本--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.1</version>
-
配置文件,配置端口号、微服务名称、zookeeper地址
server: port: 8004 spring: application: name: cloud-provider-payment cloud: zookeeper: connect-string: hw.mokespace.cn:2181
-
主启动类
@SpringBootApplication @EnableDiscoveryClient public class PaymentMain8004 { public static void main(String[] args){ SpringApplication.run(PaymentMain8004.class,args); } }
-
controller随便写一下
@RestController @Slf4j @RequestMapping("/payment") public class PaymentController { @Value("${server.port}") private String serverPort; @GetMapping("/zk") public String paymentzk(){ return "springcloud with zookeeper"+serverPort+"\t"+ UUID.randomUUID().toString(); } }
-
然后就可以启动,此时8004就注册到zk中了
注:我们在zk上注册的node是临时节点,当我们的服务一定时间内没有发送心跳那么zk就会将这个服务的node删除
创建order消费模块注册到zk
-
创建名称为 cloud-consumerzk-order80 的 Module
-
pom、配置文件、RestTemplate 与8004类似
-
controller
@RestController
@Slf4j
@RequestMapping("/consumer")
public class OrderController {
private static final String INVOKE_URL = "http://cloud-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping("/payment/zk")
public String paymentInfo(){
return restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
}
}
- 然后启动即可注册到zk
集群版zk注册
只需要修改配置文件中的connect-string参数,指定多个zk地址即可。
Consul
Consul 是一套开源的分布式服务发现和配置管理系统,它提供了一种完整的服务网格解决方案,具有如下优点:
- 服务发现:提供HTTP和DNS两种发现方式
- 健康检测:支持HTTP、TCP、Docker、Shell等方式
- KV存储:key-value的存储方式
- 多数据中心:Consul支持多数据中心
- 可视化 Web 界面
安装与启动
在官网下载一个相应的安装包,博主这里下的是 windows 版本。
exe文件的当前目录打开CMD:
# 查看consul版本
consul --version
# 开发者模式启动
consul agent -dev
访问 http://localhost:8500 即可访问可视化的 Web 页面。
创建新的pay模块
-
项目名字cloud-providerconsul-payment8006
-
pom依赖,修改如下
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency>
-
配置文件
server: port: 8004 spring: application: name: cloud-provider-payment cloud: consul: host: localhost port: 8500 discovery: service-name: ${spring.application.name}
-
主启动类、controller 和 8004 差不多,编写好后启动
-
order模块也一样,这里不再赘述
三个注册中心的异同
组件名 | 语言 | CAP | 服务健康检查 | 对外暴露接口 | SpringCloud集成 |
---|---|---|---|---|---|
Eureka | Java | AP | 可配支持 | HTTP | 已集成 |
Consul | Go | CP | 支持 | HTTP/DNS | 已集成 |
Zookeeper | Java | CP | 支持 | 客户端 | 已集成 |
注:CAP 表示 Consistency、Availability、Partition tolerance,即强一致性、可用性以及分区容错性。
- AP架构:保证可用性
- CP架构:保证一致性