聊一聊磁盘

磁盘

磁盘是一种非常常见的持久化存储设备,相较于计算机上另外一种主要的存储设备:内存,磁盘则主要具有断电数据不丢失、容量通常更大、价格低廉等特点;当然我们今天这里主要聊的是广义上的磁盘,而不是特指利用磁性来存储的狭义上的概念。

存储介质

理论上任何能够表达两种状态,且能持久性的保持的东西都可以用来造磁盘;不过我们通常还要考虑成本等其他实际的问题。

我们通常指的磁盘,按照存储介质来分,主要能分为固态硬盘和机械硬盘(狭义磁盘)这两种,分别对应的存储介质为浮栅晶体管和磁性颗粒。另外还有一些很常见的存储介质,虽然基于它们造出来的存储设备我们通常不叫磁盘,不过这里我们也可以顺带对比了解一下。

磁性颗粒

磁是一种非常重要且使用非常广泛的存储介质,我们常说的狭义上的磁盘、磁带等都是通过这种物质来存储的数据。

磁性颗粒通常是由铁的混合氧化物组成(比如BaFe12O19),这些氧化物在被施加电磁场磁化之后,内部原子的偶极子从无序变成按顺序排列,即使断电磁场撤去,部分排列仍能被长期保留,这种现象叫做磁滞现象,这就是磁性颗粒可以长久保存数据的物理学理论基础。

磁场是分为南北两级有两种朝向的,所以一个颗粒中磁场的方向就能对应我们需要存储的 0 和 1。

要读取数据的时候,通过电磁感应现象的应用(放在变化磁通量中的导体,会产生电动势),我们可以根据产生的感应电流的方向来将磁性颗粒中存储的 0 和 1 加载成我们半导体电路中的 0 和 1,进而进一步被计算读取。

写入数据时,只需要施加一个反向的大电磁场就能让原子的偶极子反向排列。

image-20221112132652919

浮栅半导体

浮栅半导体通常被用来制作闪存颗粒,即固态硬盘的重要组成单元。

浮栅半导体全称浮栅金属氧化物半导体场效应晶体管(Floating-gate MOSFET),通过捕获在浮栅层中的电子的数量来代表 0 和 1。

Floating_gate_transistor-en

浮栅层被氧化物绝缘层包围,在未施加高电压的情况下进去的电子很难出去,同时外面的电子也进不来,这样即使断电数据也还是能保存在其中。但是并不是说完全不会有电子能逃逸出去,所以这也是为什么大家说固态硬盘并不能永久的存储数据,不过一般十年左右逃逸电子的数量才会多到无法区分原始的 0 和 1 的程度。

需要写入数据时,只需要给到一个足够大的电压,浮栅外的电子在电场的作用下就会进入浮栅层,断掉电压之后电子就会变成数据被保存起来。

需要读取数据时,将晶体管导通,随着其中电子数量的不同,导通后能读到的电压也是不一样的,这样就能根据电压的数值来判断其中存储的数据位了。

根据一个特定的阈值,根据电压是否高于这个阈值来判断 0/1,后续存储厂商们为了进一步节约成本,陆续又出现了将电压划分成四份一个晶体管可存储 2 bit 信息的 MLC (Multi Level Cell)结构,可以存储 3 bit 的 TLC (Tripple Level Cell)结构,甚至可以存储 4 bit 的 QLC (Quadra Level Cell)结构。

SR锁存器

锁存器(Latch)是组成静态随机存取存储器(Static Random Access Memory)的核心部件,SRAM 利用锁存器其中锁住的电平高低来表示 0 和 1。

和电容一样,锁存器也是一种纯电路结构,一旦断电数据就全丢失了,所以不怎么用来造磁盘。

image-20220619211005412

电容

动态随机存取存储器(Dynamice Random Access Memory: DRAM) 是我们目前主要用到的内存结构,DRAM 利用电容内存储电荷的数量来代表 0 或 1。

基于锁存器的 SRAM 存储一比特需要六个晶体管,而 DRAM 则只需要一个晶体管,所以 DRAM 相对来说造价和同等容量的体积上都有很大的优势,尽管性能会要差一些。

另外 DRAM 需要不断地刷新给电容充电不然数据就会丢失,所以其被称为“动态” RAM,而“静态”的 SRAM 则没有这种烦恼。

