北邮 操作系统期末复习(下)

八、Demand Paging

本章主要讲解的是内存实际上也可以作为磁盘的缓存;

最重要的概念就是需求分页:因为现在的程序需要大量的物理内存,但是存在这样一个规律 - 一个程序百分之九十的时间都用在它百分之十的代码上,因此实际上并不需要将程序所有的代码、数据都读取到内存中,可以将内存当作disk的一个缓存,仿佛磁盘中所有的东西都在内存中,称为lazy分配策略;

这种做法有一个好处就是仿佛内存是无限大的(因为磁盘一般是足够大的),如何实现呢?借助页表以及Page fault(缺页中断是很广泛的概念)完成这种缓存的设计;

TLB是虚拟地址和物理地址的缓存,Cache是CPU和内存之间的缓存,内存是CPU和磁盘之间的缓存,后两者都是基于前者工作的,Cache的单位是块,内存的单位是页

1.Memory-mapped Files

内存映射文件本质上是和需求分页的思想是相同的(甚至可以说是一回事)

一个程序要使用磁盘的一个文件,最朴素的方法就是直接将文件读进来,第二种方法就是内存映射文件,就是操作一块内存等价于操作该文件

内存映射文件的好处是不需要read文件所有的bit,可以访问文件的任何位置

  • 好处:完全透明、不进行拷贝、pipeling:不需要将整个程序读取到内存中再运行,可以边跑边加载剩余的内存、方便进程通信

  • 坏处:很容易出现缺页

2.Page Eviction Policy

实际上这一节的页的置换策略和前面的Cache置换策略很相似,分别是FIFO、MIN(LRU的理想版本)和Random;

需求分页中一般不会使用LRU,因为LRU在内存分页中太耗时间了;

2.1 Clocking algorithm

时钟算法 - 最适合需求分页的替换算法,本质上是在最大可能上逼近LRU算法

关于Use bit,1->0是操作系统完成,0->1是硬件完成

时钟算法本质上就是一个页很久没用则替换出去,时钟算法之所以高效是因为访问页的频率很高,但是页的置换的频率很低,访问页的时候的比特位修改是硬件完成速度很快,时钟旋转这个操作相对硬件来说可能比较复杂则让软件完成即可,因为频率低所以总时间不会很高;当然时钟算法没有LRU精准,它不能记录精准的页被访问的时间的长短;

具体工作流程可以看视频理解,需要注意的是指针不会随着当前访问的页移动(即访问页的时候不调用指针旋转),只会在置换算法实施(即发生Page Fault的时候)的时候才转动

时钟的如果快速过快即一直在转,这是一个坏现象,表明一直在置换说明系统过载;

可以对时钟算法进行改进,也就是将页面的访问的机会从1改成n次,n越大理论上越逼近LRU,但是n过大就一直找不到一个合适的页导致一直旋转,一种解决方法是针对性的设置,比如替换脏页的开销大(因为要写回),所以对于脏页和干净的页的n可以不同;

九、scheduling

调度的评价指标主要是:

  • 最小化Response Time
  • 最大化Throughput(吞吐量,最大化的方式就是尽可能提高处理器的使用次数即最大化每秒操作次数)
  • Fairness(改善平均响应时间):理论上最小化响应时间做法就是给短任务更高的优先级,但是这样势必导致长任务饥饿,这就造成了不公平,所以需要给长任务机会运行 - 要实现公平性就必然会损失平均响应时间
    • 一种解决方式是高优先级的任务多一些时间片,低优先级的任务少一些时间片(注意是时间片数量),网络调包常用的最大最小化公平策略就是这种思想(让拿到最少资源的任务尽量多,让拿到最多资源的任务尽量少);
    • 另一种解决方式是如果一个任务的时间不够,那么就提高它的优先级;

下面直接介绍具体有哪些调度策略以及相关的计算

1.FCFS

假如对任务的先后次序进行调整

