分布式框架 - ZooKeeper

news2024/12/22 15:59:11

一、什么是微服务架构

1、单体架构

顾名思义一个软件系统只部署在一台服务器上。

在高并发场景中,比如电商项目,单台服务器往往难以支撑短时间内的大量请求,聪明的架构师想出了一个办法提高并发量:一台服务器不够就加一台,如果还不够就再加一台。所以衍生出了集群架构。

2、集群架构

当服务器的数量增多以后,需要一个【负载均衡】的功能来协调进来的请求,将请求分发给不同的服务器。

但是当集群中的服务器数量越来越多的时候,维护集群的成本也在攀升,不利于长期发展。

所以聪明的架构师又想到可以把单台web服务器的完整功能拆分成许多小模块,比如订单模块、商品模块,根据不同模块所承担的请求数量决定服务器的数量。

这种方式叫分布式架构。

3、分布式架构

将不同功能模块拆分,灵活部署服务器。但是这样不是很极致,一些类似权限校验的功能还没有剥离出来。

所以聪明的架构师在分布式架构的基础上提取公共系统模块,形成了微服务架构。

4、微服务架构

核心思想就是需要什么功能,就从什么系统中获取。

比如电商系统中客户想要购买一个商品,就得先创建一个订单,但是订单系统不能独立实现发货和配送,这时候就需要调用商品系统和物流系统。出现了系统之间互相调用的情况。

二、为什么要使用ZooKeeper?

前面提到,在微服务架构中出现了系统之间互相调用的情况。

那么如何实现系统之间的相互调用呢?

RPC框架可以帮助我们实现系统之间的调用。

1、RPC框架

RPC框架一般有两个选择:

Spring Cloud Netflix - Ribbon;

Apache - Dubbo

这里我们先来认识Dubbo

Dubbo微服务架构

以上是 Dubbo 的工作原理图,从抽象架构上分为两层:服务治理抽象控制面 和 Dubbo 数据面 。

  • 服务治理控制面。服务治理控制面不是特指如注册中心类的单个具体组件,而是对 Dubbo 治理体系的抽象表达。控制面包含协调服务发现的注册中心、流量管控策略、Dubbo Admin 控制台等,如果采用了 Service Mesh 架构则还包含 Istio 等服务网格控制面。
  • Dubbo 数据面。数据面代表集群部署的所有 Dubbo 进程,进程之间通过 RPC 协议实现数据交换,Dubbo 定义了微服务应用开发与调用规范并负责完成数据传输的编解码工作。
    • 服务消费者 (Dubbo Consumer),发起业务调用或 RPC 通信的 Dubbo 进程
    • 服务提供者 (Dubbo Provider),接收业务调用或 RPC 通信的 Dubbo 进程

        在上面的例子中,订单系统想要调用商品系统的时候,就需要知道商品系统的 IP+端口。但是商品系统可能是一个集群架构,如果某一个节点掉线或新增一个节点,调用方是无法获取最新消息的,也就是不知道商品系统有哪些节点可用。

        这时候就需要使用注册中心统一管理RPC框架中的节点。

2、注册中心

当RPC框架中某一个集群的节点上线或掉线时,就通知注册中心。这样当订单系统需要调用商品服务的时候,就从注册中心获取提供商品服务的 IP+端口。

在Dubbo中,官方推荐使用的注册中心是ZooKeeper

我们想构建微服务架构,可以借助RPC框架Dubbo来构建,但是Dubbo需要一个注册中心,Dubbo官方推荐的注册中心是ZooKeeper。

三、ZooKeeper介绍

1、概述

是一个分布式程序的协调服务,是Hadoop和Hbase的重要组件。提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

2、ZooKeeper集群机制

ZooKeeper是为其他程序提供服务的,所以其本身不能挂掉。ZooKeeper集群机制采用的是半数存活机制,有一半以上的节点存活才可用,所以在一般情况下集群节点最好是奇数个。