我们目前所用的内存条基本都是基于电容的 DRAM 型,主流架构为双倍数据率同步动态随机存取存储器(Double Data Rate Synchronous Dynamic Random Access Memory,简称DDR SDRAM)。

而 SRAM 则常见于 CPU 缓存这种性能要求非常高且能接受其昂贵造价的场景。

img

打孔纸带

严格意义上来说,纸带算是最早的存储介质了,通过有孔和无孔的区别来代表 0 和 1,可持久化存储,无需担心掉电丢失。

传输链路

了解了数据是如何存储之后,我们下一步要关心的问题就是,磁盘中的数据又是怎么到达内存、CPU 等其他设备中供其使用的呢?

简单地来说就是,磁盘通过物理接口插入到计算机中,然后经由总线,按照某种协议和其他设备交换数据。

NAME 全称 诞生时间 理论性能上限
PATA Parallel ATA 1986 133 MB/s
SATA Serial ATA 2000 750 MB/s
M.2 2013 8 GB/s
USB Universal Serial Bus 1996 1.21 GB/s
SAS Serial Attached SCSI 2004 1.2 GB/s

接口: INTERFACE

接口即我们平常看到的磁盘上暴露出来的那一部分金属块,磁盘插到主板上对应母口之后,形成电流和数据通路,从而使用硬盘可以被计算机识别并传输数据。

目前存在好几种主流的接口规范,不同的接口电路设计不一样,其特点和性能也大不相同。

image-20221113022429884

PATA

Parallel ATA (简称 PATA,也被称为: ATA、IDE),是早期常见的一种磁盘接口格式,不过由于并行设计的性能缺陷如今已经被 SATA 取代了。

ATA 的全称是 Advanced Technology Attachment:AT 的接口,AT 是 IBM 于 1984 年发布的一款计算机:IBM Personal Computer/AT,后面逐渐演变成了一种通用的标准。

串行与并行

传输接口通常分为串行传输的和并行传输的,比如 PATASATA 这两种典型的代表,然而跟我们通常在软件上认知不太一样的是,并行的并不一定快:

并行传输需要额外的时钟信号来协调,来确保数据不会乱序,而每根线收到时钟信号会有一定的先后顺序,所以需要准备一个误差区间,这限制了时钟的频率上限,而串行传输面对的问题则更加纯粹,不需要考虑这么复杂的问题。

image-20220625003544073

以 PATA 为例,它有十六根数据传输线,如果时钟频率能到 100MHz 那么它的传输速度上限就是 1600b/s 但是很遗憾几百 MHz 就是时钟频率当前的工艺上限了。当然实际实现的时候也会有一些其他的优化,但是即使是最新的 PATA 极限性能也只有 130MB/s。

SATA

Serial ATA (SATA) 应该是目前最常见的硬件接口类型之一了,是一种串行传输的接口,旨在取代老旧的 PATA 接口,众多半导体厂商一起创立了Serial ATA Working Group (SATA工作小组),并于 2000 年发布了 SATA 接口标准,之后 SATA 就顺其自然的占领了绝大部分的市场份额,在 2008 年一度占据了 99% 的 PC 磁盘份额,不过后面随着固态的普及,SATA 接口的性能也逐渐显得落伍了。

SATA 迭代至今总共推出了三个大版本,SATA 1.0、SATA 2.0、SATA 3.0,各自的性能上限分别为 150MB/s 300MB/s 600MB/s。

另外 SATA 还衍生出来了适用于特定场景的变种,但是基本都没能获得太大的成功:

  • mSATA (Mini SATA)小型化了,对移动设备更加友好,M.2 普及后就逐渐销声匿迹了
  • eSATA(External SATA)适用于移动外接设备的 SATA 接口,对标 USB 系列,很显然绝大部分人都只听过后者
  • SATA Express 基于 PCIe 总线的 SATA 接口,但是大家通常会选择直接用没有 ATA 包袱的 M.2

image-20220624103238209

M.2

M.2 原名 NGFF (Next Generation Form Factor),最早是由 Intel 用以取代 mSATA 同时推进系统小型化的一种全新接口规范。

