Zookeeper(从入门到掌握)看完这一篇就够了

news2024/9/22 19:44:05

文章目录

  • 一、初识 Zookeeper
    • 1.Zookeeper 概念
    • 2.Zookeeper 数据模型
    • 3.Zookeeper 服务端常用命令
    • 4.Zookeeper 客户端常用命令
  • 二、ZooKeeper JavaAPI 操作
    • 1.Curator 介绍
    • 1.Curator API 常用操作
      • (1)建立连接
      • (2)添加节点
      • (3)删除节点
      • (4)修改节点
      • (5)查询节点
      • (6)Watch事件监听
      • (7)分布式锁实现
      • (7)ZooKeeper分布式锁原理
      • (8)Curator实现分布式锁API
  • 三、ZooKeeper集群
      • (1)Leader选举:
      • (2)ZooKeeper 集群搭建
      • (3)Zookeeper 集群角色

一、初识 Zookeeper

1.Zookeeper 概念

  • Zookeeper 是 Apache Hadoop 项目下的一个子项目,是一个树形目录服务。
  • Zookeeper 翻译过来就是 动物园管理员,他是用来管 Hadoop(大象)、Hive(蜜蜂)、Pig(小猪)的管理员。简称zk
  • Zookeeper 是一个分布式的、开源的分布式应用程序的协调服务。
  • Zookeeper 提供的主要功能包括:
    • 配置管理
    • 分布式锁
    • 集群管理

2.Zookeeper 数据模型

ZooKeeper 是一个树形目录服务,其数据模型和Unix的文件系统目录树很类似,拥有一个层次化结构。
这里面的每一个节点都被称为: ZNode,每个节点上都会保存自己的数据和节点信息。
节点可以拥有子节点,同时也允许少量(1MB)数据存储在该节点之下。
节点可以分为四大类:
PERSISTENT     持久化节点
EPHEMERAL     临时节点 :-e
PERSISTENT_SEQUENTIAL     持久化顺序节点 :-s
EPHEMERAL_SEQUENTIAL     临时顺序节点 :-es
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a2b336f205e14b73b77d6ad1372404f7.png

3.Zookeeper 服务端常用命令

  • 启动 ZooKeeper 服务: ./zkServer.sh start
  • 查看 ZooKeeper 服务状态: ./zkServer.sh status
  • 停止 ZooKeeper 服务: ./zkServer.sh stop
  • 重启 ZooKeeper 服务: ./zkServer.sh restart

4.Zookeeper 客户端常用命令

  • 连接ZooKeeper服务端:./zkCli.sh –server ip:port

  • 断开连接:quit

  • 查看命令帮助:help

  • 显示指定目录下节点:ls 目录

  • 创建节点:create /节点path value

  • 获取节点值:get /节点path

  • 设置节点值:set /节点path value

  • 删除单个节点:delete /节点path
    请添加图片描述

  • 删除带有子节点的节点:deleteall /节点path
    请添加图片描述

  • 创建临时节点:create -e /节点path value

  • 创建顺序节点:create -s /节点path value
    请添加图片描述

  • 查询节点详细信息:ls –s /节点path

    • czxid:节点被创建的事务ID
    • ctime: 创建时间
    • mzxid: 最后一次被更新的事务ID
    • mtime: 修改时间
    • pzxid:子节点列表最后一次被更新的事务ID
    • cversion:子节点的版本号
    • dataversion:数据版本号
    • aclversion:权限版本号
    • ephemeralOwner:用于临时节点,代表临时节点的事务ID,如果为持久节点则为0
    • dataLength:节点存储的数据的长度
    • numChildren:当前节点的子节点个数
      请添加图片描述

二、ZooKeeper JavaAPI 操作

1.Curator 介绍

Curator 是 Apache ZooKeeper 的Java客户端库。
常见的ZooKeeper Java API :

  • 原生Java API
  • ZkClient
  • Curator

