zookeeper基础学习之六: zookeeper java客户端curator

news2024/11/25 3:07:42

简介

Curator是Netflix公司开源的一套zookeeper客户端框架,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连、反复注册Watcher和NodeExistsException异常等等。Patrixck Hunt(Zookeeper)以一句“Guava is to Java that Curator to Zookeeper”给Curator予高度评价。
Curator的maven依赖

Apache Curator 是 Apache 基金会提供的一款 ZooKeeper 客户端,它提供了一套易用性和可读性非常强的 Fluent 风格的客户端 API ,可以帮助我们快速搭建稳定可靠的 ZooKeeper 客户端程序。

为便于你更全面了解 Curator 的功能,我整理出了如下表格,展示了 Curator 提供的 jar 包:

在这里插入图片描述

添加依赖

<!-- 对zookeeper的底层api的一些封装 -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>5.0.0</version>
        </dependency>
        <!-- 封装了一些高级特性,如:Cache事件监听、选举、分布式锁、分布式Barrier -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>5.0.0</version>
        </dependency>

创建连接

public static void main(String[] args) throws Exception {
        //fluent风格
//        CuratorFramework curatorFramework1=CuratorFrameworkFactory.builder().connectString(ZKSERVERS).sessionTimeoutMs(5000).
//                retryPolicy(new ExponentialBackoffRetry(1000,3)).
//                namespace("/curator").build();
//        curatorFramework1.start();
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework client = CuratorFrameworkFactory.newClient(ZKSERVERS, retryPolicy);
        client.start();
        String result=client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).
                forPath("/curator/curator1/curator11","123".getBytes());

        System.out.println(result);
    }

curator连接的重试策略

ExponentialBackoffRetry() 衰减重试
RetryNTimes 指定最大重试次数
RetryOneTime 仅重试一次
RetryUnitilElapsed 一直重试直到规定的时间

在这里插入图片描述

基本操作

public static void main(String[] args) throws Exception {
        // Zookeeper集群地址,多个节点地址可以用逗号分隔
        String zkAddress = "127.0.0.1:2181";
        // 重试策略,如果连接不上ZooKeeper集群,会重试三次,重试间隔会递增
        RetryPolicy retryPolicy =
                new ExponentialBackoffRetry(1000, 3);
        // 创建Curator Client并启动,启动成功之后,就可以与Zookeeper进行交互了
        CuratorFramework client =
                CuratorFrameworkFactory.newClient(zkAddress, retryPolicy);
        client.start();
        // 下面简单说明Curator中常用的API
        // create()方法创建ZNode,可以调用额外方法来设置节点类型、添加Watcher
        // 下面是创建一个名为"user"的持久节点,其中会存储一个test字符串
        String path = client.create().withMode(CreateMode.PERSISTENT)
                .forPath("/user", "test".getBytes());
        System.out.println(path);
        // 输出:/user
        // checkExists()方法可以检查一个节点是否存在
        Stat stat = client.checkExists().forPath("/user");
        System.out.println(stat!=null);
        // 输出:true,返回的Stat不为null,即表示节点存在
        // getData()方法可以获取一个节点中的数据
        byte[] data = client.getData().forPath("/user");
        System.out.println(new String(data));
        // 输出:test
        // setData()方法可以设置一个节点中的数据
        stat = client.setData().forPath("/user","data".getBytes());
        data = client.getData().forPath("/user");
        System.out.println(new String(data));
        // 输出:data
        // 在/user节点下,创建多个临时顺序节点
        for (int i = 0; i < 3; i++) {
            client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                    .forPath("/user/child-");
        }
        // 获取所有子节点
        List<String> children = client.getChildren().forPath("/user");
        System.out.println(children);
        // 输出:[child-0000000002, child-0000000001, child-0000000000]
        // delete()方法可以删除指定节点,deletingChildrenIfNeeded()方法
        // 会级联删除子节点
        client.delete().deletingChildrenIfNeeded().forPath("/user");
    }

Curator 异步接口,引入了BackgroundCallback

上面介绍的创建、删除、更新、读取等方法都是同步的,Curator 提供异步接口,引入了BackgroundCallback 这个回调接口以及 CuratorListener 这个监听器,用于处理 Background 调用之后服务端返回的结果信息。BackgroundCallback 接口和 CuratorListener 监听器中接收一个 CuratorEvent 的参数,里面包含事件类型、响应码、节点路径等详细信息。

下面我们通过一个示例说明 BackgroundCallback 接口以及 CuratorListener 监听器的基本使用:

public class CuratorAsynApi {
    public static void main(String[] args) throws Exception {
        // Zookeeper集群地址,多个节点地址可以用逗号分隔
        String zkAddress = "127.0.0.1:2181";
        // 重试策略,如果连接不上ZooKeeper集群,会重试三次,重试间隔会递增
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
        // 创建Curator Client并启动,启动成功之后,就可以与Zookeeper进行交互了
        CuratorFramework client = CuratorFrameworkFactory
                .newClient(zkAddress, retryPolicy);
        client.start();
        // 添加CuratorListener监听器,针对不同的事件进行处理
        client.getCuratorListenable().addListener(
                new CuratorListener() {
                    public void eventReceived(CuratorFramework client,
                                              CuratorEvent event) throws Exception {
                        switch (event.getType()) {
                            case CREATE:
                                System.out.println("CREATE:" +
                                        event.getPath());
                                break;
                            case DELETE:
                                System.out.println("DELETE:" +
                                        event.getPath());
                                break;
                            case EXISTS:
                                System.out.println("EXISTS:" +
                                        event.getPath());
                                break;
                            case GET_DATA:
                                System.out.println("GET_DATA:" +
                                        event.getPath() + ","
                                        + new String(event.getData()));
                                break;
                            case SET_DATA:
                                System.out.println("SET_DATA:" +
                                        new String(event.getData()));
                                break;
                            case CHILDREN:
                                System.out.println("CHILDREN:" +
                                        event.getPath());
                                break;
                            default:
                        }
                    }
                });
        // 注意:下面所有的操作都添加了inBackground()方法,转换为后台操作
        client.create().withMode(CreateMode.PERSISTENT)
                .inBackground().forPath("/user", "test".getBytes());
        client.checkExists().inBackground().forPath("/user");
        client.setData().inBackground().forPath("/user",
                "setData-Test".getBytes());
        client.getData().inBackground().forPath("/user");
        for (int i = 0; i < 3; i++) {
            client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                    .inBackground().forPath("/user/child-");
        }
        client.getChildren().inBackground().forPath("/user");
        // 添加BackgroundCallback
        client.getChildren().inBackground(new BackgroundCallback() {
            public void processResult(CuratorFramework client,
                                      CuratorEvent event) throws Exception {
                System.out.println("in background:"
                        + event.getType() + "," + event.getPath());
            }
        }).forPath("/user");
        client.delete().deletingChildrenIfNeeded().inBackground()
                .forPath("/user");
        System.in.read();
    }

}

连接状态监听

除了基础的数据操作,Curator 还提供了监听连接状态的监听器——ConnectionStateListener,它主要是处理 Curator 客户端和 ZooKeeper 服务器间连接的异常情况,例如, 短暂或者长时间断开连接。

短暂断开连接时,ZooKeeper 客户端会检测到与服务端的连接已经断开,但是服务端维护的客户端 Session 尚未过期,之后客户端和服务端重新建立了连接;当客户端重新连接后,由于 Session 没有过期,ZooKeeper 能够保证连接恢复后保持正常服务。

而长时间断开连接时,Session 已过期,与先前 Session 相关的 Watcher 和临时节点都会丢失。当 Curator 重新创建了与 ZooKeeper 的连接时,会获取到 Session 过期的相关异常,Curator 会销毁老 Session,并且创建一个新的 Session。由于老 Session 关联的数据不存在了,在 ConnectionStateListener 监听到 LOST 事件时,就可以依靠本地存储的数据恢复 Session 了。

这里 Session 指的是 ZooKeeper 服务器与客户端的会话。客户端启动的时候会与服务器建立一个 TCP 连接,从第一次连接建立开始,客户端会话的生命周期也开始了。客户端能够通过心跳检测与服务器保持有效的会话,也能够向 ZooKeeper 服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的 Watch 事件通知。

