< 返回版块

lsk569937453 发表于 2024-05-17 20:56

#[derive(Clone)] pub struct DatabaseHolder { pub database_lock: Arc<Mutex>, } 目前是想要实现redis的rdb,当前是有许多线程会读写DatabaseHolder。然后做rdb的线程会获取锁,然后clone数据结构,再把锁drop掉,然后把数据写入到文件中。

碰到的问题:clone会造成内存突增,内存大概增长一倍的样子。原生的redis是使用fork+copy on write技术实现rdb的,在rust中怎么实现呢?

评论区

写评论
Bai-Jinlin 2024-05-19 19:21

1就是最经典的fork呀。

当调用fork系统调用后,父子进程的页表均映射到相同的物理地址(页帧),但是此时的双方页表项对可写区域权限为不可写,但是对于其vma来讲是可写的,这时父/子任意进程对内存进行写操作会触发保护异常,异常判断是cow导致后会讲内存进行复制,然后改写对应页表项的指向,从而减少内存复制的情况。

所以你想要备份时减少内存分配就用fork,代码大概是这样。

fn backup(){
    use fork::{fork, Fork};
    match fork() {
        Ok(Fork::Parent(_)) => { }
        Ok(Fork::Child) => {
            //todo backup
            std::process::exit(0);
        }
        _ => panic!("backup error!"),
    }
}

--
👇
lsk569937453: 1.这个方案暂时没想明白。有详细一点的方案吗? 2.dashmap是来替换RwLock的,我们无法假定用户使用redis是写多还是读多,因此数据结构无法替代Mutex。 3.rdb的目的就是将某一时刻内存中数据全部保存到文件中。因此分批次备份会导致rdb的数据不正确。这个分批次备份逻辑有问题。

--
👇
Bai-Jinlin: 三个解决方案。

  1. 学redis使用fork系统调用,与redis一样享受Linux提供的cow机制,一在内存写入不频繁的情况下减少内存复制。
  2. 使用dashmap,这是个lockfree的map,使用全程无需用锁,避免了不必要的内存复制。
  3. 使用精细的逻辑控制锁的释放,比如备份线程一次读出有限个的条目进行备份。
作者 lsk569937453 2024-05-19 17:39

1.这个方案暂时没想明白。有详细一点的方案吗? 2.dashmap是来替换RwLock的,我们无法假定用户使用redis是写多还是读多,因此数据结构无法替代Mutex。 3.rdb的目的就是将某一时刻内存中数据全部保存到文件中。因此分批次备份会导致rdb的数据不正确。这个分批次备份逻辑有问题。

--
👇
Bai-Jinlin: 三个解决方案。

  1. 学redis使用fork系统调用,与redis一样享受Linux提供的cow机制,一在内存写入不频繁的情况下减少内存复制。
  2. 使用dashmap,这是个lockfree的map,使用全程无需用锁,避免了不必要的内存复制。
  3. 使用精细的逻辑控制锁的释放,比如备份线程一次读出有限个的条目进行备份。
作者 lsk569937453 2024-05-19 17:31

这个搜到过,不过没想好数据结构。有详细一点的方法吗?

--
👇
liming01: 用Cow类型,参见: https://doc.rust-lang.org/std/borrow/enum.Cow.html

Bai-Jinlin 2024-05-18 13:31

三个解决方案。

  1. 学redis使用fork系统调用,与redis一样享受Linux提供的cow机制,一在内存写入不频繁的情况下减少内存复制。
  2. 使用dashmap,这是个lockfree的map,使用全程无需用锁,避免了不必要的内存复制。
  3. 使用精细的逻辑控制锁的释放,比如备份线程一次读出有限个的条目进行备份。
liming01 2024-05-17 22:03

用Cow类型,参见: https://doc.rust-lang.org/std/borrow/enum.Cow.html

1 共 5 条评论, 1 页