Curator 项目的目标是简化 ZooKeeper 客户端的使用。
Curator 最初是 Netfix 研发的,后来捐献了 Apache 基金会,目前是 Apache 的顶级项目。
官网:http://curator.apache.org/
要注意Curator和zookeeper的版本对应关系,参照官网

1.Curator API 常用操作

(1)建立连接

  • 引入依赖
	<!--curator-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.0</version>
        </dependency
  • 创建测试类
package com.example.curator;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.Test;

public class CuratorTest {

    //建立连接
    @Test
    public void testConnect() {

        /**
         * @param connectString         连接字符串,zk server地址和端口 "127.0.0.1:2181"
         * @param sessionTimeoutMs      会话超时时间,单位是毫秒ms
         * @param connectionTimeoutMs   连接超时时间,单位是毫秒ms
         * @param retryPolicy           重试策略
         */
        /*
        //重试策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        //第一种方式
        CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", 60 * 1000, 15 * 1000, retryPolicy);
        //开启连接
        client.start();
        */
        //第二种方式,链式创建
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("127.0.0.1:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy).namespace("smsService").build();

    }
}

(2)添加节点

    @Test
    public void testCreate() throws Exception {
        CuratorFramework client = getClient();
        //基本创建
        String path = client.create().forPath("/app1");
        System.out.println(path);

        //带数据的创建
        client.create().forPath("/app1","haha".getBytes(StandardCharsets.UTF_8));

        //设置节点类型,临时类型,默认类型持久化
        client.create().withMode(CreateMode.EPHEMERAL).forPath("/app1");

        //创建多级节点  /app4/ios
        //creatingParentsIfNeeded,如果父节点不存在则创建父节点
        client.create().creatingParentsIfNeeded().forPath("/app4/ios");

        client.close();

    }

(3)删除节点

    @Test
    public void testDelete() throws Exception {
        CuratorFramework client = getClient();

        //删除单个节点
        client.delete().forPath("/app1");
        //删除带有子节点的节点
        client.delete().deletingChildrenIfNeeded().forPath("/app1");
        //必须删除成功
        client.delete().guaranteed().forPath("/app1");
        //回调
        client.delete().guaranteed().inBackground(new BackgroundCallback() {
            @Override
            public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                System.out.println("被删除了" + event);
            }
        }).forPath("/app1");

        client.close();
    }

(4)修改节点

    @Test
    public void testSet() throws Exception {
        CuratorFramework client = getClient();

        //简单修改数据
        client.setData().forPath("/app1", "wawa".getBytes(StandardCharsets.UTF_8));

        //判断版本信息一致再修改
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath("/app1");
        int version = stat.getVersion();
        client.setData().withVersion(version).forPath("/app1", "haha".getBytes(StandardCharsets.UTF_8));

        client.close();
    }

(5)查询节点

    @Test
    public void testSearch() throws Exception {
        CuratorFramework client = getClient();
        //查询数据  get
        byte[] bytes = client.getData().forPath("/app1");
        System.out.println(new String(bytes));

        //查询子节点  ls
        List<String> path = client.getChildren().forPath("/");
        System.out.println(path);

        //查询节点状态信息  ls -s
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath("/app1");
        System.out.println("====" +stat);

        client.close();

    }

(6)Watch事件监听

