关于 LogIndexAndSequenceCollector 通过多队列来缓解🔒竞争的优化方案 #265
longfar-ncy
started this conversation in
Ideas
Replies: 1 comment
-
@luky116 luky |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
概述
LogIndexAndSequenceCollector
主要是维护一个保存 braft log index (后简称logidx)和 rocksdb sequence number (后简称seqno)映射关系的队列,作用在于可以通过 seqno 找到对应的 logidx。为此提供了 3 个 API:LogIndex FindAppliedLogIndex(SequenceNumber seqno)
:void Update(LogIndex logidx, SequenceNumber seqno)
:void Purge(LogIndex smallest_flushed_logidx)
:由于是并发场景下,三个API都应该加🔒。
其中,
Find
是在每次 flush 时调用(compaction时直接返回0,不需要争抢🔒),flush 本身也算瓶颈点,如果 find 花费时间较长(除去🔒的影响,当前采用的是二分查找,时间复杂度O(logn)),或者🔒的争抢比较激励,对 flush 还是有一定影响。Update
是在每次 apply 日志时调用,braft 的 apply 是串行化操作,这里的操作是O(1),但如果这里🔒争抢比较激烈,对性能也会有一定程度的影响。优化方向有两个:一是避免🔒的争抢,二是尽可能缩短 find 查询时间。但主要瓶颈应该在🔒的争抢上。
因此,望哥提出了通过多队列来避免争抢🔒的优化思路。
方案思路
Collector 中维护多个队列(后称小队列),同时保存多个队列的数据结构也是个队列(称大队列)。Collector 有一个整体的🔒,用于保护保存大队列;每个队列也有一个自己的🔒,用于保护小队列队列中元素的读写。
这样的好处是,
Update
只需要关注最后一个小队列,如果它不满,就直接上小队列的🔒-添加-解🔒-返回,一气呵成;如果满了,就创建一个包含要添加元素的新小队列,再把新小队列添加进大队列,这样就只需要在添加到大队列时上大🔒即可。Find
需要首先上大队列的读🔒找到对应的小队列,得到对应的小队列后就可以解锁大🔒,然后上小队列的🔒进行查找。Purge
就上大🔒删掉需要删除的队列。但这里有个进一步优化点在于,用shared_ptr
保存小队列,在删除时提前拷贝智能指针到容器里,只在大队列里做结构上的删除,这个小队列的生命周期还不不结束。当大队列遍历完了、解🔒之后,再结束掉需要删除的小队列的生命周期,这样可以把小队列的析构时间放在大🔒之外,也不影响其他API。伪代码
Beta Was this translation helpful? Give feedback.
All reactions