从零开始手写RPC框架(3)——ZooKeeper入门

news2024/11/15 21:50:18

目录

  • ZooKeeper简介
    • ZooKeeper中的一些概念
  • ZooKeeper安装与常用命令
    • 常用命令
  • ZooKeeper Java客户端 Curator入门

ZooKeeper简介

是什么?

ZooKeeper 是一个开源的分布式协调服务,本身就是一个分布式程序(只要半数以上节点存活,ZooKeeper 就能正常服务)。
它的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。
ZooKeeper 底层其实只提供了两个功能:1、管理(存储、读取)用户程序提交的数据;2、 为用户程序提供数据节点监听服务。
ZooKeeper 将数据保存在内存中,性能是不错的。 在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景)。
ZooKeeper 为我们提供了高可用、高性能、稳定的分布式数据一致性解决方案,通常被用于实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
这些功能的实现主要依赖于 ZooKeeper 提供的 数据存储+事件监听 功能。

特点

顺序一致性: 从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。
原子性: 所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。
单一系统映像: 无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的。
可靠性: 一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖。
实时性: 每个客户端的系统视图都是最新的。


ZooKeeper中的一些概念

数据模型

ZooKeeper 数据模型采用层次化的多叉树形结构,每个节点上都可以存储数据,这些数据可以是数字、字符串或者是二进制序列。并且。每个节点还可以拥有 N 个子节点,最上层是根节点以“/”来代表。
每个数据节点在 ZooKeeper 中被称为`znode`,它是 ZooKeeper 中数据的最小单元。并且,每个 znode 都有一个唯一的路径标识。

在这里插入图片描述

ZooKeeper 主要是用来协调服务的,而不是用来存储业务数据的,所以不要放比较大的数据在 znode 上,ZooKeeper 给出的每个节点的数据大小上限是 1M 。


znode

znode 分为 4 大类:

持久(PERSISTENT)节点:一旦创建就一直存在即使 ZooKeeper 集群宕机,直到将其删除。
临时(EPHEMERAL)节点:临时节点的生命周期是与 客户端会话(session) 绑定的,会话消失则节点消失。并且,临时节点只能做叶子节点 ,不能创建子节点。
持久顺序(PERSISTENT_SEQUENTIAL)节点:除了具有持久(PERSISTENT)节点的特性之外, 子节点的名称还具有顺序性。比如 /node1/app0000000001、/node1/app0000000002 。
临时顺序(EPHEMERAL_SEQUENTIAL)节点:除了具备临时(EPHEMERAL)节点的特性之外,子节点的名称还具有顺序性

每个 znode 由 2 部分组成:

stat:状态信息
data:节点存放的数据的具体内容

stat:状态信息

下面通过 get 命令来获取 根目录下的 dubbo 节点的内容,来学习一下stat的各种状态信息。

[zk: 127.0.0.1:2181(CONNECTED) 6] get /dubbo
# 该数据节点关联的数据内容为空
null
# 下面是该数据节点的一些状态信息,其实就是 Stat 对象的格式化输出
cZxid = 0x2 #create ZXID,即该数据节点被创建时的事务 id
ctime = Tue Nov 27 11:05:34 CST 2018 #create time,即该节点的创建时间
mZxid = 0x2 #modified ZXID,即该节点最终一次更新时的事务 id
mtime = Tue Nov 27 11:05:34 CST 2018 #modified time,即该节点最后一次的更新时间
pZxid = 0x3 #该节点的子节点列表最后一次修改时的事务 id,只有子节点列表变更才会更新 pZxid,子节点内容变更不会更新
cversion = 1 #子节点版本号,当前节点的子节点每次变化时值增加 1
dataVersion = 0 #数据节点内容版本号,节点创建时为 0,每更新一次节点内容(不管内容有无变化)该版本号的值增加 1
aclVersion = 0 #节点的 ACL(权限控制)版本号,表示该节点 ACL 信息变更次数
ephemeralOwner = 0x0 #创建该临时节点的会话的 sessionId;如果当前节点为持久节点,则 ephemeralOwner=0
dataLength = 0 #数据节点内容长度
numChildren = 1 #当前节点的子节点个数
对于znode 操作的权限,ZooKeeper 提供了以下 5 种:CREATE : 能创建子节点 READ:能获取节点数据和列出其子节点 WRITE : 能设置/更新节点数据 DELETE : 能删除子节点 ADMIN : 能设置节点 ACL 的权限
对于身份认证,提供了以下几种方式:world:默认方式,所有用户都可无条件访问。auth :不使用任何 id,代表任何已认证的用户。digest :用户名:密码认证方式:username:password 。ip : 对指定 ip 进行限制。

Watcher(事件监听器)

Watcher(事件监听器)是 ZooKeeper 中的一个很重要的特性

ZooKeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性。

在这里插入图片描述


Session sessionTimeout sessionID

Session 是 ZooKeeper 服务器与客户端之间的长连接。通过这个连接,客户端可以保持有效的会话、发送请求并接收响应,还能接收来自服务器的 Watcher 事件通知。
会话有一个属性叫做 sessionTimeout,代表会话的超时时间。如果客户端连接断开,只要在规定的时间内重新连接上集群中的任意一台服务器,之前创建的会话仍然有效。
在为客户端创建会话之前,服务端会为每个客户端分配一个全局唯一的 sessionID,作为会话的标识。

ZooKeeper 集群

ZooKeeper 是一种分布式协调服务,为了保证高可用性,通常以集群形式部署。由 3 台服务器即可组成ZooKeeper 集群。这些服务器在内存中维护当前状态,并通过 ZAB 协议(ZooKeeper Atomic Broadcast)保持数据一致性。常见的集群模式是 Master/Slave,其中 Master 服务器提供写服务,而 Slave 服务器通过异步复制获取最新数据并提供读服务。ZooKeeper 中不再使用传统的 Master/Slave 概念,而是引入了三种角色:Leader、Follower 和 Observer。
ZooKeeper 集群中的所有机器通过 Leader 选举 来选定一台称为“Leader”的机器。Leader 既可以为客户端提供写服务,又能提供读服务。除了 Leader 外,Follower 和 Observer 都只能提供读服务。Follower 和 Observer 唯一的区别在于 Observer 机器不参与 Leader 的选举过程,也不参与写操作的“过半写成功”策略,因此可以在不影响写性能的情况下提升集群的读性能。
当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时,就会进入 Leader 选举过程,这个过程会选举产生新的 Leader 服务器。ZooKeeper 集群中的服务器状态有下面几种:LOOKING:寻找 Leader。LEADING:Leader 状态,对应的节点为 Leader。FOLLOWING:Follower 状态,对应的节点为 Follower。OBSERVING:Observer 状态,对应节点为 Observer,该节点不参与 Leader 选举。
由于在选举时一个结点得到超半的票数才能成为Leader,所以ZooKeeper 集群在宕掉几个 ZooKeeper 服务器之后,如果剩下的 ZooKeeper 服务器个数大于宕掉的个数的话整个 ZooKeeper 才依然可用。所以ZooKeeper 集群最好是奇数台,因为2n 和 2n-1 的容忍度是一样的,何必增加那一个不必要的 ZooKeeper 呢。
对于一个集群,通常多台机器会部署在不同机房,来提高这个集群的可用性。保证可用性的同时,会发生一种机房间网络线路故障,导致机房间网络不通,而集群被割裂成几个小集群。这时候子集群各自选主导致“脑裂”的情况。ZooKeeper 的过半机制导致不可能产生 2 个 leader,因为少于等于一半是不可能产生 leader 的,这就使得不论机房的机器如何分配都不可能发生脑裂。
Paxos 算法应该可以说是 ZooKeeper 的灵魂了。但是,ZooKeeper 并没有完全采用 Paxos 算法 ,而是使用 ZAB 协议作为其保证数据一致性的核心算法。ZAB(ZooKeeper Atomic Broadcast 原子广播) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。
ZAB 协议包括两种基本的模式,分别是崩溃恢复:当整个服务框架在启动过程中,或是当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB 协议就会进入恢复模式并选举产生新的 Leader 服务器。当选举产生了新的 Leader 服务器,同时集群中已经有过半的机器与该 Leader 服务器完成了状态同步之后,ZAB 协议就会退出恢复模式。消息广播:当集群中已经有过半的 Follower 服务器完成了和 Leader 服务器的状态同步,那么整个服务框架就可以进入消息广播模式了。

在这里插入图片描述





ZooKeeper安装与常用命令

使用Docker安装zookeeper(Dokcer入门可以参考这篇博客)

docker pull zookeeper:3.5.8

