04、Hadoop3.x从入门到放弃,第四章:Hdfs基本概念与操作

ops/2025/3/1 10:12:54/

Hadoop3.x从入门到放弃,第四章:Hdfs基本概念与操作

一、Hdfs概述

1、Hdfs产生背景与定义

随着数据量越来越大, 在一个操作系统存不下所有的数据, 那么就分配到更多的操作系统管理的磁盘中,
但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。
HDFS只是分布式文件管理系统中的一种。HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;
其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。HDFS的使用场景:适合一次写入,多次读出的场景。 一个文件经过创建、写入和关闭之后就不需要改变。

2、Hdfs优点

1)、高容错性:
数据自动保存多个副本,它通过增加副本的形式,提高容错性。
某一个副本丢失后,他可以自动恢复。hdfs-site.xml 可配置相关副本数量参数
<!-- 这个参数设置为1(文件的副本数),因为是单机版hadoop -->
<property><name>dfs.replication</name><value>1</value>
</property>

在这里插入图片描述

2)、适合处理大数据:
数据规模:能够处理数据规模达到GB\TB甚至PB级别的数据。
文件规模:能够处理百万规模以上的文件数量,数量相当之大。
3)、可构建在廉价的机器上,通过多副本机制提高可靠性。

3、Hdfs缺点

1)、不适合低延时的数据访问:比如毫秒级的存储数据是做不到的。
2)、无法高效的对大量小文件进行存储:> 存储大量小文件的话,他会占用NameNode大量的【内存】来存储文件目录和块信息。这样是不可取的,因为NameNode的内存是有限的。> 大量的小文件的寻址时间会超过读取时间,违反了HDFS的设计目标。
3)、不支持并发写入 以及 文件的随机修改:> 一个文件只能有一个写,不允许多个线程同时写。> 仅支持数据append(追加),不支持文件的随机修改。

二、Hdfs组成架构

在这里插入图片描述

1)、NameNode (nn) 就是Master,他是一个主管、管理者> 管理HDFS的命名空间> 配置副本策略> 管理数据块(BLOCK)映射信息> 处理客户端读写请求2)、DataNode (dn) 就是Slaver. NameNode下达命令,DataNode执行实际操作> 存储实际的数据块> 执行数据块的读写操作3)、Client 就是客户端> 文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的block,然后进行上传。> 与NameNode交互,获取文件的位置信息> 与DataNode交互,读取或写入文件> Client提供一些命令来管理HDFS,比如NameNode格式化  (hdfs namenode -format)> Client可以通过一些命令来访问HDFS,比如对HDFS增删改查操作4)、Secondary NameNode (2NN) 并非NameNode的热备,当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务> 辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode> 在紧急情况下,可辅助恢复NameNode

三、Hdfs文件块大小设置

hdfs-site.xml
<!-- 文件块大小,1.x版本默认是64M,2.x和3x默认是128M -->
<!-- 不是说每个文件必须占128M,而是最大占128M -->
<property><name>dfs.blocksize</name><value>134217728</value> <!-- 128MB -->
</property>
Hdfs中的文件在物理上是分块存储(Block),块的大小可以通过配置参数dfs.blocksize来规定。
在1.X版本默认大小是64M,2.X和3.X版本的默认大小是128M

在这里插入图片描述

为什么块的大小不能设置太小,也不能设置太大?> HDFS块设置太小,会增加寻址时间,程序会将时间大量消耗在查找块的开始位置上。
> HDFS块设置太大,从磁盘传输数据的时间会明显大于寻址的时间,导致程序在处理这块数据的时候会非常慢。eg:普通机械硬盘,传输速率100M/s---->HDFS块设置为128M固态硬盘,传输速率200M-300M/s---->HDFS块设置为256M

四、Hdfs的Shell操作

