Redis存儲斷點續(xù)傳文件狀態(tài)的最佳實踐
1. Redis 中存儲文件上傳狀態(tài)
Redis 提供了豐富的數(shù)據(jù)結(jié)構(gòu),可以靈活地存儲和更新文件上傳的各類狀態(tài)。以下是幾種常見的實現(xiàn)方式。
使用 Hash 存儲文件狀態(tài)
在 Redis 中,每個文件的上傳狀態(tài)可以使用一個獨特的鍵(如 file_id
或者用戶 ID + 文件名的組合)來標識,所有與文件上傳相關的數(shù)據(jù)(如已上傳字節(jié)數(shù)、文件總大小、已上傳的分塊等)則存儲在一個 Hash 表中。例如:
Key: file_upload:<file_id> Fields: - uploaded_size: 已上傳的字節(jié)數(shù) - file_size: 文件的總大小 - chunks: 已上傳的分塊索引列表 - status: 當前上傳狀態(tài)(如 "uploading", "paused", "completed") - last_update_time: 上次更新的時間
存儲分塊上傳狀態(tài)
對于大文件分塊上傳,Redis 的集合(Set)或者列表(List)可以存儲每個已上傳的分塊。比如:
Key: file_chunks:<file_id> Set: {chunk_1, chunk_2, chunk_3, ...}
這樣,每個上傳的分塊都會被記錄,上傳狀態(tài)能被精準地追蹤和管理。
使用 TTL 進行狀態(tài)過期管理
對于文件上傳的臨時狀態(tài),可以設置適當?shù)倪^期時間。比如,當文件上傳完成后,自動清理 Redis 中的狀態(tài)數(shù)據(jù):
EXPIRE file_upload:<file_id> 86400 # 設置該文件狀態(tài)一天后過期
這樣避免了無用數(shù)據(jù)的長期占用內(nèi)存。
2. Redis 與數(shù)據(jù)庫保持一致
盡管 Redis 高效且快速,但它畢竟是內(nèi)存數(shù)據(jù)庫,系統(tǒng)重啟或故障時,存儲的數(shù)據(jù)可能會丟失。因此,將 Redis 中的斷點續(xù)傳狀態(tài)與數(shù)據(jù)庫中的持久化數(shù)據(jù)保持一致顯得尤為重要。
方法 1:定期同步
最簡單的方式是通過定時任務(如 Cron Job)定期將 Redis 中的上傳狀態(tài)同步到數(shù)據(jù)庫。可以設置一個后臺服務,每隔一定時間(如每小時)掃描 Redis 中所有的上傳狀態(tài),將其寫入數(shù)據(jù)庫。
數(shù)據(jù)庫表設計:
CREATE TABLE file_upload_status ( file_id VARCHAR(255) PRIMARY KEY, uploaded_size BIGINT, file_size BIGINT, chunks TEXT, -- 存儲已上傳的分塊信息,格式為 JSON status ENUM('uploading', 'paused', 'completed'), last_update_time DATETIME );
方法 2:實時同步
如果需要更高的實時性,可以采用實時同步的方法。每當 Redis 中某個文件的上傳狀態(tài)發(fā)生變化時,立即同步到數(shù)據(jù)庫??梢允褂孟㈥犃校ㄈ?Kafka 或 RabbitMQ)來異步處理同步任務,或者直接在代碼中同步更新。
例如:
- 更新 Redis 中的狀態(tài)時,觸發(fā)異步任務。
- 利用 Redis 的 Keyspace Notifications(鍵空間通知)來監(jiān)聽 Redis 中鍵的變化,并自動將變化同步到數(shù)據(jù)庫。
方法 3:雙寫機制
雙寫機制是在每次更新 Redis 時,直接同步更新數(shù)據(jù)庫。這種方式確保了每次寫操作都會同時影響 Redis 和數(shù)據(jù)庫,從而避免了數(shù)據(jù)的不一致。
例如,在更新文件上傳進度時:
MULTI # Redis 事務 HSET file_upload:<file_id> uploaded_size 1024 EXEC -- 同時更新數(shù)據(jù)庫 UPDATE file_upload_status SET uploaded_size = 1024 WHERE file_id = '<file_id>';
方法 4:系統(tǒng)重啟后的恢復
為了在系統(tǒng)重啟后能夠恢復上傳狀態(tài),可以在系統(tǒng)啟動時從數(shù)據(jù)庫加載上傳狀態(tài),并同步到 Redis。這樣即使服務重啟,斷點續(xù)傳的狀態(tài)也不會丟失。
for record in db.query("SELECT * FROM file_upload_status WHERE status = 'uploading'"): redis.hmset(f"file_upload:{record['file_id']}", { "uploaded_size": record['uploaded_size'], "file_size": record['file_size'], "status": record['status'] })
3. 一致性保障
為了確保 Redis 和數(shù)據(jù)庫中的數(shù)據(jù)一致性,我們可以采用以下策略:
- 事務控制:確保 Redis 和數(shù)據(jù)庫的寫入操作在同一個事務中完成,以保證數(shù)據(jù)的一致性。
- 消息隊列:通過消息隊列記錄 Redis 的變更事件,再由后臺服務同步到數(shù)據(jù)庫,從而避免直接操作數(shù)據(jù)庫帶來的性能瓶頸。
- 冪等性設計:確保每次操作是冪等的,即即使重復執(zhí)行,數(shù)據(jù)也不會出現(xiàn)沖突或不一致。
- 定期數(shù)據(jù)對賬:定期對 Redis 和數(shù)據(jù)庫中的數(shù)據(jù)進行比對,確保一致性。如果發(fā)現(xiàn)不一致,可以觸發(fā)修復機制。
4. 總結(jié)
Redis 作為臨時存儲,能高效地支持斷點續(xù)傳系統(tǒng)的狀態(tài)管理。結(jié)合定時同步、實時更新或雙寫機制,能夠確保 Redis 和數(shù)據(jù)庫中的數(shù)據(jù)保持一致性。在實現(xiàn)時,我們還要注意一致性保障,避免因 Redis 失效或重啟導致的數(shù)據(jù)丟失。
5. 代碼實踐
5.1 在 Redis 中存儲文件上傳狀態(tài)
首先,我們需要在 Redis 中為每個文件的上傳狀態(tài)創(chuàng)建一個 Hash 表來記錄文件的狀態(tài)。假設我們正在上傳一個大文件,采用分塊上傳。
#include <hiredis/hiredis.h> #include <iostream> #include <string> // 連接 Redis redisContext* connectToRedis() { redisContext* c = redisConnect("127.0.0.1", 6379); if (c == NULL || c->err) { if (c) { std::cerr << "Redis connection error: " << c->errstr << std::endl; } else { std::cerr << "Unable to allocate redis context\n"; } exit(1); } return c; } // 設置文件上傳狀態(tài) void setFileUploadStatus(redisContext* c, const std::string& file_id, size_t uploaded_size, size_t file_size, const std::string& status) { redisReply* reply = (redisReply*)redisCommand(c, "HSET file_upload:%s uploaded_size %zu file_size %zu status %s", file_id.c_str(), uploaded_size, file_size, status.c_str()); freeReplyObject(reply); } int main() { redisContext* c = connectToRedis(); std::string file_id = "file123"; size_t uploaded_size = 5000; // 已上傳 5000 字節(jié) size_t file_size = 10000; // 文件總大小 10000 字節(jié) std::string status = "uploading"; // 上傳狀態(tài):正在上傳 // 更新 Redis 中的文件狀態(tài) setFileUploadStatus(c, file_id, uploaded_size, file_size, status); redisFree(c); return 0; }
5.2 存儲已上傳的分塊狀態(tài)
對于分塊上傳,可以在 Redis 中使用 Set 來記錄已上傳的分塊。
// 添加已上傳分塊到 Redis Set void addUploadedChunk(redisContext* c, const std::string& file_id, const std::string& chunk_id) { redisReply* reply = (redisReply*)redisCommand(c, "SADD file_chunks:%s %s", file_id.c_str(), chunk_id.c_str()); freeReplyObject(reply); } int main() { redisContext* c = connectToRedis(); std::string file_id = "file123"; std::string chunk_id = "chunk_1"; // 上傳的第一個分塊 // 將已上傳的分塊存儲到 Redis Set 中 addUploadedChunk(c, file_id, chunk_id); redisFree(c); return 0; }
5.3 數(shù)據(jù)同步到數(shù)據(jù)庫
將 Redis 中的狀態(tài)同步到 MySQL 數(shù)據(jù)庫,以確保持久化存儲的一致性。
#include <mysql/mysql.h> // 連接 MySQL 數(shù)據(jù)庫 MYSQL* connectToDatabase() { MYSQL* conn = mysql_init(NULL); if (conn == NULL) { std::cerr << "mysql_init() failed\n"; exit(1); } conn = mysql_real_connect(conn, "localhost", "root", "password", "file_upload", 3306, NULL, 0); if (conn == NULL) { std:: cerr << "mysql_real_connect() failed\n"; exit(1); } return conn; } // 將文件上傳狀態(tài)同步到數(shù)據(jù)庫 void syncToDatabase(MYSQL* conn, const std::string& file_id, size_t uploaded_size, size_t file_size, const std::string& status) { std::string query = "UPDATE file_upload_status SET uploaded_size = " + std::to_string(uploaded_size) + ", file_size = " + std::to_string(file_size) + ", status = '" + status + "' WHERE file_id = '" + file_id + "'"; if (mysql_query(conn, query.c_str())) { std::cerr << "MySQL query failed: " << mysql_error(conn) << std::endl; } } int main() { MYSQL* conn = connectToDatabase(); std::string file_id = "file123"; size_t uploaded_size = 5000; size_t file_size = 10000; std::string status = "uploading"; // 將文件上傳狀態(tài)同步到數(shù)據(jù)庫 syncToDatabase(conn, file_id, uploaded_size, file_size, status); mysql_close(conn); return 0; }
通過這種方式,我們可以實現(xiàn)高效、穩(wěn)定的斷點續(xù)傳系統(tǒng),同時確保 Redis 和數(shù)據(jù)庫中的數(shù)據(jù)一致性。
到此這篇關于Redis存儲斷點續(xù)傳文件狀態(tài)的最佳實踐的文章就介紹到這了,更多相關Redis存儲斷點續(xù)傳文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
將MongoDB作為Redis式的內(nèi)存數(shù)據(jù)庫的使用方法
這篇文章主要介紹了將MongoDB作為Redis式的內(nèi)存數(shù)據(jù)庫的使用方法,原理其實只是將內(nèi)存虛擬作為磁盤,需要的朋友可以參考下2015-06-06Redis集群新增、刪除節(jié)點以及動態(tài)增加內(nèi)存的方法
本文主要介紹了Redis集群新增、刪除節(jié)點以及動態(tài)增加內(nèi)存的方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09如何使用Redis實現(xiàn)電商系統(tǒng)的庫存扣減
在日常開發(fā)中有很多地方都有類似扣減庫存的操作,本文主要介紹了如何使用Redis實現(xiàn)電商系統(tǒng)的庫存扣減,具有一定的參考價值,感興趣的可以了解一下2022-01-01Redis和數(shù)據(jù)庫 數(shù)據(jù)同步問題的解決
這篇文章主要介紹了Redis和數(shù)據(jù)庫 數(shù)據(jù)同步問題的解決操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01