2.SJF&SRTF

实际上上面的那种情况就是短任务优先的例子,与之相关联的还有一个被称为最短剩余时间优先的调度策略,SJF不是抢占式调度算法,SRTF是一个抢占式的调度算法;

短任务优先的缺点是导致饥饿,进而影响公平性,并且在实现的时候实际上并不知道一个任务需要执行多久;

3.RR

轮询调度实现方式有很多,时间片或者列表都可以,具体例题如下

RR的好处是对于短任务有优势,但是会导致很多上下文切换,上下文包括寄存器的值、栈的地址,切换上下文的时候主要就是更改页目录的地址,并且上下文切换会改变缓存,也会增大时间;

RR中时间片大小的设置非常重要,时间片过大就是FCFS,时间片过小导致上下文切换过于频繁得不偿失,时间片的选择一般依赖于硬件;

如果任务的运行时间都一样则FCFS肯定优于RR,但是实际上肯定有长短任务所以需要综合考虑;

4.Strict Priority Scheduling

不是所有的任务都是平等的,前台应用优先级高于后台应用,同级之间可以使用RR等调度算法;

优先级导致的问题:低优先级可能会被饥饿,或者高优先级被翻转(场景:一个高优先级的任务依赖一个锁,当前锁正在被低优先级的任务使用,但是因为优先级不能调用低优先级所以高优先级的任务和低优先级的任务都会被卡住);

解决严格优先级调度的问题一种方式是动态优先级调度算法,我们将在后面反馈队列中介绍;

5.EDF

最早DDL方法,和最短剩余时间SRTF的区别是最短剩余时间是看剩余时间,这个调度算法是看DDL结束时间

6.MFQ

前面的调度算法一般都只优化了一个方面(最多DDL、最公平…),MFQ几乎是兼顾了所有的优点,但是都不是很优秀;

基本思想:有多个队列,每个队列有不同的优先级,同级队列使用同一的调度算法,与严格优先级队列的区别就是CPU Bound的任务会从高优先级队列一直降到低优先级队列,而I/O Bound的任务会一直维持在一个高优先级的队列中;

MFQ另一个显著的特点是高优先级队列使用RR,低优先级队列使用FCFS,之所以这样设计是因为前台应用需要尽可能让短任务快速完成;

不同的前台队列因为使用的都是RR,所以需要考虑时间片的长短,因为越长的时间片越接近FCFS,所以高优先级的前台队列的时间片短,低优先级的前台队列的时间片长(注意这里是时间片的长短);

如何安排多个队列之间的调度?最简单的就是严格优先级队列调度,另一种方式就是给高优先级队列分配多的时间片,低优先级队列分配少的时间片;

当然放在最低优先级的任务还是可能面对饥饿的问题,MFQ额外增加了一个策略,即检查每个队列中的任务是否能够真正获得足够多的时间片,如果不够就主动提高其优先级

可能我们在做题的过程中会产生疑问?每个任务在使用完时间片之后就被降低到更低的优先级,那么如何体现了同级队列中RR的调度思想呢?因为我们的题目实际上是进行简化过的,假如有一个I/O主动让出的任务,那么这个任务就不会被降低优先级,只会被放在该队列的末尾,这就体现了RR的思想

7.Lottery Scheduling

彩票调度,不同之处是有了一些随机性(有时候随机可能是一件好事,实现比较简单);

基本思想:给每个任务一个彩票,在调度的时候刮奖,刮到谁(或者定制一个规则)就调度哪个任务;短任务会有多一些的彩票,长任务少一些的彩票,为了确保不会饥饿,每个任务至少都会有一个彩票;

需要注意的是彩票刮完之后不能丢掉,不然彩票少的就不会再执行了(一次没执行完还需要执行第二次);

8.RTS

调度算法 - 实时调度,针对实时操作系统,传统操作系统考虑的调度指标是效率,实时操作系统需要保证实时性,也就是可预见性

9.多处理器调度

前面讨论的问题都是基于单处理器,多处理器调度会遇见诸如锁、Cache等问题

十、锁和条件变量

这是整个操作系统在线程层面的框架,存在多个进程,每个进程中又有多个线程,线程之间有自己的CPU状态,但是线程之间共享地址空间和I/O;线程之间会有一个CPU调度器来对它们进行调度

  • 进程是最小的资源(内存)分配单位;
  • 线程是最小的调度单位,是最小的CPU调度单位;
  • 用户态和内核态之间存在系统调用和upcall进行通信;
  • 线程之间协作于是出现了上下文切换、中断以及锁的概念;

为什么需要线程同步?从开发者的角度来看似乎每个线程都在一个单独处理机上,也就是似乎有无限多个处理机,从开发者的角度来看线程是不会发生中断的,实际上应该是右边的情况:少数线程在run,其他线程在等待,这意味着线程的执行速度是不可预测的,这就可能出现一些同步的问题

  • 多处理器:多个CPU或核或超线程,这是真正的并行,能够同时跑多个线程;
  • 多道程序:多任务或多进程同时存在(实际上是轮流在run);
  • 多线程:有多个线程同时存在(实际也可能是轮流在run);

既然线程合作会产生同步问题,为什么还需要线程合作?线程合作有如下好处:

  • 首先是需要共享一些资源;

  • 期望系统能够跑的更快

    • 重叠I/O以及计算,以加快计算速度
    • 将程序切割为平行pieces
  • 模块化,因为在逻辑上很多任务就应该是多线程的

独立的线程不会出现问题(实际上并不存在完全独立的线程),但是合作的线程会出现不确定性和不可复现性,不确定性错误是非常难被找到并且不可被复现(两台机器几乎不可能出现同样的同步错误状态),因此我们很有必要使用锁这些方法来保证线程之间的状态的同步,下面是一些线程同步问题的具体例子

除了上面出现的问题以外,因为编译器会进行一定程度的优化,修改顺序以最大化并行性,但是编译器只能保证在一个线程里面的依赖是正确的,不能保证多个线程的依赖顺序(编译的时候当然不知道有什么程序会和该程序一起运行,但是这不属于线程同步的问题了)

关于线程同步,有三个概念非常重要

有些操作可以在最基本的层面上解决一定程度的同步问题,比如原子操作,对于大部分机器来说,内存的访问是原子的(load和store指令);

但是并不是所有的汇编指令都是原子的,本质上由硬件决定(只有硬件能够支持原子操作,所以不能随心所欲的认为哪条指令就应当是原子操作);

下面我们再展示一幅图,表明了为什么一定要在中间加锁这些API而不是直接使用原子操作,因为开发者直接使用底层的原子操作来实现线程安全的话是非常复杂的

1.锁

锁:阻止某人做某事,上锁的资源只能被等待才能使用,所有的同步问题一定会引入等待;

问题:如何在硬件提供的有限的原子操作的基础之上来实现我们需要的锁,进而实现互斥;

锁最基本的两个操作(这两个操作都是原子操作,因为我们在实现的时候就是按照原子操作的目标来实现的,基于硬件提供的最基本的原子操作实现)

  • 获取锁 - 如果这个锁是free的则获取,如果这个锁不是free的则一直等待;
  • 释放锁 - 将锁的状态从busy变成free,如果此时还有某些线程在等待这个锁,则适当的唤醒这些线程;

使用加锁解决牛奶问题

原理:通过加锁和解锁保证了中间代码的原子性 - 没有两个线程可以同时执行这段中间代码,这段代码被称为临界区

锁的特性如下

1.1 开关中断实现锁

锁的实现:在单处理机上最简单的实现就是加锁的时候将中断关闭,释放锁的时候将中断打开;这个方法的问题是中断不能随便开关,不能让用户线程来控制中断的开关;