###语法
hadoop fs 具体命令  /    hdfs dfs 具体命令【注:上面两个是完全相同的】
1、查看命令详情
> hadoop fs -help 具体命令 如: hadoop fs -help ls2、创建
> hadoop fs -mkdir /marvel3、其他moveFromLocal 将原来的文件剪切至marvel下
> hadoop fs -moveFromLocal C:\Users\james\Desktop\avengers.txt /marvelcopyFromLocal 将原来的文件拷贝至marvel下
>hadoop fs -copyFromLocal C:\Users\james\Desktop\x-men.txt /marvelput 将原来的文件拷贝至marvel下 等同于	copyFromLocal (更习惯于用这个命令)
>hadoop fs -put C:\Users\james\Desktop\Fantastic_Four.txt /marvel	appendToFile 追加一个文件到已经存在的文件末尾
>hadoop fs -appendToFile C:\Users\james\Desktop\Iron_Man.txt /marvel/avengers.txt	copyToLocal 将hdfs中的文件拷贝纸本地	
>hadoop fs -copyToLocal /marvel/avengers.txt C:\Users\james\Desktop\	get 将hdfs中的文件拷贝至本地  等同于copyFromLocal	
>hadoop fs -get /marvel/avengers.txt C:\Users\james\Desktop\	cp hdfs内部拷贝
>hadoop fs -cp /marvel/avengers.txt /bakmv hdfs内部移动
>hadoop fs -mv /marvel/Fantastic_Four.txt /bak/rm 删除文件或文件夹
>hadoop fs -rm /marvel/avengers.txtrm -r 递归删除文件夹和文件夹里的内容
>hadoop fs -rm -r /marvel/ls  显示目录信息	
>hadoop fs -ls /cat 显示文件内容
>hadoop fs -cat /marvel/avengers.txttail 显示末尾1kb数据
>hadoop fs -tail /marvel/avengers.txt统计文件夹的大小
>hadoop fs -du /bak设置hdfs中文件的副本数量
>hadoop fs -setrep 2 /bak/avengers.txt-chgrp、-chmod、-chown:同Linux文件系统中的用法一样,修改文件所属权限
[更改用户组]
>hadoop fs -chgrp user /marvel/avengers.txt	
[更改文件拥有者]	
>hadoop fs -chown root /marvel/avengers.txt	
[更改文件拥有者和用户组]
>hadoop fs -chown root:user /marvel/avengers.txt		
[更改文件权限为777]
>hadoop fs -chmod 777 /marvel/avengers.txt	
【注:】
>hadoop fs -setrep 2 /bak/avengers.txt
这里设置的副本数 知识记录在NameNode中的元数据中,是否真的会有这么多副本,还得看DataNode的数量,
如果目前只有3台设备,那么最大也就3个副本,只有节点数增加到10台时,副本数才能达到10.
(也就是说每台机器只能存储一个副本(每个dataNode))

五、Hdfs的API操作

1、连接远程设置

让我们的windows能够连接上远程的Hadoop集群,windows里面也得有相关的环境变量。
下载 hadoop(windows版)到非中文路径 git clone https://gitee.com/night_wish/winutils.git配置 HADOOP_HOME 环境变量

在这里插入图片描述

配置 PATH 环境变量

在这里插入图片描述

双击 bin/winutils.exe 命令看看报不报错

2、添加Maven依赖