目前随着固态硬盘的普及,M.2 接口的磁盘也越来越常见,大家通常会觉得上了 M.2 接口的硬盘就一定很快,但是除了 NVMe 协议,出现使用 SATA 协议的 M.2 磁盘也不是完全不可能出现的。

USB

通用串行总线Universal Serial Bus)是一种为外部设备连接设计的总线,首先从定义上而言它是一种“总线”,这里既包括了内部通往南桥的计算机内部的总线,计算机外部的“USB数据线”也同样在此规范的范畴内,同时 USB 标准中也包含了物理接口的规范。

在 USB 诞生之前,当时各种各样的外部电子设备,如鼠标、键盘、打印机、照相机等各自都有各自的接口标准,给用户带来了极大的困扰,所以 USB 就应运而生了,目前 USB 已经几乎完全统一了所有的外部设备接口市场,甚至相当多的非数据传输纯供电场景,比如小台灯、风扇之类的也在使用。

虽然我们可能感觉还是有好几种接口,但是其实它们都是 USB,只是不同的子类别而已:

类别 Type-A Type-B Type-C Mini-A Mini-B Mini-AB Micro-A Micro-B Micro-AB
插头(公头) 2.0 USB Type-A.svg USB Type-B.svg 不存在 USB Mini-A.svg USB Mini-B.svg 不存在 USB Micro-A.svg USB Micro-B.svg 不存在
3.2 USB 3.0 Type-A blue.svg USB 3.0 Type-B blue.svg USB Type-C icon.svg 已弃用 已弃用 已弃用 USB 3.0 Micro-B.svg
插座(母头) 2.0 USB Type-A receptacle.svg USB Type-B receptacle.svg 不存在 USB Mini-A receptacle.svg USB Mini-B receptacle.svg USB Mini-AB receptacle.svg 不存在 USB Micro-B receptacle.svg USB Micro-AB receptacle.svg
3.2 USB 3.0 Type-A receptacle blue.svg USB 3.0 Type-B receptacle blue.svg USB Type-C receptacle.svg 已弃用 已弃用 已弃用 USB 3.0 Micro-B receptacle.svg 已弃用
应用范围 计算机 扫描仪、打印机等 新式计算机、移动电话、平板电脑等 旧式便携设备 仅作为万能接头 移动电话、平板电脑等 仅作为万能接头

总线: BUS

总线是计算机内部设备和设备之间通信的线路,比如磁盘到内存、内存到 CPU之间的信号和数据的传输。

SATA

SATA 总线是 SATA 系列规范中的一员,是一种半双工总线。

和 USB 总线一样,SATA 也是通过南桥芯片连到 CPU 上。

PCIe

PCI Express,是 PCI 总线基础上诞生的一个高级版本。

PCIe 在设计上性能相对于 SATA 总线有非常大的优势,目前 PCIe 6.0 版本 4 通道理论的性能上限已经达到了 31.51 GB/s。

PCIe 是多通道的,一组 PCIe 总线最多可以有 32 个通道,每个都通可以独立全双工通信,因此传输效果可以随通道数量线性叠加,比如显卡这种对性能要求高的通常会一次性分配 16 个通道给其使用,而硬盘则四个通道就已经非常

协议: PROTOCOL

SCSI

SCSI (Small Computer System Interface) 在设计上是一种通用设备通信协议,但是目前主要还是用在存储设备上,以块为单位控制存储设备读写数据。

SCSI 也是一种经典的客户端/服务器 架构,在 SCSI 协议的概念中,客户端被称为 Initiator,服务端被叫做 Target,一个Target内部可能还有多种逻辑设备(LUN: Logic Unit)。

客户端向服务的请求被称为 CDB (Command Descriptor Block),每个 CDB 包含一个长为一字节的操作码,以及操作码附带的一些参数,操作码代表了这是一个什么请求,目前总共有 60 多种,比如常见的:WRITE、READ、Read capacity 、Inquiry、Start/Stop 等等。

SCSI

除此之外,SCSI 还存在一些变种,比如许多分布式块存储(Ceph、Longhorn、OpenEBS等)都在使用的能在 TCP/IP 协议栈上传输的 iSCSI (Internet SCSI) 协议等。

AHCI

