2023年3月

vRealize Operations Manager 安全补丁修复

背景:
记录一次安全同事在检测中发现 vRealize Operations Manager 存在安全漏洞,需要整改修复,于是到VMware官网找到对应版本vRealize Operations Manager的最新安全补丁下载并修复。

参考链接:
vRealize Operations 8.4 Security Patch for VMSA-2021-0018 (85383) (vmware.com)

操作过程

升级前准备工作

注意:
升级前先给vRealize Operations Manager所在虚拟机创建快照,防止修复失败导致平台不可用。

查看vRealize Operations Manager当前版本(浏览器输入vRealize Operations Manager的ip地址,回车,输入admin账号密码登录)

升级过程工作

1.下载最新安全补丁。


https://customerconnect.vmware.com/patch#search
下载vRealize Operations 8.4 Security Patch PAK文件。(需要VMware账号)

2.登录集群主节点vRealize Operations Manager管理员界面(
https://master-node-FODN-or-IP-address/admin
)。

注意:
这里网址需要注意不能直接在浏览器输入vROM的ip就打开,需要ip地址加上admin(https://ip-address/admin)

3.单击左侧面板中的Software Update。

4. 在主面板上单击“安装软件更新”。

5. 按照向导中的步骤定位并安装PAK文件。

6. 安装产品更新PAK文件。等待软件更新完成。期间,管理员界面会将你注销。

根据提示,下一步下一步直到安装就行。安装修复过程约半个小时。

7. 重新登录主节点管理员界面。弹出“Cluster Status”主界面,集群自动上线。状态页面还显示“联机”按钮,但不要单击它。

8. 清除浏览器缓存,如果浏览器页面没有自动刷新,请刷新页面。集群状态变为“在线”。当集群状态变为“在线”时,表示升级完成。(注意:在PAK文件更新的安装过程中,如果集群失败,状态变为离线,那么一些节点将不可用。要解决此问题,您可以访问“管理员”界面,手动使集群脱机,然后单击“完成安装”继续安装过程。)

9. 单击“软件更新”检查更新是否完成。在主窗格中出现一条指示更新成功完成的消息。

安全补丁修复后,vRealize Operations Manager版本号。

官方解决方案

vRealize Operations 8.4 Security Patch for VMSA-2021-0018 (85383)

Important
:

Resolution

  1. Download the vRealize Operations 8.4 Security Patch PAK file from the VMware
    Patch Portal
    .

Note
: Select
vRealize Operations Manager
as the
Product
and select
8.4.0
as the
version
and click
Search
.
Select the option below.

  1. Log in to the primary node vRealize Operations Manager Administrator interface of your cluster at https://master-node-FQDN-or-IP-address/admin.
  2. Click
    Software Update
    in the left panel.
  3. Click
    Install a Software Update
    in the main panel.
  4. Follow the steps in the wizard to locate and install your PAK file.
  5. Install the product update PAK file.
    Wait for the software update to complete. When it does, the Administrator interface logs you out.
  6. Log back into the primary node Administrator interface.
    The main Cluster Status page appears and cluster goes online automatically. The status page also displays the Bring Online button, but do not click it.
  7. Clear the browser caches and if the browser page does not refresh automatically, refresh the page.
    The cluster status changes to Going Online. When the cluster status changes to Online, the upgrade is complete.

    Note
    : If a cluster fails and the status changes to offline during the installation process of a PAK file update then some nodes become unavailable. To fix this, you can access the Administrator interface and manually take the cluster offline and click Finish Installation to continue the installation process.
  8. Click
    Software Update
    to check that the update is done.
    A message indicating that the update completed successfully appears in the main pane.

Once the update is complete delete the snapshots you made before the software update.

系列文章目录和关于我

一丶CPU的虚拟化

一个桃子,我们称之为物理(physical)桃子。但有很多想吃这个桃子的 人,我们希望向每个想吃的人提供一个属于他的桃子,这样才能皆大欢喜。我们把给每个 人的桃子称为虚拟(virtual)桃子。我们通过某种方式,从这个物理桃子创造出许多虚拟桃子。重要的是,在这种假象中,每个人看起来都有一个物理桃子,但实际上不是。

以最基本的计算机资源 CPU 为例, 假设一个计算机只有一个 CPU(尽管现代计算机一般拥有 2 个、4 个或者更多 CPU),虚拟化要做的就是将这个 CPU 虚拟成多个虚拟 CPU 并分给每一个进程使用,因此,每个应用都以为自己在独占 CPU,但实际上只有一个 CPU。这便是CPU的虚拟化

二丶进程

1.概念

进程就是运行中的程序
。程序本身是没有生命周期的,它只是存在磁盘上面的一些指令(也可能是一些静态数据)。是操作系统让这些字节运行起来,让程序发挥作用。

2.进程的机器状态

程序在运行时可以读取或更新的内容。在任何时刻,机器的哪些部分对执行该程序很重要(进程执行过程中会使用到机器的哪些部分)

  • 内存

    指令存在内存中。正在运行的程序读取和写入的数据也在内存中。因此进程可以访问的内存(称为地址空间,address space) 是该进程的一部分

  • 寄存器

    许多指令明确地读取或更新寄存器

  • 程序计数器

    代表程序当前正在执行哪个指令;类似地,栈指针(stack pointer)和相关的帧指针(frame pointer)用于 管理函数参数栈、局部变量和返回地址。

  • 持久存储设备

    此类 I/O 信息可能包含当前打开的文件列表

3.时分共享

通过让一个进程只运行一个时间片,然后切换到其他进程,操作系统提供了存在多个虚拟 CPU 的假象。这就是时分共享(time sharing)CPU 技术。

磁盘空间是一个空分共享资源,因为一旦将块分配给文件,在用户删除文件之前,不可能将它分配给其他文件。

4.程序如何转化为进程

操作系统如何启动并运行一个程序?进程创建实际如何进行?

  • 程序最初以某种可执行格式驻留在磁盘上

    操作系统需要将代码和所有静态数据(例如初始化变量)加载(load)到内存中,加载到进程的地址空间中

    image-20230306072917581

  • 为进程分配空间

    为程序的运行时栈分配一些内存。程序使用栈存放局部变量、函数参数和返回地址。操作系统分配这些内存,并提供给进程。

  • 为程序的堆分配一些内存

    C语言程序通过调用
    malloc()
    来请求这样的空间

  • 其他初始化任务

    如在UNIX系统中,默认情况下每个进程都有 3 个打开的文件描述符(file descriptor),用于标 准输入、输出和错误。这些描述符让程序轻松读取来自终端的输入以及打印输出到屏幕。

    操作系统需要初始化这三个文件描述符

5.进程的状态

image-20230306073241109

  • 运行

在运行状态下,进程正在处理器上运行。这意味着它正在执行 指令。

  • 就绪

在就绪状态下,进程已
准备好运行
,但没有被CPU进行调度

  • 阻塞

在阻塞状态下,一个进程执行了某种操作,直到发生其他事件时才会准备运行。一个常见的例子是,当进程向磁盘发起 I/O 请求时,它会被阻塞, 因此其他进程可以使用处理器。

为了跟踪每个进程的状态,操作系统使用
进程列表
,跟踪当前正在运行的进程的一些附加信息。操作系统还必须以某种方式跟踪被阻塞的进程(当 I/O 事件完成时,操作系统应确保唤醒正确的进程,让它准备好再次运行)

对于停止的进程,寄存器上下文将保存其寄存器的内容。当一个进程停止时,它的寄存器将被保存到这个内存位置。 通过恢复这些寄存器(将它们的值放回实际的物理寄存器中),操作系统实现恢复运行该进程。

僵尸状态:一个进程处于已退出但尚未清理的最终状态。其他进程(通常是创建进程的父进程)可以检查僵尸进程的返回代码,并查看刚刚完成的进程是否成功执行。

6.进程API

6.1.fork

image-20230320166666647399

调用fork函数,父进程fork函数返回的是子进程的进程id,子进程将返回0,如果返回小于0的数表示fork失败。

6.2.exec

使用exec系统调用,需要给定可执行程序的名称以及需要的参数,随后exec将从可执行程序中加载代码和静态数据,并用它复写自己的代码段,静态数据,堆,栈以及其他内存空间也会被重新初始化,然后操作系统就执行该程序。

因此exec()并没有创建新进程,而是直接将运行的程序替换成另一个程序。

6.4.wait

父进程调用 wait(),延迟自己的执行,直到子进程执行完毕。当子进程结束时,父进程才从wait返回。

三丶进程的调度

为了虚拟化 CPU,操作系统需要以某种方式让许多进程共享物理 CPU,让它们看起来
像是同时运行
。操作系统使用时分共享:
运行一个进程一段时间,然后运行另一个进程
实现cpu的虚拟化。

实现时分共享面临的挑战:

  • 性能

    如何在不增加系统开销的情况下,实现虚拟化cpu

  • 控制权

    如何有效地运行进程,同时保留对 CPU 的控制?控制权对于操作系统尤为重要,因为操作系统负责资源管理。如果没有控制权,一个进程可以简单地无限制运行并接管机器,或访问没有权限的信息。因此,在保持控制权的 同时获得高性能,这是构建操作系统的主要挑战之一。

1.用户态/内核态

  • 用户模式

    此模式下运行的代码会受到限制。例如,在用户模式下运行时,进程不能发出 I/O 请求。这 样做会导致处理器引发异常,操作系统可能会终止进程。

    应用程序在用户态下无法完全的访问硬件资源。

  • 内核模式

    与用户模式不同的内核模式,操作系统(或内核)就以这种模式运行。在此模式下操作系统可以访问机器的全部资源。

如果用户态的进程希望执行一些特权操作(比如读取磁盘),那么需要执行操作系统向外提供的
系统调用

要执行系统调用,程序必须执行特殊的
陷阱指令
。执行陷阱指令可以切换到内核态,完成指令后,操作系统将调用一个特殊的
从陷阱返回
指令,该指令会返回到发起调用的用户程序中,同时将 特权级别降低,回到用户模式。

image-20230320163811459

在 x86 上执行陷阱指令时,处理器会将程序计数器、标志和其他一些寄存器中的信息保存到每个进程的
内核栈
上。从陷阱中返回时将从栈弹出这些值,并恢复执行用户模式程序。

image-20230320164045240

2.进程切换

2.1 协作和抢占

  • 协作模式

    操作系统相信系统的进程会合理运行。运行时间过长的进程被假定会定期放弃 CPU,以便操作系统可以决定运行其他任务。

    进程通过调用系统调用的方式将cpu控制权转移给操作系统,例如使用yield系统调用。

  • 抢占模式

    操心系统通过
    时钟中断
    ,时钟设备可以编程为每隔几毫秒产生一次中断。产生中断时,当前正在运行的进程停止,
    操作系统中预先配置的中断处理程序会运行
    。此时,操作系统重新获得 CPU 的控制权,可以进行进程切换。

2.2 上下文切换

当操作系统进行进程切换的时候,需要

  • 为当前执行的线程

    来保存
    通用寄存器

    程序计数器
    ,以及当前正在运行的进程的
    内核栈指针

  • 为即将执行的进程

    恢复寄存器

    程序计数器
    ,并
    切换内核栈
    ,供即将运行的进程使用

image-20230320170607859

3.进程调度算法

3.1 衡量算法的指标

  • 周转时长

    完成时间 - 到达时间

  • 响应时间

    首次运行 - 到达时间

  • CPU利用率

    cpu执行任务时间/总cpu时间

  • 吞吐量

    完成任务数量/执行任务花费的时间

3.2 算法

3.2.1 先进先出/先到先服务
  • 优点:简单,而且易于实现。
  • 缺点:一些耗时较少的潜在资源消费者被排在重量级的资源消费者之后。当大任务排在小任务前的时候,小任务的周转时长指标很差劲
3.2.1 最短任务优先

这种策略在所有任务都是一起到达的时候,周转时长指标很优秀 。但是现实情况下,大任务可能比小任务先到达。这是由于最短任务优先是一个非抢占式的调度算法。

3.3.3 最短完成时间优先

受到最短任务优先的启发,在它之上加上调度程序的抢占行为,每当新工作进入系统时,它就会确定剩余工作和新工作中,
谁的剩余时间最少
,然后调度该工作

3.3.4 轮转

在一个
时间片
内运行一个工作,然后切换到运行队列中的下一个任务,而不是运行一个任务直到结束。它反复执行,直到所有任务完成。
时间片长度必须是时钟中断周期的倍数
。因此,如果时钟中断是每 10ms 中断一次, 则时间片可以是 10ms、20ms 或 10ms 的任何其他倍数。

时间片越短,那么在响应时间指标上更优先。但是频繁的上下文切换是影响整体上下文的。

轮转算法在周转时长指标上表现很糟糕,但是在进程执行io等操作时候进行轮转切换,这对于cpu的利用率和效率是有益的。

image-20230320173232314

如上图7.9在执行磁盘io操作的时候,操作系统调度其他的紧凑,让两个任务执行总时间更短。

3.3.5 多级反馈队列

多级反馈队列中有许多
独立的队列

每个队列有不同的优先级
。任何 时刻,一个工作只能存在于一个队列中。多级反馈队列总是优先执行较高优先级的工作(即在较高级队列中的工作)。同一个队列中的任务具备相同的优先级,相同优先级的任务使用
轮转

image-20230320173740536

多级反馈队列任务的优先级,会根据观察进程的行为进行调整。如果一个工作不断放弃 CPU 去等待键盘输入,这是交互型进程的可能行为, 因此会让它保持高优先级。相反,如果一个工作长时间地占用 CPU,会降低其优先级。

高优先级队列通常只有较短的时间片,因而这一层的交互工作(例如等待键盘输入这样的io操作)可以更快地切换。相反,低优先级队列中更多的是 CPU 密集型工作,配置更长的时间片会取得更好的效果

3.3.6 比例份额

基本思想很简单:每隔一段时间,都会举行一次彩票抽奖,以确定接下来应该运行哪个进程。越是应该频繁运行的进程,越是应该拥有更多地赢得彩票的机会。

彩票数代表了进程占有某个资源的份额。一个进程拥有的彩票数占总彩票数的百分比,就是它占有资源的份额。

一:硬盘存储

1、存储类型

根据存储的可以将存储分为内存和外存两类。

  • 内存:又叫做主存储器,计算机中所有程序的运行都是在内存中进行。

  • 外存:又叫做辅助存储器,因为内存容量小且断电会丢失所有数据。所以磁盘来实现数据的持久化存储。例如:硬盘,U盘,软盘,光盘

2、硬盘和磁盘:

磁盘是一个广泛的概念,是
一个总的称呼
,用来描述多种不同类型的存储介质,包括硬盘、软盘、光盘、闪存盘等等。

所以硬盘也可以被称为磁盘,因为硬盘也是一种磁性存储介质。

3、硬盘类型

根据存储原理的不同,可以将硬盘分为机械硬盘和固态硬盘两类。

  • 机械硬盘:HDD(Hard Disk Drive), 由物理盘片、磁头、控制电机、转轴等几部分组成。

  • 固态硬盘:SSD(Solid State Drive) ,用固态电子存储芯片阵列而制成的硬盘。

image

4、接口类型

从整体的角度上,硬盘接口分为IDE、SCSI、STAT、USB、M.2等类型。

  • IDE
    :133MB/s,并行接口,早期家用电脑接口(淘汰了)
  • SCSI
    :640MB/s,并行接口,早期服务器用的接口
  • SATA
    :6Gbps,SATA数据端口与电源端口是分开的,即需要两条线,一条数据线,一条电源线, 一般的家用电脑的接口
  • SAS
    :6Gbps,SAS是一整条线,数据端口与电源端口是一体化的,SAS中是包含供电线的,而SATA中不包含供电线。SATA标准其实是SAS标准的一个子集,二者可兼容,SATA硬盘可以插入SAS主板上,反之不行。
  • USB
    :Universal Serial Bus,中文叫通用串行总线,480MB/s
  • M.2
    :M.2接口,是Intel推出的一种替代MSATA新的接口规范(
    M.2就是从笔记本诞生的
    )。可以兼容多种通信协议,如sata、PCIe、USB等。如果 M.2 插槽如果不支持特定的协议,相应的固态硬盘将无法识别和使用。
    image

image

5、硬盘尺寸

服务器使用的硬盘尺寸只要有两种,LFF和SFF。

  • LFF:3.5寸硬盘

  • SFF:2.5寸硬盘

image

6、数据的存储方式

机械硬盘存储数据的时候,是将数据存储在其内部的盘面上。盘面类似于DVD光盘,每个盘面划分成了一圈一圈的磁道,最外圈是0磁盘。然后每个磁盘有划分为了N多个小块,这个小块叫做扇区。扇区大小固定,是512byte。

image

0磁道0扇区:
指的就是最外面那个磁盘的第一个扇区,大小是512字节。

7、硬盘空间的使用

在服务器上加入一块新的硬盘后,需要经过分区、格式化和挂载才能正常使用硬盘的空间。

  • 硬盘分区:
    将一个物理硬盘在逻辑上分为多个硬盘,每一个逻辑硬盘就叫做一个分区。
  • 创建文件系统
    :硬盘或分区格式化的过程就是创建文件系统的过程。
  • 挂载新文件系统
    :将额外文件系统与根文件系统某现存的目录建立起关联关系,进而使得此目录做为其它文件访问入口的行为

8、硬盘的分区说明

将硬盘进行分区具备以下优点:

  • 便于数据管理,可以将操作系统、应用程序、用户数据等分别存储在不同的分区
  • 可以安装多个操作系统和使用不同的文件系统,将不同的操作系统安装在不同的分区中,这样可以避免不同操作系统之间的冲突。
  • 可以优化磁盘的性能,将操作系统、应用程序等放置在不同的分区中,可以避免数据碎片,提升硬盘读写速度。

对硬盘进行分区的时候有两种分区方式(MBR分区和GPT)分区,不同的分区方式具有不同的特点。

MBR分区:

Master Boot Record(主引导记录),1982年开发而来,使用32位表示扇区数,分区的大小不能超过2T,最多只能有四个主分区,如果需要使用更多的分区,可以将一个分区格式化为逻辑分区,再基于逻辑分区创建多个扩展分区。

硬盘使用MBR的分区类型方式后,会将整个硬盘的分区信息放在0磁道0扇区这个512字节大小的空间中,前446字节存放boot loader,中间64字节存放分区表信息。每16字节用来标识一个分区信息。最后2字节作为标志位。

MBR的三种分区类型

  • 主分区
    :primary。可以存放数据也可以装系统
  • 扩展分区
    :extended。不能直接存数据,需要在里面划分逻辑分区才能存放数据(相当于一个容器)
  • 逻辑分区
    :logical。作用和主分区一样

GPT分区:

GUID(Globals Unique Identifiers) partition table,最多支持128个分区,其中没有扩展分区的概念。每个分区都可以是主分区.每个分区的最大空间理论上可以达到9.4ZB。

BIOS和UEFI:

作用:BIOS和UEFI都是负责计算机硬件初始化、开机自检和引导操作系统。

  • BIOS:
    是只读内存(ROM)中的一段程序,这段程序叫做"基本输入输出系統"(BasicInput/Output System),简称为BIOS,计算机通电后,第一件事就是读取ROM芯片中的程序。
  • EFI:
    (Extensible Firmware Interface)可扩展固件接口,最初由Intel开发,是Intel的专有技术。是BIOS的升级版。
  • UEFI:
    (Unified Extensible Firmware Interface)统一的可扩展固件接口,是基于EFI标准的一个具体实现,并由多个公司共同推动和支持,现在UEFI是一个开放的标准,UEFI不再是intel的专有技术。

BIOS和UEFI的区别

  • BIOS只能引导传统的MBR分区,UEFI支持MBR、GPT等分区。
  • UEFI提供了Secure Boot(安全启动)功能,在启动过程中只加载由受信任的制造商签名的软件和驱动程序。
  • UEFI支持的硬件设备和接口更多,例如USB 3.0、NVMe、网络堆栈等
  • UFEI提供了图形界面,可以用鼠标操作,BIOS只能用键盘操作。
windows:只能安装 BIOS + MBR 或是 UEFI + GPT组合。

linux:可以实现 BIOS + GPT + GRUB 组合

Linux中的设备文件:

在linux中,一切及皆文件,包括硬件设备。硬件设备会被映射为
/dev
下面的一个文件设备文件。

设备文件根据存储单位的不同分为两种

  • 块设备文件:存储单位是block,例如硬盘。
  • 字符设备文件:存储单位是char,例如键盘。

设备文件的命令规则:

# SAS,SATA,SCSI,IDE,USB: /dev/sdX

# nvme协议: /dev/nvme0n#

# 虚拟磁盘: /dev/vd 或/dev/xvd

查看块设备文件:lsblk

tom@ubuntu1604:~$ lsblk -f
NAME   FSTYPE  LABEL                           UUID                                 MOUNTPOINT
sda                                                                                 
├─sda1 ext4                                    8a39188a-59cd-4899-b4c1-22aec246c18f /
├─sda2                                                                              
└─sda5 swap                                    4442a597-37c1-4639-bc25-881505c12d98 [SWAP]
sdb                                                                                 
├─sdb1 ntfs    老毛桃U盘                       1C98D9A698D97EA8                     
└─sdb2 vfat    EFI                             0BE8-0ECB                            
sr0    iso9660 Ubuntu-Server 16.04.6 LTS amd64 2019-02-27-00-06-32-00  

二:文件系统

1、文件系统的概念

文件系统就是在操作系统中
负责管理和存储文件信息的软件结构
称为文件管理系统。

文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索。

文件系统的创建:

硬盘或分区在进行格式化的过程,就是创建文件系统的过程。

windows 常用文件系统

  • FAT32
    :最多只能支持16TB的文件系统和4GB的文件
  • NTFS
    :New Technology File System。windows独有的文件系统,linux不支持。最多只能支持16EB的文件系统和16EB的文件
  • exFAT
    :Linux和windows都支持,时为了解决FAT32等不支持4G及其更大的文件而推出de1,适合于闪存的文件系统,例如U盘。

Linux 常用文件系统

  • ext系列:
    最新版本的时ext4,Ext4的文件系统容量达到1EB,而支持单个文件则达到16TB,理论上支持无限数量的子目录。
  • xfs:
    最大可以支持8EB的文件系统,而支持单个文件则达到8EB,能以接近裸设备I/O的性能存储数据。
  • swap:
    用于Linux的交换分区,在Linux中,使用整个交换分区来提供虚拟内存。
  • iso9660:
    光盘的文件系统类型

裸文件系统

  • raw:
    裸文件系统是指未经过格式化的磁盘分区或映像文件,因此它没有文件系统结构和元数据,也没有任何文件或目录可见。

裸文件系统是一个块设备,它可以像其他块设备一样进行读写操作,因此裸文件系统通常用于虚拟化环境中,作为虚拟机磁盘镜像的基础。

网络文件系统

  • NFS:
    (Network File System)网络文件系统,一般使用在局域网中。
  • CIFS:
    (Common Internet File System)通用过internet文件系统。

虚拟文件系统

  • VFS:
    为用户程序提供文件和文件系统操作的统一接口,屏蔽不同文件系统的差异和操作细节。
    image

例如:

使用ls查看磁盘上的文件,因为文件系统的功能是由操作系统的内核提供,应用程序是通过访问文件系统,然后文件系统再去访问具体的文件,但是不同文件系统底层是实现和区别差别可能非常大。所以程序的系统调用可能会不同,为了方便程序的统一调用,就就使用了虚拟文件系统提供统一的接口。

文件系统的组成

由三部分组成,分别是内核中的模块,虚拟文件系统和用户空间的管理工具。

  • 内核中的模块
    :提供对应文件系统的功能。例如ext4, xfs, vfat
  • Linux的虚拟文件系统
    :提供统一的接口。例如VFS
  • 用户空间的管理工具
    :提供对内核文件系统管理的工具。例如mkfs.ext4, mkfs.xfs,mkfs.vfat

查看当前系统支持的文件系统:

# 方法一:
ls -l  /lib/modules/`uname -r`/kernel/fs
# 方法二:
 cat /proc/filesystems

image

2、Inode 和 Block

当某个存储设备被格式化为EXT系列的文件系统后,文件系统会将磁盘空间分为两部分:inode区域和数据区域(也称为块区域)。

Inode区域:
存放文件的元数据信息

包含了若干了Inode,每个inode存放一个文件的元数据信息(文件大小、类型、权限、UID、GID、所有者、所属组等信息)和唯一的Inode编号,以及指向文件数据块的指针。

Block区域:
存放文件真正的数据部分

  1. ​ 存放文件的真正数据部分,数据区域被分割成一个个大小相等的块,每个块通常为4KB或8KB。
  2. ​ 目录块也是存储在数据区域中的一种特殊的数据块,它存储了一组目录项,每个目录项存放一个文件的文件名和Inode编号。
    image

例如:

当需要访问一个文件时,文件系统会通过目录项找到对应的inode,然后根据inode中的信息来读取或写入文件的内容。因此,目录项在文件系统中扮演了非常重要的角色,它们充当了文件和文件系统之间的桥梁。

删除某个目录就是把目录文件的数据块部分的文件列表和文件的节点编号的映射关系删除的过程

在EXT系列文件系统中创建文件流程:

  • 首先,文件系统会找到一个未使用的inode号码,并分配给新文件。inode包含文件的元数据,如权限、所有者、创建时间、修改时间等信息。
  • 然后,文件系统会找到一个或多个未使用的数据块,这些数据块将用于存储文件的实际内容。
  • 接着文件系统会将inode与数据块的信息记录在文件系统的元数据区域中,以便以后可以找到并访问它们。
  • 最后文件系统会将文件的名称和与该文件相关联的inode号码存储在目录中。目录是一个特殊的文件,它包含文件系统中所有文件和目录的列表。

3、软链接和硬链接

软链接:
类似于windows的快捷方式

image

特点:

  • 软链接和源文件不是同一个文件

  • 允许对目录文件创建软链接。

  • 支持跨设备和跨分区创建软链接。

  • 创建一个软链接到一个目录下,没有指定软连接的名字,那么软连接的名字和源文件名一致

硬链接:
一个文件多个文件名

image

特点:

  • 不允许对目录文件创建硬链接
  • 不能跨设备、跨分区,例如sda1的文件不能硬链接到sda2上面。

4、硬盘的分区工具

fdisk

使用fdisk创建硬盘分区的时候,默认会将硬盘的分区类型格式化为MBR格式的分区类型。

例如:

# 创建分区表
root@ubuntu1804:~# fdisk /dev/sdb 

Welcome to fdisk (util-linux 2.31.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n  # 创建一个分区表
Partition type 
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p  # 创建主分区
Partition number (1-4, default 1):  # 分区编号,
First sector (2048-41943039, default 2048):  # 不输入表示从当前位置开始
Last sector, +sectors or +size{K,M,G,T,P} (2048-41943039, default 41943039): +10G # 分区的大小

Created a new partition 1 of type 'Linux' and of size 10 GiB.

Command (m for help): p # 查看分区表的信息
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x3ea7c314

Device     Boot Start      End  Sectors Size Id Type
/dev/sdb1        2048 20973567 20971520  10G 83 Linux

Command (m for help): w # 保存设置并退出
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

# 删除分区表
root@ubuntu1804:~# fdisk /dev/sdb

Welcome to fdisk (util-linux 2.31.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x3ea7c314

Device     Boot    Start      End  Sectors Size Id Type
/dev/sdb1           2048 20973567 20971520  10G 83 Linux
/dev/sdb2       20973568 31459327 10485760   5G 83 Linux

Command (m for help): d # 删除分区表
Partition number (1,2, default 2): 2 # 删除的分区表编号 表示删除第二个分区

Partition 2 has been deleted.

Command (m for help): p 
Disk /dev/sdb: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x3ea7c314

Device     Boot Start      End  Sectors Size Id Type
/dev/sdb1        2048 20973567 20971520  10G 83 Linux

Command (m for help): w  #保存退出
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

gdisk

gdisk工具是默认会把硬盘的分区类型格式化为GPT类型。如果分区类型非gpt格式,会默认转换为gpt格式。

例如:

# 新建分区表
root@ubuntu1804:~# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): n
Partition number (1-128, default 1): 
First sector (34-41943006, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-41943006, default = 41943006) or {+-}size{KMGTP}: +2G
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.

# 删除分区表
root@ubuntu1804:~# gdisk /dev/sdb
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present  # 当前硬盘的分区类型

Found valid GPT with protective MBR; using GPT.

Command (? for help): p
Disk /dev/sdb: 41943040 sectors, 20.0 GiB
Model: VMware Virtual S
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): E0199E20-EDB2-43D1-B653-3E8080E547EA
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 41943006
Partitions will be aligned on 2048-sector boundaries
Total free space is 37748669 sectors (18.0 GiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         4196351   2.0 GiB     8300  Linux filesystem

Command (? for help): d 1  # 删除标号为1的分区表
Using 1

Command (? for help): w    # 保存退出

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y  # 确认更改
OK; writing new GUID partition table (GPT) to /dev/sdb.
The operation has completed successfully.

parted

parted工具可以管理gpt和mbr类型的分区表,其它的分区类型也可以管理,例如sun、bsd等。

注意:parted的操作都是实时生效的,需要小心使用。

例如:

# 新建分区表
root@ubuntu1804:~# parted /dev/sdb                                        
GNU Parted 3.2
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p          # 将硬盘分区类型改为gpt                                                           
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start  End  Size  File system  Name  Flags

(parted) mklabel gpt                                                      
Warning: The existing disk label on /dev/sdb will be destroyed and all data on this disk will be lost. Do you want to continue?
Yes/No? yes        # 确认更改                                                            
(parted) mkpart primary ext4 0% 20%  # mkpart 分区类型 文件系统类型 分区的开始位置 分区的结束位置  -1:表示磁盘的最后
(parted) mkpart primary ext4 20% 40%                                      
(parted) mkpart primary ext4 40% 70%                                     
(parted) p         # 查看分区表信息                                                      
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name     Flags
 1      1049kB  4295MB  4294MB  ext4         primary
 2      4295MB  8590MB  4295MB  ext4         primary
 3      8590MB  15.0GB  6442MB  ext4         primary

(parted) quit                                                             
Information: You may need to update /etc/fstab.


# 删除分区表        # 退出   
root@ubuntu1804:~# parted /dev/sdb                                        
GNU Parted 3.2
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p                                                                
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name     Flags
 1      1049kB  10.7GB  10.7GB               primary

(parted) rm 1        # rm 1 表示删除编号为1的分区表                                                       
(parted) quit                                                             
Information: You may need to update /etc/fstab.

查看分区类型:

  • blkid /dev/device
PTTYPE="dos" # MBR类型  
PTTYPE="gpt" # GPT类型
  • parted -l
Partition Table: msdos # MBR类型
Partition Table: gpt  # GPT类型
  • fdisk -l
Disklabel type: dos # MBR类型
Disklabel type: gpt # GPT类型

修改分区类型

  • MBR-->GPT
parted /dev/sdb
(parted) mklabel gpt 
  • GPT-->MBR
parted /dev/sdb
(parted) mklabel msdos

5、硬盘格式化工具

mkfs工具

mkfs是一个Linux/Unix操作系统中用于创建文件系统的命令行工具,它可以用于格式化磁盘或分区,以便在上面创建新的文件系统。

例如:

# 格式化硬盘为ext4文件系统
sudo mkfs.ext4 /dev/sdb 或 sudo mkfs -t ext4 /dev/sdb

# 指定Inode的数量
sudo mkfs -t ext4 -M 2000000 /dev/sdb

常用选项:

-t {ext2|ext3|ext4|xfs} 指定文件系统类型
-b {1024|2048|4096} 指定块 block 大小,默认4kb
-L ‘LABEL’ 设置卷标,便于在系统中识别。
-i  # 指定一个inode节点的大小;默认256字节,即一个block可以存放16个inode
-N  # 指定分区中创建多少个inode,默认inode空间占总空间的1%

硬盘挂载工具

硬盘挂载是将硬盘驱动器(例如硬盘、SSD等)连接到操作系统文件系统的过程,将某个硬盘驱动器挂载到文件系统后就可以对硬盘进行读写等操作。

mount工具

例如:

# 将/dev/sdb1挂载到/mnt/data  不指定文件系统类型,会自动进行检测
sudo mount /dev/sdb1 /mnt/data

#  挂载的时候手动指定文件系统的类型
sudo mount -t ntfs /dev/sdb1 /mnt/data

说明:

使用mount进行挂载的时候,如果确定了要挂载的文件系统的类型,使用-t参数指定文件系统类型可以确保系统以正确的方式挂载文件系统,避免可能的错误和问题。

如果挂载的时候不确定文件系统的类型,系统会对文件系统进行自动检测,但是当存在多个可能的文件系统类型时,系统可能会选择错误的类型导致挂载失败。

mount命令的常用参数:

-t fstype:指定文件系统类型,如果不指定会自动进行检测
-o <挂载选项>:指定挂载选项,多个选项用逗号隔开。
	# 挂载选项
		# ro  以只读方式挂载文件系统。
		# remount    重新挂载文件系统,相当于先umount再mount
		# defaults   使用默认的挂载选项,相当于rw, suid, dev, exec, auto, nouser, async
		# async    异步模式,内存更改时,写入缓存区buffer,过一段时间再写到磁盘中,效率高,但不安全
		# sync     同步模式,内存更改时,同时写磁盘,安全,但效率低下
		# noatime  指定文件系统不更新最后访问时间
		# _netdev   当网络可用时才对网络资源进行挂载,如:NFS文件系统,如果网络不可达不加该选项会导致系统无法启动。
-r:以只读方式挂载文件系统。
-w:以可读写方式挂载文件系统,默认就是以可读可写的方式挂载
-a 自动挂载所有支持自动挂载的设备(定义在了/etc/fstab文件中,且挂载选项中有auto功能)

noatime选项说明:

使用
noatime
选项可以禁止系统更新文件或目录的访问时间戳,即
atime
属性。当文件或目录被访问时,系统不会更新
atime
属性,而是保留原来的值,可以较少磁盘IO,提高文件系统的性能。

使用noatime的场景:

在某些高并发的应用中,可能会有大量的读取操作,如果每次读取都更新
atime
属性,会对系统的性能造成很大的影响。这种情况下可以考虑加noatime选项。

不能使用noatime的场景:

如果应用程序需要用到文件的访问时间,就不能使用
noatime
选项。因为使用
noatime
选项会禁止系统更新文件或目录的访问时间戳,即
atime
属性,这会导致应用程序无法获取文件的最后访问时间,从而影响应用程序的功能。

挂载规则说明:

  • 一个挂载点同一时间只能挂载一个设备,如果挂载了多个设备就只显示最后一个设备
  • 一个设备可以挂载到多个挂载点
  • 挂载点通常是空的目录文件

umount工具

umount用于卸载挂载的文件系统。

例如:

umount device 或 umount mountpoint

# 例如:
 umount /dev/sda1

查看挂载的设备

# 方法一:使用mount命令,会列出所有已挂载的设备及其挂载点
root@ubuntu1804:~# mount
/dev/sda5 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)

# 方法二:查看内核参数
root@ubuntu1804:~# cat /proc/mounts
/dev/sda1 /boot ext4 rw,relatime,data=ordered 0 0

# 方法三:df命令
root@ubuntu1804:~# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
udev           devtmpfs  954M     0  954M   0% /dev
tmpfs          tmpfs     198M   11M  187M   6% /run
/dev/sda5      ext4       58G  4.2G   51G   8% /
tmpfs          tmpfs     986M     0  986M   0% /dev/shm
tmpfs          tmpfs     5.0M     0  5.0M   0% /run/lock
tmpfs          tmpfs     986M     0  986M   0% /sys/fs/cgroup
/dev/sda1      ext4      922M   80M  780M  10% /boot
tmpfs          tmpfs     198M     0  198M   0% /run/user/0

持久挂载:

将挂载保存到
/etc/fstab
中可以下次开机时,自动启用挂载

#使用`man 5 fstab `查看/etc/fstab配置文件格式

# 格式
	device  mountpoint   fs_type  options   0  0 
# 例如:
	/dev/sdb1 /data ext4 defaults,noatime  0 0 
	# 表示将/dev/sdb1这个分区挂载到/data这个目录,并且使用默认的挂载选项,不进行本分和文件系统检查。

# 说明
    # 备份频率(一般用不上):0:不做备份 1:每天转储 2:每隔一天转储
	# 文件系统检查的次序:开机检测文件系统的过程。其中允许的数字是0 1 2
		# 0:不自检 ,1:首先自检;一般只有rootfs才用  2:非rootfs使用

6、移动设备的管理

当把u盘设备插入linux系统后,会被内核探测为SCSI设备,会被映射到/dev下作为一个设备文件。例如:/dev/sdaX、/dev/sdbX等。

  • 图形界面:usb设备会自动挂载到
    /run/media/
    路径下。

  • 字符界面:需要手动进行usb设备的挂载才能正常使用。

![image-20230319200153939](E:\学习文档\Linux文件权限管理\Linux 存储和文件系统\Linux 存储和文件系统_img\image-20230319200153939.png)

说明:
ubuntu默认支持识别 NTFS 文件系统格式的 U 盘,CentOS 默认情况下不支持识别 NTFS 文件系统格式的 U 盘。

如果不识别需要安装
ntfs-3g
软件包来支持 NTFS 格式的 U 盘。

插入u盘后可以通过系统日志看到相关信息:

root@ubuntu1804:~# tail -f /var/log/syslog

Mar 19 17:14:51 ubuntu1804 kernel: [ 5822.106369] usb 1-1: new high-speed USB device number 8 using ehci-pci
Mar 19 17:14:51 ubuntu1804 kernel: [ 5822.455825] usb 1-1: New USB device found, idVendor=0930, idProduct=6544
Mar 19 17:14:51 ubuntu1804 kernel: [ 5822.455827] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Mar 19 17:14:51 ubuntu1804 kernel: [ 5822.455828] usb 1-1: Product: DataTraveler 2.0
Mar 19 17:14:51 ubuntu1804 kernel: [ 5822.455829] usb 1-1: Manufacturer: Kingston
Mar 19 17:14:51 ubuntu1804 kernel: [ 5822.455829] usb 1-1: SerialNumber: 001BFC3653BCC341E91386F4
Mar 19 17:14:51 ubuntu1804 kernel: [ 5822.458677] usb-storage 1-1:1.0: USB Mass Storage device detected
Mar 19 17:14:51 ubuntu1804 kernel: [ 5822.458909] scsi host33: usb-storage 1-1:1.0
Mar 19 17:14:52 ubuntu1804 kernel: [ 5823.499865] scsi 33:0:0:0: Direct-Access     Kingston DataTraveler 2.0 1.00 PQ: 0 ANSI: 4
Mar 19 17:14:52 ubuntu1804 kernel: [ 5823.500256] sd 33:0:0:0: Attached scsi generic sg3 type 0
Mar 19 17:14:52 ubuntu1804 kernel: [ 5823.504780] sd 33:0:0:0: [sdc] 60549120 512-byte logical blocks: (31.0 GB/28.9 GiB)
Mar 19 17:14:52 ubuntu1804 kernel: [ 5823.507219] sd 33:0:0:0: [sdc] Write Protect is off
Mar 19 17:14:52 ubuntu1804 kernel: [ 5823.507220] sd 33:0:0:0: [sdc] Mode Sense: 45 00 00 00
Mar 19 17:14:52 ubuntu1804 kernel: [ 5823.509773] sd 33:0:0:0: [sdc] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
Mar 19 17:14:52 ubuntu1804 kernel: [ 5823.523647]  sdc: sdc1 sdc2
Mar 19 17:14:52 ubuntu1804 kernel: [ 5823.535055] sd 33:0:0:0: [sdc] Attached SCSI removable disk

lsusb工具

lsusb工具用于显示 USB 总线上连接的设备列表。使用
lsusb
可以查看连接到计算机上的 USB 设备列表。从而判断u盘设备是否插入了系统中。

例如:查看usb设备信息:

# usbutils工具包
root@ubuntu1804:~# lsusb 
Bus 001 Device 008: ID 0930:6544 Toshiba Corp. TransMemory-Mini / Kingston DataTraveler 2.0 Stick (2GB)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub
Bus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual Mouse
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

image

7、du和df使用说明

du
:disk usage。
一般是用来查看目录或指定文件的大小

选项:

-h               # 自动使用合适的单位进行显示,默认单位是kb
-s               # 显示指定目录或文件的总大小
--exclude=/path  # 用于排除指定的文件或目录

例如:

# 查看整个系统的大小,但不统计/sys和/proc这连个虚拟文件系统
    root@ecs-1746-0001:~# du -sh  --exclude='/proc' --exclude='/sys' /
    23G	/


# 统计某个目录下目录文件的大小 
    # 需要进入待统计的目录
    root@ecs-1746-0001:~# cd DeploySystem-Ubuntu-20.04/

    root@ecs-1746-0001:~/DeploySystem-Ubuntu-20.04# du -sh */ | sort -rh
    2.1G	packages/
    5.6M	lib/
    3.1M	phplib/
    156K	conf/
    48K	include/
    16K	job/
    4.0K	SourceCode/

# */通配符表示所有子目录

# 统计某个目录下每个文件的大小 
    # 1. 进入该目录
    root@ecs-1746-0001:~# cd DeploySystem-Ubuntu-20.04/
    # 2. 进行统计
    root@ecs-1746-0001:~/DeploySystem-Ubuntu-20.04# du -ah --exclude='{'.','..'}'  */   | sort -rh | more

    # --exclude='{'.','..'}'表示不统计.和..文件 
    # */通配符表示所有子目录

df:
disk free,主要用来查看挂载了的文件系统情况。

注意:
df看到的文件系统中真实占用的空间大小,而非表面上的空间大小。因为文件系统本身就有元数据,所以即使是刚创建的干净文件系统,也会占用一定的空间

选项:

-h:自动使用合适的单位进行数据的显示
-T:显示文件系统的类型

例如:

root@ubuntu1804:~# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
udev           devtmpfs  954M     0  954M   0% /dev
tmpfs          tmpfs     198M   11M  187M   6% /run
/dev/sda5      ext4       58G  4.2G   51G   8% /
tmpfs          tmpfs     986M     0  986M   0% /dev/shm
tmpfs          tmpfs     5.0M     0  5.0M   0% /run/lock
tmpfs          tmpfs     986M     0  986M   0% /sys/fs/cgroup
/dev/sda1      ext4      922M   80M  780M  10% /boot
tmpfs          tmpfs     198M     0  198M   0% /run/user/1000
tmpfs          tmpfs     198M     0  198M   0% /run/user/0

df和du统计信息不相同的情况:

  • df > du
    的情况:

当把文件删除了,但是空间并没有被释放(有进程再使用这个文件,删除了这个文件不会马上释放空间)时候,使用df看到的数据比du统计的大。即:
df>du

例如:

# 创建要给1G大小的文件
root@ubuntu1804:~# dd if=/dev/zero of=./a.txt bs=1G count=1
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 1.23766 s, 868 MB/s


# 
root@ubuntu1804:~# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/sda5      ext4       58G  5.2G   50G  10% /
/dev/sda1      ext4      922M   80M  780M  10% /boot

root@ubuntu1804:~# du -sh /
5.2G	/

# 在另一个窗口使用vim打开这个文件
root@ubuntu1804:~# vim a.txt

# 在本窗口删除该文件
root@ubuntu1804:~# rm -rf a.txt 

# 使用lsof查看,发现a.txt这个文件被vim进程使用,所以删除了文件没有释放空间
root@ubuntu1804:~# lsof | grep delete
vim     22197    root    3r    REG      8,5 1073741824    3673208 /root/a.txt (deleted)

# 再次统计大小
root@ubuntu1804:~# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/sda5      ext4       58G  5.2G   50G  10% /
/dev/sda1      ext4      922M   80M  780M  10% /boot

root@ubuntu1804:~# du -sh /
4.2G	/
  • df < du
    的情况:

当某个目录文件挂载到其他设备了的时候(多个设备空间的组合),这就是所说的文件系统重叠时候。即
df < du

例如:

# /dev/sda5分区挂载到/根目录下,显示已经用了4.2G空间
root@ubuntu1804:~# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/sda5      ext4       58G  4.2G   51G   8% /
/dev/sda1      ext4      922M   80M  780M  10% /boot

# 使用du工具统计根目录大小也是4.2G
root@ubuntu1804:~# du -sh / 
4.2G	/

# 将sdb1分区挂载到/xx下
root@ubuntu1804:~# mount /dev/sdb1 /xx
# 创建要给1G大小的文件
root@ubuntu1804:~# dd if=/dev/zero of=/xx/a.txt bs=1G count=1
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 10.6664 s, 101 MB/s

# 再次使用du统计/的大小已经变为了5.2G
root@ubuntu1804:~# du -sh /
5.2G

# 使用df查看 仍然是4.2G
root@ubuntu1804:~# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/sda5      ext4       58G  4.2G   51G   8% /
/dev/sda1      ext4      922M   80M  780M  10% /boot
/dev/sdb1      ext4      3.9G  1.1G  2.7G  28% /xx


本篇文章主要讲解如何在Unity中使用Joint组件完成一些刚体物理之间的连接效果,并且讲解一个简单案例。

什么是Joint

官方文档介绍
Joint可以连接一个刚体与 另一个刚体 或世界空间某点,Joint可以通过施加力的方式来限制运动,joint中文翻译可以叫 约束。
在力学观点下,运动分为6个自由度,沿着xyz轴的位移,绕xyz轴的旋转。
通过将某些轴的位移和旋转给一些限制条件来达到限制刚体运动的目的。

Unity的Joint实际就是调用了
NVIDIA PhysX的PxConstraint

有哪些Joint

PhysX提供了 Fixed Joint,Character Joint、Hinge Joint、Spring Joint等等。
这些种种的Joint其实都是基于通用的 Configurable Joint调配参数封装出来的,比如Fixed Joint就是将6自由度运动全部配置为lock,两只刚体加上了这个约束就会绑定在一起,没有任何相对运动。

通过点击这个按钮我们可以看到一些用来调节joint参数的Gizmos。

Joint计算原理

在Unity中 Joint是作为Component存在,他必须依附一个Go,这个被依附的Go需要有rigidbody,Joint会影响这个刚体,
通常我们指定另一个刚体到ConnectedBody上表示另一个被Joint影响的刚体,如果想要这个joint attached 刚体被固定在空间点上,那么conectedBody可以不填。

自由度配置

Joint拥有3个位移自由度和3个旋转自由度。相应的,在Configurable Joint中对应如下几个参数:

  • 位移有 - XMotion、YMotion、ZMotion
  • 旋转有 - AngularXMotion,AngularYMotion,AngularZMotion
    在这6个自由度上,分配有以下三种配置:
  • ConfigurableJointMotion.Free
  • ConfigurableJointMotion.Locked
  • ConfigurableJointMotion.Limited
    其中Free意味着约束不存在。比如XMotion Free,代表了两个刚体在X轴向可以相对随意移动。
    Locked则表示刚性约束,比如XMotion Locked代表了两个刚体在X轴向的相对位置被完全固定不可改变。(但在实际物理模拟中是存在被强行拆散可能性的,例如刚体穿插等等,会导致Solver失败)
    Limited则意味着有限范围的偏差。当超出有效范围时,约束将会开始生效,企图使两个刚体回到正常偏差范围内。

Axis与Anchor

Joint默认会以这个attach的GO的Transform坐标系作为Joint的六自由度坐标系,如果我们想要一个另外的坐标系,需要填Axis和SecondAxis,他会作为这个body transform的child而存在。

然后是使用Joint是最容易出错的点——Anchor
这里我们画一幅图来说明

cubeA 身上放了一个Joint组件,连接着cubeB,cubeA的anchor放在蓝圈位置,joint的坐标系的xy是红绿线。
anchor实际上有两个,一个连着A 叫Anchor,另一个连着B,叫ConnectedAnchor,一般我们都会勾选AutoConfigureConnectedAnchor让两个anchor在一起。
从anchor到A的连线在joint游戏开始时 anchor到重心的距离会被记录,可以看做一个不可变形的刚杆(如果anchor在某个cubeA的中心那么属于cubeA到anchor就没有钢杆了),
游戏运行时anchor和conectedanchor会发生相对运动, 以joint坐标系为准,这里我们假定没有自己配置Axis,那么joint坐标系就是A的坐标系,
如果此时我们配置了Joint的XYZ的Motion为lock,其他angular xyz motion为free,并且把A的刚体配置成Kinematic(让他不受重力下落影响,固定在空中),
那么就会得到一根钢杆一头在蓝圈 一头在cube的重心的自由旋转运动,拽着A去甩B其实有点像双节棍。

如果我们配置了angular xyz为lock,xyz的motion中某个轴 比如Y轴为free,那么便可以得到沿着y轴的滑动一样的效果。

通过对于不同维度的控制我们可以得到很多不一样的效果。

Limit与Spring

整个计算流程包括三步
1、计算两物体轴向距离
2、将轴向距离投影到joint空间下
3、调节轴向距离满足joint参数

如果我们想让两个anchor的某些轴向的位移在一个范围里运动,那便可以将这几个轴的motion调整为limit,这种两个anchor的距离(注意是距离,算的是两点作差的值)会被限制在limit内,
如果把A固定,B自由下落那么B到了某个点位就会啪的一下卡住,好像撞到了地面一样,实际上是被Joint拉住了。
如果我们想他在这个边缘位置不要这么生硬的停下而是有弹性、柔和一点的运动,那么可以配置spring值。

需要注意的是xyz都是共享一个limit的,只存在anchor之间 按线运动、按圆圈运动、在球体范围内运动三种情况。
默认spring是0,表示没有任何弹簧就是一个很刚性的约束(看起来非常硬)。
damper标志了弹簧震动的阻尼系数,阻尼会根据刚体运动速度产生一个反向的作用力,以降低震动的频率。

angular limit和其spring的配置原理也是一样的,只不过是计算轴向距离变成计算两个rotation的差异,另外angularlimit关于主轴的计算可定制性更强,可以存在最小负角和最大正角,其他两个轴则定义相对限制多。
按两个方向分别进行定义是由现实意义的,因为人的很多关节都是这样的。比如你的膝关节、肘关节都只能往一个角度弯曲,而不能反向弯曲。这也决定了当我们使用Joint来模拟物理骨骼时,必须正确的分配Joint主轴朝向。
至于为什么不每个轴都分配最大和最小角度,可能是有数学限制吧,这里博主也不知道。

Drive与Target

上述所讲的anchor与anchor之间的限制主要还是一种受到外力导致运动后 应该怎么限制运动,
其实Joint还提供了一种内力驱动来让Joint对两个刚体产生力,很多的结构比如挖掘机旋转关节,车轮的悬挂系统都会输出一些内部的力对外做功。
要配置这些力我们就要用到Drive和Target。
首先一般用drive的轴的自由度配置都会配成free,然后通过配置target position、target rotation来对两anchor连接的刚体施加力。
主要分为几个步骤
1、计算两个刚体的坐标差异
2、将差异投影到joint坐标系
3、计算差异和配置的target的距离
4、为了让距离满足0,会对两刚体求解施加力

PositionRelative = PositionOfConnected - PositionOfBinded
ErrorOfPosition = TargetPosition - PositionRelative 
F = Spring * ErrorOfPosition - Damp * Velocity
  • PositionOfBinded为Joint所绑定的刚体Anchor位置
  • PositionOfConnected为另一个连接的刚体的Anchor位置
  • PositionRelative为当前两者位置之差,而TargetPosition则为预期之差
  • ErrorOfPosition为预期和当前的差项,Joint将根据这个差项产生一个弹性力作用于两个刚体,使得PositionRelative在迭代中逼近TargetPosition

关于Rotation
差异和target 计算的部分包括:

ErrorOfRotation = TargetRotation - (RotationRelative - RotationRelativeInited)
  • RotationOfBinded为Joint所绑定刚体的旋转量
  • RotationOfConnected为连接刚体的旋转量
  • RotationRelative = RotationOfConnected - RotationOfBinded 为两者之差,也可以理解为Connected相对于Binded的旋转量。
  • RotationRelativeInited为初始情况下的RotationRelative

所有的Drive,都由以下结构构成:

  • PositionSpring - 表示驱动力的弹性系数
  • PositionDamper - 表示驱动力的阻尼系数
  • MaximumForce - 表示最大驱动力值。即意味着F不随着Error无限增大
    利用以上的定义,将会使用以下公式产生弹性力:
    \(F_{drive}=Spring*E - Damp * dE/dt\)
    E代表了当前状态与目标状态之差。

可以用代码运行时去修改target position、target rotation来获得一些有趣的物理效果。

Joint应用案例

讲解一个基于Joint的吊车的实现

车轮

旋转

车轮我们使用了capsule collider,连接在box拼接的车身的刚体上
然后让capsule collider关于轴心方向的轴的旋转是free的,其他旋转都lock,接着我们希望车轮有一点轻微的悬挂系统,如果此时我们把joint组件加在了车轮上,使用车轮坐标系,我们会发现joint没法找到一个稳定的上方向,这导致我们决定将joint加在车身,让joint坐标系跟车身保持一致,维持一个相对稳定的Joint坐标系。

红色的圆圈表示这个joint绑定的东西在joint坐标系的x轴可以自由的旋转。

这里的anchor配置相当重要,anchor位置为车轮的中心在车身坐标系下的相对位置,这里我通过编辑器写了一点计算代码配置anchor位置。

然后我们通过控制车轮的x轴角速度便可以实现一个摩擦力驱动的车轮了。

悬挂系统

我们xyz的linear motion都是lock住的,这样遇到一些凸起的路面我们轮子就和车身的相对距离永远不变,这样不符合真实的感觉,真实的感觉应该是轮子会往上有一点抬升,而车身不会有y轴方向的运动。

这里我们的y轴和车身绑定已经相当稳定,我们可以把y轴配置成free,然后把yDrive调大,target position是000,其实也就是让这个车轮回归初始位置的意思,这样当车轮支撑车身时候车身会有重力影响产生一定的下沉同时有被举起的感觉,悬空时车轮也会往下掉一点,遇到障碍物是压过了障碍物的轮子会比其他轮子往上抬升一点。

总体运动起来 车身的震动幅度相比没有悬挂系统更小一点。

吊臂

旋转

吊车的大臂可以以转台为中心来做旋转,我们以y为上方向 配置angular y motion为free,然后在运行时根据输入来配置target rotation,可以实现大臂绕着一个点旋转,通过把drive和damp同时拉大可以获得一个有些重量感的吊臂。

抬升

抬升的做法有一点trick,对于一般的吊车这里通常是液压的,由下面的浅红色小臂通过液压给力然后把红色的大臂推出去。大臂配置一个绕轴旋转。
但是笔者经过尝试,发现这种通过给力的方式在车子运动起来的同时大臂会摇摇晃晃,因为是通过力来作用的,就很容易出现弹簧一样的感觉,并且也不利于控制具体的抬升角度。

于是这里的做法是大臂尾部两个joint得到一个绕轴旋转,绕轴旋转的joint通过配置drive 和 target rotation来让吊臂产生某个角度的抬升。

接着我们制作了一个小臂的一头连着大臂一头连着转台,连着大臂的那端可以沿着小臂轴向有位移,形成了一个动轨滑块结构。

然后让这个小臂对大臂施加一个拉力,这个力往下,而上一个joint给的力往上,以此可以减少大臂的摇晃感。

吊钩

伸长

最后是吊钩,吊钩其实就是让这个钩子可以沿着一条轴伸长,始终日常垂直往下,这里我显示给钩子摆了一个垂直往下的姿势,y轴向上,然后joint组件添加在钩子上,anchor一头绑在吊臂上,一头绑在吊钩center,
允许y轴可以free运动,用ydrive来分离两个anchor,驱动吊钩往下运动,这样就得到了一个绕着初始点旋转的一根弹性杆,用来做伸长后的吊钩看起来还行。

除了这些外,给一些angular的drive并且target rotation配置成000,可以让吊钩在空中甩来甩去时更快的回到垂直向下的初始旋转位置。

吸附

最后吊钩要把东西吊起来,可以做一个范围检测,运行时创建一个lock的joint 把钩子和被钩的东西绑在一起,然后再收起吊绳,我们就能吊起东西了!

总结

对绳子不太满意,因为有点弹性杆的感觉,实际上这种拉的紧绷的钢性绳子相当难模拟,拉起时候的感觉也会有弹来弹去的味道,暂时没有想到很好的解决办法

引用

https://docs.unity3d.com/cn/current/Manual/class-ConfigurableJoint.html
https://zhuanlan.zhihu.com/p/380394542

flyingziming
2023.3.20

1 背景

在我们实际的开发过程中,我们的某些数据可能经常使用,但是过了一段时间,这个数据就不怎么使用了,即我们的数据存在一个





等这些特性。那么针对
数据的热度
,我们可以采用不同的策略,存储到不同的存储介质上。
比如:

  1. 针对经常访问的数据,我们可以存储在
    SSD
    上。
  2. 针对访问频率不高的,我们可以存储在
    DISK
    ,即普通的硬盘上。
  3. 针对几乎不会访问的数据,保存在归档介质上。

注意:那么hdfs自己知道哪些数据是热数据,哪些数据是冷数据吗,貌似是不知道的,需要我们自己去判断

2 hdfs异构存储类型和存储策略

2.1 hdfs支持的存储类型

hdfs
支持如下
4
中存储类型

  • ARCHIVE:
    它具有
    高存储密度
    (PB级存储)但
    计算能力弱
    ,一般用于归档文件的存储。
  • DISK :
    普通磁盘,
    默认的存储类型
  • SSD :
    SSD固态硬盘
  • RAM_DISK:
    支持在
    内存
    中写入单个副本文件

hdfs支持的存储类型

2.2 hdfs如何知道数据存储目录是那种存储类型

hdfs
是不会自动检测我们指定的数据存储目录是何种存储类型的,需要我们在配置的时候告诉
hdfs

指定目录的存储类型

vim hdfs-site.xml

<property>
    <name>dfs.datanode.data.dir</name>
    <value>[SSD]file:///var/hadoop/dfs/data1,[DISK]file:///var/hadoop/dfs/data2</value>
</property>

从上面的配置中可以
/var/hadoop/dfs/data1
前面指定了
[SSD]
,则说明
data1
这个目录是一个
SSD
的存储介质,
但是具体是不是真的SSD类型,这个是不会去校验的。

hdfs如何知道数据存储目录是那种存储类型

2.3 存储策略

2.3.1 在hdfs中支持如下存储策略

  • Hot:
    用于存储和计算。当我们的数据是

    数据时,可以使用这种存储策略,所有的副本都在DISK中。
  • Warm:
    仅适用于计算有限的存储。不再使用的数据或需要归档的数据从热存储移动到冷存储。当一个块

    时,所有副本都存储在ARCHIVE中。
  • Cold:
    部分热和部分冷。当一个块是热的时,它的一些副本存储在DISK中,其余的副本存储在ARCHIVE中。
  • All_SSD:
    用于将所有副本存储在SSD中。
  • One_SSD:
    用于将其中一个副本存储在SSD中。其余副本存储在DISK中。
  • Lazy_Persist:
    用于在内存中写入具有单个副本的块。副本首先用RAM_DISK写入,然后懒惰地保存在DISK中。
  • Provided:
    用于在HDFS之外存储数据
    hdfs支持的存储策略

2.3.2 存储策略表

存储策略表

2.3.4 Storage Policy Resolution

创建文件或目录时,未指定其存储策略。可以使用
storagePolicy -setStoragePolicy
命令指定存储策略。
文件或目录的有效存储策略由以下规则解析。

  1. 如果文件或目录指定了存储策略,则返回它。
  2. 对于未指定的文件或目录,如果是根目录,则返回默认存储策略。否则,返回其父级的有效存储策略。

有效的存储策略可以通过
storagePolicy -getStoragePolicy
命令检索。

2.3.5 配置存储策略

  • dfs.storage.policy.enabled
    用于启用或禁止存储策略特性,默认值是
    true
  • dfs.datanode.data.dir
    在每个数据节点上,逗号分隔的存储位置应标记其存储类型。这允许存储策略根据策略将块放置在不同的存储类型上。

举例说明

  1. 如果一个datanode 上的存储位置
    /grid/dn/disk0

    DISK
    类型,应该配置为
    [DISK]file:///grid/dn/disk0
  2. 如果一个datanode 上的存储位置
    /grid/dn/disk0

    SSD
    类型,应该配置为
    [SSD]file:///grid/dn/disk0
  3. 如果一个datanode 上的存储位置
    /grid/dn/disk0

    ARCHIVE
    类型,应该配置为
    [ARCHIVE]file:///grid/dn/disk0

如果
没有显式标记
的存储类型,则datanode存储位置的默认存储类型将是
DISK

2.3.6 基于存储策略的数据移动


已经存在

文件/目录

设置新的存储策略
将改变命名空间中的策略,
但它不会在存储介质之间物理移动块。
此处介绍基于
Mover
来解决这个问题,具体的细节需要看官方文档。

mover工具的使用

2.3.7 存储策略命令

2.3.7.1 列出所有存储策略

hdfs storagepolicies -listPolicies

2.3.7.2 为文件或目录设置存储策略

hdfs storagepolicies -setStoragePolicy -path <path> -policy <policy>

<path>
:需要设置存储策略的文件或目录
<policy>
:存储策略的名字

2.3.7.3 取消存储策略

hdfs storagepolicies -unsetStoragePolicy -path <path>

取消对文件或目录的存储策略设置。在unset命令之后,将应用最近祖先的存储策略,如果没有任何祖先的策略,则将应用默认存储策略。

2.3.7.4 获取文件或目录的存储策略。

hdfs storagepolicies -getStoragePolicy -path <path>

2.3.7.5 查看文件块分布

hdfs fsck xxx -files -blocks -locations

3 hdfs异构存储案例

3.1 环境准备

ip地址 节点名 存储类型
192.168.121.140 hadoop01 DISK,ARCHIVE
192.168.121.141 hadoop02 DISK,SSD
192.168.121.142 hadoop03 SSD,ARCHIVE

3.2 节点 hdfs-site.xml配置文件

3.2.1 hadoop01

<property>
	<name>dfs.replication</name>
	<value>2</value>
</property>
<!-- 开启hdfs异构存储策略 -->
<property>
	<name>dfs.storage.policy.enabled</name>
	<value>true</value>
</property>
<!-- 配置block块的存储目录,配置hdfds数据的存储目录 -->
<property>
	<name>dfs.datanode.data.dir</name> 
	<value>[DISK]file:///opt/bigdata/hadoop-3.3.4/data/disk,[ARCHIVE]file:///opt/bigdata/hadoop-3.3.4/data/archive</value>
</property>

3.2.2 hadoop02

<property>
	<name>dfs.replication</name>
	<value>2</value>
</property>
<!-- 开启hdfs异构存储策略 -->
<property>
	<name>dfs.storage.policy.enabled</name>
	<value>true</value>
</property>
<!-- 配置block块的存储目录,配置hdfds数据的存储目录 -->
<property>
	<name>dfs.datanode.data.dir</name> 
	<value>[DISK]file:///opt/bigdata/hadoop-3.3.4/data/disk,[SSD]file:///opt/bigdata/hadoop-3.3.4/data/ssd</value>
</property>

3.2.3 hadoop03

<property>
	<name>dfs.replication</name>
	<value>2</value>
</property>
<!-- 开启hdfs异构存储策略 -->
<property>
	<name>dfs.storage.policy.enabled</name>
	<value>true</value>
</property>
<!-- 配置block块的存储目录,配置hdfds数据的存储目录 -->
<property>
	<name>dfs.datanode.data.dir</name> 
	<value>[SSD]file:///opt/bigdata/hadoop-3.3.4/data/ssd,[ARCHIVE]file:///opt/bigdata/hadoop-3.3.4/data/archive</value>
</property>

3.3 重启hdfs集群,并看数据目录存储类型是否正确

查看数据目录的存储类型

3.4 案例演示

此处仅仅只是演示
Warm
类型。

由之前的存储策略表(
2.3.2
)可知,
Warm
类型的策略,只有一个块存储在
DISK
存储上,其余的全部存储在
ARCHIVE
存储上。

# hdfs 上创建目录
[hadoopdeploy@hadoop01 hadoop]$ hadoop fs -mkdir -p /var/data/storage
# 上传文件到 hdfs 目录中
[hadoopdeploy@hadoop01 hadoop]$ hadoop fs -put /etc/profile /var/data/storage/profile
# 设置 /var/data/storage 目录的存储策略为 warm
[hadoopdeploy@hadoop01 hadoop]$ hdfs storagepolicies -setStoragePolicy -path /var/data/storage -policy WARM
Set storage policy WARM on /var/data/storage
# 查看 /var/data/storage 目录的文件块分布,发现还是 2个 DISK,说明历史数据需要迁移,使用 mover 命令
[hadoopdeploy@hadoop01 hadoop]$ hdfs fsck /var/data/storage -files -blocks -locations
Connecting to namenode via http://hadoop01:9870/fsck?ugi=hadoopdeploy&files=1&blocks=1&locations=1&path=%2Fvar%2Fdata%2Fstorage
FSCK started by hadoopdeploy (auth:SIMPLE) from /192.168.121.140 for path /var/data/storage at Sat Mar 18 17:49:48 CST 2023

/var/data/storage <dir>
/var/data/storage/profile 2098 bytes, replicated: replication=2, 1 block(s):  OK
0. BP-1760726666663-192.168.121.140-1676791226380:blk_1073741858_1036 len=2098 Live_repl=2  [DatanodeInfoWithStorage[192.168.121.141:9866,DS-e86f80ba-6f04-4074-ab96-f58212c3c0e2,DISK], DatanodeInfoWithStorage[192.168.121.140:9866,DS-ca40e8cf-4d38-4a42-bfcb-e636087e9025,DISK]]
......

# 将 /var/data/storage 按照存储策略移动数据块
[hadoopdeploy@hadoop01 hadoop]$ hdfs mover /var/data/storage
2023-03-18 17:52:04,620 INFO mover.Mover: namenodes = {hdfs://hadoop01:8020=null}
2023-03-18 17:52:04,630 INFO balancer.NameNodeConnector: getBlocks calls for hdfs://hadoop01:8020 will be rate-limited to 20 per second
2023-03-18 17:52:05,368 INFO net.NetworkTopology: Adding a new node: /default-rack/192.168.121.142:9866
2023-03-18 17:52:05,368 INFO net.NetworkTopology: Adding a new node: /default-rack/192.168.121.140:9866
2023-03-18 17:52:05,368 INFO net.NetworkTopology: Adding a new node: /default-rack/192.168.121.141:9866
2023-03-18 17:52:05,402 INFO balancer.Dispatcher: Start moving blk_1073741858_1036 with size=2098 from 192.168.121.140:9866:DISK to 192.168.121.140:9866:ARCHIVE through 192.168.121.140:9866
2023-03-18 17:52:05,412 INFO balancer.Dispatcher: Successfully moved blk_1073741858_1036 with size=2098 from 192.168.121.140:9866:DISK to 192.168.121.140:9866:ARCHIVE through 192.168.121.140:9866
Mover Successful: all blocks satisfy the specified storage policy. Exiting...
2023-3-18 17:52:15       Mover took 10sec
# 重新查看 /var/data/storage 目录的文件块分布,发现还是 一个是 DISK 另外一个 ARCHIVE,说明存储策略生效了
pdeploy@hadoop01 hadoop]$ hdfs fsck /var/data/storage -files -blocks -locations
Connecting to namenode via http://hadoop01:9870/fsck?ugi=hadoopdeploy&files=1&blocks=1&locations=1&path=%2Fvar%2Fdata%2Fstorage
FSCK started by hadoopdeploy (auth:SIMPLE) from /192.168.121.140 for path /var/data/storage at Sat Mar 18 17:53:23 CST 2023

/var/data/storage <dir>
/var/data/storage/profile 2098 bytes, replicated: replication=2, 1 block(s):  OK
0. BP-1760726666663-192.168.121.140-1676791226380:blk_1073741858_1036 len=2098 Live_repl=2  [DatanodeInfoWithStorage[192.168.121.141:9866,DS-e86f80ba-6f04-4074-ab96-f58212c3c0e2,DISK], DatanodeInfoWithStorage[192.168.121.140:9866,DS-cf50253c-ea3f-46f6-bdd9-4ac1ad3907d2,ARCHIVE]]

查看文件块分布

4 参考文档

1、
https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/ArchivalStorage.html
2、
https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml