自学zookeeper+Dubbo

Zookeeper是什么

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

1. 数据结构

Zookeeper维护一个类似文件系统的数据结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LiLuFkkJ-1655164090030)(imgs/807121434154.png)]

每个子目录项如 NameService 都被称作为 znode(目录节点),和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。

有四种类型的znode:

  • PERSISTENT-持久化目录节点

客户端与zookeeper断开连接后,该节点依旧存在

  • PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点

客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

  • EPHEMERAL-临时目录节点

客户端与zookeeper断开连接后,该节点被删除

  • EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点

客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

2. 监听通知机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。

Zookeeper可以做什么

Zookeeper可以用于:

  1. 服务注册和发现

  2. 配置管理

  3. 分布式锁

  4. 集群管理

Zookeeper的安装

单机版安装

1)安装java

2)下载、解压zookeeper

3)修改zoo_sample.conf 为zoo.conf

4)启动服务

./zkServer.sh start
其它:
./zkServer.sh stop
./zkServer.sh restart
./zkServer.sh status

5)启动客户端

./zkCli.sh
客户端命令:
查看目录		ls /
创建节点		create /name	value
查看节点		get /name
修改			set /name value
删除			delete /name
退出			quit

集群安装

Step1:配置JAVA环境,检验环境:java -version

Step2:下载并解压zookeeper

  1. # cd /usr/local
  2. # wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz
  3. # tar -zxvf zookeeper-3.4.12.tar.gz
  4. # cd zookeeper-3.4.12

Step3:重命名 zoo_sample.cfg文件

# cp conf/zoo_sample.cfg conf/zoo-1.cfg

Step4:修改配置文件zoo-1.cfg,原配置文件里有的,修改成下面的值,没有的则加上

   1. # vim conf/zoo-1.cfg
   2. dataDir=/tmp/zookeeper-1
   3. clientPort=2181
   4. server.1=127.0.0.1:2888:3888
   5. server.2=127.0.0.1:2889:3889
   6. server.3=127.0.0.1:2890:3890

Step4:再从zoo-1.cfg复制两个配置文件zoo-2.cfg和zoo-3.cfg,只需修改dataDir和clientPort不同即可

  1. # cp conf/zoo-1.cfg conf/zoo-2.cfg
  2. # cp conf/zoo-1.cfg conf/zoo-3.cfg
  3. # vim conf/zoo-2.cfg
  4. dataDir=/tmp/zookeeper-2
  5. clientPort=2182
  6. # vim conf/zoo-2.cfg
  7. dataDir=/tmp/zookeeper-3
  8. clientPort=2183

Step5:标识Server ID

创建三个文件夹/tmp/zookeeper-1,/tmp/zookeeper-2,/tmp/zookeeper-2,在每个目录中创建文件myid 文件,写入当前实例的server id,即1.2.3

  1. \# cd /tmp/zookeeper-1
  2. \# vim myid
  3. 1
  4. \# cd /tmp/zookeeper-2
  5. \# vim myid
  6. 2
  7. \# cd /tmp/zookeeper-3
  8. \# vim myid
  9. 3

Step6:启动三个zookeeper实例

   1. \# bin/zkServer.sh start conf/zoo-1.cfg
   2. \# bin/zkServer.sh start conf/zoo-2.cfg
   3. \# bin/zkServer.sh start conf/zoo-3.cfg

Step7:检测集群状态,也可以直接用命令“zkCli.sh -server IP:PORT”连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FIQ8CvCx-1655164090033)(imgs/712144336907.png)]

Zookeeper面试题

问题1:为什么最好使用奇数台服务器构成 ZooKeeper 集群?

我们知道在 ZooKeeper 中 Leader 选举算法采用了 Zab 协议。Zab 核心思想是当多数 Server 写成功,则任务数据写成功:

  • 如果有 3 个 Server,则最多允许 1 个 Server 挂掉。
  • 如果有 4 个 Server,则同样最多允许 1 个 Server 挂掉。

既然 3 个或者 4 个 Server,同样最多允许 1 个 Server 挂掉,那么它们的可靠性是一样的。

问题2:监听原理
1)首先要有一个main()线程
2)在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责网络连接通信(connet),一个负责监听(listener)。
3)通过connect线程将注册的监听事件发送给Zookeeper。
4)在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。
5)Zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程。
6)listener线程内部调用了process()方法。

