A. 文件管理和内部存储哪个才是真正的内存显示
一 内存,内部存储和外部存储文件管理
1. 可对Android手机存储空间做如下划分:整个存储空间分为内部存储和外部存储两部分,内部存储中又包含RAM和ROM等部分。
2. 具体概念区分
内部存储,即InternalStorage,也常说内置存储卡,这是手机内置的存储空间,出厂时就被确定,是手机的一个硬件指标。类比电脑的内存。
外部存储,即ExternalStorage,也常说外置存储卡,手机出厂时并不存在,是由用户自由扩展的存储空间,常见的就是SD卡。类比电脑的外接移动硬盘。
RAM,即常说的运行时内存,是手机运行时存储数据和指令的地方,注意是运行时内存。类比电脑的内存条。
ROM,用来存放一些系统文件,应用配置和其他数据的地方,是内部存储中主要存储区域。类比于Windows电脑的C盘。
3. 以小米的红米手机系列为例,打开设置中的关于手机一项,可以看到下图:上图中运行内存即RAM,共2G,机身存储即内部存储,共8G。
打开手机的文件管理,再点击手机一项,可以看到下图:上图中箭头所指的地方,可以进行内部存储与外部存储的切换,当前页为内部存储下的展示,这只是android系统存储数据的一部分而已,大部分数据都对用户隐藏。至于红框部分下面继续讲。
B. 程序员必备知识(操作系统5-文件系统)
本篇与之前的第三篇的内存管理知识点有相似的地方
对于运行的进程来说,内存就像一个纸箱子, 仅仅是一个暂存数据的地方, 而且空间有限。如果我们想要进程结束之后,数据依然能够保存下来,就不能只保存在内存里,而是应该保存在 外部存储 中。就像图书馆这种地方,不仅空间大,而且能够永久保存。
我们最常用的外部存储就是 硬盘 ,数据是以文件的形式保存在硬盘上的。为了管理这些文件,我们在规划文件系统的时候,需要考虑到以下几点。
第一点,文件系统要有严格的组织形式,使得文件能够 以块为单位进行存储 。这就像图书馆里,我们会给设置一排排书架,然后再把书架分成一个个小格子,有的项目存放的资料非常多,一个格子放不下,就需要多个格子来进行存放。我们把这个区域称为存放原始资料的 仓库区 。
第二点,文件系统中也要有 索引区 ,用来方便查找一个文件分成的多个块都存放在了什么位置。这就好比,图书馆的书太多了,为了方便查找,我们需要专门设置一排书架,这里面会写清楚整个档案库有哪些资料,资料在哪个架子的哪个格子上。这样找资料的时候就不用跑遍整个档案库,在这个书架上找到后,直奔目标书架就可以了。
第三点,如果文件系统中有的文件是热点文件,近期经常被读取和写入,文件系统应该有 缓存层 。这就相当于图书馆里面的热门图书区,这里面的书都是畅销书或者是常常被借还的图书。因为借还的次数比较多,那就没必要每次有人还了之后,还放回遥远的货架,我们可以专门开辟一个区域, 放置这些借还频次高的图书。这样借还的效率就会提高。
第四点,文件应该用 文件夹 的形式组织起来,方便管理和查询。这就像在图书馆里面,你可以给这些资料分门别类,比如分成计算机类.文学类.历史类等等。这样你也容易管理,项目组借阅的时候只要在某个类别中去找就可以了。
在文件系统中,每个文件都有一个名字,这样我们访问一个文件,希望通过它的名字就可以找到。文件名就是一个普通的文本。 当然文件名会经常冲突,不同用户取相同的名字的情况还是会经常出现的。
要想把很多的文件有序地组织起来,我们就需要把它们成为 目录 或者文件夹。这样,一个文件夹里可以包含文件夹,也可以包含文件,这样就形成了一种 树形结构 。而我们可以将不同的用户放在不同的用户目录下,就可以一定程度上避免了命名的冲突问题。
第五点,Linux 内核要在自己的内存里面维护一套数据结构,来保存哪些文件被哪些进程打开和使用 。这就好比,图书馆里会有个图书管理系统,记录哪些书被借阅了,被谁借阅了,借阅了多久,什么时候归还。
文件系统是操作系统中负责管理持久数据的子系统,说简单点,就是负责把用户的文件存到磁盘硬件中,因为即使计算机断电了,磁盘里的数据并不会丢失,所以可以持久化的保存文件。
文件系统的基本数据单位是 文件 ,它的目的是对磁盘上的文件进行组织管理,那组织的方式不同,就会形成不同的文件系统。
Linux最经典的一句话是:“一切皆文件”,不仅普通的文件和目录,就连块设备、管道、socket 等,也都是统一交给文件系统管理的。
Linux文件系统会为每个文件分配两个数据结构: 索引节点(index node) 和 目录项(directory entry) ,它们主要用来记录文件的元信息和目录层次结构。
●索引节点,也就是inode, 用来记录文件的元信息,比如inode编号、文件大小访问权限、创建时间、修改时间、 数据在磁盘的位置 等等。 索引节点是文件的唯一标识 ,它们之间一一对应, 也同样都会被 存储在硬盘 中,所以索引节点同样占用磁盘空间。
●目录项,也就是dentry, 用来记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。多个目录项关联起来,就会形成 目录结构 ,但它与索引节点不同的是,目录项是由内核维护的一个数据结构,不存放于磁盘,而是 缓存在内存 。
由于索引节点唯一标识一个文件,而目录项记录着文件的名,所以目录项和索引节点的关系是多对一,也就是说,一个文件可以有多个别字。比如,硬链接的实现就是多个目录项中的索引节点指向同一个文件。
注意,目录也是文件,也是用索引节点唯一标识,和普通文件不同的是,普通文件在磁盘里面保存的是文件数据,而目录文件在磁盘里面保存子目录或文件。
(PS:目录项和目录不是一个东西!你也不是一个东西(^_=), 虽然名字很相近,但目录是个文件。持久化存储在磁盘,而目录项是内核一个数据结构,缓存在内存。
如果查询目录频繁从磁盘读,效率会很低,所以内核会把已经读过的目录用目录项这个数据结构缓存在内存,下次再次读到相同的目录时,只需从内存读就可以,大大提高了 文件系统的效率。
目录项这个数据结构不只是表示目录,也是可以表示文件的。)
磁盘读写的最小单位是 扇区 ,扇区的大小只有512B大小,很明显,如果每次读写都以这么小为单位,那这读写的效率会非常低。
所以,文件系统把多个扇区组成了一个 逻辑块 ,每次读写的最小单位就是逻辑块(数据块) , Linux中的逻辑块大小为4KB,也就是一次性读写 8个扇区,这将大大提高了磁盘的读写的效率。
以上就是索引节点、目录项以及文件数据的关系,下面这个图就很好的展示了它们之间的关系:
索引节点是存储在硬盘上的数据,那么为了加速文件的访问,通常会把索引节点加载到内存中。
另外,磁盘进行格式化的时候,会被分成三个存储区域,分别是超级块、索引节点区和数据块区。
●超级块,用来存储文件系统的详细信息,比如块个数、块大小、空闲块等等。
●索引节点区,用来存储索引节点;
●数据块区,用来存储文件或目录数据;
我们不可能把超级块和索引节点区全部加载到内存,这样内存肯定撑不住,所以只有当需要使用的时候,才将其加载进内存,它们加载进内存的时机是不同的.
●超级块:当文件系统挂载时进入内存;
●索引节点区:当文件被访问时进入内存;
文件系统的种类众多,而操作系统希望 对用户提供一个统一的接口 ,于是在用户层与文件系统层引入了中间层,这个中间层就称为 虚拟文件系统(Virtual File System, VFS) 。
VFS定义了一组所有文件系统都支持的数据结构和标准接口,这样程序员不需要了解文件系统的工作原理,只需要了解VFS提供的统一接口即可。
在Linux文件系统中,用户空间、系统调用、虚拟机文件系统、缓存、文件系统以及存储之间的关系如下图:
Linux支持的文件系统也不少,根据存储位置的不同,可以把文件系统分为三类:
●磁盘的文件系统,它是直接把数据存储在磁盘中,比如Ext 2/3/4. XFS 等都是这类文件系统。
●内存的文件系统,这类文件系统的数据不是存储在硬盘的,而是占用内存空间,我们经常用到的/proc 和/sys文件系统都属于这一类,读写这类文件,实际上是读写内核中相关的数据。
●网络的文件系统,用来访问其他计算机主机数据的文件系统,比如NFS. SMB等等。
文件系统首先要先挂载到某个目录才可以正常使用,比如Linux系统在启动时,会把文件系统挂载到根目录。
在操作系统的辅助之下,磁盘中的数据在计算机中都会呈现为易读的形式,并且我们不需要关心数据到底是如何存放在磁盘中,存放在磁盘的哪个地方等等问题,这些全部都是由操作系统完成的。
那么,文件数据在磁盘中究竟是怎么样的呢?我们来一探究竟!
磁盘中的存储单元会被划分为一个个的“ 块 ”,也被称为 扇区 ,扇区的大小一般都为512byte.这说明即使一块数据不足512byte,那么它也要占用512byte的磁盘空间。
而几乎所有的文件系统都会把文件分割成固定大小的块来存储,通常一个块的大小为4K。如果磁盘中的扇区为512byte,而文件系统的块大小为4K,那么文件系统的存储单元就为8个扇区。这也是前面提到的一个问题,文件大小和占用空间之间有什么区别?文件大小是文件实际的大小,而占用空间则是因为即使它的实际大小没有达到那么大,但是这部分空间实际也被占用,其他文件数据无法使用这部分的空间。所以我们 写入1byte的数据到文本中,但是它占用的空间也会是4K。
这里要注意在Windows下的NTFS文件系统中,如果一开始文件数据小于 1K,那么则不会分配磁盘块来存储,而是存在一个文件表中。但是一旦文件数据大于1K,那么不管以后文件的大小,都会分配以4K为单位的磁盘空间来存储。
与内存管理一样,为了方便对磁盘的管理,文件的逻辑地址也被分为一个个的文件块。于是文件的逻辑地址就是(逻辑块号,块内地址)。用户通过逻辑地址来操作文件,操作系统负责完成逻辑地址与物理地址的映射。
不同的文件系统为文件分配磁盘空间会有不同的方式,这些方式各自都有优缺点。
连续分配要求每个文件在磁盘上有一组连续的块,该分配方式较为简单。
通过上图可以看到,文件的逻辑块号的顺序是与物理块号相同的,这样就可以实现随机存取了,只要知道了第一个逻辑块的物理地址, 那么就可以快速访问到其他逻辑块的物理地址。那么操作系统如何完成逻辑块与物理块之间的映射呢?实际上,文件都是存放在目录下的,而目录是一种有结构文件, 所以在文件目录的记录中会存放目录下所有文件的信息,每一个文件或者目录都是一个记录。 而这些信息就包括文件的起始块号和占有块号的数量。
那么操作系统如何完成逻辑块与物理块之间的映射呢? (逻辑块号, 块内地址) -> (物理块号, 块内地址),只需要知道逻辑块号对应的物理块号即可,块内地址不变。
用户访问一个文件的内容,操作系统通过文件的标识符找到目录项FCB, 物理块号=起始块号+逻辑块号。 当然,还需要检查逻辑块号是否合法,是否超过长度等。因为可以根据逻辑块号直接算出物理块号,所以连续分配支持 顺序访问和随机访问 。
因为读/写文件是需要移动磁头的,如果访问两个相隔很远的磁盘块,移动磁头的时间就会变长。使用连续分配来作为文件的分配方式,会使文件的磁盘块相邻,所以文件的读/写速度最快。
连续空间存放的方式虽然读写效率高,但是有 磁盘空间碎片 和 文件长度不易扩展 的缺陷。
如下图,如果文件B被删除,磁盘上就留下一块空缺,这时,如果新来的文件小于其中的一个空缺,我们就可以将其放在相应空缺里。但如果该文件的大小大于所
有的空缺,但却小于空缺大小之和,则虽然磁盘上有足够的空缺,但该文件还是不能存放。当然了,我们可以通过将现有文件进行挪动来腾出空间以容纳新的文件,但是这个在磁盘挪动文件是非常耗时,所以这种方式不太现实。
另外一个缺陷是文件长度扩展不方便,例如上图中的文件A要想扩大一下,需要更多的磁盘空间,唯一的办法就只能是挪动的方式,前面也说了,这种方式效率是非常低的。
那么有没有更好的方式来解决上面的问题呢?答案当然有,既然连续空间存放的方式不太行,那么我们就改变存放的方式,使用非连续空间存放方式来解决这些缺陷。
非连续空间存放方式分为 链表方式 和 索引方式 。
链式分配采取离散分配的方式,可以为文件分配离散的磁盘块。它有两种分配方式:显示链接和隐式链接。
隐式链接是只目录项中只会记录文件所占磁盘块中的第一块的地址和最后一块磁盘块的地址, 然后通过在每一个磁盘块中存放一个指向下一 磁盘块的指针, 从而可以根据指针找到下一块磁盘块。如果需要分配新的磁盘块,则使用最后一块磁盘块中的指针指向新的磁盘块,然后修改新的磁盘块为最后的磁盘块。
我们来思考一个问题, 采用隐式链接如何将实现逻辑块号转换为物理块号呢?
用户给出需要访问的逻辑块号i,操作系统需要找到所需访问文件的目录项FCB.从目录项中可以知道文件的起始块号,然后将逻辑块号0的数据读入内存,由此知道1号逻辑块的物理块号,然后再读入1号逻辑块的数据进内存,此次类推,最终可以找到用户所需访问的逻辑块号i。访问逻辑块号i,总共需要i+ 1次磁盘1/0操作。
得出结论: 隐式链接分配只能顺序访问,不支持随机访问,查找效率低 。
我们来思考另外一个问题,采用隐式链接是否方便文件拓展?
我们知道目录项中存有结束块号的物理地址,所以我们如果要拓展文件,只需要将新分配的磁盘块挂载到结束块号的后面即可,修改结束块号的指针指向新分配的磁盘块,然后修改目录项。
得出结论: 隐式链接分配很方便文件拓展。所有空闲磁盘块都可以被利用到,无碎片问题,存储利用率高。
显示链接是把用于链接各个物理块的指针显式地存放在一张表中,该表称为文件分配表(FAT, File Allocation Table)。
由于查找记录的过程是在内存中进行的,因而不仅显着地 提高了检索速度 ,而且 大大减少了访问磁盘的次数 。但也正是整个表都存放在内存中的关系,它的主要的缺点是 不适 用于大磁盘 。
比如,对于200GB的磁盘和1KB大小的块,这张表需要有2亿项,每一项对应于这2亿个磁盘块中的一个块,每项如果需要4个字节,那这张表要占用800MB内存,很显然FAT方案对于大磁盘而言不太合适。
一直都在,加油!(*゜Д゜)σ凸←自爆按钮
链表的方式解决了连续分配的磁盘碎片和文件动态打展的问题,但是不能有效支持直接访问(FAT除外) ,索引的方式可以解决这个问题。
索引的实现是为每个文件创建一个 索引数据块 ,里面存放的 是指向文件数据块的指针列表 ,说白了就像书的目录一样,要找哪个章节的内容,看目录查就可以。
另外, 文件头需要包含指向索引数据块的指针 ,这样就可以通过文件头知道索引数据块的位置,再通过索弓|数据块里的索引信息找到对应的数据块。
创建文件时,索引块的所有指针都设为空。当首次写入第i块时,先从空闲空间中取得一个块, 再将其地址写到索引块的第i个条目。
索引的方式优点在于:
●文件的创建、增大、缩小很方便;
●不会有碎片的问题;
●支持顺序读写和随机读写;
由于索引数据也是存放在磁盘块的,如果文件很小,明明只需一块就可以存放的下,但还是需要额外分配一块来存放索引数据,所以缺陷之一就是存储索引带来的开销。
如果文件很大,大到一个索引数据块放不下索引信息,这时又要如何处理大文件的存放呢?我们可以通过组合的方式,来处理大文件的存储。
先来看看 链表+索引 的组合,这种组合称为 链式索引块 ,它的实现方式是在 索引数据块留出一个存放下一个索引数据块的指针 ,于是当一个索引数据块的索引信息用完了,就可以通过指针的方式,找到下一个索引数据块的信息。那这种方式也会出现前面提到的链表方式的问题,万一某个指针损坏了,后面的数据也就会无法读取了。
还有另外一种组合方式是 索引+索引 的方式,这种组合称为多级索引块,实现方式是通过一个索引块来存放多个索引数据块,一层套一层索引, 像极了俄罗斯套娃是吧๑乛◡乛๑
前面说到的文件的存储是针对已经被占用的数据块组织和管理,接下来的问题是,如果我要保存一个数据块, 我应该放在硬盘上的哪个位置呢?难道需要将所有的块扫描一遍,找个空的地方随便放吗?
那这种方式效率就太低了,所以针对磁盘的空闲空间也是要引入管理的机制,接下来介绍几种常见的方法:
●空闲表法
●空闲链表法
●位图法
空闲表法
空闲表法就是为所有空闲空间建立一张表,表内容包括空闲区的第一个块号和该空闲区的块个数,注意,这个方式是连续分配的。如下图:
当请求分配磁盘空间时,系统依次扫描空闲表里的内容,直到找到一个合适的空闲区域为止。当用户撤销一个文件时,系统回收文件空间。这时,也需顺序扫描空闲表,寻找一个空闲表条目并将释放空间的第一个物理块号及它占用的块数填到这个条目中。
这种方法仅当有少量的空闲区时才有较好的效果。因为,如果存储空间中有着大量的小的空闲区,则空闲表变得很大,这样查询效率会很低。另外,这种分配技术适用于建立连续文件。
空闲链表法
我们也可以使用链表的方式来管理空闲空间,每一个空闲块里有一个指针指向下一个空闲块,这样也能很方便的找到空闲块并管理起来。如下图:
当创建文件需要一块或几块时,就从链头上依次取下一块或几块。反之,当回收空间时,把这些空闲块依次接到链头上。
这种技术只要在主存中保存一个指针, 令它指向第一个空闲块。其特点是简单,但不能随机访问,工作效率低,因为每当在链上增加或移动空闲块时需要做很多1/0操作,同时数据块的指针消耗了一定的存储空间。
空闲表法和空闲链表法都不适合用于大型文件系统,因为这会使空闲表或空闲链表太大。
位图法
位图是利用二进制的一位来表示磁盘中一个盘块的使用情况,磁盘上所有的盘块都有一个二进制位与之对应。
当值为0时,表示对应的盘块空闲,值为1时,表示对应的盘块已分配。它形式如下:
在Linux文件系统就采用了位图的方式来管理空闲空间,不仅用于数据空闲块的管理,还用于inode空闲块的管理,因为inode也是存储在磁盘的,自然也要有对其管理。
前面提到Linux是用位图的方式管理空闲空间,用户在创建一个新文件时, Linux 内核会通过inode的位图找到空闲可用的inode,并进行分配。要存储数据时,会通过块的位图找到空闲的块,并分配,但仔细计算一下还是有问题的。
数据块的位图是放在磁盘块里的,假设是放在一个块里,一个块4K,每位表示一个数据块,共可以表示4 * 1024 * 8 = 2^15个空闲块,由于1个数据块是4K大小,那么最大可以表示的空间为2^15 * 4 * 1024 = 2^27个byte,也就是128M。
也就是说按照上面的结构,如果采用(一个块的位图+ 一系列的块),外加一(个块的inode的位图+一系列的inode)的结构能表示的最大空间也就128M,
这太少了,现在很多文件都比这个大。
在Linux文件系统,把这个结构称为一个 块组 ,那么有N多的块组,就能够表示N大的文件。
最终,整个文件系统格式就是下面这个样子。
最前面的第一个块是引导块,在系统启动时用于启用引导,接着后面就是一个一个连续的块组了,块组的内容如下:
● 超级块 ,包含的是文件系统的重要信息,比如inode总个数、块总个数、每个块组的inode个数、每个块组的块个数等等。
● 块组描述符 ,包含文件系统中各个块组的状态,比如块组中空闲块和inode的数目等,每个块组都包含了文件系统中“所有块组的组描述符信息”。
● 数据位图和inode位图 ,用于表示对应的数据块或inode是空闲的,还是被使用中。
● inode 列表 ,包含了块组中所有的inode, inode 用于保存文件系统中与各个文件和目录相关的所有元数据。
● 数据块 ,包含文件的有用数据。
你可以会发现每个块组里有很多重复的信息,比如 超级块和块组描述符表,这两个都是全局信息,而且非常的重要 ,这么做是有两个原因:
●如果系统崩溃破坏了超级块或块组描述符,有关文件系统结构和内容的所有信息都会丢失。如果有冗余的副本,该信息是可能恢复的。
●通过使文件和管理数据尽可能接近,减少了磁头寻道和旋转,这可以提高文件系统的性能。
不过,Ext2 的后续版本采用了稀疏技术。该做法是,超级块和块组描述符表不再存储到文件系统的每个块组中,而是只写入到块组0、块组1和其他ID可以表示为3、5、7的幂的块组中。
在前面,我们知道了一个普通文件是如何存储的,但还有一个特殊的文件,经常用到的目录,它是如何保存的呢?
基于Linux 一切切皆文件的设计思想,目录其实也是个文件,你甚至可以通过vim打开它,它也有inode, inode 里面也是指向一些块。
和普通文件不同的是, 普通文件的块里面保存的是文件数据,而目录文件的块里面保存的是目录里面一项一项的文件信息 。
在目录文件的块中,最简单的保存格式就是 列表 ,就是一项一项地将目录下的文件信息(如文件名、文件inode.文件类型等)列在表里。
列表中每一项就代表该目录下的文件的文件名和对应的inode,通过这个inode,就可以找到真正的文件。
通常,第一项是“则”,表示当前目录,第二项是.,表示上一级目录, 接下来就是一项一项的文件名和inode。
如果一个目录有超级多的文件,我们要想在这个目录下找文件,按照列表一项一项的找,效率就不高了。
于是,保存目录的格式改成 哈希表 ,对文件名进行哈希计算,把哈希值保存起来,如果我们要查找一个目录下面的文件名,可以通过名称取哈希。如果哈希能够匹配上,就说明这个文件的信息在相应的块里面。
Linux系统的ext文件系统就是采用了哈希表,来保存目录的内容,这种方法的优点是查找非常迅速,插入和删除也较简单,不过需要一些预备措施来避免哈希冲突。
目录查询是通过在磁盘上反复搜索完成,需要不断地进行/0操作,开销较大。所以,为了减少/0操作,把当前使用的文件目录缓存在内存,以后要使用该文件时只要在内存中操作,从而降低了磁盘操作次数,提高了文件系统的访问速度。
感谢您的阅读,希望您能摄取到知识!加油!冲冲冲!(发现光,追随光,成为光,散发光!)我是程序员耶耶!有缘再见。<-biubiu-⊂(`ω´∩)
C. 内存卡内存是属于内部存储还是系统内存或外存储卡另外两种分别属于什麽
是外部存储,系统内存指的是存储系统app和文件的,这部分存储必须root后才可以自己存储文件,内部存储就是你可以随意下载app,存储各种资料的部分,内存卡是扩展的外部存储。
D. 简述计算机存储系统的三级存储体系概念
高速缓存:位于计算机内部或某些设备内部,速度比较快; 内部存储器:位于计算机内部,就是通常所说的内存; 外部存储器:就是光盘,U盘,磁带等等。 通常计算机内还有寄存器的,这个速度是最快的,不过容量太小。
E. 云计算时代操作系统Kubernetes之存储(中)
我们在POD中定义数据卷的时候,必须指定数据卷的类型。由于存储技术的发展远远早于Kubernetes平台的诞生,并且随着Kubernetes的日益流行,新的存储技术和方案也在日新月异,因此数据卷可以说理所当然的有很多很多类型,有些是通用的类型,而有些需要底层特定存储技术的支持,下边是Kubernetes支持的数据卷类型不完全清单:
- emptyDir类型,emptyDir类型的数据卷允许POD将数据保存到指定的文件夹中,并且数据在POD的整个生命周期中可见。保存数据的文件夹在POD启动前被创建,并且刚开始文件夹为空,这也是叫empty的缘由。
- hostPath类型,从宿主机的文件系统挂载文件到POD中。
- nfs类型,NFS类型的存储卷挂载到POD中。
- cephfs,cinder,fc等,用来支持不同类型的网络存储。
- configMap,secret,downwardAPI,以及projected类型,四种卷类型,用来将POD和Kubernetes的相关信息通过文件暴露给外部,这些卷类型主要用来配置应用程序。这几种类型笔者会在后续的文章中详细介绍。
- persistentVolumeClaim类型(PVC),一种轻量级的集成外部存储能力的方案。在这种类型的数据卷类型中,PersistentVolumeClaim类型的存储对象指向PersistentVolume类型的存储对象,真实的外部存储系统由PersistentVolume这个对象来引用。由于这是Kuberntes强烈建议大家使用的存储类型,因此笔者会在后续的文章中,单独来详细介绍。
- csi类型,一种通过CSI来扩展存储的方式。这种方式允许所有实现了CSI(Container Storage Interface)接口的存储实现能够被POD引用,在POD初始化的过程中,CSI驱动会将存储卷attach到POD上。
上边罗列的只是数量巨大存储卷类型中很小一部分,每种类型都有对应的使用场景。笔者在本篇以及后续的文章中,着重介绍最具代表性的几个类型,来帮助大家理解Kubernetes存储体系。首先我们从最简单的emptyDir类型开始,这种类型的数据卷用来在容器重启场景中保持状态。
还记得我们在前边文章中介绍如何在同一个POD中部署两个容器实例的例子吗?当时的做法是通过post-start hook来执行fortune命令产生一个名言警句写入文件中,运行在另外一个容器中的Nginx服务器由于挂载了相同的volume,因此会直接将这个信息返回给客户端请求。这个保存fortune产生的名言警句的文件在容器的文件系统中,这就意味着当容器由于liveness probe三次失败重启后,你会看到不同的名言警句,虽然说看起来问题不大,但是从原理上讲,数据由于容器重启丢失。
我们来验证一下上边的推理是否符合事实,请在自己的本地环境中部署yunpan-fs.yaml,然后执行kubectl port-forward yunpan-fs 1080:80来创建客户端代理,访问服务返回名言警句。然后通过命令让Nginx重新启动,重新访问服务,你可以看到两次返回的数据不一致,这就证明了保存在容器文件系统的数据,在容器重启的场景下,不会保持。在笔者的本地环境输出如下图:
如上图所示,重启容器后会产生新的名言警句,这就意味着容器重启后保存在文件系统中的数据丢失了。如果我们要在这种重启的场景中保持数据状态,那么就必须确保数据被保存在数据卷中,而emptyDir是解决这个问题的完美方案。当emptyDir类型的数据卷被挂载到容器中,应用写到挂载目录的数据文件,在容器重启后,能够继续保持。
emptyDir类型的数据卷可以让容器即便是重启后,可以让写到文件中的数据状态保持;或者容器的文件系统为只读,但是应用在运行的过程中,需要写状态到文件中等场景,我们也可以使用emptyDir类型的数据卷来在同一个POD的多个容器之前,进行数据共享。
废话不多说了,咱直接修改fortune pod来把post-start hook执行fortune命令返回的名言警句写到emptyDir类型的数据卷中,这样当容器重启后,就不会出现数据丢失了。我们其实要修改的地方不多,主要包括:1,给POD增加emptyDir类型的数据卷定义;2,在容器中将这个数据卷挂载到指定的目录。
另外我们对命令的执行进行了一点点优化,post-start hook会在每次容器启动后都会执行,因此我们需要防止重启后对fortune命令输出对已经存在文件的覆盖,因此我们对post-start命令脚本也做了优化,如下图所示:
注:post-start hook脚本被更新成"ls /usr/share/nginx/html/quote || (apk add fortune && fortune > /usr/share/nginx/html/quote)",如果读者对Linux shell脚本不是很熟悉,这句肯定看的云里雾里,我们来稍微解释一下。首先ls命令先执行,我们这里用ls来检查quote文件是否存在,你有所不值得是,当ls后边给的文件存在的时候,命令返回0,而如果不存在,就返回非0。由于我们使用||将两个表达式进行了组合,因此当左边的ls quote执行成功,那么右边的语句就压根不会执行。通过这种方式,如果quote文件存在,那么咱就直接跳过了。而当文件不存在,才需要执行右边的一串命令,安装fortune和执行fortune来产生名言警句。这句脚本确保名言警句只被生成并写入一次,也就是只在容器第一次启动的时候。
如上图所示,我们定义了emptyDir类型的数据卷content,并挂载到nginx容器指定目录/usr/share/nginx/html(这个是Nginx服务器默认用来扫描静态资源的目录)。在POD中配置volume需要提供配置参数,接下来我们详细聊聊如何配置emptyDir类型的数据卷。
对于emptyDir类型的存储卷,Kubernetes要求配置如下两个属性:
- medium,文件夹的存储介质,如果留空不配置,那么默认就是宿主机的(工作节点)磁盘。除了磁盘之外,我们还可以配置Memory,这会导致数据卷使用tmpfs文件系统,这是一个在内存文件系统。
- sizeLimit,文件夹需要的磁盘空间大小,比如我们如果需要限制这个文件夹中文件的大小为10M,那么就可以设置为10Mi。
注:我们上边的例子中,emptyDir类型的数据卷content未显示的定义任何字段,取默认值,大括号非常明确的表达了这一点,但是并不是必须的。
在POD中定义完数据卷只完成了工作的一半,工作的另一半就是将数据卷挂载到容器实例中,这通过在容器spec.containers域通过volumeMounts来引用。volumeMounts除了要制定name之外,还需要包含mountPath字段,来指定数据卷被具体挂载到容器文件系统的文件目录树的那个路径。笔者上边提供的例子中,emptyDir类型的数据卷被挂载到了/usr/share/ngxin/html目录,因为这也是post-start hook将名言警句写到文件的路径。
由于使用了emptyDir类型的数据卷之后,名言警句被写入到了宿主机的文件系统,因此数据在POD的整个生命周期都会保持,因此我们无论重启nginx容器多少次,返回的数据(名言警句)都不应该有任何变化。
接下来,我们将这个新版本基于fortune命令的名言警句网站部署到Kubernetes集群,并人为的让nginx容器重启,你会发现无论我们重启多少次,quote接口返回的内容都一样。背后的原理是,因为我们只在容器第一次启动的时候,才创建quote文件,并且当容器重启重新挂载数据卷后,这个quote文件仍然存在。你可能会问,这个文件到底在宿主机的啥地方啊,可以运行kubectl exec yunpan-emptydir -- mount --list | grep nginx/html来发现,如下图所示:
如上图所示,通过使用emptyDir类型的数据局content,我们成功让容器重启之后,保持数据状态。接下来,我们继续看另外一个例子,如何通过数据卷在两个容器时间共享数据。
如笔者前边多次提到,我们也可以使用emptyDir类型的数据卷来在同一个POD中的两个容器之间共享数据,这里需要注意的是,我们无法通过emptyDir类型的数据卷在不同PDO中不同的容器间共享数据,请继续阅读。
我们基于fortune的名言警句网站目前略显无趣,因为每次都返回相同的谚语,我们希望这个行为能够增强,比如每30分钟更换一次。为了实现这个功能,我们需要将post-start hook替换成容器,并且在容器中,fortune命令每30秒运行一次。为了使大家学习更加容易,笔者已经构建好了需要的容器,并上传到Docker Hub,大家可以自行通过命令 docker pull qigaopan/yunpan-fortune:v1.0拉取。
好了,我们已经把需要的容器镜像都准备好了,接下来我们来编写POD的YAML文件,如下图所示:
如上图所示,emptyDir类型的数据卷被两个容器共享(共同挂载),容器fortune将数据写到content数据卷,在nginx容器中,相同的数据卷被以read-only的模式被挂载到nginx的默认目录。
注:我们在前边文章中反复强调过一个事实,同一个POD中的多个容器几乎是同时启动的,因此可能存在微小的一段时间,ngxin服务器已经成功运行起来,但是quote文件尚未生成。聪明的你可能想到了,要避免这种场景,我们可以使用初始化容器。
接着,我们将fortune POD部署到Kubernetes集群中,两个容器几乎同时开始运行。fortune容器每30秒更新一次谚语(名言警句),nginx容器基于相同的数据文件服务客户端请求,当POD中的两个容器都Ready后,可以验证一下输出,是否每30秒后,quote请求对应的谚语的返回会更新。
由于在fortune例子中emptyDir类型的数据卷会在宿主机的磁盘上创建共享目录,因此数据读写的性能,完全取决于工作节点上硬件的类型。如果我们的应用需要高性能的IO操作,那么磁盘可能不是最合适的存储介质。
Kubernetes允许我们使用tmpfs文件系统来创建数据卷,而tmpfs将数据保存在内存中,我们只需要在POD的YAML文件中,把emptyDir的字段meim设置为Memory。
其实Memory类型的数据卷除了提供较高的IO之外,数据安全性也比磁盘高。由于数据并没有落盘,因此数据不容易被恶意攻击者窃取,因此建议大家可以在自己的项目上考虑这种数据卷类型。另外我们也可以通过参数sizeLimit来约束数据卷的size,特别对于Memory类型的数据卷来说,请务必设置sizeLimit,以防内存被耗尽。
在前边的内容中,我们将目光主要集中在如何在POD中定义数据卷,而没有详细介绍volume是如何挂载到容器中的,接下来我们来看看在容器中挂载数据卷具体需要设置哪些参数。如下图所示,是我们在新版本的fortune POD定义中关于content数据卷挂载的配置:
从上图可以看出,挂载数据卷到容器中,我们需要至少配置两个字段:name和mountPath,其中name字段是我们在POD定义的数据卷的名字,而mountPath字段指定了数据卷应该挂载到容器文件系统的文件数的那个目录。
除了这两个必须提供的参数之外,我们还有一些可选的参数可以配置,详细的可配置参数清单如下:
- name字段,如笔者上边的介绍,name字段就是我们在POD中挂载的数据卷的name
- mountPath字段,前文应介绍,不累述
- readOnly字段,是否以只读的模式挂载数据卷,默认是false,也就是以读写的方式挂载数据卷。
- mountPropagation字段,设置如果在数据卷内部挂载额外的文件系统会发生什么。有几个选项,默认是none,指如果宿主机在数据卷中挂在了额外的文件系统,容器不会收到任何通知,反之亦然;还有两个选项HostToContainer和Bidirectional,具体含义如命名,如果要了解详情,可以参考官方文档。
- subPath字段,默认为“”,意味着整个数据卷都被挂载到mountPath指定的目录,当设置为非空的字符串后,只有subPath指定的文件路径被挂载到容器中
- subPathExpr字段,使用类似于shell提供的$(ENV_VAR_NAME)语句,只能使用环境变量。
在大部分场景下,我们只需要设置name和mountPath就可以了,顶多额外多配置参数readOnly。mountPropagation参数只有在一些复杂配置的场景下才会用到,当我们用一个数据卷来提供不同的文件夹给不同的容器的时候,subPath和subPathExpr非常有用。另外这两个参数也可以用作多个PDO共享一个数据卷的场景。
好了,这篇文章的内容就这么多了,下篇文章我们继续介绍存储,看看如何访问宿主机文件系统中的数据文件,敬请期待!
F. 计算机系统中的存储器系统是指ram存储器
1 . 计算机的RAM(Random Access Memory)的别名为随机存取记忆体,它相当于计算机上的移动存储,用来存储和保存数据的。它在任何时候都可以读写,RAM通常是作为操作系统或其他正在运行程序的临时存储介质(可称作系统内存)。
G. 分布式文件存储系统通过什么方式提高可用性和安全性
分布式存储的六大优点
1. 高性能
一个具有高性能的分布式存户通常能够高效地管理读缓存和写缓存,并且支持自动的分级存储。分布式存储通过将热点区域内数据映射到高速存储中,来提高系统响应速度;一旦这些区域不再是热点,那么存储系统会将它们移出高速存储。而写缓存技术则可使配合高速存储来明显改变整体存储的性能,按照一定的策略,先将数据写入高速存储,再在适当的时间进行同步落盘。
2. 支持分级存储
由于通过网络进行松耦合链接,分布式存储允许高速存储和低速存储分开部署,或者任意比例混布。在不可预测的业务环境或者敏捷应用情况下,分层存储的优势可以发挥到最佳。解决了目前缓存分层存储最大的问题是当性能池读不命中后,从冷池提取数据的粒度太大,导致延迟高,从而给造成整体的性能的抖动的问题。
3. 多副本的一致性
与传统的存储架构使用RAID模式来保证数据的可靠性不同,分布式存储采用了多副本备份机制。在存储数据之前,分布式存储对数据进行了分片,分片后的数据按照一定的规则保存在集群节点上。为了保证多个数据副本之间的一致性,分布式存储通常采用的是一个副本写入,多个副本读取的强一致性技术,使用镜像、条带、分布式校验等方式满足租户对于可靠性不同的需求。在读取数据失败的时候,系统可以通过从其他副本读取数据,重新写入该副本进行恢复,从而保证副本的总数固定;当数据长时间处于不一致状态时,系统会自动数据重建恢复,同时租户可设定数据恢复的带宽规则,最小化对业务的影响。
4. 容灾与备份
在分布式存储的容灾中,一个重要的手段就是多时间点快照技术,使得用户生产系统能够实现一定时间间隔下的各版本数据的保存。特别值得一提的是,多时间点快照技术支持同时提取多个时间点样本同时恢复,这对于很多逻辑错误的灾难定位十分有用,如果用户有多台服务器或虚拟机可以用作系统恢复,通过比照和分析,可以快速找到哪个时间点才是需要回复的时间点,降低了故障定位的难度,缩短了定位时间。这个功能还非常有利于进行故障重现,从而进行分析和研究,避免灾难在未来再次发生。多副本技术,数据条带化放置,多时间点快照和周期增量复制等技术为分布式存储的高可靠性提供了保障。
5. 弹性扩展
得益于合理的分布式架构,分布式存储可预估并且弹性扩展计算、存储容量和性能。分布式存储的水平扩展有以下几个特性:
1) 节点扩展后,旧数据会自动迁移到新节点,实现负载均衡,避免单点过热的情况出现;
2) 水平扩展只需要将新节点和原有集群连接到同一网络,整个过程不会对业务造成影响;
3) 当节点被添加到集群,集群系统的整体容量和性能也随之线性扩展,此后新节点的资源就会被管理平台接管,被用于分配或者回收。
6. 存储系统标准化
随着分布式存储的发展,存储行业的标准化进程也不断推进,分布式存储优先采用行业标准接口(SMI-S或OpenStack Cinder)进行存储接入。在平台层面,通过将异构存储资源进行抽象化,将传统的存储设备级的操作封装成面向存储资源的操作,从而简化异构存储基础架构的操作,以实现存储资源的集中管理,并能够自动执行创建、变更、回收等整个存储生命周期流程。基于异构存储整合的功能,用户可以实现跨不同品牌、介质地实现容灾,如用中低端阵列为高端阵列容灾,用不同磁盘阵列为闪存阵列容灾等等,从侧面降低了存储采购和管理成本。
H. 块储存,对象存储,文件存储的区别和联系
通常来讲,磁盘阵列都是基于Block块的存储,而所有的NAS产品都是文件级存储。
1. 块存储:DAS SAN
a) DAS(Direct Attach Storage): 是直接连接于主机服务器的一种存储方式,每台服务器有独立的存储设备,每台主机服务器的存储设备无法互通,需要跨主机存取资料室,必须经过相对复杂的设定,若主机分属不同的操作系统,则更复杂。
应用:单一网络环境下且数据交换量不大,性能要求不高的环境,技术实现较早。
b) SAN(Storage Area Network): 是一种高速(光纤)网络联接专业主机服务器的一种存储方式,此系统会位于主机群的后端,它使用高速I/O联接方式,如:SCSI,ESCON及Fibre-Channels.特点是,代价高、性能好。但是由于SAN系统的价格较高,且可扩展性较差,已不能满足成千上万个CPU规模的系统。
应用:对网速要求高、对数据可靠性和安全性要求高、对数据共享的性能要求高的应用环境中。
2. 文件存储
通常NAS产品都是文件级存储。
NAS(Network Attached Storage):是一套网络存储设备,通常直接连在网络上并提供资料存取服务,一套NAS储存设备就如同一个提供数据文件服务的系统,特点是性价比高。
它采用NFS或CIFS命令集访问数据,以文件为传输协议,可扩展性好、价格便宜、用户易管理。目前在集群计算中应用较多的NFS文件系统,但由于NAS的协议开销高、带宽低、延迟大,不利于在高性能集群中应用。
3. 对象存储:
总体上讲,对象存储同时兼具SAN高级直接访问磁盘特点及NAS的分布式共享特点。
核心是将数据通路(数据读或写)和控制通路(元数据)分离,并且基于对象存储设备(OSD),构建存储系统,每个对象存储设备具备一定的职能,能够自动管理其上的数据分布。
对象储存结构组成部分(对象、对象存储设备、元数据服务器、对象存储系统的客户端)
3.1 对象
一个对象实际就是文件的数据和一组属性信息的组合。
3.2 对象存储设备(OSD)
OSD具有一定的智能,它有自己的CPU、内存、网络和磁盘系统。
OSD提供三个主要功能:包括数据存储和安全访问
(1)数据存储 (2)智能分布 (3)每个对象元数据的管理
3.3 元数据服务器(Metadata Server , MDS)
MDS控制Client与OSD对象的交互,主要提供以下几个功能:
(1) 对象存储访问
允许Client直接访问对象,OSD接收到请求时先验证该能力,再访问。
(2) 文件和目录访问管理
MDS在存储系统上构建一个文件结构,限额控制、包括目录、文件的创建、访问控制等
(3) Client Cache 一致性
为提高性能,在对象存储系统设计时通常支持Client的Cache。因此带来了Cache一致性的问题,当Cache文件发生改变时,将通知Client刷新Cache,以防Cache不一致引发的问题。
对象存储:
一个文件包含了属性(术语叫matadata元数据,例如该文件的大小、修改时间、存储路径等)以及内容(简称数据)。
以往的文件系统,存储过程将文件按文件系统的最小块来打散,再写进硬盘,过程中没有区分元数据(metadata)和数据。而在每个块最后才会告知下一个块的地址,因此只能一个一个读,速度慢。
而对象存储则将元数据独立出来,控制节点叫元数据服务器(服务器+对象存储管理软件),里面主要存储对象的属性(主要是对象的数据被打散存放到了那几台分布式服务器中的信息),而其他负责存储数据的分布式服务器叫做OSD,主要负责存储文件的数据部分。当用户访问对象时,会先访问元数据服务器,元数据服务器只负责反馈对象存储在那些OSD。假设反馈文件A存储在B,C,D三台OSD,那么用户就会再次访问三台OSD服务器去读取数据。
这时三台OSD同时对外传输数据,因此传输的速度就加快了。OSD服务器数量越多,这种读写速度的提升就越大。
另一方面,对象存储软件有专门的文件系统,所以OSD对外又相当于文件服务器,那么就不存在文件共享方面的困难了,也解决了文件共享方面的问题。
因此对象存储的出现,很好的结合了块存储与文件存储的优点。
为什么还要使用块存储和文件存储:
1.有一类应用是需要存储直接裸盘映射的,比如数据库。因为数据库需要存储裸盘映射给自己后,再根据自己的数据库文件系统来对了裸盘进行格式化,因此不能采用其他已经被格式化为某种文件系统的存储。此类更适合块存储。
2.对象存储的成本比普通的文件存储还是较高,需要购买专门的对象存储软件以及大容量硬盘。如果对数据量要求不是海量,只是为了作文件共享的时候,直接用文件存储的形式就好了,性价比高。
I. 谁给我解释下内部存储,系统存储,系统缓存,内
1、内部存储:内置在设备内的存储器,区别于外置存储,外置存储是在外部通过数据线、卡槽、网线等其他方式连接至设备的存储器。内部存储是硬件,是实体存储设备。
2、系统存储:用于存放系统文件的存储空间。只得是实体存储设备内存放系统的那部分空间。
3、系统缓存:用于存放系统运行时需要使用或产生的临时文件的存放空间,为了提高系统调取文件的速度,每次都会将该文件相邻的文件的一块调取到系统缓存,以便系统下次调取到该相邻文件时可以加快调取速度。这个存放相邻调取文件的地方叫做缓存。顾名思义,临时文件在该处做个缓冲存储。存放缓存的存储器是实体存储器,是硬件,但是缓存本身是一个空间概念,只是个大小。
4、内存,由于普通存储器的存取速度不足以满足CPU的处理速度,我们需要一个速度非常高的存储设备来连接CPU和普通存储器。缓存是一种方式,但是还不够,所以需要在中间在放置个内存。它的空间比缓存大,比外部存储器小,速度比缓存慢但是比外部存储器快。是实体存储器,是硬件。