AHCI (Advanced Host Controller Interface) 和 SCSI 比较像,是从 SATA 3 规范中单独剥离出来的上层传输协议,目前也主要还是配合 SATA 总线在使用,SATA 硬盘当下市场占用量还是不小的,所以 AHCI 协议也还是比较常见的。

NVMe

NVMe (Non-Volatile Memory Express) ,NVE 非易失性存储通常是指断电后数据不会丢失的半导体存储,即 FLASH,FLASH 颗粒是固态硬盘的底层存储介质,所以我们通过名字就不难知道,这是一种为了 SSD 存储场景设计的传输协议。

在固态硬盘发展初期,固态硬盘都是和机械硬盘一样用着 SATA 接口,然后通过 AHCI 协议传输,但是随着固态硬盘工艺发展带来的性能提升,这些为了传统机械硬盘设计的规范逐渐成为了制约性能继续提升的瓶颈,所以后来就有了 NVMe 协议。

不像 SCSI/AHCI 命令请求都是单队列,队列深度也只有 32/64,而NVMe 最多支持 64k 条深度为 64k 的队列;同时 NVMe 读写的指令则更加精简,可以用更少的交互次数完成读写请求;此外 NVMe支持同时从多核处理器接受命令和优先处理请求,这样能更加充分地发挥现代多核处理的性能。

和 SCSI 一样,NVMe 在设计时也不是绑定在 PCIe 总线的,NVMe over TCP、NVMe over RDMA 目前逐渐被许多追求极致性能的分布式块存储采用。

逻辑结构

上面说完了磁盘的物理结构,其实现可以说是五花八门的,但是其实干的其实就是存数据这一件事,所以操作系统引入了一种统一的逻辑结构来更好的操作磁盘。

寻址

首先最关键的问题就是寻址,即:我的数据存在哪里?

目前主流的寻址算法是 LBA (Logic Block Accessing),把磁盘分成 512 字节的一个个块(有的标准中块大小也可能是 1024 或者 2028 字节),然后用一个正整数来标识块的编号,当操作系统要访问一块具体的数据时,只需要告知磁盘控制器快号,磁盘控制器就会根据块号换算出来其对应的物理地址(比如柱面、磁头、扇区)。

其实这种逻辑结构跟内存一样,用一个一维数组来表示数据的位置,不过磁盘的一个单元是 512B 而内存则是 1B。

早期还存在一种过 CHS (Cylinder/Head/Sector)寻址方式,但是存在 8GB 的大小限制而且也耦合于旋转式磁面盘这一种介质,所以很快就被 LBA 所取代了。

分区与引导

明确了地址管理机制之后,人们又在磁盘上迭代了两个高级逻辑功能:分区和引导。

分区是在底层磁盘空间之上的一层逻辑抽象,能把一个磁盘在逻辑上分成几个区,分区之间容量和数据都是隔离的。

有了分区之后我们就能在一块盘上不同的分区用不同的文件系统、或者装几个操作系统,而且彼此之间完全隔离,即使一个分区使用不当甚至是损坏也不会影响到其他的分区。比如我们使用 Windows 电脑的时候拿到新电脑的第一件事情就是分区,C 盘用来装系统,其他盘装数据,这样电脑重装系统了其他盘中数据也不会受影响。

磁盘开头的一段空间会记录这块盘上的分区信息,常见分区信息的组织格式有两个:MBRGPT

MBR 早期电脑用得比较多,但是存在分区数和卷大小的限制,数据相对来说也比较容易损坏,所以后面有了 GPT,目前新的电脑上 MBR 就比较少见了,除非引导程序还是老的 BIOS 出于兼容性考虑。

GPT 出于兼容性考虑,避免不支持 GPT 的系统直接识别成坏盘导致数据丢失,磁盘的第一个扇区(前 512 字节)还是留给了 MBR,不过只做保护用,分区数据还是写入在之后的空间中。

诞生时间 最大分区大小 最大主分区数 总大小
MBR (Master Boot Record) 1983 2TB 4 512字节
GPT (GUID Partition Table ) 1998 18 EB 128 -

大致的磁盘逻辑结构如下图所示,至于每个分区里面的逻辑结构,这就是文件系统负责去组织的事情了。

未命名文件(5)

我们的操作系统那一堆数据也是需要放到磁盘上的,但是分区之后这就引入了另一个问题,如果一块盘上两个分区一个装了 Linux 一个装了 Windows 该选择加载哪一个系统呢?