我们可以设置客户端会话的超时时间(sessionTimeout),当服务器压力太大、网络故障或是客户端主动断开连接等原因导致连接断开时,只要客户端在 sessionTimeout 规定的时间内能够重新连接到 ZooKeeper 集群中任意一个实例,那么之前创建的会话仍然有效。ZooKeeper 通过 sessionID 唯一标识 Session,所以在 ZooKeeper 集群中,sessionID 需要保证全局唯一。 由于 ZooKeeper 会将 Session 信息存放到硬盘中,即使节点重启,之前未过期的 Session 仍然会存在。

public class CuratorSessionApi {
    public static void main(String[] args) throws Exception {
        // Zookeeper集群地址,多个节点地址可以用逗号分隔
        String zkAddress = "127.0.0.1:2181";
        // 重试策略,如果连接不上ZooKeeper集群,会重试三次,重试间隔会递增
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
        // 创建Curator Client并启动,启动成功之后,就可以与Zookeeper进行交互了
        CuratorFramework client = CuratorFrameworkFactory
                .newClient(zkAddress, retryPolicy);
        client.start();
        // 添加ConnectionStateListener监听器
        client.getConnectionStateListenable().addListener(
                new ConnectionStateListener() {
                    public void stateChanged(CuratorFramework client,
                                             ConnectionState newState) {
                        // 这里我们可以针对不同的连接状态进行特殊的处理
                        switch (newState) {
                            case CONNECTED:
                                // 第一次成功连接到ZooKeeper之后会进入该状态。
                                // 对于每个CuratorFramework对象,此状态仅出现一次
                                System.out.println("第一次成功连接到ZooKeeper之后会进入该状态");
                                break;
                            case SUSPENDED: //   ZooKeeper的连接丢失
                                System.out.println("ZooKeeper的连接丢失");
                                break;
                            case RECONNECTED: // 丢失的连接被重新建立
                                System.out.println("丢失的连接被重新建立");
                                break;
                            case LOST:
                                System.out.println("当Curator认为会话已经过期时,则进入此状态");
                                // 当Curator认为会话已经过期时,则进入此状态
                                break;
                            case READ_ONLY: // 连接进入只读模式
                                System.out.println("连接进入只读模式");
                                break;
                        }
                    }
                });
        client.close();
        System.in.read();
    }
}

Watcher

Watcher 监听机制是 ZooKeeper 中非常重要的特性,可以监听某个节点上发生的特定事件,例如,监听节点数据变更、节点删除、子节点状态变更等事件。当相应事件发生时,ZooKeeper 会产生一个 Watcher 事件,并且发送到客户端。通过 Watcher 机制,就可以使用 ZooKeeper 实现分布式锁、集群管理等功能。

在 Curator 客户端中,我们可以使用 usingWatcher() 方法添加 Watcher,前面示例中,能够添加 Watcher 的有 checkExists()、getData()以及 getChildren() 三个方法,下面我们来看一个具体的示例:

public class CuratorWatcherApi {

    public static void main(String[] args) throws Exception {
        // Zookeeper集群地址,多个节点地址可以用逗号分隔
        String zkAddress = "127.0.0.1:2181";
        // 重试策略,如果连接不上ZooKeeper集群,会重试三次,重试间隔会递增
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
        // 创建Curator Client并启动,启动成功之后,就可以与Zookeeper进行交互了
        CuratorFramework client = CuratorFrameworkFactory
                .newClient(zkAddress, retryPolicy);
        client.start();
        try {
            client.create().withMode(CreateMode.PERSISTENT)
                    .forPath("/user", "test".getBytes());
        } catch (Exception e) {
        }
        // 这里通过usingWatcher()方法添加一个Watcher
        List<String> children = client.getChildren().usingWatcher(
                new CuratorWatcher() {
                    public void process(WatchedEvent event) throws Exception {
                        System.out.println(event.getType() + "," +
                                event.getPath());
                    }
                }).forPath("/user");
        System.out.println(children);
        System.in.read();
    }
}

接下来,我们打开 ZooKeeper 的命令行客户端,在 /user 节点下先后添加两个子节点,此时我们只得到一行输出:

NodeChildrenChanged,/user