关中断和开中断之间运行的代码都是操作系统的可信任的代码,而不能是未知的用户代码

之所以需要关闭中断是为了避免两个线程同时进入临界区;

另一个重点是中断什么时候应该被打开,一般来说中断总是在代码的最后打开,中断在中途打开很可能出现问题

1.2 RMW实现锁

使用开关中断实现锁在多处理器的情况也可以实现,即使得所有的处理器一起中断,但是开销太大了(多处理器每个处理器都有L1缓存,需要注意缓存一致性),所以实现了更多的基础的原子操作,这些原子操作的集合被称为RMW;

使用RMW既可以在单核也可以在多核的情况下实现锁;

具体的RMW操作有很多,我们这里展示的是其中比较常用的原子操作,不同的原子操作与处理器和硬件是相关的

这里只介绍使用t&s实现自旋锁,基于test&set实现的自旋锁的缺点是存在忙等待或者优先级翻转的问题,这也是自旋锁的名字的由来

对于用户来说自旋锁的开销太大,所以可以进一步的优化(尽管前面我们说最好不要对锁进行优化),这里的优化主要是解决了busy waiting的问题,并且会主动放弃锁的持有权

2.条件变量

事实证明条件变量优于信号量以实现锁,锁在某些情况下会出现拿着锁空等(死锁)这种问题,在等待期间我们应当将锁释放掉,条件变量就是用来做这个事情的;

条件变量有三个函数

wait函数的传入参数是一个锁,调用wait函数会释放掉这个锁,同时将这个线程放在一个等待队列中,直到接收到一些特定的信号才会唤醒这些等待线程,当这些线程被唤醒之后会重新尝试获取这些锁,注意获取锁的操作是在该函数返回返回值之前,这意味着wait函数可以理解为在实现过程中将锁丢掉再将锁拿回来,效果就是再wait前持有锁,wait之后仍然持有锁

下面使用条件变量解决生产者-消费者问题

假设这里持有锁但是需要等待生产者队列产生产品才能工作,所以我们再等待的过程中调用wait释放掉锁,当生产者进程生产出产品后会发出signal进而唤醒并归还锁,执行之后的操作

如何实现删除操作?此处需要注意一定会考试

使用条件变量需要注意以下两个原则

  • 条件变量的使用一定是在持有锁的状态下进行
  • while循环而不是if是因为很多条件变量它默认就只能使用while,否则会出现问题
    • 管程模型主要有两种,其中Hoare模型可以使用if,而Mesa模型只能使用while

3.信号量

信号量可以理解为锁的一个更加强大的实现,但是信号量被认为是一种不太好的同步机制,反之只需要锁和条件变量就能够实现所有的同步

可以认为信号量是一个整数值,这个整数值不会是负数,信号量整数有且仅有两种操作 - P、V

  • P操作试图给信号量-1,如果这个信号量是0则P操作必须等到有线程给这个信号量+1后才能执行(类似wait操作)
  • V操作试图给信号量+1,如果有P操作在等待则唤醒P操作(类似signal操作)

信号量和锁很像,但是更强的功能在于锁只有两种状态,但是信号量可以使用多个值表示多种状态;

信号量的特点:

  • 信号量不能是负数;
  • 只能对信号量进行P、V操作(P、V操作一定是原子性的操作)
  • 初始信号量的值不同可以实现不同的信号量的功能

使用信号量解决生产者-消费者问题,需要设置如下三个信号量

对于上述Producer中的第一条和第二条代码如果交换顺序会导致死锁,这也是为什么信号量不太好的原因 - 太容易死锁

4.小结

Q:在锁的各种实现过程中,加锁和释放锁操作是否都需要陷入内核态?

A:首先开关中断一定需要陷入内核态,但是使用test&set不是特权指令所以不需要陷入内核;

Q:队列锁是什么?

A:队列锁实际上就是对自旋锁的改进,在等待的时候会进入等待队列;

