当前位置: 首页 > news >正文

Hadoop--HDFS

注意机器启动过之后,同步的时候不要同步data文件夹

一次写入,多次读出,不支持文件修改。适合数据分析,不适合网盘应用

分布式存储,文件系统。

优点:

  • 高容错性。多复制,丢失自动恢复
  • 适合大数据,数据以及文件规模
  • 可以在廉价机器上,多副本来实现高可靠

缺点:

  • 不适合低延时数据访问
  • 无法对小文件高效存储
  • 不支持并发多线程同时写入、文件随机修改,只支持append

组成

nn:master,

  • 管理HDFS命名空间;
  • 配置副本策略(放在那个nn节点);
  • 管理数据块Block(DN里面存放的是一个个数据块,不是简单的文件)的映射信息;
  • 处理客户端读写请求

dn:slave,nn下达指令,DN执行操作。

  • 存储实际的数据块,数据块的形式存在
  • 执行读写操作。

client:

  • 文件切块,block大小由此处决定,平衡数据存储
  • 与NN交互,获取文件位置信息
  • DN交互,获取文件信息
  • 访问和管理HDFS

2NN:

  • NN助手

HDFS文件块:

物理上是分块存储的,大小可以通过配置参数来决定,默认是128M

1603193559306-81fcda9c-9072-45f0-901c-a124fcd71e8f.png

web页面无法新建文件夹权限问题

http://hadoop101:9870/explorer.html#/

在浏览器创建目录和删除目录及文件,是dr.who用户,dr.who其实是hadoop中http访问的静态用户名,并没有啥特殊含义,可以通过修改core-site.xml,配置为当前用户

<property>

 <name>hadoop.http.staticuser.user</name>

 <value>deltaqin</value>

</property>

另外,通过查看hdfs的默认配置hdfs-default.xml发现hdfs默认是开启权限检查的。

dfs.permissions.enabled=true #是否在HDFS中开启权限检查,默认为true

解决

第一种方案

直接修改/user目录的权限设置,操作如下:

hdfs dfs -chmod -R 755 /user

第二种方案

在Hadoop的配置文件core-site.xml中增加如下配置:

1605078784553-1d5477b7-651f-4f6a-a05c-2ba8b2857e7c.gif

<property>

 <name>hadoop.http.staticuser.user</name>

 <value>deltaqin</value>

</property>

<property>

 <name>dfs.permissions.enabled</name>

 <value>false</value>

</property>

命令行操作