运行 ZooKeeper容器

docker run -d --name zookeeper -p 2181:2181 zookeeper:3.5.8

进入容器,然后再进入bin目录

docker exec -it zookeeper bash
cd bin/

连接ZooKeeper服务

./zkCli.sh -server 127.0.0.1:2181

请添加图片描述

安装演示完毕,下面演示常用命令。



常用命令

可以通过help查看常用命令。

创建节点(create 命令)

使用 create 命令可以在指定路径下创建一个 Znode。标志参数指定了创建的 Znode 是临时、持久还是顺序的。默认情况下,所有 Znodes 都是持久的。
临时 Znodes(标志:-e)在会话过期或客户端断开连接时会自动删除。
顺序 Znodes 确保 Znode 路径是唯一的,并在路径后添加序列号。例如,路径 /myapp 可能会被转换为 /myapp0000000001。

示例:

创建持久 Znode:create /FirstZnode "Myfirstzookeeper-app"
创建顺序 Znode:create -s /FirstZnode "second-data"
创建临时 Znode:create -e /SecondZnode "Ephemeral-data"

通过create 命令在根目录创建了 node1 节点,与它关联的字符串是"node1"

[zk: 127.0.0.1:2181(CONNECTED) 5] create /node1 "node1"

通过 create 命令在node1 节点下创建了 node1.1 节点,与它关联的内容是数字 123

[zk: 127.0.0.1:2181(CONNECTED) 18] get -s /node1/node1.1
123
cZxid = 0x3
ctime = Sat Mar 02 12:04:01 UTC 2024
mZxid = 0x3
mtime = Sat Mar 02 12:04:01 UTC 2024
pZxid = 0x3
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0

获取节点数据(get 命令)

使用 get 命令可以获取指定 Znode 的关联数据和元数据。
默认情况下,get 命令只返回节点的名称,而不包含数据。
要获取节点的数据,请使用 -s 标志。
示例:
获取节点名称:get /myapp
获取节点数据:get -s /myapp

监事节点变化(get -w命令)

使用 get 命令并设置 watch 标志,可以监视指定 Znode 的变化。例如:get -w /myapp:监视 /myapp 的变化。

更新节点数据内容(set 命令)

更新node1结点数据内容为字符串"set node1"

[zk: 127.0.0.1:2181(CONNECTED) 11] set /node1 "set node1"

查看某个目录下的子节点(ls 命令)

通过 ls 命令查看 node1 目录下的节点

[zk: 127.0.0.1:2181(CONNECTED) 12] ls /node1
[node1.1]

查看节点状态(stat 命令)

[zk: 127.0.0.1:2181(CONNECTED) 19] stat /node1
cZxid = 0x2
ctime = Sat Mar 02 12:03:26 UTC 2024
mZxid = 0x2
mtime = Sat Mar 02 12:03:26 UTC 2024
pZxid = 0x3
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 1

查看节点信息和状态(ls2 或ls -s命令)

ls2 命令更像是 ls 命令和stat 命令的结合。ls2 命令返回的信息包括 2 部分:1. 子节点列表 2. 当前节点的 stat 信息。

[zk: 127.0.0.1:2181(CONNECTED) 20] ls2 /node1
‘ls2’ has been deprecated. Please use ‘ls [-s] path’ instead.
[node1.1]
cZxid = 0x2
ctime = Sat Mar 02 12:03:26 UTC 2024
mZxid = 0x2
mtime = Sat Mar 02 12:03:26 UTC 2024
pZxid = 0x3
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 1

删除节点(delete 命令)

如果你要删除某一个节点,那么这个节点必须无子节点才行。

[zk: 127.0.0.1:2181(CONNECTED) 3] delete /node1/node1.1




ZooKeeper Java客户端 Curator入门

Curator 是Netflix公司开源的一套 ZooKeeper Java客户端框架,相比于 Zookeeper 自带的客户端zookeeper 来说,Curator 的封装更加完善,各种 API 都可以比较方便地使用。

Curator4.0+版本对ZooKeeper 3.5.x支持比较好。开始之前将下面的依赖添加进项目。

<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-framework</artifactId>
	<version>4.2.0</version>
</dependency>
<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-recipes</artifactId>
	<version>4.2.0</version>
</dependency>

连接 ZooKeeper 客户端

通过CuratorFrameworkFactory 创建CuratorFramework 对象,然后再调用 CuratorFramework 对象的 start() 方法即可

