快速入门Zookeeper

news2024/12/23 9:50:22

Zookeeper

ZooKeeper作为一个强大的开源分布式协调服务,扮演着分布式系统中至关重要的角色。它提供了一个中心化的服务,用于维护配置信息、命名、提供分布式同步以及提供组服务等。通过其高性能和可靠的特性,ZooKeeper能够确保在复杂的分布式环境中,各个节点和服务之间的协调和通信得以顺利进行。无论是在大规模的Web服务、云基础设施管理,还是大数据处理框架中,ZooKeeper都是实现服务发现、负载均衡、数据发布/订阅等关键功能的首选工具。它的出现极大地简化了分布式系统设计中的一致性问题,使得开发者可以更加专注于业务逻辑的实现。

在这里插入图片描述

安装配置

学习笔记:快速入门ZooKeeper技术

zookeeper命令操作

zookeeper数据模型
在这里插入图片描述
服务端命令操作
• 启动 ZooKeeper 服务: ./zkServer.sh start
• 查看 ZooKeeper 服务状态: ./zkServer.sh status
• 停止 ZooKeeper 服务: ./zkServer.sh stop
• 重启 ZooKeeper 服务: ./zkServer.sh restart
客户端命令操作
在这里插入图片描述
连接ZooKeeper服务端:

./zkCli.sh –server ip:port

在这里插入图片描述

断开链接

quit

在这里插入图片描述
查看节点信息

ls /dubbo

在这里插入图片描述
创建节点并赋值(没有加任何参数就是持久化的

create /节点path value

在这里插入图片描述

设置节点值

set /节点path value

在这里插入图片描述
删除节点值

delete /path

在这里插入图片描述
不能重复创建节点,但是可以创建子节点往下延申

create /app1/p1
create /app1/p2

在这里插入图片描述
子节点存在的时候,不允许直接删除父节点
直接删除子节点的节点

deleteall /节点path

在这里插入图片描述
创建临时顺序节点

create -e /节点path value

退出会话,重新打开xshell查询会发现临时节点没有了

创建持久化顺序节点

create -s /节点path value

如果生成多次,会发现顺序产生多个节点
在这里插入图片描述
查看创建顺序临时节点

create -es /节点路径

在这里插入图片描述
在这里插入图片描述

查看节点详细信息

ls -s /节点path(ls2 /)

之前使用过Dubbo,这里可以看一下服务提供方的ip地址
在这里插入图片描述
在这里插入图片描述

JAVA API操作

在这里插入图片描述注意
因为Curator是ZooKeeper的Java客户端库,所以二者的版本要对应起来可以看下官网的说明。
Zookeeper 3.5X 的版本可以用Curator4.0版本
低版本的Curator不能用高版本的Zookeeper,反之则可以。

导入pom.xml

<dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

        <!--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>
        <!--日志-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </dependency>

    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

建立链接

public class CuratorTest {
    /**
     * 建立连接
     */
    @Test
    public void testConnection() {
        // 1.第一种方式
        // 重试策略,该策略重试设定的次数,每次重试之间的睡眠时间都会增加
        /**
         * 参数:
         * baseSleepTimeMs – 重试之间等待的初始时间量
         * 最大重试 次数 – 重试的最大次数
         */
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);

        /**
         * Create a new client
         *
         * @param connectString       list of servers to connect to 连接字符串,地址+端口 例如“192. 168.149.135:2181, 192.168.149.135”
         * @param sessionTimeoutMs    session timeout 会话超时时间 单位毫秒
         * @param connectionTimeoutMs connection timeout 连接超时时间 单位毫秒
         * @param retryPolicy         retry policy to use 策略
         * @return client
         */

        CuratorFramework client =
                CuratorFrameworkFactory.newClient("192. 168.149.135:2181", 60 * 1000, 15 * 1000, retryPolicy);

        client.start();
    }
}
 /**
     * 建立连接 方式二
     */
    @Test
    public void testConnection2() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);

        // 第二种方式
        CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().connectString("192. 168.149.135:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy)
                .namespace("itheima");;
        
        builder.build().start();

    }

注意这里建议把namespace加上,相当于是根目录
在这里插入图片描述
添加节点