之所以这样,是因为通过 usingWatcher() 方法添加的 CuratorWatcher 只会触发一次,触发完毕后就会销毁。checkExists() 方法、getData() 方法通过 usingWatcher() 方法添加的 Watcher 也是一样的原理,只不过监听的事件不同,你若感兴趣的话,可以自行尝试一下。

相信你已经感受到,直接通过注册 Watcher 进行事件监听不是特别方便,需要我们自己反复注册 Watcher。Apache Curator 引入了 Cache 来实现对 ZooKeeper 服务端事件的监听。Cache 是 Curator 中对事件监听的包装,其对事件的监听其实可以近似看作是一个本地缓存视图和远程ZooKeeper 视图的对比过程。同时,Curator 能够自动为开发人员处理反复注册监听,从而大大简化了代码的复杂程度。

实践中常用的 Cache 有三大类:

  • NodeCache。 对一个节点进行监听,监听事件包括指定节点的增删改操作。注意哦,NodeCache 不仅可以监听数据节点的内容变更,也能监听指定节点是否存在,如果原本节点不存在,那么 Cache 就会在节点被创建后触发 NodeCacheListener,删除操作亦然。
  • PathChildrenCache。 对指定节点的一级子节点进行监听,监听事件包括子节点的增删改操作,但是不对该节点的操作监听。
  • TreeCache。 综合 NodeCache 和 PathChildrenCache 的功能,是对指定节点以及其子节点进行监听,同时还可以设置监听的深度。
    下面通过示例介绍上述三种 Cache 的基本使用:
public class CuratorWatcherCacheApi {
    public static void main(String[] args) throws Exception {
        // Zookeeper集群地址,多个节点地址可以用逗号分隔
        String zkAddress = "127.0.0.1:2181";
        // 重试策略,如果连接不上ZooKeeper集群,会重试三次,重试间隔会递增
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
        // 创建Curator Client并启动,启动成功之后,就可以与Zookeeper进行交互了
        CuratorFramework client = CuratorFrameworkFactory
                .newClient(zkAddress, retryPolicy);
        client.start();
        // 创建NodeCache,监听的是"/user"这个节点
        NodeCache nodeCache = new NodeCache(client, "/user");
        // start()方法有个boolean类型的参数,默认是false。如果设置为true,
        // 那么NodeCache在第一次启动的时候就会立刻从ZooKeeper上读取对应节点的
        // 数据内容,并保存在Cache中。
        nodeCache.start(true);
        if (nodeCache.getCurrentData() != null) {
            System.out.println("NodeCache节点初始化数据为:"
                    + new String(nodeCache.getCurrentData().getData()));
        } else {
            System.out.println("NodeCache节点数据为空");
        }
        // 添加监听器
        nodeCache.getListenable().addListener(() -> {
            String data = new String(nodeCache.getCurrentData().getData());
            System.out.println("NodeCache节点路径:" + nodeCache.getCurrentData().getPath()
                    + ",节点数据为:" + data);
        });
        // 创建PathChildrenCache实例,监听的是"user"这个节点
        PathChildrenCache childrenCache = new PathChildrenCache(client, "/user", true);
        // StartMode指定的初始化的模式
        // NORMAL:普通异步初始化
        // BUILD_INITIAL_CACHE:同步初始化
        // POST_INITIALIZED_EVENT:异步初始化,初始化之后会触发事件
        childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
        // childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
        // childrenCache.start(PathChildrenCache.StartMode.NORMAL);
        List<ChildData> children = childrenCache.getCurrentData();
        System.out.println("获取子节点列表:");
        // 如果是BUILD_INITIAL_CACHE可以获取这个数据,如果不是就不行
        children.forEach(childData -> {
            System.out.println(new String(childData.getData()));
        });
        childrenCache.getListenable().addListener(((client1, event) -> {
            System.out.println(LocalDateTime.now() + "  " + event.getType());
            if (event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)) {
                System.out.println("PathChildrenCache:子节点初始化成功...");
            } else if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)) {
                String path = event.getData().getPath();
                System.out.println("PathChildrenCache添加子节点:" + event.getData().getPath());
                System.out.println("PathChildrenCache子节点数据:" + new String(event.getData().getData()));
            } else if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {
                System.out.println("PathChildrenCache删除子节点:" + event.getData().getPath());
            } else if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {
                System.out.println("PathChildrenCache修改子节点路径:" + event.getData().getPath());
                System.out.println("PathChildrenCache修改子节点数据:" + new String(event.getData().getData()));
            }
        }));
        // 创建TreeCache实例监听"user"节点
        TreeCache cache = TreeCache.newBuilder(client, "/user").setCacheData(false).build();
        cache.getListenable().addListener((c, event) -> {
            if (event.getData() != null) {
                System.out.println("TreeCache,type=" + event.getType() + " path=" + event.getData().getPath());
            } else {
                System.out.println("TreeCache,type=" + event.getType());
            }
        });
        cache.start();
        System.in.read();
    }
}