private static final int BASE_SLEEP_TIME = 1000; //重试之间等待的初始时间
private static final int MAX_RETRIES = 3; //最大重试次数

// Retry strategy. Retry 3 times, and will increase the sleep time between
retries.
// 创建一个重试策略,使用指数退避重试,这意味着每次重试之间的等待时间会逐渐增加
RetryPolicy retryPolicy = new ExponentialBackoffRetry(BASE_SLEEP_TIME,
MAX_RETRIES);

// 创建一个ZooKeeper客户端
CuratorFramework zkClient = CuratorFrameworkFactory.builder()
	// the server to connect to (can be a server list)
	.connectString("127.0.0.1:2181") //要连接的服务器列表
	.retryPolicy(retryPolicy) //重试策略
	.build();
zkClient.start();//启动一个ZooKeeper客户端,建立与ZooKeeper服务器的连接。



数据节点的增删改查

我们前面介绍通常是将 znode 分为 4 大类:

持久(PERSISTENT)节点:一旦创建就一直存在即使 ZooKeeper 集群宕机,直到将其删除。
临时(EPHEMERAL)节点:临时节点的生命周期是与 客户端会话(session) 绑定的,会话消失则节点消失。并且,临时节点只能做叶子节点 ,不能创建子节点。
持久顺序(PERSISTENT_SEQUENTIAL)节点:除了具有持久(PERSISTENT)节点的特性之外, 子节点的名称还具有顺序性。比如 /node1/app0000000001、/node1/app0000000002 。
临时顺序(EPHEMERAL_SEQUENTIAL)节点:除了具备临时(EPHEMERAL)节点的特性之外,子节点的名称还具有顺序性

在使用的 ZooKeeper 的时候,会发现 CreateMode 类中实际有 7种 znode 类型 ,但是用的最多的还是上面介绍的 4 种。

创建节点

a.创建持久化节点

zkClient.create().forPath("/node1/00001");
zkClient.create().withMode(CreateMode.PERSISTENT).forPath("/node1/00002");

//父节点node1还未创建时运行上面代码会报错,或者可以选择下面的代码,父节点node1不存在时自动创建

zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/node1/00001");

b.创建临时节点

zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/node1/00001");

c.创建节点并指定数据内容

zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/node1/00001", "java".getBytes());
byte[] dataStr = zkClient.getData().forPath("/node1/00001");//获取节点的数据内容并输出,获取到的是byte数组
System.out.println(new String(dataStr)); //获取节点的数据内容并转换为字符串

d.检测节点是否存在

if (zkClient.checkExists().forPath("/node1/00001") != null) {
    System.out.println("节点存在");
} else {
    System.out.println("节点不存在");
}
//不为null的话会返回一个Stat对象,Stat对象包含了节点的元数据,如版本号、创建时间等,说明刚刚节点创建成功了,


删除节点

a.删除一个子节点

zkClient.delete().forPath("/node1/00001");

b.删除一个节点以及其下的所有子节点

zkClient.delete().deletingChildrenIfNeeded().forPath("/node1");


获取/更新节点数据内容

zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/node1/00001","java".getBytes());
zkClient.getData().forPath("/node1/00001");//获取节点的数据内容
zkClient.setData().forPath("/node1/00001","c++".getBytes());//更新节点数据内容

获取某个节点的所有子节点路径

List<String> childrenPaths = zkClient.getChildren().forPath("/node1");




监听器

下面通过一个案例演示监听器的用法,下面是给某个节点注册子节点监听器 。注册了监听器之后,这个节点的子节点发生变化比如增加、减少或者更新的时候,你可以自定义回调操作。

String path = "/node1";
// 创建一个PathChildrenCache,它用于监听ZNode的子节点的变化
PathChildrenCache pathChildrenCache = new PathChildrenCache(zkClient, path,true);//true代表节点的数据内容也会被获取并存储在ChildData对象中
        
// 创建一个监听器
PathChildrenCacheListener pathChildrenCacheListener = (curatorFramework,
                                                       pathChildrenCacheEvent) -> {
    // do something 这里是当监听到子节点变化时要执行的代码
};
// 将监听器添加到PathChildrenCache
pathChildrenCache.getListenable().addListener(pathChildrenCacheListener);
// 启动PathChildrenCache
pathChildrenCache.start();