public class CuratorTest {
	// 声明为成员变量 
    private CuratorFramework client;
    /**
     * 建立连接 方式二
     */
    @Before
    public void testConnection2() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);

        // 第二种方式
        client = CuratorFrameworkFactory.builder().connectString("192. 168.149.135:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy)
                .namespace("itheima").build();

        client.start();
    }

    /**
     * 创建节点
     * 持久、临时、顺序
     * 设置数据
     * <p>
     * 1.基本创建
     * 2.创建节点,带有数据
     * 3.设置节点的类型
     * 4.创建多级节点
     */
    @Test
    public void testCreate() throws Exception {
        // client操作
    }

    @After
    /**
     * 关闭连接
     */
    public void close() {
        if (null != client) {
            client.close();
        }
    }
}

(1).创建一个基础的节点
我们先创建一个基础的节点
CuratorTest.java

    @Test
    public void testCreate() throws Exception {
        String path = client.create().forPath("/app4");
        System.out.println(path);
    }

(2).创建一个带有数据的节点
CuratorTest.java

    @Test
    public void testCreateValue() throws Exception {
        String path = client.create().forPath("/app5", "heima".getBytes());
        System.out.println(path);
    }

(3).设置节点的类型
CuratorTest.java
创建临时节点

    /**
     * 设置节点类型
     *
     * @throws Exception
     */
    @Test
    public void testCreateType() throws Exception {
        String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app6", "number6".getBytes());
        System.out.println(path);
    }

(4).创建多级节点
CuratorTest.java

 /**
     * 多级节点
     *
     * @throws Exception
     */
    @Test
    public void testCreateManyTypes() throws Exception {
        // creatingParentsIfNeeded()如果父节点不存在,就创建一个节点
        String path = client.create().creatingParentsIfNeeded().forPath("/app8/p8", "number8".getBytes());
        System.out.println(path);
    }

查询节点
(1).查询数据
CuratorTest.java

    /**
     * 获取、查询
     * 1.查询数据
     * 2.查询子节点
     * 3.查询节点的状态 ls -s
     */
    @Test
    public void testGet() throws Exception {
        byte[] bytes = client.getData().forPath("/app7");
        System.out.println(new String(bytes));
    }

(2).查询子节点
CuratorTest.java

    /**
     * 获取、查询
     * 2.查询子节点
     */
    @Test
    public void testGetSon() throws Exception {
        List<String> path = client.getChildren().forPath("/app8");
        System.out.println(path);
    }

(3).查询节点的状态 ls -s
CuratorTest.java

    /**
     * 3.查询节点的状态 ls -s
     */
    @Test
    public void testGetStatus() throws Exception {
        Stat stat = new Stat();
        System.out.println("查询前:" + stat);
        client.getData().storingStatIn(stat).forPath("/app8/p8");
        System.out.println("查询后:" + stat);
    }

修改节点
修改数据
修改前用Zookeeper查询

    /**
     * 修改数据
     *
     * @throws Exception
     */
    @Test
    public void testSet() throws Exception {
        client.setData().forPath("/app7", "dong77".getBytes());
    }

根据版本修改数据⭐(推荐)
CuratorTest.java

    /**
     * 按照版本修改
     *
     * @throws Exception
     */
    @Test
    public void testSetForVersion() throws Exception {
        int version = 0;
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath("/app7");
        version = stat.getVersion();
        System.out.println("当前version是:" + version);
        client.setData().withVersion(version).forPath("/app7", "luka7".getBytes());
    }

删除节点

    /**
     * 1.删除单个节点
     *
     * @throws Exception
     */
    @Test
    public void testDelete() throws Exception {
        client.delete().forPath("/app5");
    }

删除带有子节点的节点
删除前节点app7是有子节点的

    /**
     * 2.删除带有子节点的节点
     *
     * @throws Exception
     */
    @Test
    public void testDeleteWithSon() throws Exception {
        client.delete().deletingChildrenIfNeeded().forPath("/app7");
    }

必须成功的删除节点⭐(推荐):防止网络抖动,本质抖动。
删除前app4还在

    /**
     * 3.必须成功的删除节点
     *
     * @throws Exception
     */
    @Test
    public void testDeleteSucceed() throws Exception {
        client.delete().guaranteed().forPath("/app4");
    }

回调
删除前有节点