ZooKeeper 允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性。
ZooKeeper 中引入了Watcher机制来实现了发布/订阅功能能,能够让多个订阅者同时监听某一个对象,当一个对象自身状态变化时,会通知所有订阅者。
ZooKeeper 原生支持通过注册Watcher来进行事件监听,但是其使用并不是特别方便
需要开发人员自己反复注册Watcher,比较繁琐。
Curator引入了 Cache 来实现对 ZooKeeper 服务端事件的监听。
ZooKeeper提供了三种Watcher:

  • NodeCache : 只是监听某一个特定的节点
    @Test
    public void testNodeCache() throws Exception {
        CuratorFramework client = getClient();

        //删除NodeCache对象
        NodeCache nodeCache = new NodeCache(client, "/app");
        //注册监听
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                System.out.println("节点变化了");
                //拿到变化后的数据
                byte[] data = nodeCache.getCurrentData().getData();
                System.out.println(new String(data));
            }
        });
        //开启监听,如果设置为true,则开启监听时,加载缓冲数据
        nodeCache.start(true);

        client.close();
    }
  • PathChildrenCache : 监控一个ZNode的子节点.,感知不到自己的变化。
    @Test
    public void testPathChildrenCache() throws Exception {
        CuratorFramework client = getClient();

        //删除监听对象
        PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app", true);
        //注册监听
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
                System.out.println("子节点变化了" + event);
            }
        });
        //开启监听,如果设置为true,则开启监听时,加载缓冲数据
        pathChildrenCache.start();

        client.close();
    }
  • TreeCache : 可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合
    @Test
    public void testTreeCache() throws Exception {
        CuratorFramework client = getClient();

        //删除监听对象
        TreeCache treeCache = new TreeCache(client, "/");
        //注册监听
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
                System.out.println("有节点变化了" + event);
            }

        });
        //开启监听,如果设置为true,则开启监听时,加载缓冲数据
        treeCache.start();

        client.close();
    }

(7)分布式锁实现

在我们进行单机应用开发,涉及并发同步的时候,我们往往采用synchronized或者Lock的方式来解决多线程间的代码同步问题,这时多线程的运行都是在同一个JVM之下,没有任何问题。
但当我们的应用是分布式集群工作的情况下,属于多JVM下的工作环境,跨JVM之间已经无法通过多线程的锁解决同步问题。
那么就需要一种更加高级的锁机制,来处理种跨机器的进程之间的数据同步问题——这就是分布式锁。
请添加图片描述
请添加图片描述

(7)ZooKeeper分布式锁原理

核心思想:当客户端要获取锁,则创建节点,使用完锁,则删除该节点。

  • 客户端获取锁时,在lock节点下创建临时顺序节点。
  • 然后获取lock下面的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。使用完锁后,将该节点删除。
  • 如果发现自己创建的节点并非lock所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器,监听删除事件。
  • 如果发现比自己小的那个节点被删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是lock子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。
    请添加图片描述

(8)Curator实现分布式锁API

在Curator中有五种锁方案:

  • InterProcessSemaphoreMutex:分布式排它锁(非可重入锁)
  • InterProcessMutex:分布式可重入排它锁
  • InterProcessReadWriteLock:分布式读写锁
  • InterProcessMultiLock:将多个锁作为单个实体管理的容器
  • InterProcessSemaphoreV2:共享信号量

三、ZooKeeper集群

(1)Leader选举:

  • Serverid:服务器ID
    比如有三台服务器,编号分别是1,2,3。
    编号越大在选择算法中的权重越大。
  • Zxid:数据ID
    服务器中存放的最大数据ID.值越大说明数据 越新,在选举算法中数据越新权重越大。
  • 在Leader选举的过程中,如果某台ZooKeeper
    获得了超过半数的选票,
    则此ZooKeeper就可以成为Leader了。

(2)ZooKeeper 集群搭建

  • 搭建要求

真实的集群是需要部署在不同的服务器上的,但是在我们测试时同时启动很多个虚拟机内存会吃不消,所以我们通常会搭建伪集群,也就是把所有的服务都搭建在一台虚拟机上,用端口进行区分。

我们这里要求搭建一个三个节点的Zookeeper集群(伪集群)。

  • 准备工作

重新部署一台虚拟机作为我们搭建集群的测试服务器。

(1)安装JDK 【此步骤省略】。

(2)Zookeeper压缩包上传到服务器
(3)将Zookeeper解压 ,建立/usr/local/zookeeper-cluster目录,将解压后的Zookeeper复制到以下三个目录

/usr/local/zookeeper-cluster/zookeeper-1

/usr/local/zookeeper-cluster/zookeeper-2

/usr/local/zookeeper-cluster/zookeeper-3

