《Zookeeper 分布式过程协同技术详解》读书笔记-2

news2025/3/23 8:35:30

目录

  • zk的一些内部原理和应用
    • 请求,事务和标识
      • 读写操作
      • 事务标识(zxid)
    • 群首选举
    • Zab协议(ZooKeeper Atomic Broadcast protocol)
    • 文件系统和监听通知机制
      • 分布式配置中心, 简单Demo
        • java code
      • 集群管理
        • code
      • 分布式锁

zk的一些内部原理和应用

请求,事务和标识

读写操作

  1. 只读请求(exists, getData,getChildren)会在zk服务其本地处理,然后返回给客户端(所以zk处理以只读请求为主要负载时,性能会很高,可以增加更多的服务器到zk集群,这样能处理更多的读请求)

因为ZooKeeper集群中所有的server节点都拥有相同的数据,所以读的时候可以在任意一台server节点上,客户端连接到集群中某一节点,读请求,然后直接返回。当然因为ZooKeeper协议的原因(一半以上的server节点都成功写入了数据,这次写请求便算是成功),读数据的时候可能会读到数据不是最新的server节点,所以比较推荐使用watch机制,在数据改变时,及时感知到

  1. 写操作(create, delete, setData) 将会被转发给群首(群首会执行相应请求,并形成状态更新,我们称为事务(Transaction))

在这里插入图片描述

  1. Client向Zookeeper的server1发送一个写请求,客户端写数据到服务器1上;
  2. 如果server1不是Leader,那么server1会把接收到的写请求转发给Leader;然后Leader会将写请求转发给每个server;
    • server1和server2负责写数据,并且两个Follower的写入数据是一致的,保存相同的数据副本;
    • server1和server2写数据成功后,通知Leader;
  3. 当Leader收到集群半数以上的节点写成功的消息后,说明该写操作执行成功;
    • 这里是3台服务器,只要2台Follower服务器写成功就ok
    • 因为client访问的是server1,所以Leader会告知server1集群中数据写成功;
  4. 被访问的server1进一步通知client数据写成功,这时,客户端就知道整个写操作成功了

事务标识(zxid)

当群首产生了一个事务,就会为该事务分配一个标识符,我们称之 为ZooKeeper会话ID(zxid),通过Zxid对事务进行标识,就可以按照群 首所指定的顺序在各个服务器中按序执行

zxid为一个long型(64位)整数,分为两部分:时间戳(epoch)部 分和计数器(counter)部分。每个部分为32位,在我们讨论zab(Zookeeper Atomic Broadcast )协议 时,我们就会发现时间戳(epoch)和计数器(counter)的具体作用, 我们通过该协议来广播各个服务器的状态变更信息。

eg:

setData 加上事务(版本和新数据值),一个事务为一个单位,以原子方式执行;ZooKeeper集群以事务方式运行,并确保所 有的变更操作以原子方式被执行,同时不会被其他事务所干扰;并不存在传统的关系数据库中所涉及的回滚机制,而是 确保事务的每一步操作都互不干扰

同时一个事务还具有幂等性,也就是说,我们可以对同一个事务执 行两次,我们得到的结果还是一样的,我们甚至还可以对多个事务执行 多次,同样也会得到一样的结果,前提是我们确保多个事务的执行顺序 每次都是一样的。事务的幂等性可以让我们在进行恢复处理时更加简单。

实际上,ZooKeeper的每个节点维护者两个Zxid值,为别为:cZxid、mZxid。

(1)cZxid: 是节点的创建时间所对应的Zxid格式时间戳。

(2)mZxid:是节点的修改时间所对应的Zxid格式时间戳。

高32位是epoch用来标识Leader关系是否改变,每次一个Leader被选出来,它都会有一个新的epoch。低32位是个递增计数。

群首选举