bin/hadoop fs 
bin/hdfs dfshadoop fs 
hdfs dfs
# 启动Hadoop集群(方便后续的测试)
# 101
sbin/start-dfs.sh
# 102
sbin/start-yarn.sh# -help:输出这个命令参数
hadoop fs -help rm#上传
# -moveFromLocal:从本地剪切粘贴到HDFS
touch kongming.txt
hadoop fs  -moveFromLocal  ./kongming.txt  /sanguo/shuguo
# -copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去
hadoop fs -copyFromLocal README.txt /
# -appendToFile:追加一个文件到已经存在的文件末尾
touch liubei.txt
vi liubei.txt
# 输入
san gu mao lu
hadoop fs -appendToFile liubei.txt /sanguo/shuguo/kongming.txt
# -put:等同于copyFromLocal
hadoop fs -put ./zaiyiqi.txt /user/atguigu/test/# 下载
# -copyToLocal:从HDFS拷贝到本地
hadoop fs -copyToLocal /sanguo/shuguo/kongming.txt ./
# -get:等同于copyToLocal,就是从HDFS下载文件到本地
hadoop fs -get /sanguo/shuguo/kongming.txt ./
# -getmerge:合并下载多个文件,比如HDFS的目录 /user/atguigu/test下有多个文件:log.1, log.2,log.3,...
hadoop fs -getmerge /user/atguigu/test/* ./zaiyiqi.txt# HDFS直接操作
# -ls: 显示目录信息
hadoop fs -ls /
# -mkdir:在HDFS上创建目录
hadoop fs -mkdir -p /sanguo/shuguo
# -cat:显示文件内容
hadoop fs -cat /sanguo/shuguo/kongming.txt
# -chgrp 、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限
hadoop fs  -chmod  666  /sanguo/shuguo/kongming.txt
hadoop fs  -chown  deltaqin:deltaqin   /sanguo/shuguo/kongming.txt
# -cp :从HDFS的一个路径拷贝到HDFS的另一个路径
hadoop fs -cp /sanguo/shuguo/kongming.txt /zhuge.txt
# -mv:在HDFS目录中移动文件
hadoop fs -mv /zhuge.txt /sanguo/shuguo/
# -tail:显示一个文件的末尾
hadoop fs -tail /sanguo/shuguo/kongming.txt
# -rm:删除文件或文件夹
hadoop fs -rm /user/atguigu/test/jinlian2.txt
# -rmdir:删除空目录
hadoop fs -mkdir /test
hadoop fs -rmdir /test
# -du统计文件夹的大小信息
hadoop fs -du -s -h /user/atguigu/test
2.7 K  /user/atguigu/testhadoop fs -du  -h /user/atguigu/test
1.3 K  /user/atguigu/test/README.txt
15     /user/atguigu/test/jinlian.txt
1.4 K  /user/atguigu/test/zaiyiqi.txt# -setrep:设置HDFS中文件的副本数量
hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt

客户端操作

连接和关闭

@Before
public void before() throws IOException, InterruptedException {
//        相当于site文件,配置HDFS
//        Configuration configuration = new Configuration();
//        2个副本
//        configuration.set("dfs.replication", "2");
//        128/2 = 64M
//        configuration.set("dfs.blocksize", "67108864");//1. 新建HDFS对象fileSystem = FileSystem.get(URI.create("hdfs://hadoop101:8020"),new Configuration(), "deltaqin");
}@After
public void after() throws IOException {fileSystem.close();
}

基本操作API

/*** 上传* @throws IOException* @throws InterruptedException*/
@Test
public void put() throws IOException, InterruptedException {//        相当于site文件,配置HDFS//        Configuration configuration = new Configuration();//        2个副本//        configuration.set("dfs.replication", "2");//        128/2 = 64M//        configuration.set("dfs.blocksize", "67108864");//2. 操作集群fileSystem.copyFromLocalFile(new Path("/Users/qinzetao/Pictures/QQ20200621-0.jpg"),new Path("/1.jpg"));
}/*** 下载**/
@Test
public void get() throws IOException {fileSystem.copyToLocalFile(new Path("/1.jpg"),new Path("/Users/qinzetao/Documents/大数据/1_hadoop/代码/Hadoop/hdfs200105"));
}/*** 查看文件和文件夹* @throws IOException*/
@Test
public void ls() throws IOException {FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));for (FileStatus fileStatus : fileStatuses) {System.out.println(fileStatus.getPath());System.out.println(fileStatus.getOwner());System.out.println("=================");}
}/*** 查看文件* @throws IOException*/
@Test
public void lf() throws IOException {RemoteIterator<LocatedFileStatus> statusRemoteIterator =fileSystem.listFiles(new Path("/"), true);while (statusRemoteIterator.hasNext()) {LocatedFileStatus fileStatus = statusRemoteIterator.next();System.out.println(fileStatus.getPath());BlockLocation[] blockLocations = fileStatus.getBlockLocations();for (int i = 0; i < blockLocations.length; i++) {System.out.println("第" + i + "块");String[] hosts = blockLocations[i].getHosts();for (String host : hosts) {System.out.print(host + " ");}System.out.println();}System.out.println("===================================");}
}/*** 追加*/
@Test
public void append() throws IOException {FSDataOutputStream append = fileSystem.append(new Path("/README.txt"));append.write("TestAPI".getBytes());IOUtils.closeStream(append);
}/*** 移动*/
@Test
public void mv() throws IOException {fileSystem.rename(new Path("/1.jpg"),new Path("/logs/2.jpg"));
}

数据流

写数据

完整流程