启动程序后自己在客户端进行增加节点,修改数据等操作,观察输出这里不进行截图了

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

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

相关文章

微信小程序开发系列(三十四)·自定义组件的创建、注册以及使用(数据和方法事件的使用)

目录 1. 分类和简介 2. 公共组件 2.1 创建 2.2 注册 2.3 使用 3. 页面组件 3.1 创建 3.2 注册 3.3 使用 4. 组件的数据和方法的使用 4.1 组件数据的修改 4.2 方法事件的使用 1. 分类和简介 小程序目前已经支持组件化开发&#xff0c;可以将页面中的功能…

【PyTorch】基础学习:一文详细介绍 torch.load() 的用法和应用

【PyTorch】基础学习&#xff1a;一文详细介绍 torch.load() 的用法和应用 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f44…

基于Android Studio的小米便签App的代码泛读结对心得体会

本次实验我本来最开始使用的是2023.2.1.23的Android studio版本&#xff0c;但是在选择项目的时候没有编程语言为java的选项导致导入项目之后运行不起来。 创建完项目之后默认的代码块是MainActivity.kt&#xff0c;这里面不能编写java代码 所以我选择了退版本退到21海豚版本…

AcWing 2. 01背包问题

题目描述 解题思路&#xff1a; 相关代码&#xff1a; import java.util.Scanner; public class Main {public static void main(String[] args){Scanner scanner new Scanner(System.in);/** 背包问题的物品下标最好从1开始。* *//*定义一f[i][j]数组&#xff0c;i表示的…

Java学习笔记------常用API(五)

爬虫 从网站中获取 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.regex.Matcher; import java.util.reg…

论文浅尝 | GPT-RE:基于大语言模型针对关系抽取的上下文学习

笔记整理&#xff1a;张廉臣&#xff0c;东南大学硕士&#xff0c;研究方向为自然语言处理、信息抽取 链接&#xff1a;https://arxiv.org/pdf/2305.02105.pdf 1、动机 在很多自然语言处理任务中&#xff0c;上下文学习的性能已经媲美甚至超过了全资源微调的方法。但是&#xf…

2022年第十三届蓝桥杯比赛Java B组 【全部真题答案解析-第一部分】

最近回顾了Java B组的试题&#xff0c;深有感触&#xff1a;脑子长时间不用会锈住&#xff0c;很可怕。 兄弟们&#xff0c;都给我从被窝里爬起来&#xff0c;赶紧开始卷&#xff01;&#xff01;&#xff01; 2022年第十三届蓝桥杯Java B组(第一部分 A~F题) 目录 一、填空题 …

Rabbit MQ详解

写在前面,由于Rabbit MQ涉及的内容较多&#xff0c;赶在春招我个人先按照我认为重要的内容进行一定总结&#xff0c;也算是个学习笔记吧。主要参考官方文档、其他优秀文章、大模型问答。自己边学习边总结。后面有时间我会慢慢把所有内容补全&#xff0c;分享出来也是希望可以给…

可视化搭建一个智慧零售订单平台

前言 智慧零售行业是在数字化浪潮中快速发展的一个领域&#xff0c;它利用先进的信息技术和大数据分析来提升零售业务的效率和顾客体验。智慧零售订单平台&#xff0c;具有跨平台、数据智能清洗和建模&#xff0c;以及更加丰富的数据展示形式等优势。智慧零售订单平台可以以文…

MySQL8空间索引失效