/**
     * 4.回调
     *
     * @throws Exception
     */
    @Test
    public void testDeleteReturnFun() throws Exception {
        BackgroundCallback callback = new BackgroundCallback() {
            @Override
            public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                System.out.println("我被删除了");
                System.out.println(event);
            }
        };
        client.delete().inBackground(callback).forPath("/app8");
    }

Watch事件监听

在这里插入图片描述
(1).NodeCache给指定一个节点注册监听器
用代码实现一下:
命名空间下面可能没有子节点的话,过一会儿就会删除命名空间
CuratorTest.java

 /**
     * NodeCache : 只是监听某一个特定的节点
     *
     * @throws Exception
     */
    @Test
    public void testNodeCache() throws Exception {
        while (true) {
            /**
             * Params:
             * client – curztor client 客户端
             * path – the full path to the node to cache  要缓存的节点的完整路径
             * dataIsCompressed – if true, data in the path is compressed 如果为 true,则路径中的数据被压缩,默认不压缩
             */
            // 1.创建NodeCache对象
            NodeCache nodeCache = new NodeCache(client, "/app1");

            // 2.注册监听8
            nodeCache.getListenable().addListener(new NodeCacheListener() {
                @Override
                public void nodeChanged() throws Exception {
                    System.out.println("节点变化了");
                }
            });

            // 3.开启监听 如果为 true,将在此方法返回之前调用, rebuild() 以便获得节点的初始视图
            nodeCache.start(true);
        }

    }

现在想知道节点变成了什么,这里需要修改代码
CuratorTest.java

 /**
     * NodeCache : 只是监听某一个特定的节点
     *
     * @throws Exception
     */
    @Test
    public void testNodeCache() throws Exception {

        /**
         * Params:
         * client – curztor client 客户端
         * path – the full path to the node to cache  要缓存的节点的完整路径
         * dataIsCompressed – if true, data in the path is compressed 如果为 true,则路径中的数据被压缩,默认不压缩
         */
        // 1.创建NodeCache对象
        NodeCache nodeCache = new NodeCache(client, "/app1");

        // 2.注册监听
        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));
            }
        });

        // 3.开启监听 如果为 true,将在此方法返回之前调用, rebuild() 以便获得节点的初始视图
        nodeCache.start(true);
        while (true) {
        }


    }

(2).PathChildrenCache(监听某个节点的子节点们 )
测试前先给app1节点创建3个子节点

/**
     * PathChildrenCache : 监控一个ZNode的所有子节点.
     *
     * @throws Exception
     */
    @Test
    public void testPathChildrenCache() throws Exception {
        /**
         *  如果为 true,则除了统计信息之外,还会缓存节点内容
         */
        // 1.创建监听对象
        PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app1", true);

        // 2.绑定监听器
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                System.out.println("子节点变化了");
                System.out.println(event);
            }
        });
        pathChildrenCache.start();

        while (true) {

        }
    }

那现在我想看到具体子节点的变化情况和变化的值呢。修改CuratorTest.java修改PathChildrenCache构造函数,最后一个值是false,然后输出监听信息。

/**
     * PathChildrenCache : 监控一个ZNode的所有子节点.
     *
     * @throws Exception
     */
    @Test
    public void testPathChildrenCache() throws Exception {
        /**
         *  如果为 true,则除了统计信息之外,还会缓存节点内容
         */
        // 1.创建监听对象
        PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app1", false);

        // 2.绑定监听器
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                System.out.println("子节点变化了");
                System.out.println(event);

                // 1.获取类型
                PathChildrenCacheEvent.Type type = event.getType();
                // 2.判断类型是否是update
                if (type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {
                    byte[] bytes = event.getData().getData();
                    System.out.println("数据被更新了:" + new String(bytes));
                } else if (type.equals(PathChildrenCacheEvent.Type.CHILD_ADDED)) {
                    byte[] bytes = event.getData().getData();
                    System.out.println("数据被添加了:" + new String(bytes));
                } else if (type.equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {
                    byte[] bytes = event.getData().getData();
                    System.out.println("数据被删除了:" + new String(bytes));
                }

            }
        });
        pathChildrenCache.start();

        while (true) {

        }
    }

(3).TreeCache(监听某个节点自己和所有的子节点们)
CuratorTest.java

