前言

随着 Kubernetes 的 CSI 规范成为容器业界统一的存储接入标准,现在几乎所有的云计算厂商都支持自家的容器通过 CSI 规范去接入外部存储,能够应用于 CSI 与 FlexVolume 的存储插件更是多达数十上百款,下图就展示了部分容器存储提供商,可以说,容器存储已经算是形成了初步的生态环境。
在这里插入图片描述
目前出现过的存储系统和设备,都可以划分到块存储、文件存储和对象存储这三种存储类型之中,其划分的根本依据不是各种存储是如何储存数据的,而是各种存储会提供什么形式的接口来供外部访问数据,不同的外部访问接口会反过来影响存储的内部结构、性能与功能表现。
虽然块存储、文件存储和对象存储可以彼此协同工作,但它们各自都有自己明确的擅长领域与优缺点。所以,只有理解它们的工作原理,因地制宜地选择最适合的存储,才能让系统达到最佳的工作状态。

块存储

块存储是数据存储最古老的形式,它把数据都储存在一个或多个固定长度的块(Block)中,想要读写访问数据,就必须使用与存储相匹配的协议(SCSI、SATA、SAS、FCP、FCoE、iSCSI……)。

你可以把存储设备中由块构成的信息流,与网络设备中由数据包构成的信息流进行对比。事实上,像 iSCSI 这种协议真的就是建设在 TCP/IP 网络之上,让上层以 SCSI 作为应用层协议对外提供服务的。
硬盘就是最经典的块存储设备,以机械硬盘为例,一个块就是一个扇区,大小通常在 512 Bytes 至 4096 Bytes 之间。老式机械硬盘用柱面 - 磁头 - 扇区号(Cylinder-Head-Sector,CHS)组成的编号进行寻址,现代机械硬盘只用一个逻辑块编号(Logical Block Addressing,LBA)进行寻址。

为了便于管理,硬盘通常会以多个块(这些块甚至可以来自不同的物理设备,比如磁盘阵列的情况)来组成一个逻辑分区(Partition),将分区进行高级格式化之后就形成了卷(Volume)。
块存储由于贴近底层硬件,没有文件、目录、访问权限等的牵绊,所以性能通常都是最优秀的(吞吐量高,延迟低)。

操作系统内核中,许多地方就是直接通过块设备(Block Device)接口来访问硬盘,一些追求 I/O 性能的软件,比如高性能的数据库也会支持直接读写块设备以提升磁盘 I/O。块存储具有排它性,一旦块设备被某个客户端挂载后,其他客户端就无法再访问上面的数据了。因此,Kubernetes 中挂载的块存储,大多的访问模式都要求必须是 RWO(ReadWriteOnce)的。

文件存储

文件存储是最贴近人类用户的数据存储形式,数据存储在长度不固定的文件之中,用户可以针对文件进行新增、写入、追加、移动、复制、删除、重命名等各种操作,通常文件存储还会提供有文件查找、目录管理、权限控制等额外的高级功能。(更像是文件系统)
POSIX接口(Portable Operating System Interface,POSIX)已经成为了文件存储事实标准,被各种商用的存储系统和操作系统共同支持。
绝大多数传统的文件存储都是基于块存储之上去实现的,我们可以近似地认为文件是由块所组成的更高级存储单位,对于固定不会发生变动的文件,直接让每个文件连续占用若干个块,在文件头尾加入标志区分即可,就比如像磁带、CD-ROM、DVD-ROM,就采用了由连续块来构成文件的存储方案。
对于可能发生变动的场景,我们就必须考虑如何跨多个不连续的块来构成为文件。这种需求从数据结构的角度看,只需要在每个块中记录好下一个块的地址,形成链表结构就能满足。但是链表的缺点是只能依次顺序访问,这样访问文件中的任何内容都要从头读取多个块,这显然过于低效了。
被广泛运用的解决方案是把形成链表的指针整合起来统一存放,这就是文件分配表(File Allocation Table,FAT)。既然已经有了专门组织块结构来构成文件的分配表,那在表中再加入其他控制信息,就能很方便地扩展出更多的高级功能。比如除了文件占用的块地址信息外,在表中再加上文件的逻辑位置就形成了目录,加上文件的访问标志就形成了权限,我们还可以再加上文件的名称、创建时间、所有者、修改者等一系列的元数据信息,来构成其他应用形式。

我们把定义文件分配表应该如何实现、储存哪些信息、提供什么功能的标准称为文件系统(File System),FAT32、NTFS、exFAT、ext2/3/4、XFS、BTRFS 等都是很常用的文件系统。而前面提到的对分区进行高级格式化操作,实际上就是在初始化一套空白的文件系统,供后续用户与应用程序访问

文件存储相对于块存储来说是更高层次的存储类型,加入目录、权限等元素后形成的树状结构以及路径访问的方式,方便了人们对它的理解、记忆和访问;文件系统能够提供进程正在打开或正在读写某个文件的信息,这也有利于文件的共享处理。

但在另一方面,计算机需要把路径进行分解,然后逐级向下查找,最后才能查找到需要的文件。而要从文件分配表中确定具体数据存储的位置,就要判断文件的访问权限,并要记录每次修改文件的用户与时间,这些额外操作对于性能产生的负面影响也是无可避免的。因此,如果一个系统选择不采用文件存储的话,那磁盘 I/O 性能一般就是最主要的原因。

对象存储

对象存储是相对较新的数据存储形式,它是一种随着云数据中心的兴起而发展起来的存储,是以非结构化数据为目标的存储方案。

这里的“对象”可以理解为一个元数据及与其配对的一个逻辑数据块的组合,元数据提供了对象所包含的上下文信息,比如数据的类型、大小、权限、创建人、创建时间,等等,数据块则存储了对象的具体内容。你也可以简单地理解为数据和元数据这两样东西共同构成了一个对象。

每个对象都有属于自己的全局唯一标识,这个标识会直接开放给最终用户使用,作为访问该对象的主要凭据,通常会是以 UUID 的形式呈现。对象存储的访问接口就是根据该唯一标识,对逻辑数据块进行的读写删除操作的,通常接口都会十分简单,甚至连修改操作权限都不会提供。

对象存储基本上只会在分布式存储系统之上去实现,由于对象存储天生就有明确的“元数据”概念,不必依靠文件系统来提供数据的描述信息,因此,完全可以将一大批对象的元数据集中存放在某一台(组)服务器上,再辅以多台 OSD(Object Storage Device)服务器来存储对象的数据块部分。

当外部要访问对象时,多台 OSD 能够同时对外发送数据,因此对象存储不仅易于共享、拥有庞大的容量,还能提供非常高的吞吐量。不过,由于需要先经过元数据查询确定 OSD 存放对象的确切位置,这个过程可能涉及多次网络传输,所以在延迟方面就会表现得相对较差。
数据传输的吞吐量和延迟性
由于对象的元数据仅描述对象本身的信息,与其他对象都没有关联,换而言之每个对象都是相互独立的,自然也就不存在目录的概念,可见对象存储天然就是扁平化的,与软件系统中很常见的 K/V 访问相类似。

总结

从目前的存储技术发展来看,其实不会有哪一种存储方案能够包打天下。你要知道,不同业务系统的场景需求不同,对存储的诉求就会不同,那么选择自然也会不同。
以亚马逊销售材料中三种存储的对比为例:
在这里插入图片描述

此文章为3月Day11学习笔记,内容来源于极客时间《周志明的软件架构课

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