Q:中断处理程序可以使用自旋锁吗?

A:中断处理程序一般都使用的是自旋锁,因为中断处理程序不能写sleep函数(中断处理函数必须跑得很快)并且中断处理函数最好不要嵌套中断或者其他函数,因此中断处理程序的运行时间实际上是非常短的,所以使用自旋锁进行等待是没问题的

十一、readers_writers and deadlock

1.读写者问题

明天再重新听一下这部分的实现,一定要会写代码;

主要实现RWLock类以及四个函数

2.死锁

Q:饥饿和死锁的区别?

A:饥饿是指线程一直等待,死锁是指对资源的申请陷入循环;死锁会导致饥饿,但是饥饿不一定导致死锁(因为饥饿一段时间后可能自动解除饥饿,但是如果没有外部干扰则死锁会一直存在);

关于银行家算法和哲学家进餐问题看王道和blog,银行家算法一定会考;

十二、disk and fs abstraction

1.磁盘

内存是非持久性存储设备,外存是持久性存储设备;

下面主要介绍两类二级存储器(注意除了主存储器以外的其他外存储器都是二级存储器):

  • 磁盘是物理结构,闪存是电路结构;
  • 闪存一般用于手机中,随机读取速度大于磁盘;

关于磁盘的构造一定要搞清楚,磁盘的计算等是考点;

磁盘容量计算公式

关于磁盘的计算题主要如下

2.read的生命周期

Q:read和write系统调用的区别是什么呢?

A:read和write在形式几乎相同,对文件系统来说,写和读的区别在于写可能会有一个buffer在kernel中,写的时候先写入缓存再写入内存;

3.文件系统

对上面的I/O系统做一个细致的划分就可以得到I/O栈(注意其组成)

什么是MM I/O呢?实际上是操作系统管理I/O设备的一种方式,需要注意的是MM I/O和Port I/O是对应的,前者只需要使用常规的读写内存的操作就可以操作I/O设备,但是后者只能使用单独的特殊命令来读写I/O设备;

文件系统主要有以下的功能

分角度看待文件系统:

  • 用户角度来看就是持久存储的抽象
  • 系统有两个角度,系统调用和文件系统的角度
    • 系统调用来看全是Bytes
    • OS来看就是block,一个block的大小一般大于等于一个扇区的大小,block是逻辑单位,扇区是物理单位

注意:一切文件系统的操作都是以block为单位,一个文件就是一个block集合;

3.1 文件和目录

文件和目录是文件系统管理磁盘的两个手段:

  • 文件是block集合;
  • 目录是逻辑概念,表示映射结构,本质上是树状分层结构;

将磁盘组织成线性扇区队列的方式有两种:

  • 第一种是由磁盘的物理结构决定的三元组寻址[cylinder, surface, sector]
  • 第二种是将所有的扇区都统一编号,使用控制器做映射,不需要关心使用的底层存储器,称为逻辑块寻址LBA

十三、fs design

文件系统的底层是存储设备(一般考虑块设备而不是字符设备)

文件系统的工作流程如下

打开一个文件实际上就是做了一个文件名的解析,主要流程如下

之后的所有操作都是在句柄上进行

1.目录

目录的作用如下 - 将文件名转换为文件号

目录一般是树状结构,根目录一般都是操作系统预先设定好的值

将文件名映射到磁盘号需要做多少次磁盘的访问?

2.文件

文件的主要功能就是讲述如何从文件号映射到真正的数据块;

这里直接拿常见的三种文件系统举例说明

2.1 FAT

FAT表的长度和block的数量相同,每一个文件号会指向其中一个block

访问其中的data block的方式类似于指针解引用

Q:FAT存在哪里?

A:FAT既可以理解为一个文件系统,也可以理解为一个表,FAT存放在磁盘中固定的特殊位置上;

Q:FAT中哪些磁盘块是空的?

A:FAT值等于0就是空的;

Q:如何在FAT中尽量保证局部性呢?