[root@localhost ~]# mkdir /usr/local/zookeeper-cluster
[root@localhost ~]# cp -r  apache-zookeeper-3.5.6-bin /usr/local/zookeeper-cluster/zookeeper-1
[root@localhost ~]# cp -r  apache-zookeeper-3.5.6-bin /usr/local/zookeeper-cluster/zookeeper-2
[root@localhost ~]# cp -r  apache-zookeeper-3.5.6-bin /usr/local/zookeeper-cluster/zookeeper-3

(4)创建data目录 ,并且将 conf下zoo_sample.cfg 文件改名为 zoo.cfg

mkdir /usr/local/zookeeper-cluster/zookeeper-1/data
mkdir /usr/local/zookeeper-cluster/zookeeper-2/data
mkdir /usr/local/zookeeper-cluster/zookeeper-3/data

mv  /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo_sample.cfg  /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg
mv  /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo_sample.cfg  /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg
mv  /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo_sample.cfg  /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg

(5) 配置每一个Zookeeper 的dataDir 和 clientPort 分别为2181 2182 2183

修改/usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg

vim /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg

clientPort=2181
dataDir=/usr/local/zookeeper-cluster/zookeeper-1/data

修改/usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg

vim /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg

clientPort=2182
dataDir=/usr/local/zookeeper-cluster/zookeeper-2/data

修改/usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg

vim /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg

clientPort=2183
dataDir=/usr/local/zookeeper-cluster/zookeeper-3/data
  • 1.3 配置集群

(1)在每个zookeeper的 data 目录下创建一个 myid 文件,内容分别是1、2、3 。这个文件就是记录每个服务器的ID

echo 1 >/usr/local/zookeeper-cluster/zookeeper-1/data/myid
echo 2 >/usr/local/zookeeper-cluster/zookeeper-2/data/myid
echo 3 >/usr/local/zookeeper-cluster/zookeeper-3/data/myid

(2)在每一个zookeeper 的 zoo.cfg配置客户端访问端口(clientPort)和集群服务器IP列表。

集群服务器IP列表如下

vim /usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg
vim /usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg
vim /usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg

server.1=192.168.149.135:2881:3881
server.2=192.168.149.135:2882:3882
server.3=192.168.149.135:2883:3883

解释:server.服务器ID=服务器IP地址:服务器之间通信端口:服务器之间投票选举端口

  • 1.4 启动集群

启动集群就是分别启动每个实例。

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh start
/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh start
/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh start

在这里插入图片描述

启动后我们查询一下每个实例的运行状态

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

先查询第一个服务

请添加图片描述

Mode为follower表示是跟随者(从)

再查询第二个服务Mod 为leader表示是领导者(主)
在这里插入图片描述

查询第三个为跟随者(从)
在这里插入图片描述

  • 模拟集群异常

(1)首先我们先测试如果是从服务器挂掉,会怎么样

把3号服务器停掉,观察1号和2号,发现状态并没有变化

/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh stop

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status

在这里插入图片描述

由此得出结论,3个节点的集群,从服务器挂掉,集群正常

(2)我们再把1号服务器(从服务器)也停掉,查看2号(主服务器)的状态,发现已经停止运行了。

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh stop

/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status

在这里插入图片描述

由此得出结论,3个节点的集群,2个从服务器都挂掉,主服务器也无法运行。因为可运行的机器没有超过集群总数量的半数。

(3)我们再次把1号服务器启动起来,发现2号服务器又开始正常工作了。而且依然是领导者。

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh start

/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status

在这里插入图片描述

(4)我们把3号服务器也启动起来,把2号服务器停掉,停掉后观察1号和3号的状态。

/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh start
/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh stop

/usr/local/zookeeper-cluster/zookeeper-1/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

在这里插入图片描述

发现新的leader产生了~

由此我们得出结论,当集群中的主服务器挂了,集群中的其他服务器会自动进行选举状态,然后产生新得leader

(5)我们再次测试,当我们把2号服务器重新启动起来启动后,会发生什么?2号服务器会再次成为新的领导吗?我们看结果

/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh start

/usr/local/zookeeper-cluster/zookeeper-2/bin/zkServer.sh status
/usr/local/zookeeper-cluster/zookeeper-3/bin/zkServer.sh status

在这里插入图片描述

在这里插入图片描述

我们会发现,2号服务器启动后依然是跟随者(从服务器),3号服务器依然是领导者(主服务器),没有撼动3号服务器的领导地位。

由此我们得出结论,当领导者产生后,再次有新服务器加入集群,不会影响到现任领导者。

(3)Zookeeper 集群角色

在ZooKeeper集群服中务中有三个角色:

  • Leader 领导者 :
    • 处理事务请求
    • 集群内部各服务器的调度者
  • Follower 跟随者 :
    • 处理客户端非事务请求,转发事务请求给Leader服务器
    • 参与Leader选举投票
  • Observer 观察者:
    • 处理客户端非事务请求,转发事务请求给Leader服务器

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

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

相关文章

对链表的进一步认识

********以下内容均是个人理解&#xff0c;个人语言&#xff0c;仅代表个人观点&#xff0c;希望能对你有所帮助*************** 1.对链表的进一步深入理解分析 &#xff08;1&#xff09;逻辑结构&#xff1a;想象出来的&#xff0c;并不是真实存在的&#xff0c;例如里面的…

idm线程越多越好吗 idm线程数多少合适

IDM&#xff08;Internet Download Manager&#xff09;是一款流行的下载管理软件&#xff0c;它支持多线程下载&#xff0c;这意味着它可以同时建立多个连接来下载文件的不同部分&#xff0c;从而提高下载速度。我们在使用IDM的时候总是有很多疑问&#xff0c;今天我们学习IDM…

HIT The Wiorld,HIT世界官网地址+配置要求+测试时间+加速器分享

HIT The Wiorld&#xff0c;HIT世界官网地址配置要求测试时间加速器分享 NEXON新游《HIT&#xff1a;世界&#xff08;HIT&#xff1a;The World&#xff09;》将在4月17日上线&#xff0c;目前已在官网开启事前预约预创建角色。Hit :the world&#xff08;HIT:世界&#xff…

鸿蒙 Failed :entry:default@CompileResource...

Failed :entry:defaultCompileResource... media 文件夹下有文件夹或者图片名称包含中文字符 rawfile 文件夹下文件名称、图片名称不能包含中文字符

说说你对链表的理解?常见的操作有哪些?

一、是什么 链表&#xff08;Linked List&#xff09;是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的&#xff0c;由一系列结点&#xff08;链表中每一个元素称为结点&#xff09;组成 每个结点包括两个部分&…

Hdevelop编辑器常用功能

1、灰度直方图 【阈值分割】——对应算子threshold 通过菜单【可视化】-【工具】-【灰度直方图】打开&#xff0c;打开后选中【变量窗口】的某张图片即可进行灰度直方图分析。 刚打开并选中某张图片&#xff1a; 调节【最小化】和【最大化】的两个竖线&#xff0c;此时图中绿…

Spectre漏洞 v2 版本再现,影响英特尔 CPU + Linux 组合设备

近日&#xff0c;网络安全研究人员披露了针对英特尔系统上 Linux 内核的首个原生 Spectre v2 漏洞&#xff0c;该漏洞是2018 年曝出的严重处理器“幽灵”&#xff08;Spectre&#xff09;漏洞 v2 衍生版本&#xff0c;利用该漏洞可以从内存中读取敏感数据&#xff0c;主要影响英…

笔记84:关于递归法的一些感悟

题目1&#xff1a;二叉树的前序遍历 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(…

C# 关于进程回收管理的一款工具设计与分享

目录 设计初衷 开发运行环境 Craneoffice ProcessGC 运行主界面 管理任务与策略 其它设置 移动存储设备管理 核心代码-计时器监控 小结 设计初衷 在使用 COM 模式操作 OFFICE 组件的开发过程中&#xff0c;当操作完相关文档后&#xff0c;在某些情况下仍然无法释放掉…