3、ZooKeeper中的角色

Leader - 主节点

唯一能处理事务请求的节点,保证集群事务处理的顺序性。

集群内部各服务的调度者。

Follower - 从节点

处理非事务请求,将接收到的事务请求转发给主节点处理。

参与事务请求Proposal的投票。

参与Leader选举投票。

Observer - 观察者

处理非事务请求,将接收到的事务请求转发给主节点处理。

不参与任何投票。

四、准备ZooKeeper集群环境

1、准备3个节点

准备3个centos 7.0 的虚拟机节点,并且安装配置好 JDK 1.8。

我使用VM Ware创建了1个虚拟机节点,是

192.168.0.1

创建快照后复制两个节点,分别修改ip地址

# 修改网络配置文件
vim /etc/sysconfig/network-scripts/ifcfg-ens33

192.168.0.2

192.168.0.3

2、节点关系的映射

每个节点设置相应的ip和主机名的映射关系,方便集群环境的部署。

修改hosts配置文件中的信息。

# 修改 hosts 文件
vim /etc/hosts 

192.168.0.1 allwe01
192.168.0.2 allwe02
192.168.0.3 allwe03

3、免密登录配置

关于ZooKeeper集群环境的搭建,可以先在一个节点安装且配置好相关配置文件,然后再分发到其他的节点上,再到各个节点上做一些个性化配置即可。相对于给每一个节点单独安装高效一些。

但是在使用脚本分发这些配置的时候需要登录到其他的节点,这样有些繁琐,所以我们来配置一下免密登录。

① 生成公钥 & 私钥

ssh-keygen

集群服务器的每一个节点都生成自己的公钥 &私钥

② 发送公钥给目标节点

发送公钥给需要免密登录的节点。

ssh-copy-id allwe01
ssh-copy-id allwe02
ssh-copy-id allwe03

③ 创建工作目录

cd /
mkdir allwe01

在每一个节点都创建一个工作目录。

④ 测试向其他节点发送文件功能

先登录 allwe01 服务器,执行下面的命令。 

scp -r a.txt allwe02:/allwe02

# a.txt         目标文件
# allwe02       目标服务器
# :/allwe02     目标服务器的目标目录

再登录 allwe02 服务器,查看接收的文件。

发送成功!

4、关闭防火墙

# 查看防火墙状态
firewall -cmd --state

我的虚拟机没安装防火墙。

5、安装 JDK

java 

java -version

五、动手搭建ZooKeeper集群

1、安装ZooKeeper

从官网下载安装包:apache-zookeeper-3.6.4-bin.tar.gz

# 解压文件
tar -zxvf apache-zookeeper-3.6.4-bin.tar.gz

2、修改配置

① 修改zoo_sample.cfg文件名称为 zoo.cfg

# 修改文件名称
mv zoo_sample.cfg zoo.cfg

② 修改配置文件内容

tickTime=2000                # zookeeper内部最小单位时间 - 2000ms

initLimit=10                 # follower在启动过程中从Leader同步数据的时间

syncLimit=5                  # 心跳检查间隔时间 - 5s

dataDir=/opt/zookeeper/data  # zookeeper缓存的数据存储目录

clientPort=2181              # 客户端端口号

# 集群环境 - 配置相关节点信息
# 2888 - 心跳端口
# 3888 - 数据端口

server.1 = allwe01:2888:3888
server.2 = allwe02:2888:3888
server.3 = allwe03:2888:3888

③ 配置myid文件

需要在zookeeper的数据存储目录创建一个myid文件,文件内容仅一行信息,表示当前节点在集群中的标识,范围是1 ~ 255,每个节点的myid数字和在zoo.cfg中配置的数字对应。

3、分发文件

配置好一个ZooKeeper节点后,就可以将这个ZooKeeper文件夹分发给其他节点服务器。分别修改myid文件即可。

 scp -r zookeeper allwe02:/opt/
 scp -r zookeeper allwe03:/opt/