<!--版本要和服务对应--><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>3.1.0</version>
</dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.1.0</version>
</dependency>
package com.lee.hadoop.hdfs;import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import lombok.extern.slf4j.Slf4j;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.junit.jupiter.api.Test;/*** @author Lee* @version 1.0* @description* @date 2024/3/15 16:58* 注意:* 客户端去操作 HDFS 时,是有一个用户身份的。默认情况下,HDFS 客户端 API 会从* 采用 Windows 默认用户访问 HDFS,会报权限异常错误。所以在访问 HDFS 时,一定要配置用户。* * 配置文件优先级:* hdfs-default.xml < hdfs-site.xml < resource/hdfs-site.xml < java里的configuration*/
@Slf4j
public class HdfsClientTest {private FileSystem fileSystem;/*** 文件系统相关的配置在 Hadoop 中可以包括以下一些常见参数:** 1. fs.defaultFS:默认文件系统的 URI。* 2. dfs.replication:文件的副本数量。* 3. dfs.namenode.name.dir:NameNode 存储元数据的目录。* 4. dfs.datanode.data.dir:DataNode 存储数据块的目录。* 5. dfs.permissions.enabled:是否启用权限检查。* 6. dfs.blocksize:数据块的大小。* 7. dfs.namenode.handler.count:NameNode 处理请求的线程数。* 8. dfs.replication.max:文件的最大副本数量。* 9. dfs.client.read.shortcircuit:是否启用客户端短路读取等。*/public HdfsClientTest() throws URISyntaxException, IOException, InterruptedException {//连接集群的nn地址URI uri = new URI("hdfs://localhost:9000");//创建一个配置文件Configuration configuration = new Configuration();//设置默认副本数 客户端代码中设置的值 > ClassPath 下的用户自定义配置文件 > 然后是服务器的自定义配置 (xxx-site.xml) > 服务器的默认配置 (xxx-default.xml)//configuration.set("dfs.replication","1");//用户---默认是windows用户String user = "james";// 1 获取客户端对象fileSystem = FileSystem.get(uri, configuration, user);}/*** 关闭* @throws IOException*/@Testpublic void close() throws IOException {// 3 关闭资源fileSystem.close();}/*** 1、创建文件夹*/@Testpublic void testMkdir() throws IOException {Path path = new Path("/hebei");fileSystem.mkdirs(path);close();}/*** 2、上传*/@Testpublic void testCopyFromLocal() throws IOException {//参数一:delSrc 是否删除原数据//参数二:是否允许覆盖//参数三: 原数据路径//参数四:目的地路径Path sPath = new Path("C:\\Users\\james\\Desktop\\WorkTmp.txt");Path dPath = new Path("/hebei");fileSystem.copyFromLocalFile(false,true,sPath,dPath);close();}/*** 2、设置副本数(默认是3)*  或者 通过  configuration.set("dfs.replication","2");  设置*/@Testpublic void editReplication() throws IOException {Path sPath = new Path("/hebei/WorkTmp.txt");fileSystem.setReplication(sPath, (short) 1);close();}/*** 3、下载*/@Testpublic void testGet() throws IOException {Path sPath = new Path("/hebei/WorkTmp.txt");Path dPath = new Path("C:\\Users\\james\\Desktop\\dest");//fileSystem.copyToLocalFile(sPath,dPath);fileSystem.copyToLocalFile(false,sPath,dPath,false);close();}/*** 4、重命名 和 移动*/@Testpublic void rename() throws IOException {//参数一:原文件路径//参数二:目标文件路径Path sPath = new Path("/hebei/WorkTmp.txt");Path dPath = new Path("/henan/WorkTmp_tmp.txt");fileSystem.rename(sPath,dPath);close();}/*** 4、删除*/@Testpublic void testDelete() throws IOException {//参数一:删除文件或目录//参数二:是否递归删除Path sPath = new Path("/hebei/WorkTmp_tmp.txt");fileSystem.delete(sPath,true);close();}/*** 5、判断是文件夹还是目录*/@Testpublic void testFileOrDirectory() throws IOException {Path sPath = new Path("/bak");FileStatus[] fileStatuses = fileSystem.listStatus(sPath);for(FileStatus fileStatus : fileStatuses){log.info("=====>{}, is a {}",fileStatus.getPath().getName(),fileStatus.isDirectory()?"directory" : "file");}}/*** 6、读取文件信息*/@Testpublic void testReadFileInfo() throws IOException {//参数一:目录或文件//参数二:是否递归读取Path sPath = new Path("/bak");RemoteIterator<LocatedFileStatus> fileIterator = fileSystem.listFiles(sPath, true);while(fileIterator.hasNext()){log.info("===========start===============");LocatedFileStatus fileStatus = fileIterator.next();log.info("path:{}",fileStatus.getPath());log.info("pathName:{}",fileStatus.getPath().getName());log.info("permission:{}",fileStatus.getPermission());log.info("owner:{}",fileStatus.getOwner());log.info("group:{}",fileStatus.getGroup());log.info("len:{}",fileStatus.getLen());log.info("modificationTime:{}",fileStatus.getModificationTime());log.info("replication:{}",fileStatus.getReplication());log.info("blockSize:{}",fileStatus.getBlockSize());//获取快信息BlockLocation[] blockLocations = fileStatus.getBlockLocations();log.info("block info:{}", JSON.toJSONString(blockLocations));log.info("============end==============");}}}

六、Hdfs的读写流程

1、Hdfs写入数据流程

在这里插入图片描述

1)、客户端通过Distributed FileSystem模块向NameNode请求上传文件。2)、NameNode检查权限和父目录是否存在,并返回是否可以上传。3)、客户端请求上传第一个Block,询问上传到哪几个DataNode服务器上。4)、NameNode返回3个DataNode节点,分别是dn1\dn2\dn3.5)、客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求后会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成6)、dn1\dn2\dn3主机应答客户端。7)、客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存)以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3。dn1每传一个Packet会放入一个应答队列等待应答。8)、当一个Block传输完成后,客户端再次请求NameNode上传第二个Block的服务。

