| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> Hdfs存储策略 -> 正文阅读 |
|
[大数据]Hdfs存储策略 |
一、磁盘选择策略1.1、介绍在HDFS中,所有的数据都是存在各个DataNode上的.而这些DataNode上的数据都是存放于节点机器上的各个目录中的,而一般每个目录我们会对应到1个独立的盘,以便我们把机器的存储空间基本用上.这么多的节点,这么多块盘,HDFS在进行写操作时如何进行有效的磁盘选择呢 HDFS目前的2套磁盘选择策略都是围绕着"数据均衡"的目标设计的:RoundRobinVolumeChoosingPolicy和AvailableSpaceVolumeChoosingPolicy 1.2、RoundRobinVolumeChoosingPolicy名称可以拆成2个单词,RoundRobin和VolumeChoosingPolicy,VolumeChoosingPolicy理解为磁盘选择策略,RoundRobin这个是一个专业术语,叫做"轮询",类似的还有一些别的类似的术语,Round-Robin Scheduling(轮询调度),Round-Robin 算法等.RoundRobin轮询的意思用最简单的方式翻译就是一个一个的去遍历,到尾巴了,再从头开始。 理论上来说这种策略是蛮符合数据均衡的目标的,因为一个个的写吗,每块盘写入的次数都差不多,不存在哪块盘多写少写的现象,但是唯一的不足之处在于每次写入的数据量是无法控制的,可能我某次操作在A盘上写入了512字节的数据,在轮到B盘写的时候我写了128M的数据,数据就不均衡了,所以说轮询策略在某种程度上来说是理论上均衡但还不是最好的。 实现很简单: volumes 参数其实就是通过 dfs.datanode.data.dir 配置的目录。blockSize 就是咱们副本的大小。RoundRobinVolumeChoosingPolicy 策略先轮询的方式拿到下一个 volume ,如果这个 volume 的可用空间比需要存放的副本大小要大,则直接返回这个 volume 用于存放数据;如果当前 volume 的可用空间不足以存放副本,则以轮询的方式选择下一个 volume,直到找到可用的 volume,如果遍历完所有的 volumes 还是没有找到可以存放下副本的 volume,则抛出 DiskOutOfSpaceException 异常。 从上面的策略可以看出,这种轮询的方式虽然能够保证所有磁盘都能够被使用,但是如果 HDFS 上的文件存在大量的删除操作,可能会导致磁盘数据的分布不均匀,比如有的磁盘存储得很满了,而有的磁盘可能还有很多存储空间没有得到利用。 1.3、AvailableSpaceVolumeChoosingPolicy剩余可用空间磁盘选择策略.这个磁盘选择策略比第一种设计的就精妙很多了,首选他根据1个阈值,将所有的磁盘分为了2大类,高可用空间磁盘列表和低可用空间磁盘列表.然后通过1个随机数概率,会比较高概率下选择高剩余磁盘列表中的块,然后对这些磁盘列表进行轮询策略的选择。 可用空间磁盘选择策略是从 Hadoop 2.1.0 开始引入的(详情参见:HDFS-1804)。这种策略优先将数据写入具有最大可用空间的磁盘(通过百分比计算的)。在实现上可用空间选择策略内部用到了上面介绍的轮询磁盘选择策略,具体的实现代码在 org.apache.hadoop.hdfs.server.datanode.fsdataset.AvailableSpaceVolumeChoosingPolicy 类中,核心实现如下: areAllVolumesWithinFreeSpaceThreshold 函数的作用是先计算所有 volumes 的最大可用空间和最小可用空间,然后使用最大可用空间减去最小可用空间得到的结果和 balancedSpaceThreshold(通过 dfs.datanode.available-space-volume-choosing-policy.balanced-space-threshold 参数进行配置,默认值是 10G) 进行比较。 可用空间策略会以下面三种情况进行处理: 1、如果所有的 volumes 磁盘可用空间都差不多,那么这些磁盘得到的最大可用空间和最小可用空间差值就会很小,这时候就会使用轮询磁盘选择策略来存放副本。 2、如果 volumes 磁盘可用空间相差比较大,那么可用空间策略会将 volumes 配置中的磁盘按照一定的规则分为 highAvailableVolumes 和 lowAvailableVolumes。具体分配规则是先获取 volumes 配置的磁盘中最小可用空间,加上 balancedSpaceThreshold(10G),然后将磁盘空间大于这个值的 volumes 放到 highAvailableVolumes 里面;小于等于这个值的 volumes 放到 lowAvailableVolumes 里面。 比如我们拥有5个磁盘组成的 volumes,编号和可用空间分别为 1(1G)、2(50G)、3(25G)、4(5G)、5(30G)。按照上面的规则,这些磁盘的最小可用空间为 1G,然后加上 balancedSpaceThreshold,得到 11G,那么磁盘编号为1、4的磁盘将会放到 lowAvailableVolumes 里面,磁盘编号为2,3和5将会放到 highAvailableVolumes 里面。 到现在 volumes 里面的磁盘已经都分到 highAvailableVolumes 和 lowAvailableVolumes 里面了。 2.1、如果当前副本的大小大于 lowAvailableVolumes 里面所有磁盘最大的可用空间(mostAvailableAmongLowVolumes,在上面例子中,lowAvailableVolumes 里面最大磁盘可用空间为 5G),那么会采用轮询的方式从 highAvailableVolumes 里面获取相关 volumes 来存放副本。 2.2、剩下的情况会以 75%(通过 dfs.datanode.available-space-volume-choosing-policy.balanced-space-preference-fraction 参数进行配置,推荐将这个参数设置成 0.5 到 1.0 之间)的概率在 highAvailableVolumes 里面以轮询的方式 volumes 来存放副本;25% 的概率在 lowAvailableVolumes 里面以轮询的方式 volumes 来存放副本。 然而在一个长时间运行的集群中,由于 HDFS 中的大规模文件删除或者通过往 DataNode 中添加新的磁盘仍然会导致同一个 DataNode 中的不同磁盘存储的数据很不均衡。即使你使用的是基于可用空间的策略,卷(volume)不平衡仍可导致较低效率的磁盘I/O。比如所有新增的数据块都会往新增的磁盘上写,在此期间,其他的磁盘会处于空闲状态,这样新的磁盘将会是整个系统的瓶颈 1.4、相关配置dfs.datanode.fsdataset.volume.choosing.policy:The class name of the policy for choosing volumes in the list of directories. Defaults to org.apache.hadoop.hdfs.server.datanode.fsdataset.RoundRobinVolumeChoosingPolicy. If you would like to take into account available disk space, set the value to "org.apache.hadoop.hdfs.server.datanode.fsdataset.AvailableSpaceVolumeChoosingPolicy".。这两种磁盘选择策略都是对 org.apache.hadoop.hdfs.server.datanode.fsdataset.VolumeChoosingPolicy 接口进行实现。 dfs.datanode.available-space-volume-choosing-policy.balanced-space-threshold:默认值(10737418240:10G)只有在AvailableSpaceVolumeChoosingPolicy配置下才生效, dfs.datanode.available-space-volume-choosing-policy.balanced-space-preference-fraction:默认值(0.75f)只有在AvailableSpaceVolumeChoosingPolicy配置下才生效 参考网址:?https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml HDFS 副本存放磁盘选择策略详解_圈圈任的博客-CSDN博客 DataNode引用计数磁盘选择策略_Android路上的人的博客-CSDN博客 二、存储策略2.1、存储类型DISK:默认的存储类型,磁盘存储 ARCHIVE:具有存储密度高(PB级),但计算能力小的特点,可用于支持档案存储。 SSD:固态硬盘 RAM_DISK:DataNode中的内存空间 HDFS中是定义了这4种类型,SSD,DISK一看就知道是什么意思,这里看一下其余的2个,RAM_DISK,其实就是Memory内存,而ARCHIVE并没有特指哪种存储介质,主要的指的是高密度存储数据的介质来解决数据量的容量扩增的问题.这4类是被定义在了StorageType类中: public enum StorageType { // sorted by the speed of the storage types, from fast to slow RAM_DISK(true), SSD(false), DISK(false), ARCHIVE(false); ... 旁边的true或者false代表的是此类存储类型是否是transient特性的.transient的意思是指转瞬即逝的,并非持久化的.在HDFS中,如果没有主动声明数据目录存储类型的,默认都是DISK,配置属性dfs.datanode.data.dir中进行本地对应存储目录的设置,同时带上一个存储类型标签,声明此目录用的是哪种类型的存储介质,例子如下: [SSD]file:///grid/dn/ssd0 如果目录前没有带上[SSD]/[DISK]/[ARCHIVE]/[RAM_DISK]这4种中的任何一种,则默认是DISK类型. 2.2、存储原理
2.3、存储类型选择策略HDFS中提供热、暖、冷、ALL_SSD、One_SSD、Lazy_Persistence等存储策略。为了根据不同的存储策略将文件存储在不同的存储类型中,引入了一种新的存储策略概念。HDFS支持以下存储策略: 6种策略:
热(hot)
冷(cold)
温(warm)
全SSD
单SSD
懒持久
HDFS存储策略由以下字段组成:
当有足够的空间时,块副本将根据#3中指定的存储类型列表存储。当列表#3中的某些存储类型耗尽时,将分别使用#4和#5中指定的后备存储类型列表来替换空间外存储类型,以便进行文件创建和副本。 以下是一个典型的存储策略表格:
注意事项:
2.4、命令hdfs storagepolicies -help $ hdfs storagepolicies -help [-listPolicies] List all the existing block storage policies. [-setStoragePolicy -path <path> -policy <policy>] Set the storage policy to a file/directory. <path> The path of the file/directory to set storage policy <policy> The name of the block storage policy [-getStoragePolicy -path <path>] Get the storage policy of a file/directory. <path> The path of the file/directory for getting the storage policy 1个设置命令,2个获取命令,最简单的使用方法是事先划分好冷热数据存储目录。设置好对应的Storage Policy,然后后续相应的程序在对应分类目录下写数据,自动继承父目录的存储策略。在较新版的Hadoop发布版本中增加了数据迁移工具(hdfs mover -help)。此工具的重要用途在于他会扫描HDFS上的文件,判断文件是否满足其内部设置的存储策略,如果不满足,就会重新迁移数据到目标存储类型节点上。 列出所有存储策略:hdfs storagepolicies -listPolicies [root@node1 Examples]# hdfs storagepolicies -listPolicies Block Storage Policies: BlockStoragePolicy{PROVIDED:1, storageTypes=[PROVIDED, DISK], creationFallbacks=[PROVIDED, DISK], replicationFallbacks=[PROVIDED, DISK]} BlockStoragePolicy{COLD:2, storageTypes=[ARCHIVE], creationFallbacks=[], replicationFallbacks=[]} BlockStoragePolicy{WARM:5, storageTypes=[DISK, ARCHIVE], creationFallbacks=[DISK, ARCHIVE], replicationFallbacks=[DISK, ARCHIVE]} BlockStoragePolicy{HOT:7, storageTypes=[DISK], creationFallbacks=[], replicationFallbacks=[ARCHIVE]} BlockStoragePolicy{ONE_SSD:10, storageTypes=[SSD, DISK], creationFallbacks=[SSD, DISK], replicationFallbacks=[SSD, DISK]} BlockStoragePolicy{ALL_SSD:12, storageTypes=[SSD], creationFallbacks=[DISK], replicationFallbacks=[DISK]} BlockStoragePolicy{LAZY_PERSIST:15, storageTypes=[RAM_DISK, DISK], creationFallbacks=[DISK], replicationFallbacks=[DISK]} 设置存储策略:hdfs storagepolicies -setStoragePolicy -path?-policy
取消存储策略:取消文件或目录的存储策略。在执行unset命令之后,将应用当前目录最近的祖先存储策略,如果没有任何祖先的策略,则将应用默认的存储策略。 hdfs storagepolicies -unsetStoragePolicy -path 获取存储策略:hdfs storagepolicies -getStoragePolicy -path 2.5、配置
磁盘上的DataNode存储位置/grid/dn/disk 0应该配置为[DISK]file:///grid/dn/disk0 SSD上的DataNode存储位置/grid/dn/ssd 0应该配置为 [SSD]file:///grid/dn/ssd0 存档上的DataNode存储位置/grid/dn/Archive 0应该配置为 [ARCHIVE]file:///grid/dn/archive0 将RAM_磁盘上的DataNode存储位置/grid/dn/ram0配置为[RAM_DISK]file:///grid/dn/ram0 如果DataNode存储位置没有显式标记存储类型,它的默认存储类型将是磁盘。 2.6、冷热温三阶段数据存储为了更加充分的利用存储资源,我们可以将数据分为冷、热、温三个阶段来存储。
配置存储目录: 进入到Hadoop配置目录,编辑hdfs-site.xml <property> <name>dfs.datanode.data.dir</name> <value>[DISK]file:///export/server/hadoop-3.1.4/data/datanode,ARCHIVE]file:///export/server/hadoop-3.1.4/data/archive</value> <description>DataNode存储名称空间和事务日志的本地文件系统上的路径</description> </property> 然后分发到其他节点,再重启hdfs。 可以看到,现在配置的是两个目录,一个StorageType为ARCHIVE、一个Storage为DISK。 配置策略:
hdfs dfs -mkdir -p /data/hdfs-test/data_phase/hot hdfs dfs -mkdir -p /data/hdfs-test/data_phase/warm hdfs dfs -mkdir -p /data/hdfs-test/data_phase/cold
[root@node1 Examples]# hdfs storagepolicies -listPolicies Block Storage Policies: BlockStoragePolicy{PROVIDED:1, storageTypes=[PROVIDED, DISK], creationFallbacks=[PROVIDED, DISK], replicationFallbacks=[PROVIDED, DISK]} BlockStoragePolicy{COLD:2, storageTypes=[ARCHIVE], creationFallbacks=[], replicationFallbacks=[]} BlockStoragePolicy{WARM:5, storageTypes=[DISK, ARCHIVE], creationFallbacks=[DISK, ARCHIVE], replicationFallbacks=[DISK, ARCHIVE]} BlockStoragePolicy{HOT:7, storageTypes=[DISK], creationFallbacks=[], replicationFallbacks=[ARCHIVE]} BlockStoragePolicy{ONE_SSD:10, storageTypes=[SSD, DISK], creationFallbacks=[SSD, DISK], replicationFallbacks=[SSD, DISK]} BlockStoragePolicy{ALL_SSD:12, storageTypes=[SSD], creationFallbacks=[DISK], replicationFallbacks=[DISK]} BlockStoragePolicy{LAZY_PERSIST:15, storageTypes=[RAM_DISK, DISK], creationFallbacks=[DISK], replicationFallbacks=[DISK]}
hdfs storagepolicies -setStoragePolicy -path /data/hdfs-test/data_phase/hot -policy HOT hdfs storagepolicies -setStoragePolicy -path /data/hdfs-test/data_phase/warm -policy WARM hdfs storagepolicies -setStoragePolicy -path /data/hdfs-test/data_phase/cold -policy COLD
hdfs storagepolicies -getStoragePolicy -path /data/hdfs-test/data_phase/hot hdfs storagepolicies -getStoragePolicy -path /data/hdfs-test/data_phase/warm hdfs storagepolicies -getStoragePolicy -path /data/hdfs-test/data_phase/cold
分别上传文件 hdfs dfs -put /etc/profile /data/hdfs-test/data_phase/hot hdfs dfs -put /etc/profile /data/hdfs-test/data_phase/warm hdfs dfs -put /etc/profile /data/hdfs-test/data_phase/cold 查看不同存储策略文件的block位置 hdfs fsck /data/hdfs-test/data_phase/hot/profile -files -blocks -locations [root@node1 hadoop]# hdfs fsck /data/hdfs-test/data_phase/hot/profile -files -blocks -locations Connecting to namenode via http://node1.itcast.cn:9870/fsck?ugi=root&files=1&blocks=1&locations=1&path=%2Fdata%2Fhdfs-test%2Fdata_phase%2Fhot%2Fprofile FSCK started by root (auth:SIMPLE) from /192.168.88.100 for path /data/hdfs-test/data_phase/hot/profile at Sun Oct 11 22:03:05 CST 2020 /data/hdfs-test/data_phase/hot/profile 3158 bytes, replicated: replication=3, 1 block(s): OK 0. BP-538037512-192.168.88.100-1600884040401:blk_1073742535_1750 len=3158 Live_repl=3 [DatanodeInfoWithStorage[192.168.88.101:9866,DS-96feb29a-5dfd-4692-81ea-9e7f100166fe,DISK], DatanodeInfoWithStorage[192.168.88.100:9866,DS-79739be9-5f9b-4f96-a005-aa5b507899f5,DISK], DatanodeInfoWithStorage[192.168.88.102:9866,DS-e28af2f2-21ae-4aa6-932e-e376dd04ddde,DISK]] hdfs fsck /data/hdfs-test/data_phase/warm/profile -files -blocks -locations /data/hdfs-test/data_phase/warm/profile 3158 bytes, replicated: replication=3, 1 block(s): OK 0. BP-538037512-192.168.88.100-1600884040401:blk_1073742536_1751 len=3158 Live_repl=3 [DatanodeInfoWithStorage[192.168.88.102:9866,DS-636f34a0-682c-4d1b-b4ee-b4c34e857957,ARCHIVE], DatanodeInfoWithStorage[192.168.88.101:9866,DS-ff6970f8-43e0-431f-9041-fc440a44fdb0,ARCHIVE], DatanodeInfoWithStorage[192.168.88.100:9866,DS-79739be9-5f9b-4f96-a005-aa5b507899f5,DISK]] hdfs fsck /data/hdfs-test/data_phase/cold/profile -files -blocks -locations /data/hdfs-test/data_phase/cold/profile 3158 bytes, replicated: replication=3, 1 block(s): OK 0. BP-538037512-192.168.88.100-1600884040401:blk_1073742537_1752 len=3158 Live_repl=3 [DatanodeInfoWithStorage[192.168.88.102:9866,DS-636f34a0-682c-4d1b-b4ee-b4c34e857957,ARCHIVE], DatanodeInfoWithStorage[192.168.88.101:9866,DS-ff6970f8-43e0-431f-9041-fc440a44fdb0,ARCHIVE], DatanodeInfoWithStorage[192.168.88.100:9866,DS-ca9759a0-f6f0-4b8b-af38-d96f603bca93,ARCHIVE]] 我们可以看到:
参考:?HDFS异构存储_Android路上的人的博客-CSDN博客_异构存储 2.7、内存存储介绍
该特性从ApacheHadoop 2.6.0开始支持。 适用场景
配置 1、确定用于存储在内存中的副本内存量
<property> <name>dfs.datanode.max.locked.memory</name> <value>34359738368</value> </property> 在设置此值时,请记住,还需要内存中的空间来处理其他事情,例如数据节点和应用程序JVM堆以及操作系统页缓存。如果在与数据节点相同的节点上运行YARN节点管理器进程,则还需要YARN容器的内存 2、配置datanode
下面的设置可以在大多数Linux发行版上运行,目前不支持在其他平台上使用RAM磁盘。 选择tmpfs(VS ramfs)
挂载RAM磁盘
sudo mount -t tmpfs -o size=32g tmpfs /mnt/dn-tmpfs/
设置RAM_DISK存储类型tmpfs标签
<property> <name>dfs.datanode.data.dir</name> <value>/grid/0,/grid/1,/grid/2,[RAM_DISK]/mnt/dn-tmpfs</value> </property>
其他配置
可以通过以下三种方式之一进行设置:
hdfs storagepolicies -setStoragePolicy -path <path> -policy LAZY_PERSIST #命令方式 fs.setStoragePolicy(path, "LAZY_PERSIST"); //编程方式 三、副本放置策略3.1、介绍目前在HDFS中现有的副本放置策略类有2大继承子类,分别为BlockPlacementPolicyDefault, BlockPlacementPolicyWithNodeGroup, 最经典的3副本策略用的就是BlockPlacementPolicyDefault策略类.3副本如何存放在这个策略中得到了非常完美的实现.在BlockPlacementPolicyDefault类中的注释具体解释了3个副本的存放位置: The class is responsible for choosing the desired number of targets for placing block replicas. The replica placement strategy is that if the writer is on a datanode, the 1st replica is placed on the local machine, otherwise a random datanode. The 2nd replica is placed on a datanode that is on a different rack. The 3rd replica is placed on a datanode which is on a different node of the rack as the second replica. 简要概况起来3点: 1st replica. 如果写请求方所在机器是其中一个datanode,则直接存放在本地,否则随机在集群中选择一个datanode. 2nd replica. 第二个副本存放于不同第一个副本的所在的机架. 3rd replica.第三个副本存放于第二个副本所在的机架,但是属于不同的节点 3.2、BlockPlacementPolicyDefault策略核心方法chooseTargets 在默认放置策略方法类中,核心方法就是chooseTargets,但是在这里有2种同名实现方法,唯一的区别是有无favoredNodes参数.favoredNodes的意思是偏爱,喜爱的节点,只要分为如下三个步骤:
Pipeline节点的形成:整个过程就是传入目标节点列表参数,经过getPipeline方法的处理,然后返回此pipeline.先来看getPipeline的注释: Return a pipeline of nodes. The pipeline is formed finding a shortest path that starts from the writer and traverses all nodes This is basically a traveling salesman problem. 关键是这句The pipeline is formed finding a shortest path that starts from the writer,就是说从writer所在节点开始,总是寻找相对路径最短的目标节点,最终形成pipeline,学习过算法的人应该知道,这其实也是经典的TSP旅行商问题 一句话概况来说,就是选出一个源节点,根据这个节点,遍历当前可选的下一个目标节点,找出一个最短距离的节点,作为下一轮选举的源节点,这样每2个节点之间的距离总是最近的,于是整个pipeline节点间的距离和就保证是足够小的了.那么现在另外一个问题还没有解决,如何定义和计算2个节点直接的距离: 要计算其中的距离,我们首先要了解HDFS中如何定义节点间的距离,其中涉及到了拓扑逻辑结构的概念,结构图如下: 这里显示的是一个三层结构的树形效果图,Root可以看出是一个大的集群,下面划分出了许多个机架,每个机架下面又有很多属于此机架的节点.在每个连接点中,是通过交换机和路由器进行连接的.每个节点间的距离计算方式是通过寻找最近的公共祖先所需要的距离作为最终的结果.比如Node1到Node2的距离是2,就是Node1->Rack1, Rack1->Node2.同理,Rack1的Node1到Rack2的Node1的距离就是4. chooseTarget方法主逻辑: final Node localNode = chooseTarget(numOfReplicas, writer, excludedNodes, blocksize, maxNodesPerRack, results, avoidStaleNodes, storagePolicy, EnumSet.noneOf(StorageType.class), results.isEmpty()); numOfReplicas, 额外需要复制的副本数 excludedNodes,移除节点集合,此集合内的节点不应被考虑作为目标节点 results,当前已经选择好的目标节点集合 storagePolicy,存储类型选择策略 首节点的选择:
经典的3副本存放位置,多余的副本随机存放的原理即可.当然在其间选择的过程中可能会发生异常,因为有的时候我们没有配置机架感知,集群中都属于一个默认机架的default-rack,则会导致chooseRemoteRack的方法出错,因为没有满足条件的其余机架,这时需要一些重试策略. chooseLocalStorage,chooseLocalRack,chooseRemoteRack和chooseRandom方法,四个选择目标节点位置的方法其实是一个优先级渐渐降低的方法,首先选择本地存储位置.如果没有满足条件的,再选择本地机架的节点,如果还是没有满足条件的,进一步降级选择不同机架的节点,最后随机选择集群中的节点 目标节点存储判断好坏条件:
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/16 1:43:08- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |