bluestore 流程解析

1.整体流程


图片发自简书App


图中展示了流程中的关键路径及涉及到的线程与队列。下面详细阐述工作流程。

重点关注:状态切换;kv存储数据的GC时机

1.1 queue_transactions

queue_transactions是store统一的入口,各个存储引擎如filestore、kvstore、bluestore都得实现这个入口。在queue_transactions里先初始化transaction(初始化状态为STATE_PREPARE),然后在_txc_add_transaction根据操作码的类型进行不同处理,将其放到transaction里,前一篇文章里的I/O映射逻辑就是根据操作码OP_WRITE在BlueStore::_write里进行处理。BlueStore::_write –> BlueStore::_do_write –> (_do_write_small/_do_write_big) –> _do_alloc_write 分配空间,如果采用aio就会调用bdev->aio_write准备aio的结构,放在pending_aios里,如果不是aio就直接pwrite(如果是非direct的还需要sync)。

1.2 STATE_PREPARE

_txc_state_proc里就是状态机的处理逻辑,根据所处的状态进行不同阶段的处理。起始状态是STATE_PREPARE,在这个状态下回检查是否还有未完成的aio,如果有就将状态置为STATE_AIO_WAIT,并调用_txc_aio_submit进行处理,否则就直接进入到下一个状态STATE_AIO_WAIT的处理。

在_txc_aio_submit里就是就是调用bdev->aio_submit –> KernelDevice::aio_submit –> io_submit将aio提交到内核进行处理(注:目前支持KernelDevice和NVMEDevice,这里以KernelDevice为例)。

使用linux Aio时,将I/O提交后,当内核处理完成后会通知到用户态,一种方式是使用eventfd,将其注册到epoll里,当内核处理I/O完成后会触发eventfd的事件从而进行处理;另外一种方式是用一个单独的线程,轮询调用io_getevents去获取完成的事件。在bluestore里采用的是第二种方式,对应的线程是KernelDevice::_aio_thread,当I/O处理完后会调用回调函数aio_cb进行处理(这个回调函数是在bluestore启动时创建KernelDevice设置的),在aio_cb中调用_txc_aio_finish –> _txc_state_proc,从而进入到下一个状态STATE_AIO_WAIT的处理。

1.3 STATE_AIO_WAIT

在这个状态里是调用_txc_finish_io进行处理,会将状态设置成STATE_IO_DONE。因为aio的完成可能是乱序的,有可能后提交的I/O先完成,但是需要保证kv事务的顺序性。bluestore里通过OpSequencer来保证kv事务的顺序性(在_txc_create里会将新的txc放到osr->q里,即q.push_back。在_osr_reap_done里从osr->q里挨个剔除完成的。),在_txc_finish_io里就是实现通过OpSequencer来保证每个事务在处于某个状态时,这个事务之前的事务也必须在这个状态,即使某个事务的I/O先完成,也得等到它之前的事务的I/O也完成后才能进入到下个状态的处理。

做了这个保证后,再对按序对STATE_IO_DONE状态的事务调用_txc_state_proc进入下一个状态的处理。

1.4 STATE_IO_DONE

进入这个状态后,会设置下个状态为STATE_KV_QUEUED,然后会根据bluestore_sync_transaction和bluestore_sync_submit_transaction这两个配置参数的组合作不同的处理:

1)bluestore_sync_transaction为true:表示同步提交kv到rocksdb并持久化,对应调用_txc_finalize_kv后再调用db->submit_transaction,即rocksdb::Write并设置rocksdb::WriteOptions.sync=true;

2)bluestore_sync_transaction为false,bluestore_sync_submit_transaction为true:表示将kv提交到rocksdb,但是不sync,也就是没有落盘,对应调用_txc_finalize_kv后再调用db->submit_transaction_sync,即rocksdb::Write,但rocksdb::WriteOptions.sync=false;

不管采用何种处理方式,最后都会将事务放到kv_queue里,然后通过kv_cond通知_kv_sync_thread。

1.5 _kv_sync_thread处理kv_queue

_kv_sync_thread线程里就是处理kv_queue和wal_cleanup_queue里的事务。按照流程,这一步走到从kv_queue里取事务进行处理的过程。处理的时候是将kv_queue替换给kv_committing,然后后续对kv_committing进行处理。

当bluestore_sync_transaction和bluestore_sync_submit_transaction都为false时(也就是在前一个状态里没做事务相关处理,直接放到kv_queue里了),会遍历kv_committing里的事务,调用_txc_finalize_kv将空间分配释放相关的元数据在kv事务进行处理(如设置key、删除key等),然后db->submit_transaction将kv提交到rocksdb,但是没有落盘。

然后都会调用db->submit_transaction_sync来进行提交并刷盘的动作,这样即使在1.4那一步已经提交sync了,这里也会多做一次,以确保不管前面是没提交、只提交了没sync、提交并sync了的,到了这一步操作后事务都落盘了。

对于每个处理完的事务,都会调用_txc_state_proc进入到下一个状态STATE_KV_QUEUED的处理。

1.6 STATE_KV_QUEUED

设置状态为STATE_KV_DONE,然后调用_txc_finish_kv处理onreadable、oncommit回调,就是将回调放到finisher queue里,触发finisher thread去进行回调的处理(即如果各个副本都处理完成,就会发送对应的响应给客户端)。然后直接进入到STATE_KV_DONE状态的处理。

1.7 STATE_KV_DONE

如果没有wal事务要处理,就直接设置状态为STATE_FINISHING,然后跳出此处处理,在下一次处理到该事务时判断到状态为STATE_FINISHING,从而进行完成的一些处理。

下面主要介绍有wal的情况,之前一篇文章讲过当有覆盖写的时候就会进行wal,设置状态为STATE_WAL_QUEUED,然后根据配置参数bluestore_sync_wal_apply有两种处理方式:

1)当bluestore_sync_wal_apply为false,就把事务放到wal_wq中(会触发WALWQ threads去处理),结束此次处理;

2)当bluestore_sync_wal_apply为true时,直接调用_wal_apply进行处理;

在_wal_apply中会设置状态为STATE_WAL_APPLYING,然后遍历wal事务中的op,调用_do_wal_op进行处理,在_do_wal_op里调用bdev->aio_write准备aio的结构,放在pending_aios里,如果不是aio就直接pwrite(如果是非direct的还需要sync)。

当wal事务中的op都处理完后,就会调用_txc_state_proc进入到下一个状态的处理。

1.8 WALWQ threads

上面说到在bluestore_sync_wal_apply为false时,wal事务直接放到wal_wq中,交由WALWQ的线程池来处理。在这个线程池里也是调用_wal_apply进行处理,具体在上面已经说过了。处理完调用_txc_state_proc进入到下一个状态STATE_WAL_APPLYING的处理。

1.9 STATE_WAL_APPLYING

在这个状态下回检查是否还有未完成的aio,如果有就将状态置为STATE_WAL_AIO_WAIT,然后调用_txc_aio_submit提交I/O到磁盘,并结束此次处理。否则就判断是否满足后续状态,如果是就进行处理,如果不是就结束。

在KernelDevice::_aio_thread,当I/O处理完后会调用回调函数aio_cb进行处理,在aio_cb中调用_txc_aio_finish –> _txc_state_proc,从而进入到下一个状态STATE_WAL_AIO_WAIT的处理。

1.10 STATE_WAL_AIO_WAIT

在这个状态下,调用_wal_finish,设置状态为STATE_WAL_CLEANUP,然后放到wal_cleanup_queue中,通知_kv_sync_thread去处理。

1.11 _kv_sync_thread处理wal_cleanup_queue

处理的时候是将wal_cleanup_queue替换给wal_cleaning,然后后续对wal_cleaning进行处理。在1.5节里已经介绍过kv_sync_thread对kv_queue的处理,其实_kv_sync_thread在每次处理时都是同时处理kv_queue和wal_cleanup_queue里的事务,只不过本文是按照逻辑处理流程才分开描述的。

对于wal_cleanup_queue里的事务,也是调用_txc_finalize_kv将空间分配释放相关的元数据在kv事务进行处理(如设置key、删除key等),然后在接下去的db->submit_transaction_sync中统一提交kv到rocksdb并sync落盘。这次submit_transaction_sync的调用对于kv_queue和wal_cleanup_queue中事务都是一起生效的。

在处理完成后,对于wal_cleanning中的事务都会调用_txc_state_proc进行下一个状态的处理。

1.12 STATE_WAL_CLEANUP

在这个状态里就是设置状态为STATE_FINISHING,然后直接进入STATE_FINISHING状态的处理。

1.13 STATE_FINISHING

调用_txc_finish进行一些结束状态的处理。

2.总结

从上面的流程分析可以知晓,一个I/O在bluestore里经历了多个线程和队列才最终完成,对于非WAL的写,比如对齐写、写到新的blob里等,I/O先写到块设备上,然后元数据提交到rocksdb并sync了,才返回客户端写完成(在STATE_KV_QUEUED状态的处理);对于WAL(即覆盖写),没有先把数据写块设备,而是将数据和元数据作为wal一起提交到rocksdb并sync后,这样就可以返回客户端写成功了,然后在后面的动作就是将wal里的数据再写到块设备的过程,对这个object的读请求要等到把数据写到块设备完成整个wal写I/O的流程后才行,代码里对应的是_do_read里先o->flush()的操作,所以bluestore里的wal就类似filestore里的journal的作用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容