PathChildrenCacheListener的适用范围确实比较广,它可以用来监听ZooKeeper中任何ZNode的子节点的变化。然而,如果你想要监听ZNode本身的变化(例如,ZNode被删除或者ZNode的数据被改变),那么你需要使用NodeCache和NodeCacheListener。同样,如果你想要监听ZooKeeper的状态变化(例如,从连接状态变为断开状态),那么你需要使用ConnectionStateListener。

对于NodeCacheListener和ConnectionStateListener,它们的使用方式和PathChildrenCacheListener类似,但是需要使用NodeCache和CuratorFramework来注册。具体来说:

  • NodeCacheListener需要使用NodeCache来注册,NodeCache用于监听一个ZNode本身的变化。
  • ConnectionStateListener需要使用CuratorFramework来注册,CuratorFramework用于监听ZooKeeper的连接状态变化。

如果你要获取节点事件类型的话,可以通过:

pathChildrenCacheEvent.getType()

一共有下面几种类型:

public static enum Type {
	CHILD_ADDED,//子节点增加
	CHILD_UPDATED,//子节点更新
	CHILD_REMOVED,//子节点被删除
	CONNECTION_SUSPENDED,// 连接暂停,可能是因为网络问题
	CONNECTION_RECONNECTED,// 连接重新建立,之前的问题可能已经解决
	CONNECTION_LOST,// 连接丢失,可能是服务器端关闭了连接
	INITIALIZED;// PathChildrenCache已经初始化完成
	private Type() {
	}
}

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

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

相关文章

Vue+SpringBoot打造海南旅游景点推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四、核心代码4.1 随机景点推荐4.2 景点评价4.3 协同推荐算法4.4 网站登录4.5 查询景点美食 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的海南旅游推荐系统&#xff…

酷开科技,让酷开系统成为现代生活的变革者

电视&#xff0c;从问世就一直受到人们的追捧。还记得小时候一家人围坐在电视机前的场景&#xff0c;小小的黑白屏幕&#xff0c;牢牢的吸引着大家的目光。随着科技的不断进步&#xff0c;我们的生活也发生了翻天覆地的变化。而电视&#xff0c;也从笨重的黑白电视变成了轻薄的…

8.WEB渗透测试-Linux基础知识-Linux基础操作(二)

内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;7.WEB渗透测试-Linux基础知识-Linux基础操作&#xff08;一&#xff09;-CSDN博客 Tab键是补全命令&#xff0c;双击两下Tab键&#xff0c;会告诉你能补全的所有命令 文本编辑器指令&#xff1a;vi 输入vi 1…

React富文本编辑器开发(六)

现在&#xff0c;相关的基础知识我们应该有个大概的了解了&#xff0c;但离我们真正的开发出一个实用型的组件还有一段距离&#xff0c;不过不用担心&#xff0c;我们离目标已经越来越近。 以现在我们所了解的内容而言&#xff0c;或许你发现了一个问题&#xff0c;就是我们的编…

用Java语言创建的Spring Boot项目中,如何传递数组呢??

问题&#xff1a; 用Java语言创建的Spring Boot项目中&#xff0c;如何传递数组呢&#xff1f;&#xff1f; 在这个思路中&#xff0c;其实&#xff0c;Java作为一个后端开发的语言&#xff0c;没必要着重于如何传入&#xff0c;我们主要做的便是对传入的数组数据进行处理即可…

力扣hot6---双指针

题目&#xff1a; TLE做法&#xff08;哈希两重for循环&#xff09; 标签虽然说是用双指针&#xff0c;但是第一个想法真就不是双指针呀。。。就感觉这道题很像&#xff1a; 力扣hot1--哈希-CSDN博客 于是就用了类似的想法&#xff1a; 首先要排个序&#xff0c;至于为什么要…

MySQL 如何从 Binlog 找出变更记录并回滚

文章目录 前言1. 案例模拟1.1 确认信息1.2 下载 Binlog1.3 准备环境1.4 注册 Binlog1.5 准备结构信息1.6 Python 订阅1.7 输出结果展示 2. 原理解析2.1 程序设计2.2 模块版本 总结 前言 最近有研发同学问我&#xff1a;有一个问题&#xff0c;想查一个 ID 为 xxxx 的 sku 什么…

Linux(CentOS为例)环境下 Git提交代码加速,使用FastGithub,运行报错解决

