SpringCloud
很多的组件都已经停止更新或者进入维护阶段了,所以是时候应该学习一下这些组件的替代方案了。
今天从第一个开始吧,学习一下服务注册中心Eureka
的替代方案。
Spring Cloud版本
Spring Cloud
和Spring Boot
的版本对应情况:https://spring.io/projects/spring-cloud#overview
更具体的对应情况说明:https://start.spring.io/actuator/info (JSON数据)
Eureka的准备工作
Eureka
是一个Java
编写的注册中心,设计原则是AP
,这就意味着舍弃了数据一致性,所以Eureka
适用于需要高度响应的分布式环境,并不适用于数据严格一致的分布式环境。
关于CAP
的一篇文章,阮老师写的:点击查看
在开始Eureka
之前,先做一个RestTemplate
的准备工作,首先建立一个Provider
项目,就是一个普普通通的SpringMVC
项目,暴露一个接口就可以了,例如下面的样子:
@Value("${server.port}")
private String serverPort;
@GetMapping("payInfo")
public String payInfo() {
return "返回了一个信息!!!" + serverPort;
}
紧接着用另外一个项目(Consumer
)去访问这个接口,例如下面的样子:
@Resource
private RestTemplate restTemplate;
/**
* 这里要指向提供者接口
*/
private static final String BASE_URL = "http://localhost:8001";
@GetMapping("pay")
public String payInfo() {
return restTemplate.getForObject(BASE_URL + "/payInfo", String.class);
}
RestTemplate
的配置如下:
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
然后访问Consumer
,就可以通过Consumer
来访问到Provider
了,这样的缺点就是Provider
的地址在代码中写死了,使用注册中心可以解决这个问题。
安装Eureka服务端
Eureka
不需要专门去安装一个软件,直接在项目中创建一个项目,导入Eureka
的包就可以使用Eureka
了
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
这个包就是Eureka
的服务端,导入包之后,需要对Eureka
进行一些配置:
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
# 不把自己注册到Eureka中
register-with-eureka: false
# 不去注册中心检索服务
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
上面两个false
的作用就是用来说明,当前是服务端,不需要将自己作为服务注册到注册中心,也不需要去检索注册中心里面拥有的服务。
紧接着写一个启动类,就可以完美的启动Eureka
的服务端了。
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
@EnableEurekaServer
的作用就是启用Eureka
的服务端,启动这个main
方法就可以启动Eureka
服务了。
启动之后可以直接访问http://localhost:7001就可以看到Eureka的服务界面了,他是一个Web-UI
可以看到当前是没有实例可用的,也就是没有服务注册到Eureka
上面,接下来就让之前编写的Provider
注册上来。
关于这个页面的具体的一些细节,以及Eureka
的一些扩充内容,后面再记录。
注册Provider到Eureka
和创建服务端基本类似,只是换了换pom
和配置,启动类也发生了一点变化。
导入Eureka
的客户端
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
接下来编写application.yaml
文件
spring:
application:
name: cloud-provider-paymanet
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
上面的spring.application.name
很重要,因为这个就是注册到注册中心的名称。
编写启动类:
@SpringBootApplication
@EnableEurekaClient
public class PaymentApplication {
public static void main(String[] args) {
SpringApplication.run(PaymentApplication.class, args);
}
}
上面使用了@EnableEurekaClient
注解标明当前是Eureka
的客户端。
然后启动后,就可以在Eureka
的服务端上面看到这个实例了。
如何让Consumer
去注册中心寻找Provider
?
注册Consumer到Eureka
和Provider
同样的步骤,唯一不一样的是RestTemplate
的BASE_URL
发生了改变,不再用手动规定了,可以直接修改为:
private static final String BASE_URL = "http://CLOUD-PROVIDER-PAYMANET";
这个URL中的CLOUD-PROVIDER-PAYMANET
就是Provider
配置文件中规定的(注意是大写):
spring:
application:
name: cloud-provider-paymanet
只改了一下BASE_URL
是不足以让Consumer
找到Provider
的,还需要让RestTemplate
去自动寻找这个服务。所以之前的RestTemplate
配置需要发生一些改变了。
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
和之前不一样的只是多写了一个注解@LoadBalanced
,这个注解就可以做到让RestTemplate
去注册中心寻找地址。
到目前为止,就基本在项目中用到了Eureka
但是Eureka
只有一个,当然是不够的。
Eureka集群搭建
搭建集群很简单,但是因为是开发环境,所以我们需要再次新建一个Eureka
服务端,用这两个Eureka
服务端来一起配合做集群。
只需要在两个配置文件中互相注册一下,就可以了,三个Eureka
或者更多的Eureka
,也是一样的道理。
首先需要配置一下hosts
文件,让两个Eureka
都拥有自己的hostname
,毕竟是一台机器上模拟集群,所以只好这样做了。
127.0.0.1 eureka1
127.0.0.1 eureka2
修改配置文件:
假设这两个Eureka
的端口一个是7001
,一个是7002
,那么这两个的配置文件是下面的样子:
7001
:
server:
port: 7001
eureka:
instance:
hostname: eureka1
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka2:7002/eureka/
7002
:
server:
port: 7002
eureka:
instance:
hostname: eureka2
client:
# 不把自己注册到Eureka中
register-with-eureka: false
# 不去注册中心检索服务
fetch-registry: false
service-url:
defaultZone: http://eureka1:7001/eureka/
可以看到7001
和7002
互相注册了一下。怎么查看集群成功了呢?
同时启动7001
和7002
,查看Eureka
的界面,看到下面的内容,就是成功了。
因为有了集群,所以之前的Provider
和Consumer
也就不能简简单单的注册到一个Eureka
了,它们可以同时注册进两个Eureka
服务。
eureka:
client:
service-url:
defaultZone: http://eureka1:7001/eureka,http://eureka2:7002/eureka
可以看到两个地址中间用了,
,这样就可以同时将服务注册到两个Eureka
了。
Eureka
集群搭建完了,注册中心有了集群,但是Provider
并没有集群,照样是不安全的。
所以给Provider
也要配置集群。
配置Provider的集群
这就很简单了,只需要拥有多个Provider
就可以了,将多个Provider
同时注册到Eureka
,不就达到了集群的效果吗?所以需要拷贝一下Provider
,让Provider
拥有两个就可以了。
最后启动两个Provider
,可以看到Eureka
的界面上显示是下面这样,就意味着配置集群成功了。
Eureka的其他说明
上面简单的介绍了Eureka
的使用,Eureka
的其他信息都在这里进行补充。
Eureka中Web-UI显示信息完善
Eureka
的Web-UI
界面中的服务默认是主机名:服务名:端口
,而且鼠标放在服务上面显示的是localhost
,并不是服务对应的IP
地址,所以可以通过配置来改变。
instance:
instance-id: provider01
prefer-ip-address: true
instance-id
是Eureka
服务显示的名字,prefer-ip-address
是显示IP
地址。
然后重新启动后就可以看到效果:
DiscoveryClient对象的使用
如果要在应用内部得知注册中心有哪些服务,以及服务的详情信息,就可以直接在类中注入一个对象即可:
@Resource
private DiscoveryClient discoveryClient;
这个对象可以获取到服务的名字和实例的名字:
@GetMapping("discovery")
public DiscoveryClient discovery() {
List<String> services = discoveryClient.getServices();
for (String service : services) {
System.out.println("|- 服务的名字:" + service);
List<ServiceInstance> instances = discoveryClient.getInstances(service);
for (ServiceInstance instance : instances) {
System.out.println("\t|- 实例的信息:" + instance.getHost() + ":" + instance.getPort());
}
}
return discoveryClient;
}
控制台打印:
|- 服务的名字:cloud-consumer-order
|- 实例的信息:localhost:80
|- 服务的名字:cloud-provider-paymanet
|- 实例的信息:192.168.207.1:8001
|- 实例的信息:192.168.207.1:8002
@EnableDiscoveryClient
注解的使用
之前使用的@EnableEurekaClient
可以使用@EnableDiscoveryClient
注解来代替,因为后面将要介绍到的几种注册中心都使用的是@EnableDiscoveryClient
Eureka的自我保护
Eureka
默认是开启了自我保护机制的,30秒钟发送一次心跳,如果90秒没有发送心跳才会将服务剔除,可以关闭这个自我保护,让Eureka
一旦发现服务停止发送心跳,就立刻将服务剔除:
eureka:
server:
# 关闭自我保护
enable-self-preservation: false
# 修改检查服务失效的时间
eviction-interval-timer-in-ms: 3000
微服务可以修改默认的心跳时间:
eureka:
instance:
# 默认90秒
lease-expiration-duration-in-seconds: 10
# 默认30秒
lease-renewal-interval-in-seconds: 3
Eureka2.0停更
https://github.com/Netflix/eureka/wiki
Wiki
上面说:
The existing open source work on eureka 2.0 is discontinued. The code base and artifacts that were released as part of the existing repository of work on the 2.x branch is considered use at your own risk.
Eureka 1.x is a core part of Netflix's service discovery system and is still an active project.
既然这样的话,就应该寻找一下Eureka
的替代方案了。
替代方案1:Zookeeper
Zookeeper
之前也有过一篇文章进行记录,Zookeeper
的基本概念和安装就不介绍了,直接使用SpringCloud
和它进行整合。
Zookeeper
就不用自己去写服务端了,安装到Linux
之后启动,然后关闭防火墙,只需要在Provider
和Consumer
里面将注册中心换成Zookeeper
就可以了。
改写Provider
需要导入一个pom
坐标:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
配置文件:
spring:
application:
name: cloud-provider-paymanet
cloud:
zookeeper:
# 这里不要添加http://,因为它并不是http协议
connect-string: 192.168.207.128:2181
紧接着在启动类上面添加上@EnableDiscoveryClient
注解,然后启动一下微服务,就可以发现服务被注册到了Zookeeper
上。
或者说使用get来获取注册的微服务信息:
将微服务关闭以后过一段时间,发现zookeeper
中注册的服务也消失掉了,这就足以证明,SpringCloud
使用Zookeeper
是CP
原则,并不是AP
原则,微服务在Zookeeper
中保存的Znode
是一个临时节点。
改写Consumer
和改写Provider
一个道理。只是RestTemplate
的BASE_URL
发生了变化:
private static final String BASE_URL = "http://cloud-provider-paymanet";
Zookeeper
替代方案就到这里了,对于Zookeeper
的集群可以参照其他文章,对于Provider
的集群,和上面介绍的一个道理,这里就不再重复了。
替代方案2:Consul
下载地址:https://www.consul.io/downloads.html
下载完成后解压就是一个exe
文件,使用命令就可以操作了
# 查看Consul的版本
./consul.exe --version
# 启动Consul
./consul.exe agent -dev
启动后可以查看界面:http://localhost:8500/ui/dc1/services
然后和替换成Zookeeper
一样,替换成Consul
也需要导入pom
坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
加入配置:
spring:
application:
name: cloud-provider-paymanet
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
其他都和配置Zookeeper
一样。
如果说遇到下面的错误,只需要加入一个Maven
坐标就可以了。
加入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Eureka是AP原则,Zookeeper和Consul是CP原则
替代方案3:Nacos
可以查看该系列的第八篇文章:SpringCloud Alibaba Nacos