A:FAT使用NextFit算法,在Append一个文件的时候寻找现在文件末尾最近的空闲block,相应的,FAT会产生零碎化的问题,尽管有整理碎片的方法,但是效率太低了

Q:如何读/写一个文件?

A:直接按照FAT表block by block依次读取即可;写数据就是先append之后再修改FAT表;

Q:如何格式化一个磁盘

A:格式化磁盘,本质上就是清理磁盘然后清零FAT表,当然快速格式化就是直接清空FAT表

关于FAT文件系统,存在很多问题

2.2 FFS

FFS文件系统的特点:

  • 文件号不是直接放在FAT表中,而是放在Inode向量中
  • 多层非对称树状结构
  • FAT中文件的属性是存放在文件所在的目录中的,即不存放在文件中;而FFS文件属性是直接存放在文件对应的数据块中

理解FFS只需要理解下面的图即可

File Metadata是文件的元数据和基本属性;

DP表示直接索引,表示其中每一项直接指向其中一个datablock,和FAT相同 - inode中有12个直接索引,因此可以寻址的范围是48kB,如果文件小于等于48kB,则直接使用直接索引就足够;

Indirect Pointer一级间接索引指向的datablock不存储文件的数据,只存储索引,每个索引指向的datablock存储文件数据,二级索引和三级索引类似,要会计算其容量;

一个一级间接索引:假设一个datablock是4kB,地址都是32bit,则一个datablock可以存储1024个索引,每个索引指向一个datablock,则寻址范围为4kB*1024=4MB

FFS文件系统的特性

FFS对于稀疏文件可以良好的存储,少占用空间;

FFS还是使用bitmap管理空闲空间,0/1表示是否空闲,bitmap存放在固定的位置

Q:inode究竟存放在哪里?

A:最早的时候存放在磁道的最外面,问题就是距离datablock可能会有点远,现在存储inode会根据目录的具体结构进行存储;

Q:FFS文件系统如何保证局部性?

A:首先是块group,通过将文件数据块以合适的方式组织放置(非随机)以提高其局部性 - 将一个磁盘分为多个块组,思想是需要局部性的数据都放在同一个块组中,接着将文件的元数据等放在同一个块组中(各个块组的元数据放在自己的块组中),减少寻道时间

具体设计:同一个目录/文件下的所有文件尽量放在同一个块组中,因为同一个目录中的文件被打开的概率更大;当创建一个新文件的时候,在文件所属文件夹的块组中寻找一个inode,除非块组中已经没有空闲的inode了;需要注意的是不能将所有的目录放在一起,不然所有的文件都是在一个块组中没有意义,还是适当做一定的区分;

Q:如何在一个块组内部分配datablock?

A:思路是在块组中寻找第一个空闲块,这个方法能很好的规避碎片化,被称为FirstFit算法,需要注意的是FFS中永远不会将磁盘占满;

First Fit算法的好处,因为前面的文件将空隙填满了,所以后面的文件几乎都会是连续的

最后做一个关于FFS中文件号转化的题型

之所以上面默认直接取inode中第一个项,实际上也是因为一般只需要一个对应的block就能存储所有文件/目录

其实还有一种可能是你这个地方没理解对,实际上应该是inode中存储了信息,是可以直接找到912号block存储了foo的,反正不可能是直接在block中寻找

关于FFS的优点和缺点的整合

2.3 NTFS

NTFS中最重要的数据结构是主文件表MFT,主文件表中的每一项都是1KB大小,有时候可以直接存储数据而不仅仅只是存储索引;

MFT中条目的属性分为常驻和非常驻,常驻的意思就是直接存储在MFT表中,非常驻表示其属性的值存储在MFT指向的空间中

NTFS主要分小文件结构、中文件结构和大文件结构

对于大文件,假如文件的碎片化实在是太多了,就需要加入间接的索引;