在这里插入图片描述

2、Hdfs读数据流程

> 客户端通过 Distributed FileSystem 向NameNode 请求下载文件,NameNode先校验是否有权限,然后通过查询元数据,找到文件块所在的DataNode地址。> 挑选一台DataNode服务器 (就近原则,然后随机(会考虑当前节点的负载能力))> DataNode开始传输数据给客户端(从磁盘读取数据输入流,以Packet为单位来做校验)> 客户端以Packet为单位接收,现在本地缓存,然后写入目标文件。【注:Hdfs是串行读数据的,即读完blk_1再去读blk_2】

在这里插入图片描述

3、网络拓扑~节点距离计算

在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。那个这个最近距离如何计算?节点距离:两个节点达到最近的共同祖先节点的距离总和。

在这里插入图片描述

4、机架感知~副本存储节点选择

   对于常见情况,当复制因子为 3 时,HDFS 的放置策略是,如果写入器位于数据节点上,则将一个副本放置在本地计算机上,否则放置在随机数据节点上.将另一个副本放置在不同(远程)机架中的节点上,最后一个位于同一远程机架中的不同节点上。此策略减少了机架间写入流量,从而通常提高了写入性能。机架故障的几率远小于节点故障的几率;该政策不会影响数
据可靠性和可用性保证。然而,它确实减少了读取数据时使用的总网络带宽,因为块仅放置在两个唯一的机架中,而不是三
个。使用此策略,文件的副本不会均匀分布在机架上。三分之一的副本位于一个节点上,三分之二的副本位于一个机架上,另
外三分之一均匀分布在其余机架上。此策略可提高写入性能,而不会影响数据可靠性或读取性能。

在这里插入图片描述

七、NameNode和Secondary NameNode

1、NN和2NN工作机制

思考:NameNode中的元数据是存储在哪里的?首先,我们做个假设,如果存储在 NameNode 节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。
但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新 FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦 NameNode 节点断电,
就会产生数据丢失。因此,引入 Edits 文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到 Edits 中。
这样,一旦 NameNode 节点断电,可以通过 FsImage 和 Edits 的合并,合成元数据。但是,如果长时间添加数据到 Edits 中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行 FsImage 和 Edits 的合并,
如果这个操作由NameNode节点完成, 又会效率过低。 因此, 引入一个新的节点SecondaryNamenode,专门用于 FsImage 和 Edits 的合并。

在这里插入图片描述

阶段1:NameNode启动> 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,就直接加载编辑日志和镜像文件到内存
> 客户端对元数据进行增删改的请求
> NameNode记录操作日志,更新滚动日志(Edits)。
> NameNode在内存中对元数据进行增删改
阶段2:Secondary NameNode工作> 2NN询问NameNode会否需要CheckPoint.直接带回NameNode是否检查结果。
> 2NN请求执行CheckPoint
> NameNode滚动正在写的Edits日志
> 将滚动前的编辑日志和镜像文件拷贝到2NN
> 2NN加载编辑日志和镜像文件到内存,并合并
> 生成新的镜像文件Fsimage.chkpoint
> 拷贝 FsImage.chkPoint到NameNode
> NameNode将Fsimage.chkpoint 重新命名成fsImage

