前面我们提到过如果Eureka不能使用了,我们该用什么替换,下面我们使用Zookeeper来代替Eureka注册服务。
ZooKeeper是一个典型的分布式数据一致性的解决方案。分布式应用程序可以基于它实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。ZooKeeper可以保证如下分布式一致性特性。
- 顺序一致性从同一个客户端发起的事务请求,最终将会严格按照其发起顺序被应用到ZooKeeper中。
- 原子性所有事务请求的结果在集群中所有机器上的应用情况是一致的,也就是说要么整个集群所有集群都成功应用了某一个事务,要么都没有应用,一定不会出现集群中部分机器应用了该事务,而另外一部分没有应用的情况。
- 单一视图无论客户端连接的是哪个ZooKeeper服务器,其看到的服务端数据模型都是一致的。
- 可靠性一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会被一直保留下来,除非有另一个事务又对其进行了变更。
- 实时性通常人们看到实时性的第一反应是,一旦一个事务被成功应用,那么客户端能够立即从服务端上读取到这个事务变更后的最新数据状态。这里需要注意的是,ZooKeeper仅仅保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。
1.导读
本节我们需要建两个模块,Server和Client,其实也就是Producer和Consumer,通过两个模块我们来演示如何用Consul轻松的替换Eureka。并且模拟Client远程调用 Server端。
2. 新建Server 项目
通过新建Server 模块,来模拟对外提供对外接口
2.1 maven 配置
因为注册中心用了Zookeeper,所以需要引入Zookeeper的依赖包及服务发现的包spring-cloud-starter-zookeeper-discovery、zookeeper
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>${ackson-core-asl.version}</version>
</dependency>
<dependency>
<groupId>com.yisu.cloud</groupId>
<artifactId>fw-cloud-feign-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
2.2 应用配置
以下配置了应用的端口及应用名称,其中对Zookeeper的配置我们配置了注册地址、以及服务发现的配置,为了方便查阅,我们让配置根目录为fw-cloud,每个应用最好配置自己的instance-id,不要和其他应用冲突。
server:
port: 8661
spring:
application:
name: fw-register-zookeeper
cloud:
zookeeper:
connectString: 127.0.0.1:2181 #可修改为自己的zk
discovery:
register: true
enabled: true
instance-id: 1
root: /fw-cloud
2.3 设置对外提供的接口
Server端提供了字符串类型的和实体对象类型的,项目启动之后注册到Zookeeper即可对外提供服务。
@RestController
public class HelloWorldController {
@GetMapping("/helloWorld")
public String HelloWorld() {
return "Hello World!";
}
@GetMapping("/user")
public User getUser() {
return new User(1L,"zookeeper","test","test@qq.com","演示Zookeeper 替换Eureka");
}
}
2.4 Server 启动类
这里需要添加@EnableDiscoveryClient,和Eureka客户端引入的注解是一样的,里面的细节Spring Cloud官方已经为我们封装好了,可以直接使用。
@EnableDiscoveryClient
@SpringBootApplication
public class FwRegisterZookeeperApplication {
public static void main(String[] args) {
SpringApplication.run(FwRegisterZookeeperApplication.class, args);
}
}
Server 端导致结束
3. 新建Client 端
用来演示通过Zookeeper远程调用Server端的接口
3.1 maven 配置
配置上面和Server 端是一样的,都需要引入Zookeeper的依赖包及服务发现的包spring-cloud-starter-zookeeper-discovery、zookeeper,这也说明了Server 端既可以做 生产者也可以做消费者。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>${ackson-core-asl.version}</version>
</dependency>
<dependency>
<groupId>com.yisu.cloud</groupId>
<artifactId>fw-cloud-feign-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
3.2 应用配置
配置上面和Server也是几乎一致,只是修改了端口、应用名称及实例id instance-id,保证了存储在Zookeeper中的数据不会冲突。
server:
port: 8662
spring:
application:
name: fw-client-zookeeper-demo
cloud:
zookeeper:
connect-string: 127.0.0.1:2181
discovery:
register: true
enabled: true
instance-id: 2
root: /fw-cloud
3.3 Feign 接口
我们使用Feign来配置远程调用的服务名和调用的接口。
@FeignClient(name = "fw-register-zookeeper")
public interface ZookeeperApi {
/**
* 获取字符串信息
* @return
*/
@GetMapping("/helloWorld")
String helloWorld();
/**
* 获取用户信息demo
* @return
*/
@GetMapping("/user")
User getUser();
}
3.4 定义消费者接口
这里对外提供的接口名称可以自己定义,最终会将请求调用到Server的接口上面,并接收到执行结果返回给客户端。
@RestController
public class ZookeeperController {
@Autowired
private ZookeeperApi zookeeperApi;
/**
* hello word
* @return
*/
@GetMapping("/hello")
public String hello() {
return zookeeperApi.helloWorld();
}
/**
* 获取用户信息
* @return
*/
@GetMapping("/user")
public User getUser() {
return zookeeperApi.getUser();
}
}
3.5 Client 启动类
加上@EnableDiscoveryClient,@EnableFeignClients用于使用服务注册和开启Feign
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FwClientZookeeperApplication {
public static void main(String[] args) {
SpringApplication.run(FwClientZookeeperApplication.class, args);
}
}
4. 启动并测试
- 启动Zookeeper(有条件的可以启动Zookeeper的展示页面)
- 启动Server端
- 启动Client端
浏览器或Postman 输入 localhost:8662/hello
输入localhost:8662/user
5. 使用zkui 预览一下存储的数据
5.1下载源码包
地址:https://github.com/DeemOpen/zkui
5.2 编译解压
- 下载源码
- 之后再项目根目录上执行 mvn clean install(需要先装Maven)
到这一步说执行成功
5.3 运行zkui
将配置文件 config.cfg复制到target目录下,配置可以不用改动,默认是连接本地Zookeeper然后在target根目录下执行一下命令即可启动
java -jar zkui-2.0-SNAPSHOT-jar-with-dependencies.jar
5.4 浏览器查看
浏览器输入http://localhost:9090/登录进来之后我们可以看到根目录下有一个fw-cloud文件夹
点进来可以看到我们注册上来的两个服务
任意点击一个可以看到具体的注册信息
6. Zookeeper 的调用过程
1、当 Producer启动的时候,会向 Zookeeper写入临时文件,告诉 Zookeeper自己的 IP和 Port;
2、Zookeeper接收到 Producer的注册后,会建立一个长连接一直监听;
3、当 Consumer发送 GET方式请求 /user到 Producer时,会先从 Zookeeper中拿到一个 Producer服务的 IP和 Port,再发送 GET方式请求 /user;
4、如果服务断开连接,该节点会自动被删除。
7.总结
本节我们演示了Zookeeper如何快速的替代Eureka。实际上Eureka实现的服务治理机制强调了CAP原理中的AP,即可用性与可靠性,而Zookeeper这类强调CP(一致性、可靠性)。Eureka为了实现更高的服务可用性,牺牲了一定的一致性,在极端情况下它宁愿接受故障实例也不要丢掉“健康”实例,Consul的替换也很简单,下一节我们再分析,更多内容可以在教程中查看。
SpringCloud构建实战、从入门到复杂,包含eureka、zuul、gateway、feign、ribbon、hystrix、mq、turbine、nacos、elk、consul、zookeeper、rocketmq、kafka、分布式事务、jwt、SkyWalking、Zipkin、bootadmin等使用案例 https://github.com/xuyisu/fw-sping-cloud
详细教程可以点击左下角更多获取