Raid1源代码分析--开篇总述
前段时间由于一些事情耽搁了,最近将raid1方面的各流程整理了一遍。网上和书上,能找到关于MD下的raid1的文档资料比较少。决定开始写一个系列的关于raid1的博客,之前写过的一篇读流程也会在之后加一些修改,我阅读的代码的linux内核版本是2.6.32.61。进入实验室的时间不长,关于磁盘管理等内核方面的理解不足或者有误之处,希望批评指正。
一、Raid1简介
Raid1又称为镜像磁盘阵列。由两块或者多块盘构成这样一个阵列,并且每块盘所存储的内容都是完全一致的。意思就是盘与盘之间互为镜像,而在上层看来只有一块盘。比如说,如果现在有两块1T的盘,做成一个raid1阵列,那么在用户看来只有一块1T的盘。
这样虽然明显降低了磁盘的利用率,但是却提高了数据的安全性。如果其中有一块盘坏了,数据仍然没有丢失,因为数据在其他盘中还有备份。只是盘阵会处于降级状态,那么这种情况,只需要用热备盘来替换损坏盘即可。
Raid1中的流程可以分为三大部分:读、写、同步。读请求会选择盘阵中的一块盘中进行读操作,写请求会对盘阵中每一块盘进行写操作,同步请求会将最新数据的盘内容读取出来,然后写入其他盘中,达到同步效果。
下面将从以下几个部分来进行展开介绍:
- Raid1相关数据结构
- Raid1相关策略
- 初始化流程分析
- 读流程分析
- 写流程分析
- 同步流程分析
- raid1d函数流程分析
- bitmap相关分析(bitmap会在后续单独分析)
二、Raid1相关数据结构
1) r1_bio结构
struct r1bio_s {
atomic_t remaining; //未完成的请求数
atomic_t behind_remaining; //延迟写的未完成请求数
sector_t sector; //请求扇区号
int sectors; //请求扇区数
unsigned long state; //状态
mddev_t *mddev; //raid1设备
struct bio *master_bio; //记录上层下发的bio
int read_disk; //读请求的盘号
struct list_head retry_list; //重试请求链表
struct bitmap_update *bitmap_update; //没啥用
struct bio *bios[0]; //指向盘阵中每个盘的bio
};
这里的r1_bio主要用来管理raid1中相关的bio。通过最后一个*bios[0]柔性数组来达到管理raid1下发到每个盘的bio,通过*master_bio来管理raid1接收到上层的bio。
remaining字段和behind_remaining字段,对于延迟写的判断起到了重要作用,在写流程中会有具体分析。
bitmap_update字段没什么用,在更高的代码版本中,直接将这个字段删除了。
2)conf结构
struct r1_private_data_s {
mddev_t *mddev; //raid1设备
mirror_info_t *mirrors; //盘阵的首地址指针
int raid_disks; //盘数
int last_used; //最后一次读操作的盘号
sector_t next_seq_sect; //顺序的下一个扇区
spinlock_t device_lock; //设备锁
struct list_head retry_list; //重试请求链表
struct bio_list pending_bio_list; //正常的读写请求链表
struct bio_list flushing_bio_list;
spinlock_t resync_lock; //同步锁
int nr_pending; //pending队列请求数
int nr_waiting; //等待请求数
int nr_queued; //retry队列的请求数
int barrier; //是否设置屏障,raid1自己的一套barrier
sector_t next_resync; //下一个要同步的扇区
int fullsync; //设置是否全部同步
wait_queue_head_t wait_barrier; //进程队列,通过这个切换回守护进程
struct pool_info *poolinfo;
struct page *tmppage; //临时页
mempool_t *r1bio_pool; //正常请求的r1bio结构的缓冲池
mempool_t *r1buf_pool; //同步请求的r1bio结构的缓冲池
};
这里r1_private_data_s是用来管理整个raid1本身的。其中的pending_bio_list和retry_bio_list两个队列是守护进程与其他进程交互的“纽带”,守护进程只需处理这两个队列即可。
flushing_bio_lsit字段没什么用,在更高的代码版本中,直接将这个字段删除了。
三、Raid1相关策略
1)WriteMostly
WriteMostly是对raid1成员盘设置的一种属性,用户决定哪些成员盘是否设置为WriteMostly盘,或者一个盘也不设置WriteMostly。WriteMostly盘认为是“慢盘”。对于设置了WriteMostly的盘,尽量避免从该盘中读数据。在read balance中有体现,是优先读非WriteMostly盘。假如镜像的速度很慢,这样的设置是非常有效的。
可以只设置WriteMostly盘而不设置Write Behind模式,设置WriteMostly盘是Write Behind的前提。是否启动write behind模式,取决于超级块的设置。
2)Write Behind
只有设置了WriteMostly盘,Write Behind才有意义。Write Behind模式意味着,只要数据写入了非WriteMostly模式的磁盘,就认为写入成功返回。如果没有设置write behind模式的话,则需要写入所有盘后才能认为写入成功。
设置Write Behind模式后,如果所有非WriteMostly盘写入成功,则通知上层“所有磁盘写入成功”,raid1层接收的上层bio即可结束返回。但实际情况并非上层“看到”的这样,因为还有可能存在WriteMostly盘还未完成写操作。所以一定存在Behind pages与WriteMostly盘对应,这是在raid1中保存的接受上层的bio的页结构的一份拷贝数据,在所有盘的写请求都成功返回后,才能把behind pages这份拷贝释放,并释放r1_bio结构。Behind pages用来保证写请求能最终完成,是写请求完整性和正确性的一个必要的保障。
例如,raid1中有两个成员盘。一个成员盘是本地磁盘,另一个成员盘是局域网中的一块盘,则将局域网的磁盘设置WriteMostly盘(因为比较“慢”),然后开启write behind模式。这样在写入数据时,本地磁盘数据写完后,raid则认为该次写操作已完成。
3)Read balance
Read balance是读均衡算法。在读请求的时候,通过read balance来选取一块盘进行读操作。读均衡算法达到了在尽量避免从WriteMostly盘读数据的前提下,对于其他每个成员盘读请求负载尽量一致,并且提高读取速度。具体流程分析在“Raid1源代码分析--读流程(重新整理)”文中有详细说明。
4)barrier
在raid1中有两种barrier。一种是接收到上层的bio所具有的barrier属性,一种是raid1自身实现的一套barrier。
对于接收到上层的具有barrier属性的bio,该barrier属性由用户决定是否设置,只有在写操作的时候会出现。当md收到一个barrier bio请求时,md会先把在该barrier bio之前到达的bio完成,然后再完成barrier bio,之后再处理在barrier bio之后到达的bio。通过bio中的标记为BIO_RW_BARRIER来判断是否设置了barrier。
对于raid1自身实现的一套barrier,只有在raid1进行同步操作的时候设置,而且同步时一定会设置。因为在同步过程中是不能让其他读写请求进入raid1层“打扰”同步操作的,所以raid1会自己设计一套barrier,来满足该需求。通过conf->barrier的增减,来控制barrier的设置,并通过判断conf->barrier是否为0,来决定是否阻拦读写操作,而让读写操作进入等待状态。
5)bitmap
Bitmap主要是为了保证数据的可靠性。在写的过程中,有可能存在不稳定的因素,比如磁盘损坏,系统故障等,这样导致写入失败,在系统恢复后,raid1也需要进行恢复,传统的恢复方式就是全盘扫描计算校验或者全量同步,如果磁盘比较大,那同步恢复的过程会很长,有可能再发生其他故障,这样就会对业务有比较大的影响。以raid1来说,在发生故障时,其实两块盘的数据很多都是已经一致的了,可能只有少部分不一致,所以就没必要进行全盘扫描,但是系统并不知道两块盘哪些数据是一致的,这就需要在某个地方记录哪些是已同步的,为此,就诞生了bitmap,简单来说,bitmap就是记录raid中哪些数据是一致的,哪些是不一致的,这样在raid进行恢复的时候就不用全量同步,而是增量同步了,从而减少了恢复的时间。
bitmap的一个bit对应盘阵的一个chunk,在盘阵数据写入前,设置该chunk对应的bit,盘阵写入完成,则清除该bit。要进行同步时,参照bitmap,只有置位的bit对应的chunk才需要进行同步,这样缩短了同步的时间,提高了效率。这是最简单的一种思路。
注:bitmap小节的两段,参考资料 http://www.bitstech.net/2014/01/27/linux软raid的bitmap分析/
http://blog.csdn.net/qincp/article/details/4396517
6)pending_list与retry_list
pending_list为正常请求的队列,retry_list为重试请求队列,这两个队列是守护进程与其他进程交互的枢纽。其他进程将bio或者r1_bio添加队列中就完成了自己的任务,唤醒守护进程;守护进程只操作这两个队列,先将pending_list中的请求一次下发,然后逐一处理retry_list中的请求。只有在两个队列都为空的情况下,守护进程才会退出。pending_list中的每一项为bio,retry_list中的每一项为r1_bio,因为pending_list中的存放的是正常请求,所以直接是bio结构下发即可,而retry_list是重试请求,需要对整个盘阵的bio进行重新处理,所以是r1_bio结构。
本文来自fangpei的博客,转载请标明出处:http://www.cnblogs.com/fangpei/
Raid1源代码分析--开篇总述的更多相关文章
- Raid1源代码分析--Barrier机制
本想就此结束Raid1的专题博客,但是觉得Raid1中自己构建的一套barrier机制的设计非常巧妙,值得单独拿出来分析.它保证了同步流程和正常读写流程的并发性,也为设备冻结/解冻(freeze/un ...
- Raid1源代码分析--一些补充
Raid1的源码的读.写.同步,在本系列博客中都已经分析完成.除了barrier机制要专门拿出来分析(下一篇会写)以外,有一些问题值得思考和注意,分析如下. 1.freeze_array是如何做的? ...
- Raid1源代码分析--同步流程
同步的大流程是先读,后写.所以是分两个阶段,sync_request完成第一个阶段,sync_request_write完成第二个阶段.第一个阶段由MD发起(md_do_sync),第二个阶段由守护进 ...
- Raid1源代码分析--写流程
正确写流程的总体步骤是,raid1接收上层的写bio,申请一个r1_bio结构,将其中的所有bios[]指向该bio.假设盘阵中有N块盘.然后克隆N份上层的bio结构,并分别将每个bios[]指向克隆 ...
- Raid1源代码分析--读流程(重新整理)
五.Raid1读流程分析 两个月前,刚刚接触raid1,就阅读了raid1读流程的代码,那个时候写了一篇博客.现在回过头看看,那篇的错误很多,并且很多地方没有表述清楚.所以还是决定重新写一篇以更正之前 ...
- Raid1源代码分析--初始化流程
初始化流程代码量比较少,也比较简单.主要是run函数.(我阅读的代码的linux内核版本是2.6.32.61) 四.初始化流程分析 run函数顾名思义,很简单这就是在RAID1开始运行时调用,进行一些 ...
- Raid1源代码分析--读流程
这篇博文不足之处较多,重新整理了一下,链接:http://www.cnblogs.com/fangpei/p/3890873.html 我阅读的代码的linux内核版本是2.6.32.61.刚进实验室 ...
- Solr4.8.0源码分析(5)之查询流程分析总述
Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...
- Android4.42-Settings源代码分析之蓝牙模块Bluetooth总体实现(总)
本文为博主原创,转载请注明出处:http://blog.csdn.net/zrf1335348191/article/details/50995466 蓝牙相关代码已在另两篇文章中介绍,有须要的能够查 ...
随机推荐
- java foreach记录
实现原理解释: http://blog.csdn.net/a596620989/article/details/6930479 http://stackoverflow.com/questions/8 ...
- java中 SSL认证和keystore使用
java中 SSL认证和keystore使用 2013-10-12 11:08 10488人阅读 评论(0) 收藏 举报 目录(?)[+] 好久没用过SSL认证了,东西久不用,就有点生疏. ...
- 关于javax.crypto.BadPaddingException: Blocktype错误的几种解决方法
此文章转载自:http://www.myexception.cn/mobile/1259076.html 关于javax.crypto.BadPaddingException: Blocktype异常 ...
- 根据请求头跳转判断Android&iOS
if(navigator.userAgent.match(/Android/i)) { window.location = 'http://apk.hiapk.com/m/downloads?id=c ...
- Mac OS X下HomeBrew安装卸载
1.卸载 cd `brew --prefix` rm -rf Cellar brew prune rm `git ls-files` rm -r Library/Homebrew Library/Al ...
- 由fprintf和printf看C语言三种标准流
一.C语言中的三种标准流 1.标准输入流:stdin 2.标准输出流:stdout 3.标准错误输出流:stderr 他们的类型都是File * 二.fprintf于printf的区别 frintf( ...
- 为什么要使用Nginx?
这里做了些基准测试表明nginx打败了其它的轻量级的web服务器和代理服务器,同样也赢了相对不是那么轻量级的产品. 有人说这些基准测试是不准确的,因为在这样那样的环境下,做的比较不一致.我倾向同意基准 ...
- 我的创业劲儿,无可阻挡-JAVA学院张孝伟
导语:张孝伟,这个怀揣着创业梦想的农村小伙,为了报答父母的恩情,他开启了自己的逐梦之旅.友好的伙伴,火旺的生意.以前让他如鱼得水.就在他满足于现状的时候,一场突如其来的事故,让他一夜间倾家荡产.他是否 ...
- 用户与 Oracle DB 交互具体过程
与 Oracle DB 交互 以下的演示样例从最主要的层面描写叙述 Oracle DB 操作.该演示样例说明了一种 Oracle DB 配置,在该配置中,用户和关联server进程执行于通过网络连接的 ...
- Ajax&XMLHttpRequest
XMLHttpRequest 简单省力的方法 将文件编码成base64通过Ajax上传 HTML5学习之FileReader接口 HTML5学习之FileReader接口 通过Ajax方式上传文件,使 ...