2、Fsimage和Edits解析

NameNode被格式化后,将在./data/tmp/dfs/name/current目录中产生如下文件fsimage_0000000000000000000fsimage_0000000000000000000.md5seen_txidVERSION> Fsimage文件:HDFS文件系统元数据的一个“永久性的检查点”,其中包含HDFS文件系统的所有目录和文件inode的序列化信息
> Edits文件: 存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中
> seen_txid: 文件保存的是一个数字。就是最后一个edits_的数字
> 每次NameNode启动的时候都会将FsImage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将FsImage和Edits文件进行了合并。

3、CheckPoint时间设置

hdfs-default.xml】1>  通常情况下,2NN每个一小时执行一次<property> <name>dfs.namenode.checkpoint.period</name> <value>3600s</value> </property> 2> 一分钟检查一次操作次数,当操作次数达到1百万时,2NN执行一次<property> <name>dfs.namenode.checkpoint.txns</name> <value>1000000</value> <description>操作动作次数</description> </property> <property> <name>dfs.namenode.checkpoint.check.period</name> <value>60s</value> <description> 1 分钟检查一次操作次数</description> </property>

八、DataNode

1、DataNode工作机制

> 一个数据块在DataNode上以文件形式存储在磁盘上,包括两文件件:一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
> DataNode启动后向NameNode注册,通过后,周期性(6小时)的向NameNode上报所有的快信息。
> 心跳是每3秒一次,心跳返回结果带有NN给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟+30秒没有收到某个DataNode的心跳,则认为该节点不可用,就认为该节点挂了,不会再向其传输信息。
> 集群运行中可以安全加入和退出一些机器

在这里插入图片描述

DN向NN汇报当前解读信息的时间间隔,默认6小时:
<property> <name>dfs.blockreport.intervalMsec</name> <value>21600000</value> <description>Determines block reporting interval in milliseconds.</description> 
</property> DN扫描自己节点块信息列表的时间,默认6小时
<property> <name>dfs.datanode.directoryscan.interval</name> <value>21600s</value> <description>Interval in seconds for Datanode to scan data directories and reconcile the difference between blocks in memory and on the disk. Support multiple time unit suffix(case insensitive), as described in dfs.heartbeat.interval. </description> 
</property>

2、数据完整性

DataNode 节点上的数据损坏了,却没有发现,是很危险的,那么如何解决呢?如下是DataNode节点保证数据完整性的方法:
> 当DataNode读取Block的时候,他会结算CheckSum
> 如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏
> Client读取其他DataNode上的Block
> 常见的校验算法 crc,md5,sha1
> DataNode再起文件创建后周期验证CheckSum

3、DataNode掉线时限参数设置

hdfs-site.xml】
heartbeat.recheck.interval 的单位为毫秒,
dfs.heartbeat.interval 的单位为秒
<property> <name>dfs.namenode.heartbeat.recheck-interval</name> <value>300000</value> 
</property> <property> <name>dfs.heartbeat.interval</name> <value>3</value> 
</property> 

在这里插入图片描述

九、其他概念

1、词汇解释

Client: 凡是通过API或者HDFS命令访问HDFS的一端,都可以看做是客户。Rack: 机架,副本的放置策略与机架有关。

2、数据流单位block、packet、chunk

在DFSClient写HDFS的过程中,有三个需要搞清楚的单位:block、packet与chunk:> ·block是HDFS中文件分块的单位,一个文件没有128M也会占据一个block,size是文件的实际大小,blocksize是块的大小。【 Hadoop2.7.3开始默认为128 M,Hadoop2.7.3以下默认为64 M。】·可以在hdfs-site.xml文件中,通过dfs.block.size配置项修改默认的块大小。a、 如果block设置过小,NameNode内存中存储大量小文件的元数据信息,会导致NameNode内存过载。b、 如果block设置过小,磁盘寻址时间增大,使得程序一直在查找block的开始位置。c、 MapReduce中Map通常一次只处理一个数据块中的任务,如果block设置过大,将会导致Map任务的处理时间过长。 d、 如果block设置过大,数据传输时间远超数据寻址时间,影响数据的处理速度。> ·packet是第二大的单位,它是DFSClient向DataNode,或DataNode的Pipeline之间数据传输的基本单位,默认大小为64 kb。·可以在hdfs-site.xml文件中,通过dfs.write.packet.size配置项修改默认的packet大小。> ·chunk是最小的单位,它DFSClient向DataNode,或DataNode的Pipeline之间进行数据校验的基本单位,默认为512 byte。·可以在core-site.xml文件中,通过io.bytes.per.checksum 配置项修改默认的chunk大小。