发现问题 表结构如下&#xff0c;boundary字段建立空间索引 CREATE TABLE area (id int(11) NOT NULL COMMENT 行政区划编码,pid int(11) NOT NULL COMMENT 上级编码,deep int(11) NOT NULL COMMENT 深度,name varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_…

镜像制作实战篇

“ 在失控边缘冲杀为&#xff0c;最终解脱” CMD与EntryPoint实战 EntryPoint 与 CMD都是docker 镜像制作中的一条命令&#xff0c;它们在概念上可能有些相似&#xff0c;但在使用中&#xff0c;两者是有明显的区别的。比如&#xff0c;执行一个没有调用EntryPoint、CMD的容器会…

一起学数据分析_3(模型建立与评估_1)

使用前面清洗好的数据来建立模型。使用自变量数据来预测是否存活&#xff08;因变量&#xff09;&#xff1f; &#xff08;根据问题特征&#xff0c;选择合适的算法&#xff09;算法选择路径&#xff1a; 1.切割训练集与测试集 import pandas as pd import numpy as np impo…

使用PWM实现呼吸灯功能

CC表示的意思位捕获比较&#xff0c;CCR表示的是捕获比较寄存器 占空比等效于PWM模拟出来的电压的多少&#xff0c;占空比越大等效出的模拟电压越趋近于高电平&#xff0c;占空比越小等效出来的模拟电压越趋近于低电平&#xff0c;分辨率表示的是占空比变化的精细程度&#xf…

(done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW

一个视频&#xff1a;https://www.bilibili.com/video/BV1mb4y1y7EB/?spm_id_from333.337.search-card.all.click&vd_source7a1a0bc74158c6993c7355c5490fc600 这里有个视频&#xff0c;讲解得更加生动形象一些 总得来说&#xff0c;词袋模型(Bow, bag-of-words) 是最简…

spring boot nacos注册微服务示例demo_亲测成功

spring boot nacos注册微服务示例demo_亲测成功 先安装好Nacos Nacos安装使用 创建Maven项目 结构如图 例如项目名为: test-demo 下面有个子模块: test-demo-data-process 父模块pom.xml <?xml version"1.0" encoding"UTF-8"?> <project …

【Micropython ESP32】定时器Timer

文章目录 前言一、分频系数1.1 为什么需要分频系数1.2 分频系数怎么计算 二、如何使用定时器2.1 定时器构造函数2.2 定时器初始化2.3 关闭定时器 三、定时器示例代码总结 前言 在MicroPython中&#xff0c;ESP32微控制器提供了丰富的功能&#xff0c;其中之一是定时器&#xf…

【消息队列开发】 实现MemoryDataCenter类——管理内存数据

文章目录 &#x1f343;前言&#x1f334;数据格式的准备&#x1f332;内存操作&#x1f6a9;对于交换机&#x1f6a9;对于队列&#x1f6a9;对于绑定&#x1f6a9;对于单个消息&#x1f6a9;对于队列与消息链表&#x1f6a9;对于未确认消息&#x1f6a9;从硬盘上读取数据 ⭕总…

SpringCloud-深度理解ElasticSearch

一、Elasticsearch概述 1、Elasticsearch介绍 Elasticsearch&#xff08;简称ES&#xff09;是一个开源的分布式搜索和分析引擎&#xff0c;构建在Apache Lucene基础上。它提供了一个强大而灵活的工具&#xff0c;用于全文搜索、结构化搜索、分析以及数据可视化。ES最初设计用…

ARM和AMD介绍

一、介绍 ARM 和 AMD 都是计算机领域中的知名公司&#xff0c;它们在不同方面具有重要的影响和地位。 ARM&#xff08;Advanced RISC Machine&#xff09;&#xff1a;ARM 公司是一家总部位于英国的公司&#xff0c;专注于设计低功耗、高性能的处理器架构。ARM 架构以其精简指…

Vue前端开发记录(一)

本篇文章中的图片均为深色背景&#xff0c;请于深色模式下观看 说明&#xff1a;本篇文章的内容为vue前端的开发记录&#xff0c;作者在这方面的底蕴有限&#xff0c;所以仅作为参考 文章目录 一、安装配置nodejs,vue二、vue项目目录结构三、前期注意事项0、组件1、数不清的报…