Spring Cloud 学习笔记:Zookeeper 服务注册

Zookeeper

Zookeeper 是一个开源的分布式的,为分布式应用提供协调服务的 Apache 项目。从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化 ,Zookeeper就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应。
在这里插入图片描述

Zookeeper = 文件系统 + 通知机制

Zookeeper 维护一个类似文件系统的数据结构,Zookeeper 的命名空间的结构和文件系统很像,一个名字和文件一样使用/的路径表现,Zookeeper 的每个节点都是被路径唯一标识。
在这里插入图片描述

选举机制

  • 半数机制:集群中半数以上机器存活,集群可用。所以 Zookeeper 适合安装奇数台服务器。
  • Zookeeper 虽然在配置文件中并没有指定 Master 和 Slave。但是 Zookeeper 工作时是有一个节点为 Leader,其他则为 Follower,Leader 是通过内部的选举机制临时产生的。

以一个简单的例子来说明整个选举的过程。假设有五台服务器组成的 Zookeeper 集群,它们的 id 从 1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动:

  1. 服务器 1 启动,发起一次选举。服务器 1 投自己一票。此时服务器 1 票数一票,不够半数以上(3 票),选举无法完成,服务器 1 状态保持为 LOOKING;
  2. 服务器 2 启动,再发起一次选举。服务器 1 和 2 分别投自己一票并交换选票信息。此时服务器 1 发现服务器 2 的 ID(Zookeeper 中节点有 myid 和 txid,此处指的是 myid)比自己目前投票推举的(服务器 1)大,更改选票为推举服务器 2。此时服务器 1 票数 0 票,服务器 2 票数 2 票,没有半数以上结果,选举无法完成,服务器 1,2 状态保持 LOOKING;
  3. 服务器 3 启动,发起一次选举。此时服务器 1 和 2 都会更改选票为服务器 3。此次投票结果:服务器 1 为 0 票,服务器 2 为 0 票,服务器 3 为 3 票。此时服务器 3 的票数已经超过半数,服务器 3 当选 Leader。服务器 1,2 更改状态为 FOLLOWING,服务器 3 更改状态为 LEADING;
  4. 服务器 4 启动,发起一次选举。此时服务器 1,2,3 已经不是 LOOKING 状态,不会更改选票信息。交换选票信息结果:服务器 3 为3 票,服务器 4 为 1 票。此时服务器 4服从多数,更改选票信息为服务器 3,并更改状态为 FOLLOWING;
  5. 服务器 5 启动,同 4 一样。

原子广播

所有写请求由 Leader 完成,Leader 广播给 Follower,半数以上 Follower 持久化更改后,Leader 提交更新并通知客户端成功。任何 znode 都可以提供读请求

Zookeeper 与 Kafaka 保持数据一致性的不同点

  • zookeeper 的 leader 负责数据的读写,而 follower 只负责数据的读,如果 follower 遇到写操作会提交到 leader ;当 leader 宕机的话,使用选举机制快速选举出新的 leader,节点在一开始都处于选举阶段,只要有一个节点得到超半数节点的票数,它就可以当选准 leader。
  • kafka 只有 leader 负责读写,follower 只负责备份,如果 leader 宕机的话,kafka 动态维护了一个同步状态的副本的集合(a set of in-sync replicas),简称ISR。ISR中有 f+1 个节点,就可以允许在 f 个节点都 down 掉的情况下不会丢失消息并正常提供服务。
数据一致性

在数据有多分副本的情况下,如果网络、服务器或者软件出现故障,会导致部分副本写入成功,部分副本写入失败。这就造成各个副本之间的数据不一致,数据内容冲突。

centos7 安装 Zookeeper

Zookeeper 下载地址
在ping通 mac 端与 CentOS 端的连接后使用 scp 传输文件

scp zookeeper-3.4.14.tar.gz root@172.16.0.128:/opt/softwares

解压

tar -zxf zookeeper-3.4.14.tar.gz -C /opt/modules/

如下图所示
在这里插入图片描述
在 zookeeper 文件夹中创建一个 data 的文件夹

mkdir data

将 conf 目录下的 zoo_sample.cfg 复制一份并命名为 zoo.cfg

cp zoo_sample.cfg zoo.cfg

修改 zoo.cfg 文件
在这里插入图片描述
返回到 bin 文件夹中,使用指令启动 zookeeper 并查看状态

./zkServer.sh start

./zkServer.sh status

如下图所示
在这里插入图片描述

Spring Cloud 整合

创建子模块 cloud-provider-payment8004
pom.xml 文件中引入 zookeeper 依赖替换 eureka

<dependencies>
    <!--springboot整合zookeeper客户端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    </dependency>
    <!--Springboot整合web组件-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--引入自定义的api通用包,可以使用payment支付Entity-->
    <dependency>
        <groupId>com.hangzhou.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

application.yml

#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
  port: 8004

#服务别名----注册zookeeper到注册中心名称
spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      connect-string: 172.16.0.128:2181

PaymentMain8004.class

@SpringBootApplication
@EnableDiscoveryClient  //该注解用于想使用consul或者zookeeper作为注册中心时注册服务
public class PaymentMain8004 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8004.class,args);
    }
}

controller 层

@RestController
@Slf4j
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;

    @GetMapping(value = "/payment/zk")
    public String paymentzk(){
        return "springcloud with zookeeper:"+serverPort+"\t"+ UUID.randomUUID().toString();
    }
}

./zkCli.sh 启动 zookeeper 客户端
在这里插入图片描述
启动8004注册进 zookeeper,控制台报错
在这里插入图片描述
是因为依赖中的 zookeeper 版本与 CentOS 中的版本冲突
在这里插入图片描述
修改 pom 依赖,排除3.5.3版本的,并引入 Cent OS 中 zookeeper 的3.4.14版本

<!--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>
        </dependency>

zookeeper 还会遇到 slf4j 和 log4j 冲突的问题,此时在 zookeeper 再去掉slf4j的依赖
在这里插入图片描述
pom.xml

<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>

启动成功后服务模块入驻 zookeeper
在这里插入图片描述
微服务作为一个 znode 节点放到 zookeeper 服务器上,图中的这一大串就是在 zookeeper 上的基本信息的 json 串,就能看到 zookeeper 上8004微服务提供者的相关信息
在这里插入图片描述
并且能访问相应 url
在这里插入图片描述
此时的微服务在 zookeeper 上是一个临时节点。当服务提供者出现故障的时候,zookeeper 也是在一定时间内不会剔除服务,超时才剔除,所以 zookeeper 具备的服务节点是临时的。当再启动8004时,zookeeper 还会自动监听服务状态,但是id是一个新的id。

创建子module cloud-consumerzk-order80
pom.xml

<dependencies>
    <!--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>
    <!--Springboot整合web组件-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--引入自定义的api通用包,可以使用payment支付Entity-->
    <dependency>
        <groupId>com.hangzhou.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

application.yml

server:
  port: 80
spring:
  application:
    name: cloud-consumerzk-order
  cloud:
    #注册到zookeeper地址
    zookeeper:
      connect-string: 172.16.0.128:2181

config

@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

controller 层

@RestController
@Slf4j
public class OrderZKController {
    public static final String INVOKE_URL = "http://cloud-provider-payment";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping(value = "/consumer/payment/zk")
    public String paymentInfo(){
        String result = restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class);
        return result;
    }
}

启动 order80 后查看zk端入驻的服务
在这里插入图片描述
服务也能访问
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值