4、启动测试

sh /bin/zkServer.sh start

这里打印启动成功了。但是只启动一个节点会报错,原因是zookeeper采用半数存活机制,我们这里有3个节点,如果只有一个节点启动,报错是正常的,等半数以上的节点启动后就好了。

# 查看执行状态

sh zkServer.sh status

可以看到有的是Leader,有的是Follower。

六、ZooKeeper的Leader选举策略

半数存活机制:只有超过半数的节点存活时,集群才可用。我在上面搭建了一个3节点的集群,分别命名为allwe01、allwe02、allwe03。

1、为什么要做Leader选举?

Leader的主要作用是保证分布式数据一致性,也就是分布式事务。Leader节点具有读和写的功能,但是Follower节点和Observer节点只有读的功能。

所以在ZooKeeper中必须有且只有一个Leader节点,一旦掉线,必须选一个新的Leader节点接替工作。

2、面试问题

① 服务器初始化时的选举策略?

集群中的节点在挨个启动时,当allwe02启动后,集群可用,这时如何确定哪个是Leader?

请看VCR,每个节点都投票,将票发送给其他节点,且接收其他节点的票。选出自己认为最新的节点并且投票给它,一旦超过半数票指向同一个节点,选举成功。

等allwe03启动时,已经存在Leader节点了,所以不用选举,直接成为Follower就行了。

② 集群运行期间Leader掉线后的选举策略?

集群成功启动后,当Leader节点掉线了,剩下两个节点如何确定哪个为Leader?

ZooKeeper运行期间,如果有Leader掉线,此时集群停止对外服务,开始在内部选举新的Leader。

1)变更状态。不是观察者的节点都将自己的状态修改为Looking,开始进入Leader选举。

2)和上面画的流程图一样,事务id越大的节点优先级越高。如果事务id一样就比较myid,myid越大的优先级越高。

3)选出Leader节点后集群恢复对外服务。

七、ZooKeeper的使用

1、配置ZooKeeper的环境变量

为了简化每次操作ZooKeeper,而不用进入ZooKeeper的安装目录。将ZooKeeper的bin目录配置到环境变量中。

这样可以在服务器上的任意目录使用ZooKeeper啦!

2、连接客户端

通过 /bin 目录下的 zkCli.sh 连接。

# 默认连接本机zookeeper
sh zkCli.sh 

# 连接其他节点
sh zkCli.sh -timeout 5000 -server allwe02:2181

连接上客户端就可以使用ZooKeeper操作数据了。

3、ZooKeeper的数据结构

ZooKeeper内部是文件目录结构,根目录是【/】,可以在根目录下创建新的目录,以此来保存数据。

4、ZooKeeper的常用命令

ZooKeeper作为Dubbo的注册中心用来保存我们各个服务的节点信息,说明ZooKeeper是支持保存数据和查询操作的。

命令作用
create [-s] [-e] [-c] [-t ttl] path [data] [acl]创建持久化节点(目录)
-s:创建持久化节点,自动生成节点名
-e:创建临时节点,客户端退出时临时节点被删除
ls [-s] [-w] [-R] path查询某个节点下的节点信息和属性信息(加上 -s)
get [-s] [-w] path查询某个节点下的数据信息和属性信息(加上 -s)
set [-s] [-v version] path data给某个节点设置数据
delete [-v version] path

删除没有子节点的节点

使用deleteall删除有子节点的节点

5、属性信息解析

属性含义
cZxid创建事务id
ctime创建时间
mZxid修改事务id
mtime修改时间
pZxid上级节点事务id
cversion创建版本号
dataVersion数据版本号
aclVersion权限版本号
ephemeralOwner临时拥有者 0x0表示没有
dataLength数据长度
numChildren子节点个数

6、节点的分类

代码含义

PERSISTENT