/**
     * TreeCache : 可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合
     *
     * @throws Exception
     */
    @Test
    public void testTreeCache() throws Exception {
        TreeCache treeCache = new TreeCache(client, "/app1");
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                System.out.println("整个树节点有变化");
                System.out.println(event);
            }
        });
        treeCache.start();

        while (true) {
            
        }

    }

也想输出树节点的信息,继续修改CuratorTest.java

 /**
     * TreeCache : 可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合
     *
     * @throws Exception
     */
    @Test
    public void testTreeCache() throws Exception {
        TreeCache treeCache = new TreeCache(client, "/app1");
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                System.out.println("整个树节点有变化");
                System.out.println(event);

                TreeCacheEvent.Type type = event.getType();
                if (type.equals(TreeCacheEvent.Type.NODE_UPDATED)) {
                    byte[] bytes = event.getData().getData();
                    System.out.println("树节点数据被更新了:" + new String(bytes));
                } else if (type.equals(TreeCacheEvent.Type.NODE_ADDED)) {
                    byte[] bytes = event.getData().getData();
                    System.out.println("树节点数据被添加了:" + new String(bytes));
                } else if (type.equals(TreeCacheEvent.Type.NODE_REMOVED)) {
                    byte[] bytes = event.getData().getData();
                    System.out.println("树节点数据被删除了:" + new String(bytes));
                } else {
                    System.out.println("树节点无操作");
                }

            }
        });
        treeCache.start();

        while (true) {

        }

    }

分布式锁

在这里插入图片描述
原理
当客户端想要获得锁,则创建节点,使用完锁,则删除该节点。
在这里插入图片描述
模拟12306售票案例

在这里插入图片描述
在这里插入图片描述

创建一个测试类LockTest.java

package com.itheima;

/**
 * @ClassName: LockTest
 * @Description:
 * @Author: wty
 * @Date: 2023/3/14
 */

public class LockTest {
    public static void main(String[] args) {
        Tick12306 tick12306 = new Tick12306();
        // 创建客户端
        Thread t1 = new Thread(tick12306, "携程");
        Thread t2 = new Thread(tick12306, "飞猪");
        Thread t3 = new Thread(tick12306, "去哪儿");
        
        t1.start();
        t2.start();
        t3.start();
    }
}

创建实体类模拟12306抢票操作

package com.itheima;

/**
 * @ClassName: Tick12306
 * @Description:
 * @Author: wty
 * @Date: 2023/3/14
 */

public class Tick12306 implements Runnable {
    // 数据库的票数
    private int tickets = 100;

    @Override
    public void run() {
        while (true) {
            if (tickets > 0) {
                System.out.println("线程:" + Thread.currentThread().getName() + "买走了票,剩余" + (--tickets));
            }
        }
    }
}

解决方案:用分布式锁解决
添加工具类ClientConnection.java

public class ClientConnection {
    public static CuratorFramework getConnection() {
        ExponentialBackoffRetry retry = new ExponentialBackoffRetry(3000, 10);

        CuratorFramework client = CuratorFrameworkFactory.builder().connectString("192. 168.149.135:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000).retryPolicy(retry).build();
        client.start();
        return client;
    }
}

修改Tick12306.java

public class Tick12306 implements Runnable {
    private InterProcessMutex lock;
    // 数据库的票数
    private int tickets = 100;

    public Tick12306() {
        CuratorFramework client = ClientConnection.getConnection();
        lock = new InterProcessMutex(client, "/itheima/lock");
    }

