ZBLOG

使用类似redis设计方案,减少磁盘读写

如果要设计一个类似于 Redis 的内存数据结构,目的是减少磁盘的读写次数并提高性能,可以考虑使用以下方案。Redis 采用的是一种将数据完全放在内存中的键值存储方式,并且通过定期持久化或日志记录来保持数据安全。下面是一个简单的示例,演示如何实现一个类似 Redis 的图书管理系统。

设计思路

  1. 内存数据库:所有的数据都存储在内存中,以便快速访问。
  2. 持久化机制
    • 定期保存快照(RDB)。
    • 使用 AOF(Append Only File)日志记录每一次修改操作。
  3. 多线程支持:为了处理高并发请求,使用锁机制或无锁编程。

数据结构

我们将继续使用哈希表作为基础的数据结构,但引入一些额外的机制以支持持久化和更高效的读取:

#include <iostream>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <mutex>
#include <chrono>

struct Book {
    int id;
    std::string name;
    std::string creator;
    std::chrono::system_clock::time_point created_time;

    std::string serialize() const {
        auto time = std::chrono::system_clock::to_time_t(created_time);
        return std::to_string(id) + "," + name + "," + creator + "," + std::ctime(&time);
    }

    static Book deserialize(const std::string& data) {
        Book book;
        size_t pos = 0, lastPos = 0;

        // ID
        pos = data.find(',', lastPos);
        book.id = std::stoi(data.substr(lastPos, pos - lastPos));

        // Name
        lastPos = pos + 1;
        pos = data.find(',', lastPos);
        book.name = data.substr(lastPos, pos - lastPos);

        // Creator
        lastPos = pos + 1;
        pos = data.find(',', lastPos);
        book.creator = data.substr(lastPos, pos - lastPos);

        // Created Time
       book.created_time=std::chrono :: system_clock :: now(); // 暂时不解析时间

       return book;
   }
};

class BookManager {
private:
    std::unordered_map<int, Book> books; // 存储图书信息的哈希表
    std::mutex mtx;                      // 用于线程安全的锁

public:
    void addBook(const Book& book) {
      {
          std::lock_guard<std::mutex> lock(mtx); 
          books[book.id] = book;                 // 增加或更新图书信息
      }
      appendLog("ADD," + book.serialize());     // 同步日志记录
   }

   void removeBook(int id) {
      {
          std::lock_guard<std::mutex> lock(mtx); 
          books.erase(id);                       // 删除指定ID的图书       
      }
      appendLog("REMOVE," + std: to_string(id));     // 同步日志记录   
   }

   Book* getBook(int id) {                       //
       std: lock_guard<std: mutex> lock(mtx);  
       if (books.find(id) != books.end()) {     
           return &books[id];                    
       }
       return nullptr;                           
   }

   void persistToDisk(const std: string& filename) {  
       {                                               //
           std: lock_guard<std: mutex> lock(mtx);     //
           if (books.empty()) return;                //
          
           ofstream file(filename);                    //
           for (const auto& pair : books) {         
               file << pair.second.serialize();     
           }
         } 
     }

    
   void loadFromDisk(const string& filename){
      ifstream file(filename);
      if (!file.is_open()) return;

     string line ;
     while (getline(file,line)){
         if (!line.empty()){
             Book book=Book ::deserialize(line);
             addBook(book);
         }
     }
}

void appendLog(const string& logEntry){
 ofstream logFile("appendonly.aof", ios_base :: app ); // 以追加模式打开AOF文件 
logFile<< logEntry << endl;                               //
}
   
};

// Example usage:

int main() {
    BookManager manager;

    
manager.loadFromDisk("books.txt");  

// 添加新书籍到管理器 

manager.addBook({1, "C++ Primer", "Alice",std :: chrono :: system_clock :: now() });        
manager.addBook({2,"Effective C++","Bob",std :: chrono :: system_clock :: now() });        

manager.persistToDisk("books.txt");       

if(auto *book=manager.getBook(1)){         
cout << "Found:" << book->name << endl;      
}else{                                      
cout << "Not Found!"<<endl;                     
}

return 0;
}

功能说明:

  • 增、删、查功能与之前相同addBookremoveBookgetBook 方法仍然存在。
  • 持久化机制
    • 每当进行增加或删除操作时,会把该操作写入到 AOF 文件中,这样可以减少直接对文件的频繁读写。
  • 快照(RDB):用户可以调用 persistToDisk() 方法,将当前所有在内存中的数据持久化到文件中,用于后续加载。

多线程支持:

代码使用了 std_mutex 来保护共享资源(即 books 哈希表),确保在多线程环境下的数据一致性。

性能优化建议:

  • 可以设定一个时间间隔,让程序自动将当前状态保存到磁盘,而不是每次都手动调用函数。
  • 可以设计缓存策略,比如将最近访问过的数据保留在一块高速缓存中,以进一步提高查询效率。

这样的设计使得我们的系统能够在高并发情况下良好运作,同时保证了数据的一致性和完整性。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=21956

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?