当你的在服务器上使用Git进行推送时&#xff0c;时常会出现超时错误。这里使用FastGithub 首先下载FastGithub 这个软件作者不是为什么删除了GithUb的仓库&#xff0c;这个链接还有。下载Linux版本的 FastGithub Linux&#xff0c;Windows版本 下载完毕后解压 ./fastgithu…

Linux课程四课---Linux开发环境的使用(gcc/g++编译器的相关)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

[VSCode插件] 轻量级静态博客 - MDBlog

MDBlog VSCode插件&#xff0c;基于Markdown的轻量级静态博客系统&#xff0c;同时支持导出为可以部署的静态博客。 仓库 MDBlog 1. Features 博客基础功能&#xff1a;分类管理、文章管理、自动生成索引快捷指令&#xff1a;快捷输入表格、mermaid、wavedrom、代码块发布&a…

Photoshop 2023:重塑创意,引领数字艺术新纪元

在数字艺术的浩瀚星空中&#xff0c;Adobe Photoshop 2023&#xff08;简称PS 2023&#xff09;如同一颗璀璨的新星&#xff0c;为Mac和Windows用户带来了前所未有的创意体验。这款强大的图像处理软件不仅继承了前作的精髓&#xff0c;更在细节上进行了诸多创新&#xff0c;让每…

前端el-date-picker传递的日期格式不是自己想要的格式

解决方法&#xff1a; 添加format和value-format属性进行解决。 format“YYYY-MM-DD” value-format“YYYY-MM-DD” 注意&#xff1a;日期格式要用大写&#xff01;&#xff01;&#xff01;&#xff01;用小写会出现错误&#xff0c;不能回填选择的日期&#xff0c;会直接传入…

【 buuctf-swp】

wget 是什么东西呢&#xff1f; 那就直接过滤 http 流&#xff0c;并全部导出&#xff0c;点击 save all在导出来的一大堆里发现个 zip&#xff0c;需要输入密码&#xff0c;macOS 一大特点就是&#xff0c;如果是伪加密&#xff0c;随便输入一个密码就可以解压缩&#xff0c;…

Redis7 实现持久化的三种方式

1、概述 1.1、Redis持久化的重要性 数据恢复&#xff1a;Redis是一个内存数据库&#xff0c;如果系统或服务宕机&#xff0c;内存中的数据将会丢失。Redis的持久化机制可以把数据保存到磁盘上&#xff0c;以便在系统重启后恢复数据。这是Redis持久化最基本也是最重要的功能。…

基于阿里云OSS上传图片实战案例

一、案例描述 基于Springboot框架实现一个上传图片到阿里云服务端保存的小案例。 二、准备工作 基于Springboot免费搭载轻量级阿里云OSS数据存储库&#xff08;将本地文本、照片、视频、音频等上传云服务保存&#xff09;-CSDN博客 三、代码 新建这两个类&#xff1a;一个…

MySQL:开始深入其数据(四)select子查询

select眼熟吧?(都三节了) 又开始学习了 在 MySQL 中&#xff0c;子查询&#xff08;subquery&#xff09;是指在一个查询内嵌套另一个完整的 SELECT 语句。子查询可以嵌套在 SELECT、INSERT、UPDATE、DELETE 语句中&#xff0c;用于从内部查询结果中获取数据&#xff0c;进而完…

新加坡大带宽服务器概览

随着全球互联网的迅猛发展&#xff0c;服务器作为支撑网络应用的重要基础设施&#xff0c;扮演着越来越重要的角色。新加坡&#xff0c;作为亚洲四小龙之一&#xff0c;其服务器市场也备受关注。特别是新加坡的大带宽服务器&#xff0c;更是受到了众多企业和个人的青睐。那么&a…

LeetCode -- 79.单词搜索

1. 问题描述 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水…

SNAP:如何批量预处理Sentinel2 L2A数据集并输出为TIFF文件?

我的需求 我目前就是希望下载哨兵2号数据&#xff0c;然后在SNAP中进行批量提取真彩色波段并输出为TIFF文件。 数据集下载说明 目前哨兵网站似乎进行了一大波更新&#xff0c;连网站都换了&#xff0c;网址如下&#xff1a; https://dataspace.copernicus.eu/ 打开后界面如…

Linux课程四课---Linux开发环境的使用(自动化构建工具-make/Makefile的相关)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…