http://www.ppmy.cn/ops/162210.html

相关文章

Vue中引入bootstrap框架

方式一&#xff1a;CDN引入: 所谓cdn引入&#xff0c;本人理解是在当前界面中引用远程服务器中的bootstrap文件夹中的css/js文件&#xff0c;那么在第一次加载的时候会非常慢&#xff0c;因为它依赖于网络速度去下载文件&#xff0c;然而第二次运行界面的时候加载非常的快&…

基于ArcGIS Pro、Python、USLE、INVEST模型等多技术融合的生态系统服务构建生态安全格局高阶应用

文字目录 前言第一章、生态安全评价理论及方法介绍一、生态安全评价简介二、生态服务能力简介三、生态安全格局构建研究方法简介 第二章、平台基础一、ArcGIS Pro介绍二、Python环境配置 第三章、数据获取与清洗一、数据获取&#xff1a;二、数据预处理&#xff08;ArcGIS Pro及…

ECS单机部署Hadoop

ECS单机部署Hadoop 系统准备 更新系统 sudo yum update -y sudo yum install -y wget vim net-tools openssh-server关闭防火墙 sudo systemctl stop firewalld -- 关闭防火墙 sudo systemctl disable firewalld -- 禁止自启动 sudo systemctl status firewalld -- 查看防…

AIGC生图产品PM必须知道的Lora训练知识!

hihi&#xff0c;其实以前在方向AIGC生图技术原理和常见应用里面已经多次提到Lora的概念了&#xff0c;但是没有单独拿出来讲过&#xff0c;今天就耐心来一下&#xff01; &#x1f525; 一口气摸透AIGC文生图产品SD&#xff08;Stable Diffusion&#xff09;&#xff01; 一、…

蓝桥杯备赛 Day9 构造

构造 1.要点 考察总结归纳能力&#xff0c;没有固定解法 2.题目 2023平方差 (1)找到规律先存到set里面&#xff0c;然后要考虑最大开到1e6&#xff0c;然后暴力能得70分 (2)再观察规律&#xff0c;y为奇数或者偶数,z为奇数或者偶数&#xff0c;可以得到满足条件的为奇数和…

Redis 持久化方式:RDB(Redis Database)和 AOF(Append Only File)

本部分内容是关于博主在学习 Redis 时关于持久化部分的记录&#xff0c;介绍了 RDB 和 AOF 两种持久化方式&#xff0c;详细介绍了持久化的原理、配置、使用方式、优缺点和使用场景。并对两种持久化方式做了对比。文章最后介绍了 Redis 持久化的意义并与其他常见的缓存技术做了…

Java 输入输出流

Java 输入输出流 本小节将介绍 Java 中的基本输入输出操作&#xff0c;涵盖输入输出的基本概念、流的概念、输入输出流的应用场景、File 类的使用以及 Java 提供的输入输出流相关 API。 1. 什么是输入和输出&#xff08;I/O&#xff09; 1.1 基本概念 在计算机中&#xff0…

Android实现漂亮的波纹动画

Android实现漂亮的波纹动画 本文章讲述如何使用二维画布canvas和camera、矩阵实现二、三维波纹动画效果&#xff08;波纹大小变化、画笔透明度变化、画笔粗细变化&#xff09; 一、UI界面 界面主要分为三部分 第一部分&#xff1a;输入框&#xff0c;根据输入x轴、Y轴、Z轴倾…