1603273564363-337e2cad-db3d-44e5-a1be-c2f15aedbae3.png

注意每一块选择存放在哪些节点是完全独立的过程。

1603289601957-eaee2fbb-7a37-4bf5-a4f2-d96caa29ab9f.png

节点选择

NameNode选择距离待上传数据最近距离的DataNode接收数据

  • 节点距离(网络拓扑距离):两个节点到达最近的共同祖先的距离总和。
  • rack:机架,看做路由器,下面有很多DN

1603290273477-ff81af91-618f-4414-a001-8276021df114.png1603290330852-8bfaf171-977e-4cee-99ed-216b0255aad9.png

机架感知(副本存储节点****选择)

副本放置策略:For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on the local machine if the writer is on a datanode, otherwise on a random datanode, another replica on a node in a different (remote) rack, and the last on a different node in the same remote rack.

  • 第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个。
  • 第二个副本和第一个副本位于相同机架,随机节点 。
  • 第三个副本位于不同机架,随机节点。 

1603294115959-72d488ca-4174-4449-9274-49feb843592a.png

读数据

1603273690031-cf68b7e3-9d11-45e0-9855-30d23c347a70.png

1603294195957-fb8cf1c2-bfb9-40b7-80ba-6e4ef533d620.png

NameNode和SecondaryNameNode

元数据要求读写快,放在内存里面

涉及到持久化问题,如何提高效率?

利用多级缓存的思想!!!

  • FSImage文件是HDFS中名字节点NameNode上文件/目录元数据在特定某一时刻的持久化存储文件。(相当于是内存的镜像)
  • edits.log记录的是该干什么,不是元数据,元数据是读取这个记录之后读取对应的元数据放到内存里面得到的。
  • 日志和image都在磁盘上,一个是日志,一个是数据

NN

NN只持久化操作日志,

edits.log:记录操作,编辑日志

fsimage:edits持久化,镜像文件

1603273776396-ee7a2e41-c159-478e-868d-d9c3ad4e4b11.png

NameNode被格式化之后,将在 $HADOOP_HOME/data/tmp/dfs/name/current 目录中产生如下文件:

  • Fsimage文件:(记录某一时刻内存状态)HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息。
  • Edits文件:(记录过程,没有元数据)存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中。
  • seen_txid文件保存的是一个数字,就是最后一个edits_的数字
  • 每次NameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并。

启动流程

重启结束之后会触发一次合并,保存为checkpoint

  • 1603352971665-6a8b9049-b62c-4406-892c-506d51eb6bba.png

2NN

1603273800838-1bc12f2d-a5af-44b8-8e31-0cc19a50c6cf.png1603294276853-6a375035-bed6-401c-a7e1-73d974b6ddfd.png

1603273907292-410af2e5-abef-48d9-9906-57aa9a709e8e.png

Fsimage和Edits

格式化会生成一个空的fsimage,就可以启动了。

oiv查看Fsimage文件

oev                  apply the offline edits viewer to an edits file

oiv                  apply the offline fsimage viewer to an fsimage

hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径pwd
/opt/module/hadoop-3.1.3/data/tmp/dfs/name/current
hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-3.1.3/fsimage.xml 
cat /opt/module/hadoop-3.1.3/fsimage.xml

记录块信息,几块,多大

Fsimage中只记录由哪些块组成,没有记录块所对应DataNode,为什么?

在集群刚刚启动后,加载fsimage之后,要求DataNode上报数据块信息,并间隔一段时间后再次上报。(在安全模式里面,由DN主动向NN汇报,不让NN维护可以避免自己拿到的是陈旧的位置,)

oev查看Edits文件

hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-3.1.3/edits.xml
cat /opt/module/hadoop-3.1.3/edits.xml

内部是一个个的record,记录的是一个个操作

NameNode如何确定下次开机启动的时候合并哪些Edits?

CheckPoint时间设置

通常情况下,SecondaryNameNode每隔一小时执行一次。下图所示:

1603352867177-fadd666a-d320-434a-ab89-944ab04dc6e7.png