NTFS中文件的元数据并不是存在文件的本身,而是存储在一些固定的文件中,即这些文件是专门存储MFT这些结构的;

前面的文件系统都是把重要的结构简单的存放在固定的位置,但是在NTFS中将这些结构本身也作为文件来管理,好处是统一管理 ;

Q:假如MFT本身是一个文件我们如何读它?

A:因为读文件本身就需要MFT,但是MFT本身又是一个文件,无限循环,一般会直接约定NTFS的卷的第一个扇区指向MFT的第一个条目;

Q:NTFS如何保证局部性?

A:因为是变长的,所以使用bestfit,找到最小的合适的datablock即可

2.4 VFS

虚拟文件系统VFS用于给用户提供统一的接口,VFS并不是只提供统一的API接口,实际上还进行其他工作,比如协调Cache、路径查找等;

十四、reliable fs

前面一直在讲文件系统功能和效率如何优化,本章讲解如何使得文件系统更加可靠;

为什么需要可靠性?因为存储设备本身可能并不可靠(断电等行为),所以文件系统需要保证可靠性

Q:可靠的文件系统的可靠,指的是什么?

A:要么操作全部完成,要么一个操作都没有执行 - 即保证在各种错误情况下都能可靠,这与同步问题的原子性操作其实很类似;

主要有两类技术保证文件系统的可靠性:事务和RAID冗余阵列

1.Transactions

并不是所有的文件系统都使用事务,但是基本所有的数据库都使用事务;

一个事务本质上就是一系列原子的行为,核心概念就是将两个consistent状态转换,不会出现中间状态

一个事务的行为主要分为三个步骤,begin updates commit

事务保证了四个非常重要的属性

怎么实现一个事务?一个非常重要的手段就是logging,日志的思想非常简单,先将所有需要做的update写入log,写完log再写存储器;

注意:log中是append-only,不能修改

下面这个流程是事务的具体实现,被称为Redo loggiong

其中添加commit record的操作可以理解为一个原子操作

性能方面,log中记录了几乎所有的操作和数据的修改,本身就要写磁盘,现在还要写log,这将导致速度慢;

这也是为什么有些文件系统不采用事务的方式(实际上因为log是顺序的所以其实对性能影响也不会很大)

事务中的顺序非常重要

现在主要有两种实现事务的方法 - Journaling和Logging,其中Journaling只会对metadata的数据进行事务操作,而 Logging会对所有的数据进行事务操作,这是为了在效率和可靠性之间做一个权衡;

2.RAID

RAID的整体思想非常简单,即将数据存储在多个Disk中,即使一个磁盘坏了也可以通过另一个磁盘恢复,恢复方法有多种,恢复方法既可以在硬件层面也可以在软件层面;

RAID会有不同的Level

  • RAID 0:Raid0技术是把多块(至少两块)物理硬盘通过工具绑在一起,将数据分成几块分别依次写入到各个物理硬盘中。这样,硬盘的读写性能会提高数倍,但是RAID 0也有局限性,提高读写速率的同时,如
    果任意中的一块硬盘发生故障,将会导致整个系统的数据都受到破坏

  • RAID 1表示两个磁盘各存储完整的数据,整个I/O的速度是比较快的,但是写的时候是比较慢的 - 一个磁盘坏了直接读另一个磁盘恢复

  • RAID 1对空间的浪费很大,RAID 5是对它的优化,使用奇偶校验;图中data被划分成不同的条带,将条带顺序的分配到不同的磁盘上,其中P0、P1等都是奇偶校验,异或操作可以得到其中某个错误的条带Unit中的一个条带的数据,即恢复 - 之所以奇偶校验旋转排列是为了避免Disk不平衡的问题(存储奇偶校验的Disk会被写的次数多),另外条带的大小需要考虑平衡性;RAID5的缺点是如果两个条带坏了就不能恢复,同时还需要知道需要恢复的磁盘是哪个才能恢复

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坂.y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值