DRBD源码分析(四)——activelog

新浪微博 QQ空间

大概有半年时间没有分析过DRBD的源码了。今天又翻出了DRBD的代码,想看一下activelog的作用和原理。

首先是看DRBD手册中关于activelog的介绍:http://www.drbd.org/users-guide-8.3/s-activity-log.html

手册的内容很精炼,只是简单介绍了工作原理,activelog中记录的是最近写入磁盘中的IO,每一条activelog对应着一个4M的数据块。62条这样的日志组成一个512bit的sector,整个activelog由若干个这样的sector组成。activelog的条数是可以指定的,在drbd.conf文件中可以配置,配置值为:activelog能记录的数据块的大小,注意不是日志的条数。该值的含义也就是:当出现故障重启时,需要在主备两端同步的数据块的总大小。

当写入新的4M数据块时,DRBD会刷新一次activelog,activelog是循环写入的,在元数据里面会记录当前的所有日志中,哪一条是最老的。因此当反转覆盖发生时,需要更新元数据。事实上,当运行的时间足够长时,反转覆盖在每一次添加一个4M数据块时都会发生。但是当指定的size值与512bit(代表240多M,具体值要根据代码计算。)不是整数倍关系时,在最后一个sector反转时,需要写两个sector,因此从这个角度讲,activelog的size最好是整数个sector,这样可以减少一部分不必要的写两个sector。

具体的activelog的结构为:

/* We maintain a trivial check sum in our on disk activity log.
* With that we can ensure correct operation even when the storage
* device might do a partial (last) sector write while loosing power.
*/
struct __packed al_transaction {
u32 magic;
u32 tr_number;
struct __packed {
u32 pos;
u32 extent; } updates[1 + AL_EXTENTS_PT];
u32 xor_sum;
};

这里AL_EXTENTS_PT的值为62。

再来看具体的日志记录过程:当主端在开始写入一个新的4M数据块时,就会将该块需要写入的位置记录到activelog,写activelog的过程本身就在一次bio的处理过程中,在bio处理过程中,不能再调用bio的处理函数,因此写activelog需要使用一个异步任务,这个在代码里面的注释有详细的说明:

void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector)
{
unsigned int enr = (sector >> (AL_EXTENT_SHIFT-9));
struct lc_element *al_ext;
struct update_al_work al_work;

D_ASSERT(atomic_read(&mdev->local_cnt) > 0);

trace_drbd_actlog(mdev, sector, "al_begin_io");

wait_event(mdev->al_wait, (al_ext = _al_get(mdev, enr)));

if (al_ext->lc_number != enr) {
/* drbd_al_write_transaction(mdev,al_ext,enr);
* recurses into generic_make_request(), which
* disallows recursion, bios being serialized on the
* current->bio_tail list now.
* we have to delegate updates to the activity log
* to the worker thread. */
init_completion(&al_work.event);
al_work.al_ext = al_ext;
al_work.enr = enr;
al_work.old_enr = al_ext->lc_number;
al_work.w.cb = w_al_write_transaction;
drbd_queue_work_front(&mdev->data.work, &al_work.w);
wait_for_completion(&al_work.event);
dev_err(DEV, "w_al_write_transaction called\n");
mdev->al_writ_cnt++;

/*
DUMPI(al_ext->lc_number);
DUMPI(mdev->act_log->new_number);
*/
spin_lock_irq(&mdev->al_lock);
lc_changed(mdev->act_log, al_ext);
spin_unlock_irq(&mdev->al_lock);
wake_up(&mdev->al_wait);
}
}

等待activelog写完成后,才发起IO本地写入流程和发往对端。

假设,本端写入完成后,IO还没有发往对端前,此时本端出现类似掉电的情况,这样本端的IO已经下盘,而对端的IO还没有下盘,两端出现了数据不一致,这样当本端启动时,则需要从此时的主端同步所有的数据,当整个镜像盘非常大时,这个同步过程会非常漫长。有了activelog后,同步慢的问题可以得到很好的解决,如果对端升主后,写入的数据未超出activelog能cover的数据块的size时,可以只比对本端记录的acitvesize的数据,将这部分数据同步到本端即可。因此同步时间,取决于activelog的大小。当然如果本端下点时间过长,对端在做主期间写入了太多的数据,那么还是需要作全盘同步的。这是不可避免的。activelog只是解决临时的主节点重启的问题。

在DRBD的官网上面有一篇文章详细介绍activelog的设计原理:Rapid resynchronization for replicated storage Activity-logging for DRBD

新浪微博 QQ空间

| 1 分2 分3 分4 分5 分 (4.50- 12票) Loading ... Loading ... | 这篇文章归档在:DRBD, 存储技术 | 标签: , , . | 永久链接:链接 | 评论(5) |

5 条评论

  1. 评论于 二月 28, 2019 at 00:24:32 CST | 评论链接

    看 DRBD8.4 的代码,11 年初提了一个 Patch,把 al 的 size 改成 512Byte 了……

  2. dubaodao
    评论于 六月 23, 2018 at 07:47:10 CST | 评论链接

    我的qq9178-65322,希望和您交流。

  3. dubaodao
    评论于 六月 23, 2018 at 07:44:33 CST | 评论链接

    al配合bitmap的话,还可以把bitmap持久化到硬盘,进一步保障了幸存节点掉电也不会丢失记录。请您确认下。

    • dubaodao
      评论于 六月 23, 2018 at 07:45:53 CST | 评论链接

      我的qq9178-65322,希望和您交流。

  4. 匿名
    评论于 六月 23, 2018 at 07:41:49 CST | 评论链接

    “因此同步时间,取决于activelog的大小。当然如果本端下点时间过长,对端在做主期间写入了太多的数据,那么还是需要作全盘同步的。这是不可避免的。” 这样说不对吧,bitmap可以保障下电时间很长,差异超过al的时候也可以快速同步。

评论

邮箱地址不会被泄露, 标记为 * 的项目必填。

8 - 2 = *



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <img alt="" src="" class=""> <pre class=""> <q cite=""> <s> <strike> <strong>

返回顶部