2、常见的监听
1)监听节点数据的变化
get path [watch]
2)监听子节点增减的变化
ls path [watch]

问题3:Leader选举机制

1)半数机制:集群中半数以上机器存活,集群可用

2)Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的,Leader是处理事务的唯一节点,follower收到事务请求也会将事情请求转发给leader,由leader处理协调zookeeper中的其他节点。

3)以一个简单的例子来说明整个选举的过程。

假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么,如图5-8所示。

(1)服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;

(2)服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的ID比自己目前投票推举的(服务器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一样当小弟。

Zookeeper的基本使用

<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
	<groupId>org.apache.zookeeper</groupId>
	<artifactId>zookeeper</artifactId>
	<version>3.4.14</version>
</dependency>
public class ZkDemo implements Watcher {

    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static ZooKeeper zooKeeper = null;
    private static Stat stat = new Stat();

    public static void main(String[] args) throws Exception {
        String path = "/xray";
        zooKeeper = new ZooKeeper("192.168.31.165:2181",5000,new ZkDemo());
        countDownLatch.await();
        byte[] data = zooKeeper.getData(path, true, stat);
        System.out.println(new String(data));
        Thread.sleep(Integer.MAX_VALUE);
    }

    @Override
    public void process(WatchedEvent watchedEvent) {
        if(Event.KeeperState.SyncConnected == watchedEvent.getState()){
            if(Event.EventType.None == watchedEvent.getType() && null == watchedEvent.getPath()){
                countDownLatch.countDown();
            }else if(Event.EventType.NodeDataChanged == watchedEvent.getType()){
                try {
                    System.out.println("发生修改:" + new String(zooKeeper.getData(watchedEvent.getPath(),true,stat)));
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Dubbo是什么

Dubbo是一款高性能、轻量级的开源Java RPC框架

它提供了三大核心能力:

  1. 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。

  2. 软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。

  3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。

Dubbo的架构

img

  • Provider: 暴露服务的服务提供方。
  • Consumer: 调用远程服务的服务消费方。
  • Registry: 服务注册与发现的注册中心。
  • Monitor: 统计服务的调用次调和调用时间的监控中心。
  • Container: 服务运行容器。

Zookeeper和Dubbo的入门案例

  1. 安装和启动Zookeeper
  2. 父项目依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.3</version>
</dependency>

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.7.3</version>
</dependency>

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.0.1</version>
</dependency>

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>2.8.0</version>
</dependency>

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.13</version>
</dependency>

<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.10</version>
</dependency>
  1. 新建通用项目保存接口

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JowH3CIH-1655164090037)(imgs/1624437582463.png)]

    package com.hp.service;
    public interface HelloService {
        String hello(String name);
    }
    
  2. 服务提供者

配置

server.port=6606
spring.application.name=provider-service
#Dubbo
dubbo.application.name=provider-service
dubbo.registry.protocol=zookeeper
dubbo.registry.address=zookeeper://192.168.31.165:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
#dubbo扫描接口的包
dubbo.scan.base-packages=com.hp.provider_service.service

接口实现

package com.hp.provider_service.service.impl;

import com.hp.service.HelloService;
import org.apache.dubbo.config.annotation.Service;

@Service(version = "1.0.0",interfaceClass = HelloService.class)
public class HelloServiceImpl implements HelloService {
    @Override
    public String hello(String name) {
        return "Hello!!" + name;
    }
}
  1. 服务消费者

配置

server.port=7707
dubbo.application.name=consumer-service
dubbo.registry.protocol=zookeeper
dubbo.registry.address=zookeeper://192.168.31.165:2181

调用提供者接口

@RestController
public class HelloController {

    @Reference(version = "1.0.0")
    private HelloService helloService;

    @RequestMapping("/hello")
    public String hello(String name){
        return helloService.hello(name);
    }
}

stry.protocol=zookeeper
dubbo.registry.address=zookeeper://192.168.31.165:2181


调用提供者接口

@RestController
public class HelloController {

@Reference(version = "1.0.0")
private HelloService helloService;

@RequestMapping("/hello")
public String hello(String name){
    return helloService.hello(name);
        }

}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值