所以磁盘还有一个引导的功能,在开头第一个扇区的 MBR 区域内,有一段446 字节的空间,在 BIOS 根据配置的顺序尝试从该磁盘上加载操作系统时会被执行,比如我们常见的 grub、windows BOOTMGR 等,由用户配置引导程序来决定要启动哪个系统。

RAID

磁盘相对于其他计算机硬件而言其实算是非常容易损坏的,为了减少潜在的磁盘损坏带来的影响,大家自然而然就有了把一份数据放多块盘上,一块坏了另一块顶上这种朴素的想法,后来不断规范化之后,就有了我们现在的 RAID 系列标准。

RAID (Redundant Array of Independent Disks) 冗余磁盘阵列,依据磁盘排列组合的方式不同,分为 0到6 7个级别,目前 0 1 5 6 会比较常见一点。

raid

RAID0

就是简单地把磁盘组合一起形成一块大盘,数据并没有任何冗余,甚至危险性还提升了,因为任何一块盘不可用都会导致整个 RAID 后的盘数据全部丢失,好处就是文件会散落多块盘上,整体的 IOPS 和带宽都会提升,适合对性能和容量要求比较高的临时存储场景,或者有的主板只能通过 RAID 插盘又不想做 RAID 浪费空间的话可以做单盘 RAID 0。

RAID1

RAID 1 会把一块磁盘中的数据完全复制到另一块磁盘中,虽然会浪费一半的空间,甚至会损耗部分写性能,但是只有两块盘又想要可用的时候就只能考虑 RAID 1了,通常我们做服务器系统盘的时候会考虑这种方式。

RAID 5

RAID 5 会在每一块盘中存一部分数据的奇偶校验码,这样即使一块盘挂了,也能根据其他盘的数据和奇偶校验码算出来缺失的数据进行恢复,至少需要三块盘,综合成本、性能、可用性下的最佳选择。

RAID 6

RAID 6 在 5 的基础上又引入了一种校验码,能容忍两块盘挂掉,至少需要 4 块盘。

RAID 组合

最基础的 RAID 级别就只有 0-6 这 7种了,但是 RAID 之间也是能组合的,比如常见的 RAID 10,就是先做 RAID 1 把盘两两一组互备,然后再做RAID 0 拼成一块,类似的还有 RAID 50、RAID 60 等等。

整体对比

RAID等级 最少硬盘 最大容错 可用容量 读取性能 写入性能 安全性 目的 应用产业
单一硬盘 (参考) 0 1 1 1
0 2 0 n n n 一个硬盘异常,全部硬盘都会异常 追求最大容量、速度 视频剪接缓存用途
1 2 n-1 1 n 1 高,一个正常即可 追求最大安全性 个人、企业备份
5 3 1 n-1 n-1 n-1 中下至中 追求最大容量、最小预算 个人、小型企业备份
6 4 2 n-2 n-2 n-2 中至中高,仅安全性较RAID 5高 同RAID 5,但较安全 个人、企业备份
10 4 综合RAID 0/1优点,理论速度较快 大型数据库、服务器
50 6 提升资料安全
60 8 提升资料安全

文件系统

磁盘只是提供了最基本的基于块的读写接口,它只关心怎么保存好写入进来的 01 比特流,而我们日常使用时肯定不可能直接肉眼去使用比特流,所以中间还需要引入一层抽象——文件系统。

文件系统提供了目录文件这种虚拟的概念,替我们屏蔽了底层磁盘的细节,使得我们不需要再关心我们的数据到底存在物理上哪个磁道哪个扇区等。

我们可以通过cat /proc/filesystems来查看当前内核支持的文件系统。

常见的文件系统如下:

开发者 诞生时间 最大文件大小 最大卷大小 稀疏文件 硬链接 Copy On Write
ZFS Sun 2004 16 EB 256 ZB
EXT4 - 2006 16 TB 1 EB
NTFS Microsoft 1993 16 EB 16 EB
BtrFS Oracle 2007 16 EB 16 EB
exFAT Microsoft 2006 127 PB 64 ZB
FAT32 Microsoft 1996 2 GB 2 TB
XFS Silicon Graphics 1994 8 EB 8 EB
APFS Apple 2017 8 EB
HFS Apple 1985 2 GB 2 TB