    @Override
    public void run() {
        while (true) {
            // 获取锁
            try {
                lock.acquire(3, TimeUnit.SECONDS);
                if (tickets > 0) {
                    System.out.println("线程:" + Thread.currentThread().getName() + "买走了票,剩余" + (--tickets));
                    Thread.sleep(100);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                try {
                    lock.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

zookeeper 集群

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
配置每一个Zookeeper 的dataDir 和 clientPort 分别为2181 2182 2183

修改/usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
模拟集群异常
(1)首先我们先测试如果是从服务器挂掉,会怎么样
把3号服务器停掉,观察1号和2号,发现状态并没有变化。
在这里插入图片描述
在这里插入图片描述

由此得出结论,3个节点的集群,从服务器挂掉,集群正常
(2)我们再把1号服务器(从服务器)也停掉,查看2号(主服务器)的状态,发现已经停止运行了。
在这里插入图片描述
由此得出结论,3个节点的集群,2个从服务器都挂掉,主服务器也无法运行。因为可运行的机器没有超过集群总数量的半数。
(3)我们再次把1号服务器启动起来,发现2号服务器又开始正常工作了。而且依然是领导者。
在这里插入图片描述
(4)我们把3号服务器也启动起来,把2号服务器停掉,停掉后观察1号和3号的状态。
在这里插入图片描述
(5)我们再次测试,当我们把2号服务器重新启动起来启动后,会发生什么?2号服务器会再次成为新的领导吗?结果2号服务器启动后依然是跟随者(从服务器),3号服务器依然是领导者(主服务器),没有撼动3号服务器的领导地位。由此我们得出结论,当领导者产生后,再次有新服务器加入集群,不会影响到现任领导者

集群角色

在这里插入图片描述

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

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

相关文章

服务器上安装Orcale数据库以及PL SQL工具(中文)

一、前期准备 1、oracle数据库安装包–>Oracle下载地址&#xff0c;版本根据当时情况就下最新的就行&#xff0c;下载时间可能有点长&#xff0c;耐心点。 2、PL SQL工具下载地址–>PL SQL下载地址&#xff0c;百度网盘可以共享【限速&#xff0c;没办法&#xff01;&am…

协程6 --- HOOK

文章目录 HOOK 概述链接运行时动态链接 linux上的常见HOOK方式修改函数指针用户态动态库拦截getpidmalloc 第一版malloc 第二版malloc/free通过指针获取到空间大小malloc 第三版strncmp 内核态系统调用拦截堆栈式文件系统 协程的HOOK HOOK 概述 原理&#xff1a;修改符号指向 …

[0342].第12节:加载与存储指令及算数指令

我的后端学习大纲 JVM学习大纲 一、加载与存储指令&#xff1a; 加载&#xff1a;主要是指的将数据压入到操作数栈中&#xff0c;那么这个数据可能来源于常量池也可能来自于局部变量表 1.iload_0占1个字节。iload 0 占3个字节。 2.因为操作码数量有限&#xff0c;只有256个&…

spark的学习-06

SparkSQL读写数据的方式 1&#xff09;输入Source 方式一&#xff1a;给定读取数据源的类型和地址 spark.read.format("json").load(path) spark.read.format("csv").load(path) spark.read.format("parquet").load(path) 方式二&#xff1a…

ODOO学习笔记(5):ODOO开发规范

一、代码结构与布局 模块结构&#xff1a; 每个ODOO模块应具有清晰的结构&#xff0c;通常包含以下目录和文件&#xff1a; models&#xff1a;存放业务逻辑相关的模型类定义&#xff0c;如定义数据库表结构、业务规则等。views&#xff1a;用于放置各种视图文件&#xff0c;包…

【性能测试】linux服务器性能监控常用命令

CPU 性能监控指令 top 命令 基本功能&#xff1a;top 命令是 Linux 系统中最常用的性能监控工具之一。它可以实时显示系统中各个进程的资源占用情况&#xff0c;包括 CPU 使用率、内存使用量、进程状态等信息。在性能测试监控服务器性能时&#xff0c;通过 top 命令可以快速查…

ROS2humble版本使用colcon构建包

colcon与与catkin相比&#xff0c;没有 devel 目录。 创建工作空间 首先&#xff0c;创建一个目录 ( ros2_example_ws ) 来包含我们的工作区: mkdir -p ~/ros2_example_ws/src cd ~/ros2_example_ws 此时&#xff0c;工作区包含一个空目录 src : . └── src1 directory, …

VUE使用TS开发打包时发现校验问题无法打包

解决办法&#xff1a; 找到 tsconfig.app.json 这个文件&#xff0c;把他的include改为一个实际存在的空文件即可

vscode+EIDE开发环境搭建

嵌入式知识框架目录篇章&#xff1a;返回请点我 热门优质文章 文章标题等级&#xff1a;低中高推荐指数5√最佳vscode安装配置使用调试【保姆级教程】中√√√[VSCODE]基于EIDE插件搭建vscode下的STM32单片机开发环境中√√√官方安装高√√√√VScode利用EIDE和cortex-debug…

kafka面试题解答(四)

5、消费者组和分区数之间的关系是怎样的&#xff1f; 消费者组数小于等于分区数&#xff0c;消费者组内每个消费者负责消费不同分区的数据&#xff0c;一个分区只能由一个组内消费者消费。 6、kafka如何知道哪个消费者消费哪个分区&#xff1f; 生产者把数据发送给各个分区&…

C#入门 020 事件(类型成员)

初步了解事件 定义:单词Event&#xff0c;译为“事件” 《牛津词典》中的解释是“a thing that happens, especially something important通顺的解释就是“能够发生的什么事情” 角色:使对象或类具备通知能力的成员 事件(event)是一种使对象或类能够提供通知的成员对象O拥有…

单链表算法题(数据结构)

1. 反转链表 https://leetcode.cn/problems/reverse-linked-list/description/ 题目&#xff1a; 看到这个题目的时候我们怎么去想呢&#xff1f;如果我们反应快的话&#xff0c;应该可以想到我们可以从1遍历到5然后依次头插&#xff0c;但是其实我们还有更好的办法&#xff…

Python 如何通过 cron 或 schedule 实现爬虫的自动定时运行

Python 如何通过 cron 或 schedule 实现爬虫的自动定时运行 自动定时运行爬虫是很多数据采集项目的基本需求。例如&#xff0c;每天采集一次新闻数据&#xff0c;或每小时更新股票行情数据等。通过 Python 实现定时任务&#xff0c;可以保证数据采集的高效和持续性。本文将带大…

初学mongoDB

MongoDB 是一个开源的 NoSQL 数据库&#xff0c;由 C 语言编写。它与传统的关系型数据库不同&#xff0c;MongoDB 使用的是一种基于文档的存储模型&#xff0c;不需要定义固定的表结构&#xff0c;可以灵活地存储和管理大量的非结构化数据。下面是 MongoDB 的一些核心特性&…

Ubuntu 的 ROS 操作系统turtlebot3环境搭建

引言 本文介绍如何在Ubuntu系统中为TurtleBot3配置ROS环境&#xff0c;包括安装和配置ROS Noetic的步骤&#xff0c;为PC端控制TurtleBot3提供操作指南。 安装和配置的过程分为PC设置、系统安装、依赖安装等部分&#xff0c;并在最后进行网络配置&#xff0c;确保PC端能够顺利…

图像增强的100种方法

文章目录 什么是图像增强 &#xff1f;一、亮度和对比度调整1.1、线性方法1.1.1、灰度反转&#xff08;Gray Inversion&#xff09;1.1.2、对比度拉伸&#xff08;Contrast Stretching&#xff09;1.1.3、对比度和亮度增强&#xff08;Contrast and Brightness&#xff09; 1.2…

Android Kotlin Flow 冷流 热流

在 Android 开发中&#xff0c;Flow 是 Kotlin 协程库的一部分&#xff0c;用于处理异步数据流的一个组件。本质上&#xff0c;Flow 是一个能够异步生产多个值的数据流&#xff0c;与 suspend 函数返回单个值的模式相对应。Flow 更类似于 RxJava 中的 Observable&#xff0c;但…

Web服务器nginx实验2修改端口、默认目录、默认文件访问web页面

修改默认目录、默认文件&#xff1a; 创建配置文件&#xff1a; 里面写&#xff1a;&#xff08;访问的位置是/haha目录里面的haha.html&#xff09; 把haha里面的index.html改名为haha.html&#xff1a; 重启服务&#xff1a; 关闭防火墙、改宽松模式&#xff1a; 用Windows访…

Maven最佳实践

文章目录 1.摘要 本文主要介绍Maven使用&#xff0c;作为Maven使用手册来记录。 2.介绍 Maven是项目管理工具&#xff0c;将项目开发和管理过程抽象成一个项目对象模型&#xff0c;使用pom.xml 文件进行依赖管理和项目构建。 Maven 中pom.xml 是根据坐标信息来定位资源的位置&a…

el-table 纵向垂直表头处理

项目中表格展示会遇到需要纵向垂直表头情况&#xff0c;下面&#xff0c;我们基于el-table组件来实现这种表格。 以下是这次需要用到的数据表格&#xff0c;已知左侧违章名称是固定的&#xff0c;而月份是不固定的&#xff0c;在后端返回数据格式已确定的情况下&#xff0c;需…