持久化节点

PERSISTENT_SEQUENTIAL

持久化有序节点

EPHEMERAL

临时节点

EPHEMERAL_SEQUENTIAL

临时有序节点

1)临时节点下不允许创建任何节点。

7、ZooKeeper的事件监听

1)监听数据的改变

# 获取app1的数据,且开启对app1的监听
get -w /app1

使用allwe01客户端开启监听某个节点的数据内容变化。

但是只能触发一次监听,如果想要实现持续监听,那么需要在下次读取数据时再次使用监听命令。

allwe02客户端修改/app1节点的数据:

allwe01接收到监听动态:

2)监听子节点的改变

# 开启监听 /app1 的子节点变化
ls -w /app1

在allwe01的客户端节点开启对 /app1 的子节点的监听。

但是只能触发一次监听,如果想要实现持续监听,那么需要在下次读取节点信息时再次使用监听命令。

在allwe02的客户端修改 /app1 的子节点。

allwe01的客户端收到监听。

 8、关于注册中心的使用思路

八、Java API操作ZooKeeper

package zookeeper;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.List;

/**
 * zookeeper连接客户端
 *
 * @Author: AllWe
 * @Date: 2024/09/19/19:25
 */
public class Test01 {

    /**
     * 客户端地址
     */
    private static String ip = "192.168.0.1:2181, 192.168.0.2:2181, 192.168.0.3:2181";

    /**
     * 连接超时时间
     */
    private static int outTime = 50000;

    /**
     * zookeeper连接对象
     */
    private static ZooKeeper zooKeeper = null;

    /**
     * 创建连接
     */
    static {
        try {
            zooKeeper = new ZooKeeper(ip, outTime, new Watcher());
            System.out.println("创建连接成功!连接信息:" + zooKeeper);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 连接zookeeper客户端 - 测试增删改查
     */
    @Test
    public void crud() throws Exception {
        // 删除目标节点
        zooKeeper.delete("/app1/app1.4", -1);
        // 判断目标节点是否存在
        Stat exists = zooKeeper.exists("/app1/app1.4", true);
        if (exists != null) {
            System.out.println("节点存在");
        } else {
            System.out.println("节点不存在");
            // 创建节点
            String s = zooKeeper.create("/app1/app1.4", "hello world".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println(s);
            // 修改节点数据
            zooKeeper.setData("/app1/app1.4", "lalala".getBytes(), -1);
        }
        System.out.println("======================================");
        // 获取目标节点的子节点
        List<String> children = zooKeeper.getChildren("/app1", true);
        System.out.println(children);
        for (String child : children) {
            // 查询节点的数据
            byte[] data = zooKeeper.getData("/app1/" + child, false, null);
            if (data != null) {
                System.out.println(new String(data));
            }
        }
    }

    /**
     * 连接zookeeper客户端 - 测试子节点监听
     */
    @Test
    public void nodeChildrenChange() throws Exception {
        List<String> children = zooKeeper.getChildren("/app1", new Watcher());
        System.out.println("children:" + children);

        Thread.sleep(Integer.MAX_VALUE);
    }

    /**
     * 连接zookeeper客户端 - 测试节点数据监听
     */
    @Test
    public void nodeDataChange() throws Exception {
        byte[] data = zooKeeper.getData("/app1", new Watcher(), null);
        if (data != null)
            System.out.println("----->" + new String(data));

        Thread.sleep(Integer.MAX_VALUE);
    }
}
package zookeeper;

import org.apache.zookeeper.WatchedEvent;

/**
 * zookeeper 监听器
 *
 * @Author: AllWe
 * @Date: 2024/09/19/19:29
 */
public class Watcher implements org.apache.zookeeper.Watcher {

    /**
     * 触发监听器回调方法
     * @param watchedEvent
     */
    @Override
    public void process(WatchedEvent watchedEvent) {
        System.out.println("触发了监听器回调方法");
        System.out.println("watchedEvent.type:" + watchedEvent.getType());
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2164661.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Bottleneck、CSP、DP结构详细介绍

文章目录 前言一、BottleneckDarknetBottleneck 二、CSPCSP思想pp-picodet中的CSPLayer DP卷积 前言 本篇文章详细介绍了三种神经网络中常见的结构&#xff0c;bottleneck、CSP、DP&#xff0c;并附上了代码加深理解。 一、Bottleneck Bottleneck出现在ResNet50/101/152这种…

矩阵特征值怎么求?矩阵特征值计算器来帮你

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f4da;今天我们要探讨一个数学和编程领域中经常遇到的问题——矩阵特征值的计算方式&#xff0c;以及如何计算一个2x2矩阵的特征值。无论你是数学爱好者&#xff0c;还是编程高手&#xff0c;这个主题都可能对你有所…

29 C 语言中的随机数实现:rand 与 srand

目录 1 为什么需要随机数&#xff1f; 1.1 背景介绍 1.2 应用场景 2 C 语言实现随机数 2.1 rand() 函数 2.1.1 函数原型 2.1.2 功能说明 2.1.3 案例演示 2.2 srand() 函数 2.2.1 函数原型 2.2.2 功能说明 2.2.3 案例演示 2.3 指定范围的随机数 2.3.1 获…

为什么 qt 成为 c++ 界面编程的第一选择?

一、前言 为什么现在QT越来越成为界面编程的第一选择&#xff0c;笔者从事qt界面编程已经有接近8年&#xff0c;在这之前我做C界面都是基于MFC&#xff0c;也做过5年左右。当时为什么会从MFC转到QT&#xff0c;主要原因是MFC开发界面想做得好看一些十分困难&#xff0c;引用第…

hexo github部署,通过域名访问你的博客

hexo github部署&#xff0c;通过域名访问你的博客 hexo 常用命令hexo github 部署 在部署之前&#xff0c;了解一下hexo的常用命令 hexo 常用命令 hexo new "My New Post" # 新建文章 hexo n "My New Post"hexo generate # 生成静态文件 hexo ghexo serv…

【CTF】Nginx日志注入

Nginx日志注入&#xff1a; 日志包含漏洞的成因还是服务器没有进行严格的过滤 &#xff0c;导致用户可以进行任意文件读取&#xff0c;但是前提是服务器需要开启了记录日志的功能才可以利用这个漏洞。 对于Apache&#xff0c;日志存放路径&#xff1a;/var/log/apache/access.l…

【论文阅读】FedBABU:TOWARD ENHANCED REPRESENTATION FOR FEDERATED IMAGE CLASSIFICATION

算法流程&#xff1a; 训练过程中冻结客户端的头部参数&#xff0c;只训练主体参数。训练完之后再在客户端本地跑几个epoch微调一下&#xff08;文章推荐5个&#xff09;。 由于该算法与FedPer思路过于相似&#xff0c;故读完后跑了个实验。 FedPer:训练过程中只聚合主体参数。…

Redis --- redis事务和分布式事务锁

redis事务基本实现 Redis 可以通过 MULTI&#xff0c;EXEC&#xff0c;DISCARD 和 WATCH 等命令来实现事务(transaction)功能。 > MULTI OK > SET USER "Guide哥" QUEUED > GET USER QUEUED > EXEC 1) OK 2) "Guide哥"使用 MULTI命令后可以输入…

Linux应用开发实验班——JSON-RPC

目录 前言 1.是什么JSON-RPC 2.常用的JSON函数 1.创建JSON 2.根据名字获取JSON 3.获取JSON的值 4.删除JSON 3.如何进行远程调用 服务器 客户端 4.基于JSON-RPC进行硬件操作 课程链接 前言 学习的课程是百问网韦东山老师的课程&#xff0c;对更详细步骤感兴趣的同学…

LINUX网络编程:Tcp(2)

目录 1.Tcp流量控制 2.滑动窗口 2.1滑动窗口的更新 2.2滑动窗口的丢包问题 1.报文丢失的情况 2.ACK丢失的情况 3.拥塞控制 3.1慢启动 3.2拥塞窗口的增长 1.Tcp流量控制 为什会有流量控制&#xff1f; 1.在网络通信中&#xff0c;假如发送方的发送能力特别的强&#xff0…

支付宝沙箱环境 支付

一 什么是沙箱&#xff1a; 沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境 支付宝正式和沙箱环境的区别 &#xff1a; AI&#xff1a; 从沙箱到正式环境&#xff1a; 当应用程序开发完成后&#xff0c;需要将应用程序从沙箱环境迁移到正式环境。 这通常涉及…

opencv图像增强十四:opencv两种白平衡介绍及实现

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、白平衡介绍二、灰度世界法三、完美反射法 前言 在摄影与影像领域&#xff0c;白平衡是一个至关重要的概念。它直接影响着画面的色彩表现&#xff0c;关系到…

构建网络遇到的问题-AlexNet

1.对模型进行初始化采用的一般代码 def _initialize_weights(self):for m in self.modules(): # 遍历模型每一层if isinstance(m, nn.Conv2d): # 判定m层是否属于nn.Conv2d类型nn.init.kaiming_normal_(m.weight, modefan_out, nonlinearityrelu)if m.bias is not None:nn.in…

从自动化到智能化:AI如何推动业务流程自动化

引言&#xff1a;从自动化到智能化的必然趋势 在当今数字化时代&#xff0c;企业为了提升效率、降低成本&#xff0c;纷纷采用自动化技术来简化重复性任务。然而&#xff0c;传统自动化仅限于标准化操作&#xff0c;无法应对复杂的决策和多变的市场环境。随着人工智能&#xff…

基于springboot垃圾分类网站

基于springboot垃圾分类网站 摘 要 本论文主要论述了如何使用JAVA语言开发一个垃圾分类网站 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述垃圾分类网站的当…

Android开发拍身份证带人像框和国徽框效果

Android开发拍身份证带人像框和国徽框效果 拍身份证时往往要带上外框辅助用户拍照&#xff0c;这也是很常见的需求。 一、思路 自定义Camera和自定义拍照的界面&#xff0c;把外框画上去&#xff0c;做个遮罩 二、效果图&#xff1a; Android开发教程实战案例源码分享-拍身…

深入理解计算机系统-Bomb Lab

使用 头歌 平台 GDB 调试器 反汇编函数

动力锂电池电芯壳体市场前景:预计2030年全球市场规模将达到49.2亿美元

动力锂电池罐起着传输能量、承载电解液、保护安全等重要作用&#xff0c;是锂电池的重要组成部分。 据QYResearch调研团队最新报告“全球动力锂电池电芯壳体市场报告2024-2030”显示&#xff0c;预计2030年全球动力锂电池电芯壳体市场规模将达到49.2亿美元&#xff0c;未来几年…

分布式算法

分布式场景下的核心问题 分布式场景下困扰我们的3个核心问题&#xff08;CAP&#xff09;&#xff1a;一致性、可用性、分区容错性。 1、一致性&#xff08;Consistency&#xff09;&#xff1a;无论服务如何拆分&#xff0c;所有实例节点同一时间看到是相同的数据。 2、可用性…

开源链动 2+1 模式 S2B2C 商城小程序:社交电商团队为王的新引擎

摘要&#xff1a;本文深入探讨在社交电商领域中&#xff0c;团队的重要性以及如何借助开源链动 21 模式 S2B2C 商城小程序&#xff0c;打造具有强大竞争力的团队&#xff0c;实现个人价值与影响力的放大&#xff0c;创造被动收入&#xff0c;迈向财富自由之路&#xff0c;同时为…