hdfs-default.xml:

<property><name>dfs.namenode.checkpoint.period</name><value>3600</value>
</property>

一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。

<property><name>dfs.namenode.checkpoint.txns</name><value>1000000</value>
<description>操作动作次数</description>
</property><property><name>dfs.namenode.checkpoint.check.period</name><value>60</value>
<description> 1分钟检查一次操作次数</description>
</property >

(现在都用HA,不用这个)NameNode故障处理

NameNode故障后,可以采用如下两种方法恢复数据。

将SecondaryNameNode中数据拷贝到NameNode存储数据的目录

2NN的数据其实只是NN的部分数据,所以这个一般不再使用

kill -9 NameNode进程
# 删除NameNode存储的数据(/opt/module/hadoop-3.1.3/data/tmp/dfs/name)
rm -rf /opt/module/hadoop-3.1.3/data/tmp/dfs/name/*
# 拷贝SecondaryNameNode中数据到原NameNode存储数据目录
scp -r atguigu@hadoop104:/opt/module/hadoop-3.1.3/data/tmp/dfs/namesecondary/* ./name/
# 重新启动NameNode
hdfs --daemon start namenode

使用-importCheckpoint选项启动NameNode守护进程,从而将SecondaryNameNode 中数据拷贝到NameNode目录中。

修改hdfs-site.xml中的

<property><name>dfs.namenode.checkpoint.period</name><value>120</value>
</property><property><name>dfs.namenode.name.dir</name><value>/opt/module/hadoop-3.1.3/data/tmp/dfs/name</value>
</property>
kill -9 NameNode进程
# 删除NameNode存储的数据(/opt/module/hadoop-3.1.3/data/tmp/dfs/name)
rm -rf /opt/module/hadoop-3.1.3/data/tmp/dfs/name/*
# 如果SecondaryNameNode不和NameNode在一个主机节点上,需要将
# SecondaryNameNode存储数据的目录拷贝到NameNode存储数据的平级目录,并删除in_use.lock文件
scp -r atguigu@hadoop104:/opt/module/hadoop-3.1.3/data/tmp/dfs/namesecondary ./rm -rf in_use.lockpwd
/opt/module/hadoop-3.1.3/data/tmp/dfsls
data  name  namesecondary# 导入检查点数据(等待一会ctrl+c结束掉)
bin/hdfs namenode -importCheckpoint# 启动NameNode
hdfs --daemon start namenode

集群安全模式

集群状态不正确的时候,就加入,启动的时候也会进入。

  • NameNode启动

NameNode启动时,首先将镜像文件(Fsimage)载入内存,并执行编辑日志(Edits)中的各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的Fsimage文件和一个空的编辑日志。此时,NameNode开始监听DataNode请求。这个过程期间,NameNode一直运行在安全模式,即NameNode的文件系统对于客户端来说是只读的。 

  • DataNode启动

系统中的数据块的位置并不是由NameNode维护的,而是以块列表的形式存储在DataNode中。在系统的正常操作期间,NameNode会在内存中保留所有块位置的映射信息。在安全模式下,各个DataNode会向NameNode发送最新的块列表信息,NameNode了解到足够多的块位置信息之后,即可高效运行文件系统。

  • 安全模式退出判断

如果满足“最小副本条件”,NameNode会在30秒钟之后就退出安全模式。所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1,一块只要有一个副本就可以)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以NameNode不会进入安全模式。

  • 以下内容可以不看:

集群处于安全模式,不能执行重要操作(写操作)。集群启动完成后,自动退出安全模式。

(1)bin/hdfs dfsadmin -safemode get (功能描述:查看安全模式状态)

(2)bin/hdfs dfsadmin -safemode enter   (功能描述:进入安全模式状态)

(3)bin/hdfs dfsadmin -safemode leave (功能描述:离开安全模式状态)

(4)bin/hdfs dfsadmin -safemode wait (功能描述:等待安全模式状态)

# 查看当前模式
hdfs dfsadmin -safemode get
Safe mode is OFF
# 先进入安全模式
hdfs dfsadmin -safemode enter
# 创建并执行下面的脚本
# 在/opt/module/hadoop-3.1.3路径上,编辑一个脚本safemode.sh
touch safemode.sh
vim safemode.sh
#!/bin/bash
hdfs dfsadmin -safemode wait
hdfs dfs -put /opt/module/hadoop-3.1.3/README.txt /
chmod 777 safemode.sh./safemode.sh # 再打开一个窗口,执行
hdfs dfsadmin -safemode leave# 观察
# 观察上一个窗口
Safe mode is OFF# HDFS集群上已经有上传的数据了。

DataNode

  • 原理:把文件数据整整齐齐切开之后按照block存放,想要直接自己恢复的话,可以复制出来,使用cat将文件追加,拼接起来之后直接解压就可以获取原始数据
  • 块也有自己的元数据

1603273863314-18220667-53b6-41ec-a2ff-d04bcd3fc4cb.png

1603295948595-b0a28719-0042-4637-9c51-6a346cc3b3df.png

保证数据完整性的方法

(1)当DataNode读取Block的时候,它会计算CheckSum。

(2)如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。

(3)Client读取其他DataNode上的Block。

(4)DataNode在其文件创建后周期验证CheckSum。

掉线处理(时限设置)

1603296050338-47e3ce57-df94-4448-89de-f6adec86f223.png

需要注意的是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>

添加新数据****节点

在原有集群基础上动态添加新的数据节点。

再克隆一台hadoop104主机,修改IP地址和主机名称,

-a 包含所有属性以及角色权限复制

sudo rsync -av /opt/module hadoop104:/opt
sudo rsync -av /etc/profile.d hadoop104:/etc

删除原来HDFS文件系统留存的文件(/opt/module/hadoop-3.1.3/data和log),source一下配置文件 source /etc/profile


注意这里使用的不是群起,所以不需要配置workers

# 停止DataNode
hdfs --daemon stop datanode# 直接启动DataNode,即可关联到集群
hdfs --daemon start datanode
sbin/yarn-daemon.sh start nodemanager# 在hadoop104上上传文件
hadoop fs -put /opt/module/hadoop-3.1.3/LICENSE.txt /# 如果数据不均衡,可以用命令实现集群的再平衡
./start-balancer.sh
starting balancer, logging to /opt/module/hadoop-3.1.3/logs/hadoop-atguigu-balancer-hadoop102.out
Time Stamp               Iteration#  Bytes Already Moved  Bytes Left To Move  Bytes Being Moved

退役旧数据****节点

添加白****名单

添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,都会被退出。

# 在NameNode的/opt/module/hadoop-3.1.3/etc/hadoop目录下创建dfs.hosts文件
pwd
/opt/module/hadoop-3.1.3/etc/hadooptouch dfs.hosts
vi dfs.hosts
# 添加如下主机名称(不添加hadoop105)
hadoop102
hadoop103
hadoop104
# 在NameNode的hdfs-site.xml配置文件中增加dfs.hosts属性
<property><name>dfs.hosts</name><value>/opt/module/hadoop-3.1.3/etc/hadoop/dfs.hosts</value>
</property>
# 配置文件分发
xsync hdfs-site.xml
# 刷新NameNode
hdfs dfsadmin -refreshNodes
Refresh nodes successful
# 更新ResourceManager节点
yarn rmadmin -refreshNodes
17/06/24 14:17:11 INFO client.RMProxy: Connecting to ResourceManager at hadoop103/192.168.1.103:8033# 在web浏览器上查看
# 如果数据不均衡,可以用命令实现集群的再平衡
./start-balancer.sh
starting balancer, logging to /opt/module/hadoop-3.1.3/logs/hadoop-atguigu-balancer-hadoop102.out
Time Stamp               Iteration#  Bytes Already Moved  Bytes Left To Move  Bytes Being Moved

黑名单****退役

在黑名单上面的主机都会被强制退出。

# 在NameNode的/opt/module/hadoop-3.1.3/etc/hadoop目录下创建dfs.hosts.exclude文件
pwd
/opt/module/hadoop-3.1.3/etc/hadooptouch dfs.hosts.exclude
vi dfs.hosts.exclude
# 添加如下主机名称(要退役的节点)
hadoop105# 在NameNode的hdfs-site.xml配置文件中增加dfs.hosts.exclude属性
<property><name>dfs.hosts.exclude</name><value>/opt/module/hadoop-3.1.3/etc/hadoop/dfs.hosts.exclude</value>
</property># 刷新NameNode、刷新ResourceManager
hdfs dfsadmin -refreshNodes
Refresh nodes successfulyarn rmadmin -refreshNodes
17/06/24 14:55:56 INFO client.RMProxy: Connecting to ResourceManager at hadoop103/192.168.1.103:8033# 检查Web浏览器,退役节点的状态为decommission in progress(退役中),说明数据节点正在复制块到其他节点
# 等待退役节点状态为decommissioned(所有块已经复制完成),停止该节点及节点资源管理器。
# 注意:如果副本数是3,服役的节点小于等于3,是不能退役成功的,需要修改副本数后才能退役# 退役之后就可以关闭,退役完成意味着数据备份完成,
# 注意这里不是群起,群关闭,所以只需要单独在需要操作的机器上关闭
hdfs --daemon stop datanode
stopping datanodesbin/yarn-daemon.sh stop nodemanager
stopping nodemanager# 如果数据不均衡,可以用命令实现集群的再平衡
sbin/start-balancer.sh 
starting balancer, logging to /opt/module/hadoop-3.1.3/logs/hadoop-atguigu-balancer-hadoop102.out
Time Stamp               Iteration#  Bytes Already Moved  Bytes Left To Move  Bytes Being Moved
# 注意:不允许白名单和黑名单中同时出现同一个主机名称。

Datanode多****目录配置

DataNode也可以配置成多个目录,每个目录存储的数据不一样。:数据不是副本

配置namenode所在的机器的hdfs-site.xml,数据就会均匀的放在data/data和data/data2

<property><name>dfs.datanode.data.dir</name><value>file:///${hadoop.tmp.dir}/dfs/data1,file:///${hadoop.tmp.dir}/dfs/data2</value>
</property>

Hadoop3新特性

  • 最低java版本由7升级为8
  • 引入纠删码,默认3副本,开销较大,只是为了提高容错能力。纠删码在不到百分之50的数据冗余的情况下提供和3副本相同的容错机制,所以使用纠删码作为副本机制的改进
  • 重写shell脚本。
http://www.hskmm.com/?act=detail&tid=29720

相关文章:

  • Redis总结
  • 函数柯里化
  • 防抖与节流
  • 大数据概述
  • 10月——算法竞赛回坑杂记
  • 20232308 2025-2026-1 《网络与系统攻防技术》实验一实验报告
  • Redis知识点汇总
  • 乐理 -05 乐音 乐级
  • Redis实现分布式锁以及Redis客户端比较
  • 一致性哈希原理
  • 缓存和数据库数据的一致性
  • Redis不同数据类型代码场景实践
  • 布隆过滤器
  • Redis持久化
  • 上下文与this指向
  • [数据库] Microsoft SQL Server 数据库
  • 02 | 在环境中使用Airsim插件
  • 01 | UE5.3+Airsim+VS2022+Windows10(无人机仿真环境)
  • 对于使用ant design组件库的疑问
  • 阅读《构建之法》提出的5个问题
  • 提示工程介绍
  • DshanPI-A1 RK3576 gstreamer播放16路视频与硬件加速
  • freertos的调度过程
  • 「2025 高一上学期笔记 / 日记」
  • 「2025 暑假日记 / 笔记」
  • 2025羊城杯初赛Misc-writeup
  • 将 GPU 级性能带到企业级 Java:CUDA 集成实用指南
  • 我的个人空间
  • 2025.10.12总结
  • Windows 文件管理器中重复的 OneDrive 图标原因与解决方案