XFS

XFS 是一款为了最大化并行 IO 能力和支持海量存储场景而设计的高性能文件系统,于内核 2.4 版本合入主线,我们很熟悉的发行版 CentOS 7 的默认文件系统就是 XFS。

一个 XFS 文件系统会被分为一些大小相同的 Allocation Group,在初始化文件系统时指定,默认是 4 个;每个 AG 可以视为一个单独的文件系统,每个 AG 有自己独立的 B+ 树数据结构维护着其空闲块列表、inodes 等元信息,可以很大程度上的提升系统的并发度。

XFS 文件通过 Extent 数组来管理真实数据所在的块,在文件大到一定程度会转化为一棵 B+ 树,这使得 XFS 能很好的应对巨型文件。

XFS 支持 WAL 日志,会在写入变更之前把元数据先写日志,降低了元数据断电丢失导致系统出现不一致,引起文件系统崩溃的风险。

不过 XFS 文件系统一旦创建就无法缩容,只能扩容,好在通常我们也比较少会遇到需要缩容的场景。

EXT

EXT (Extended Filesystem) 目前总共有四代文件系统了:ext1、ext2、ext3、ext4,Linux 阵营的元老级文件系统了,ext4 目前仍广泛活跃于互联网世界众多服务器之中,虽然目前可扩展性和巨大规模场景略显不足,新特性上支持也比较少,但是论稳定性而言还是非常靠谱的。

FAT

FAT 系列文件系统是微软为了 windows 不断迭代设计的一系列文件系统,有 FAT12FAT16FAT32ExFAT 四名成员。不过后面其固定硬盘的份额逐渐被 NTFS 所取代,目前主要活跃于移动存储领域。

FAT 文件系统由四部分区域组成:保留扇区文件分配表根目录区域数据区域

FAT 系列是用簇(Cluster, 默认 4K) 来做为存储的最小单元,使用 File Allocation Table 表来记录簇号,各个表项之间串成一条条链表。

另外 FAT 系列有一个很实用的点在于,它是同时被 Windows 和 OS X 原生支持的,所以用来格式化到移动存储设备上在两种系统传输文件就很方便,不过其不支持日志记录,所以在使用移动设备时注意不要直接拔出设备,系统损坏的风险会比较大。

NTFS

NTFS (New Technology File System) 是我们目前绝大多数 windows 设备的默认文件系统,广泛的运行于大量个人电脑上。

磁盘性能测试

拿到一块磁盘之后,知道它的性能大概是什么样的,确认厂商提供给我们的参数有没有虚标,这个时候我们可以使用一些工具来对磁盘进行性能测试。

最常用的磁盘性能测试工具莫过于 fio (Flexible IO Tester)了,它支持非常多的参数以只支持不同场景的测试需求,具体各参数用法可以参考其官方文档:https://fio.readthedocs.io/en/latest/fio_doc.htm。

这里我们一起来看一个顺序读性能测试的例子。

先安装 fio:yum install fio -y或者apt-get install fio

然后准备我们的测试命令:

fio -directory=/root/test-dir  \ # 测试的目录,会在该目录下生成测试文件,需要确保该目录在目标测试磁盘上
    -rw=read \   # IO模式(读测试 or 写测试),常见项:read write randwrite randrw
    -bs=4k \   # blocksize IO 的块大小,默认为 4KB
    -direct=1 \  # 设置开启 Direct ID,不走内核缓存,只看磁盘本身的性能
    -time_based=1 \ # 根据运行时长来停止程序
    -runtime=120 \ # 运行时间 120 秒
    -name=core-test \ # 这个任务的名称,随便起
    -numjobs=1 \ # 并发任务数量 
    -nrfiles=1 \ # 文件数量,测大文件顺序读写可以设置为1,测小文件场景时设置为多个
    -size=1000M # 总共测试的文件大小

命令设置的是运行 120 秒,两分钟后我们就能拿到测试报告了,如下图所示,图中标红的就是我们最关心的核心指标:带宽和 IOPS:

image-20220706220542878

磁盘性能监控

除了在刚拿到磁盘之后的性能测试,在线上运行期间对磁盘的性能进行监控,及时暴露问题也是很有必要的。

