如果要设计一个类似于 Redis 的内存数据结构,目的是减少磁盘的读写次数并提高性能,可以考虑使用以下方案。Redis 采用的是一种将数据完全放在内存中的键值存储方式,并且通过定期持久化或日志记录来保持数据安全。下面是一个简单的示例,演示如何实现一个类似 Redis 的图书管理系统。
设计思路
- 内存数据库:所有的数据都存储在内存中,以便快速访问。
- 持久化机制:
- 定期保存快照(RDB)。
- 使用 AOF(Append Only File)日志记录每一次修改操作。
- 多线程支持:为了处理高并发请求,使用锁机制或无锁编程。
数据结构
我们将继续使用哈希表作为基础的数据结构,但引入一些额外的机制以支持持久化和更高效的读取:
#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;
}
功能说明:
- 增、删、查功能与之前相同:
addBook
、removeBook
和getBook
方法仍然存在。 - 持久化机制:
- 每当进行增加或删除操作时,会把该操作写入到 AOF 文件中,这样可以减少直接对文件的频繁读写。
- 快照(RDB):用户可以调用
persistToDisk()
方法,将当前所有在内存中的数据持久化到文件中,用于后续加载。
多线程支持:
代码使用了 std_mutex
来保护共享资源(即 books
哈希表),确保在多线程环境下的数据一致性。
性能优化建议:
- 可以设定一个时间间隔,让程序自动将当前状态保存到磁盘,而不是每次都手动调用函数。
- 可以设计缓存策略,比如将最近访问过的数据保留在一块高速缓存中,以进一步提高查询效率。
这样的设计使得我们的系统能够在高并发情况下良好运作,同时保证了数据的一致性和完整性。
内容由零声教学AI助手提供,问题来源于学员提问