3 个版本 (破坏性更新)
0.4.0 | 2023年7月3日 |
---|---|
0.3.0 | 2023年3月23日 |
0.2.0 | 2023年3月13日 |
#4 in #durable
130KB
3K SLoC
这是什么?
此crate实现了一种高效处理多个记录日志的解决方案。每个记录日志都有自己的“本地”位置概念。可以单独截断每个队列。
目标
- 持久化,在
fsync
策略上提供一些灵活性。 - 提供在特定位置截断队列的方法
- 处理任意数量的队列
- 具有有限的IO
- 速度快
- 提供实现推回的可能性
pub struct MultiRecordLog {
pub async fn create_queue(&mut self, queue: &str) -> Result<(), CreateQueueError>;
pub async fn delete_queue(&mut self, queue: &str) -> Result<(), DeleteQueueError>;
pub fn queue_exists(&self, queue: &str) -> bool;
pub fn list_queues(&self) -> impl Iterator<Item = &str> {
pub async fn append_record(
&mut self,
queue: &str,
position_opt: Option<u64>,
payload: &[u8],
);
pub async fn truncate(&mut self, queue: &str, position: u64) -> Result<(), TruncateError>;
pub fn range<R>(
&self,
queue: &str,
range: R,
) -> Option<impl Iterator<Item = (u64, &[u8])> + '_>;
}
非目标
这不是Kafka。该记录日志是为“少量数据”设计的。所有保留的数据都可以放入RAM中。
在quickwit的上下文中,该队列用于PushAPI,并打算包含1单位的数据。(60MB/s意味着3.6GB的RAM)
仅在启动时读取记录日志文件。读取记录日志文件的高性能不是目标。另一方面,快速写入很重要。
实现细节。
mrecordlog
将多个独立的队列多路复用到同一个记录日志中。这种方法的好处是限制了所需文件描述符的数量,更重要的是,限制了 fsync
的数量。
它还提供了截断给定记录日志队列的可能性。实际的数据删除发生在文件仅包含删除的记录时。然后,只有在那时,整个文件才会被删除。
该记录日志每1GB生成一个新的文件。一旦所有队列在文件的最后一个记录之后都被截断,记录日志文件就会被删除。
没有压缩逻辑。
待办事项
- 添加背压。
- 添加fsync策略
- 更好的测试
- 非自增位置
- 减少Arc
依赖项
~3–5.5MB
~90K SLoC