iostat

iostat 是一个可以用来查看磁盘瞬时状态的命令行工具,各大发行版应该都有预装,它的数据来源主要来源于 /proc/diskstats文件。

输入 iostat -x 即可看到每块磁盘的详细监控指标:

root@cloudnative-core:~ # iostat -x
Linux 3.10.0-862.14.4.el7.x86_64 (cloudnative-core) 	09/09/2022 	_x86_64_	(4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          40.98    0.02    2.18    0.03    0.00   56.79

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
vda               0.00     3.42    0.35    5.16    12.82    59.64    26.32     0.02  qq  4.27    3.99    4.29   0.35   0.19
vdb               0.00     0.20    0.29    0.37     7.86    48.93   172.0     0.02   28.85    8.11   45.05   0.63   0.04
scd0              0.00     0.00    0.00    0.00     0.00     0.00    17.45     0.00    0.31    0.31    0.00   0.30   0.00

磁盘设备相关列含义如下:

  • rrqm/s:每秒发起的读IO请求
  • wrqm/s:每秒发起的写IO请求/秒
  • r/s: 每秒完成的读 IO 数,即我们通常关注的 IOPS
  • w/s: 每秒完成的写 IO 数
  • rkB/s:每秒读了多少 KB 数据,即我们通常关注的 IO 带宽
  • wkB/s:每秒写了多少 KB 数据
  • avgrq-sz:每个请求的平均扇区数,一个扇区通常是 512B,所以如果 avgrq-sz172 的话,那么对应的平均请求大小就是 172*512B = 88.06KB,可以基于该参数分析使用该磁盘的业务 IO 场景是 大 IO 多还是小 IO 多
  • avgqu-sz:该磁盘的平均队列长度,即平均下来每秒在处理中 or 等待中的 IO 请求数量,可以基于此参数来判断磁盘的繁忙程度
  • await :IO 平均处理时间(包括在队列等待时间),单位毫秒
  • r_await: 读 IO 请求的平均处理时间(包括在队列等待时间),单位毫秒
  • w_await:写 IO 请求的平均处理时间(包括在队列等待时间),单位毫秒
  • svctm:已废弃
  • %util:(IO Usage Times) 该设备有 IO 的时间占比,100% 意味着设备所有的时间都有 IO 可能过载,不过通常现在的磁盘设备支持并发处理,所以就算每时每刻都在处理 IO 请求,也有可能是只有一个队列在处理其他的队列是空闲的,但是除了这种特殊的场景,大致也是能反映磁盘负载的

node-exporter

除了排除故障的瞬时监控,常驻监控也是有必要的,最常用的系统监控利器莫过于 node-exporter 了,node-exporter 会不断的捕获系统中各种指标,比如 CPU、内存、IO、网络等,然后由 prometheus 抓取存储在时序数据库中供监控或者报警组件查询。

iostat 中的指标基本都能在 node-exporter 提供的 metrics 中找到对应的映射:

  • rrqm/srate(node_disk_reads_merged_total[5m])
  • wrqm/srate(node_disk_writes_merged_total[5m])
  • r/s: rate(node_disk_reads_completed_total[5m])
  • w/s: rate(node_disk_writes_completed_total[5m])
  • rkB/srate(node_disk_read_bytes_total[5m]) / 1024
  • wkB/srate(node_disk_written_bytes_total[5m]) / 1024
  • avgrq-sz(rate(node_disk_read_bytes_total[5m]) + rate(node_disk_written_bytes_total[5m])) / (rate(node_disk_reads_completed_total[5m]) + rate(node_disk_writes_completed_total[5m]))
  • avgqu-szrate(node_disk_io_time_weighted_seconds_total[5m])
  • await(rate(node_disk_read_time_seconds_total[5m]) + rate(node_disk_write_time_seconds_total[5m])) / (rate(node_disk_reads_completed_total[5m]) + rate(node_disk_writes_completed_total[5m]))
  • r_awaitrate(node_disk_read_time_seconds_total[5m]) / rate(node_disk_reads_completed_total[5m])
  • w_awaitrate(node_disk_write_time_seconds_total[5m]) / rate(node_disk_writes_completed_total[5m])
  • svctm:已废弃
  • %utilrate(node_disk_io_time_seconds_total[5m])