群首为集群中的服务器选择出来的一个服务器,并会一直被集群所 认可。设置群首的目的是为了对客户端所发起的ZooKeeper状态变更请 求进行排序,包括:create、setData和delete操作。群首将每一个请求转 换为一个事务,将这些事务发送给追随者,确保集 群按照群首确定的顺序接受并处理这些事务。

  • 每个服务器启动后进入LOOKING状态,开始选举一个新的群首或 查找已经存在的群首,如果群首已经存在,其他服务器就会通知这个新 启动的服务器,告知哪个服务器是群首,与此同时,新的服务器会与群 首建立连接,以确保自己的状态与群首一致。

  • 如果集群中所有的服务器均处于LOOKING状态,这些服务器之间 就会进行通信来选举一个群首,通过信息交换对群首选举达成共识的选 择。在本次选举过程中胜出的服务器将进入LEADING状态,而集群中 其他服务器将会进入FOLLOWING状态。

当一个服务器进入LOOKING状态,就会发送向集群中每个服 务器发送一个通知消息,如下

投票<服务器标识,最近执行的事务的zxid信息>
(vote<sid, zxid>

在这里插入图片描述

在这里插入图片描述

快速群首选举的快速指的是什么?

Zab协议(ZooKeeper Atomic Broadcast protocol)

在接收到一个写请求操作后,追随者会将请求转发给群首,群首将探索性地执行该请求,并将执行结果以事务的方式对状态更新进行广播。一个事务中包含服务器需要执行变更的确切操作,当事务提交时, 服务器就会将这些变更反馈到数据树上,其中数据树为ZooKeeper用于 保存状态信息的数据结构(请参考DataTree类)。

之后我们需要面对的问题便是服务器如何确认一个事务是否已经提 交,由此引入了我们所采用的协议:Zab:ZooKeeper原子广播协议 (ZooKeeper Atomic Broadcast protocol)。

  • propose: leader 广播给 followers
  • accept: followers收到广播信息给leader发送确认消息
  • commit: leader收到确认仲裁数量后发送消息给follower进行提交操作
    在这里插入图片描述
    具体如下:
    在这里插入图片描述

两个保障(依靠了zxid)

  1. 一个被选举的群首确保在提交完所有之前的时间戳内需要提交的 事务,之后才开始广播新的事务。
  2. 在任何时间点,都不会出现两个被仲裁支持的群首。

为了实现第一个需求,群首并不会马上处于活动状态,直到确保仲 裁数量的服务器认可这个群首新的时间戳值。一个时间戳的最初状态必 须包含所有的之前已经提交的事务,或者某些已经被其他服务器接受, 但尚未提交完成的事务。这一点非常重要,在群首进行时间戳e的任何 新的提案前,必须保证自时间戳开始值到时间戳e-1内的所有提案被提 交。如果一个提案消息处于时间戳e’<e,在群首处理时间戳e的第一个提 案消息前没有提交之前的这个提案,那么旧的提案将永远不会被提交。

文件系统和监听通知机制

分布式配置中心, 简单Demo

  1. 在zookeeper里增加一个目录节点,并把配置信息存储在里面(作为配置中心存储)

在这里插入图片描述

  1. 多个客户端能够读取到
    在这里插入图片描述
  2. 服务端配置改变,客户端(所有注册监听的客户端)都能监听到事件
    在这里插入图片描述
    在这里插入图片描述
java code
package demo;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;

import java.util.concurrent.CountDownLatch;

/**
 * @Author mubi
 * @Date 2020/3/27 22:36
 */
public class ZooKeeperProSync implements Watcher {

    private static CountDownLatch connectedSemaphore = new CountDownLatch(1);
    private static ZooKeeper zk = null;
    private static Stat stat = new Stat();

    public static void main(String[] args) throws Exception {
        // zookeeper配置数据的存放路径
        String path = "/myconfig";
        // 连接zookeeper并且注册一个监听器
        zk = new ZooKeeper("127.0.0.1:2281", 5000, new ZooKeeperProSync());
        // 等待zk连接成功的通知(等待connectedSemaphore.countDown()减少为0)
        connectedSemaphore.await();
        // 获取path目录节点的配置数据,并注册对节点的监听
        System.out.println(new String(zk.getData(path, true, stat)));
        Thread.sleep(Integer.MAX_VALUE);
    }

    @Override
    public void process(WatchedEvent event) {
        // zk连接成功通知事件
        if (KeeperState.SyncConnected == event.getState()) {
            if (EventType.None == event.getType() && null == event.getPath()) {
                connectedSemaphore.countDown();
            }else if (event.getType() == EventType.NodeDataChanged) {
                // zk目录节点数据变化通知事件
                try {
                    System.out.println("配置已修改,新值为:" + new String(zk.getData(event.getPath(), true, stat)));
                    // TODO 具体业务
                } catch (Exception e) {

                }
            }
        }
    }
}

集群管理

集群管理原理:机器的加入/退出,选举leader节点

在这里插入图片描述

  • 持久节点 / 临时节点
  • 有序节点 / 无序节点

可以临时+有序构成server,然后最小编号节点作为leader节点

  1. 创建集群节点目录(持久节点)
    在这里插入图片描述
  2. 启动服务,并加入和减少机器观察
    在这里插入图片描述
    在这里插入图片描述
code
  • AppMaster
package demo;

import java.util.ArrayList;
import java.util.List;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooKeeper;

/**
 * @Author mubi
 * @Date 2020/3/27 23:43
 */
public class AppMaster {
    private String clusterNode = "mycluster";
    private ZooKeeper zk;
    private volatile List<String> serverList;

    public void connectZookeeper() throws Exception
    {
        // 注册全局默认watcher
        zk = new ZooKeeper("127.0.0.1:2281", 5000, new Watcher()
        {
            @Override
            public void process(WatchedEvent event)
            {
                if (event.getType() == EventType.NodeChildrenChanged
                        && ("/" + clusterNode).equals(event.getPath()))
                {
                    try
                    {
                        updateServerList();
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        });

        updateServerList();
    }

    private void updateServerList() throws Exception
    {
        List<String> newServerList = new ArrayList<String>();

        // watcher注册后,只能监听事件一次,参数true表示继续使用默认watcher监听事件
        List<String> subList = zk.getChildren("/" + clusterNode, true);
        for (String subNode : subList)
        {
            // 获取节点数据
            byte[] data = zk.getData("/" + clusterNode + "/" + subNode, false, null);
            newServerList.add(new String(data, "utf-8"));
        }

        serverList = newServerList;
        System.out.println("server list updated: " + serverList);
    }

    public static void main(String[] args) throws Exception
    {
        AppMaster ac = new AppMaster();
        ac.connectZookeeper();
        Thread.sleep(Long.MAX_VALUE);
    }
}

  • AppServer
package demo;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;


/**
 * @Author mubi
 * @Date 2020/3/27 23:44
 */
public class AppServer extends Thread
{
    private String clusterNode = "mycluster";
    private String serverNode = "server_address";
    private String serverName;

    @Override
    public void run()
    {
        try {
            connectZookeeper(serverName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void connectZookeeper(String address) throws Exception
    {
        ZooKeeper zk = new ZooKeeper("127.0.0.1:2281", 5000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {}
        });

        // 关键方法,创建包含自增长id名称的目录,这个方法支持了分布式锁的实现
        // 四个参数:
        // 1、目录名称 2、目录文本信息
        // 3、文件夹权限,Ids.OPEN_ACL_UNSAFE表示所有权限
        // 4、目录类型,CreateMode.EPHEMERAL_SEQUENTIAL表示创建临时目录,session断开连接则目录自动删除
        String createdPath = zk.create(
                "/" + clusterNode + "/" + serverNode,
                address.getBytes("utf-8"),
                Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("create: " + createdPath);
        Thread.sleep(Integer.MAX_VALUE);
    }

    public AppServer(String serverName)
    {
        this.serverName = serverName;
    }
}


  • Server1
package demo;

/**
 * @Author mubi
 * @Date 2020/3/27 23:46
 */

public class Server1
{
    public static void main(String[] args) throws Exception
    {
        AppServer server1 = new AppServer("Server1");
        server1.start();
    }
}

分布式锁

一个zookeeper分布式锁,首先需要创建一个父节点,尽量是持久节点(PERSISTENT类型),然后每个要获得锁的线程都会在这个节点下创建个临时顺序节点,由于序号的递增性,可以规定排号最小的那个获得锁。所以,每个线程在尝试占用锁之前,首先判断自己是排号是不是当前最小,如果是,则获取锁。

避免羊群效应:所谓羊群效应就是每个节点挂掉,所有节点都去监听,然后做出反应,这样会给服务器带来巨大压力。所以有了临时顺序节点,当一个节点挂掉,只有它后面的那一个节点才做出反应。

在这里插入图片描述

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

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

相关文章

HTML5+CSS多层级ol标签序号样式问题

在CSS中&#xff0c;ol标签用于创建有序列表&#xff0c;而多层级的ol标签可以通过CSS实现不同的序号样式。以下是一些常见的问题和解决方案&#xff1a; 1. 多层级ol的序号格式问题 默认情况下&#xff0c;多层级的ol标签会自动继承父级的序号格式&#xff0c;但有时我们可能…

网络初始2:网络编程--基于UDP和TCP实现回显器

基础概念 1.发送端与接受端 在通过网络传输信息时&#xff0c;会有两个进程&#xff0c;接收端和发送端。 发送端&#xff1a;数据的发送方进程&#xff0c;即网络通信中的源主机。 接收端&#xff1a;数据的接收方进程&#xff0c;即网路通信中的目的主机。 2.Socet套接字…

vtkCamera类的Dolly函数作用及相机拉近拉远

录 1. 预备知识 1.1.相机焦点 2. vtkCamera类的Dolly函数作用 3. 附加说明 1. 预备知识 要理解vtkCamera类的Dolly函数作用,就必须先了解vtkCamera类表示的相机的各种属性。  VTK是用vtkCamera类来表示三维渲染场景中的相机。vtkCamera负责把三维场景投影到二维平面,如…

车载音频架构图详解(精简)

目录 上图是车载音频架构图,对这个图我们进行详细的分析 左边第一层 是 app 常用的类有MediaPlayer和MediaRecorder, AudioTrack和AudioRecorder 第二层 是framework提供给应用的多媒体功能的AP

使用神经网络对驾驶数据进行道路类型分类

摘要 道路分类&#xff0c;了解我们是在城市、农村地区还是在高速公路上驾驶&#xff0c;可以提高现代驾驶员辅助系统的性能&#xff0c;并有助于了解驾驶习惯。本研究的重点是仅使用车速数据来普遍解决这个问题。已经开发了一种数据记录方法&#xff0c;用于为 On-board Diagn…

S4D480 S4HANA 基于PDF的表单打印

2022年元旦的笔记草稿 SAP的表单打印从最早的SAPScripts 到后来的SMARTFORM&#xff0c;步入S4时代后由于Fiori的逐渐普及&#xff0c;更适应Web的Adobe Form成了SAP主流output文件格式。 目录 一、 基于PDF表单打印系统架构Interface 接口Form 表单ContextLayout 二、表单接…

qt QOpenGLTexture详解

1. 概述 QOpenGLTexture 是 Qt5 提供的一个类&#xff0c;用于表示和管理 OpenGL 纹理。它封装了 OpenGL 纹理的创建、分配存储、绑定和设置像素数据等操作&#xff0c;简化了 OpenGL 纹理的使用。 2. 重要函数 构造函数&#xff1a; QOpenGLTexture(const QImage &image,…

Deepseek-R1推理模型API接入调用指南 ChatGPT Web Midjourney Proxy 开源项目接入Deepseek教程

DeepSeek-R1和OpenAI o1模型都属于推理任务模型&#xff0c;两个模型各有优点&#xff1a;DeepSeek-R1 在后训练阶段大规模使用了强化学习技术&#xff0c;在仅有极少标注数据的情况下&#xff0c;极大提升了模型推理能力。在数学、代码、自然语言推理等任务上&#xff0c;性能…

蓝耘智算携手DeepSeek,共创AI未来

&#x1f31f; 各位看官号&#xff0c;我是egoist2023&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; &#x1f680; 今天来学习如何通过蓝耘智算使用DeepSeek R1模型 &#x1f44d; 如果觉得这篇文章有帮助&#xff0c;欢迎您一键三连&a…

【网络编程】之数据链路层

【网络编程】之数据链路层 数据链路层基本介绍基本功能常见协议 以太网什么是以太网以太网协议帧格式数据链路层的以太网帧报文如何封装/解封装以及分用以太网通信原理传统的以太网与集线器现代以太网与交换机碰撞域的概念 Mac地址基本概念为什么要使用Mac地址而不是使用IP地址…

EasyExcel 复杂填充

EasyExcel ​Excel表格中用{}或者{.} 来表示包裹要填充的变量&#xff0c;如果单元格文本中本来就有{、}左右大括号&#xff0c;需要在括号前面使用斜杠转义\{ 、\}。 ​代码中被填充数据的实体对象的成员变量名或被填充map集合的key需要和Excel中被{}包裹的变量名称一致。 …

通过VSCode直接连接使用 GPT的编程助手

GPT的编程助手在VSC上可以直接使用 选择相应的版本都可以正常使用。每个月可以使用40条&#xff0c;超过限制要付费。 如下图对应的4o和claude3.5等模型都可以使用。VSC直接连接即可。 配置步骤如下&#xff1a; 安装VSCODE 直接&#xff0c;官网下载就行 https://code.vis…

【算法与数据结构】并查集详解+题目

目录 一&#xff0c;什么是并查集 二&#xff0c;并查集的结构 三&#xff0c;并查集的代码实现 1&#xff0c;并查集的大致结构和初始化 2&#xff0c;find操作 3&#xff0c;Union操作 4&#xff0c;优化 小结&#xff1a; 四&#xff0c;并查集的应用场景 省份…

Java 集合数据处理技巧:使用 Stream API 实现多种操作

​ 在 Java 开发中&#xff0c;对集合数据进行处理是非常常见的需求&#xff0c;例如去重、排序、分组、求和等。Java 8 引入的 Stream API 为我们提供了一种简洁、高效的方式来处理集合数据。本文将详细介绍如何使用 Stream API 实现多种集合数据处理操作&#xff0c;并给出相…

OSI 参考模型和 TCP/IP 参考模型

数据通信是很复杂的&#xff0c;很难在一个协议中完成所有功能。因此在制定协议时经常采用的思路是将复杂的数据通信功能由若干协议分别完成&#xff0c;然后将这些协议按照一定的方式组织起来。最典型的是采用分层的方式来组织协议&#xff0c;每一层都有一套清晰明确的功能和…

SD NAND 的 SDIO在STM32上的应用详解(上篇)

目录 上篇&#xff1a; 一.SDIO简介 二.SD卡简介/内部结构 1.SD卡/SD NAND引脚 2.SD卡寄存器 3.FLASH存储器 三.SDIO总线拓扑 中篇&#xff1a; 四.SDIO功能框图(重点) 1.SDIO适配器 2.控制单元 3.命令通道(重点) 4.数…

基于图像处理的裂缝检测与特征提取

一、引言 裂缝检测是基础设施监测中至关重要的一项任务,尤其是在土木工程和建筑工程领域。随着自动化技术的发展,传统的人工巡检方法逐渐被基于图像分析的自动化检测系统所取代。通过计算机视觉和图像处理技术,能够高效、精确地提取裂缝的几何特征,如长度、宽度、方向、面…

执行pnpm run dev报错:node:events:491 throw er; // Unhandled ‘error‘ event的解决方案

vite搭建的vue项目&#xff0c;使用pnpm包管理工具&#xff0c;执行pnpm run dev&#xff0c;报如下错误&#xff1a; 报错原因&#xff1a; pnpm依赖安装不完整&#xff0c;缺少esbuild.exe文件&#xff0c;导致无法执行启动命令。 解决方案&#xff1a; 根据错误提示中提到…

「软件设计模式」建造者模式(Builder)

深入解析建造者模式&#xff1a;用C打造灵活对象构建流水线 引言&#xff1a;当对象构建遇上排列组合 在开发复杂业务系统时&#xff0c;你是否经常面对这样的类&#xff1a;它有20个成员变量&#xff0c;其中5个是必填项&#xff0c;15个是可选项。当用户需要创建豪华套餐A&…

uniapp 安卓10+ 选择并上传文件

plus.io.chooseFile({title: 选择文件,filetypes: [mp3], // 允许的文件类型multiple: false, // 是否允许多选}, (res) > {console.log(虚拟路径666&#xff1a;, res);var arr[{name: files,uri: res.files[0],}]let obj {"tableName": "mingmen_daily_mi…