2024.4.19 Python爬虫复习day07 可视化3

综合案例 需求: 已知2020年疫情数据,都是json数据,需要从文件中读出,进行处理和分析,最终实现数据可视化折线图 相关知识点: json json简介: 本质是一个特定格式的字符串 举例: [{},{},{}] 或者 {}python中json包: import jsonpython数据转为json数据: 变量接收json…

Unity类银河恶魔城学习记录12-17 p139 In game UI源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI.cs using UnityEngine;public class UI : MonoBehaviour {[SerializeFie…

kworker(kworker/u2:1,kworker/0:13,kworker/0:1H) 工作队列的命名

1、概述 工作队列是除软中断和tasklet以外最常用的下半部机制之一。工作队列的基本原理是把work(需要推迟执行的函数)交由一个内核线程来异步执行。关于工作队列的具体使用请读者参考其他资料&#xff0c;本文不再概述。 在创建工作队列时,可以通过flag参数指定创建的工作队列…

(四)C++自制植物大战僵尸游戏启动流程

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、启动方式 鼠标左键单机VS2022上方工具栏中绿色三角按钮&#xff08;本地Windows调试器&#xff09;进行项目启动。第一次启动项目需要编译项目中所有代码文件&#xff0c;编译生成需要一定的时间。不同性能的电…

AVB简介(二): gPTP简介

AVB简介&#xff08;二&#xff09;: gPTP简介 一、时间同步要解决的问题二、gPTP的主要思想2.1 体系结构2.2 主时钟选取2.3 绝对时间同步2.4 相对时间同步 三、影响校时精度的因素3.1 传输时延不对称3.2 驻留时间3.3 时间戳采样点3.4 时钟频率3.5 传输路径延时测量方式3.6 时钟…

idea运行Tomcat,控制台日志的中文乱码

一 版本 win10&#xff0c;idea2022,jdk18,tomcat9 二 问题描述 在idea上可以运行Tomcat。服务器启动后&#xff0c;可以正常访问本地的html文件。但是控制台的Tomcat日志出现了乱码&#xff1a;server与Tomcat Catlina Log两处。 三 无效的解决之道 1 idea的Help选项Edit …

Spring ORM

Spring Data JPA 作为Spring Data 中对于关系型数据库支持的一种框架技术,属于 ORM 的一种,通过得当的使用,可以大大简化开发过程中对于数据操作的复杂度。 Java里面写的一段DB操作逻辑,是如何一步步被传递到 DB 中执行了的呢?为什么 Java 里面可以去对接不同产商的 DB 产…

ExtendSim花生酱加工厂模型

该模型展示了ExtendSim可靠性模块与ExtendeSim离散速率技术相结合的协同作用。 在花生酱加工厂的最初阶段&#xff0c;花生经过烘烤和冷却。冷却后的花生经过热烫或水烫去外皮。这些经过漂白的花生进入过程的混合部分&#xff0c;在研磨机中用盐、葡萄糖和氢化油稳定剂将其粉碎…

MySQL排序你真的掌握了吗?5个问题考考你

测试sql数据 CREATE TABLE student (id int NOT NULL AUTO_INCREMENT,name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,age int DEFAULT NULL,money int DEFAULT NULL,PRIMARY KEY (id) USING BTREE,KEY index_name (age) ); INSERT INTO st…

【Linux】线程的控制

目录 POSIX线程库 常用的POSIX线程库接口声明&#xff1a; 注意事项 创建一个进程 pthread_create函数 参数 返回值 使用示例 线程ID和进程地址空间布局 线程ID 进程地址空间布局 示例图 获取一个进程的线程ID 函数原型 返回值 使用示例 注意事项 线程终止 p…

SpringBoot项目整合ACTable实现实体类快速生产数据库表

1.安装 ACTable依赖 <dependency> <groupId>com.gitee.sunchenbin.mybatis.actable</groupId> <artifactId>mybatis-enhance-actable</artifactId> <version>1.5.0.RELEASE</version> </dependency> 使用mybatis…