
1) 【一句话结论】
针对万兴喵库数据备份工具的离线缓存需求,设计分层架构(存储层+缓存层+同步层),采用LRU/LFU动态缓存策略,结合乐观锁与增量同步机制,支持数据完整性校验(MD5)和版本回滚,确保离线操作的一致性、安全性及高效性,并处理极端场景(如网络断开、密钥泄露)。
2) 【原理/概念讲解】
老师口吻解释系统核心模块:
3) 【对比与适用场景】
| 策略 | 定义 | 特性 | 适用场景(万兴喵库) | 注意点 |
|---|---|---|---|---|
| LRU | 根据访问时间排序,淘汰最久未访问的 | 实现简单(O(1)时间复杂度),适合高频访问数据 | 图片、高频小文档(如常用模板),访问模式稳定 | 可能误淘汰近期高频但未访问的数据(如用户刚编辑的图片,但未立即访问) |
| LFU | 根据访问频率排序,淘汰访问次数最少的 | 需记录访问次数(O(1)更新,O(n)查询),适合访问频率差异大的数据 | 文档、资料(如热门教程/冷门资料),需保留冷门但可能被访问的内容 | 计数器可能溢出(需定期重置),实现复杂度较高 |
4) 【示例】
伪代码展示核心逻辑(含乐观锁、版本控制、断点续传、数据校验):
// 存储层:SQLite表结构
// 表1: data_store (key, data_md5, data_version, data, last_access, file_type)
// 表2: pending_sync (key, operation_type, data_md5, data_version, sync_status)
class OfflineCache {
private Map<String, CacheEntry> cacheMap;
private SQLiteDatabase db;
private SyncManager syncManager;
private static final int MAX_CACHE_SIZE = 100;
private static final int MAX_PENDING_SIZE = 1000;
// 添加/更新缓存(带版本控制与MD5校验)
void put(String key, byte[] data, long serverVersion) {
String md5 = MD5Util.md5(data);
CacheEntry entry = new CacheEntry(data, md5, serverVersion, System.currentTimeMillis(), "image");
cacheMap.put(key, entry);
db.save(key, md5, serverVersion, data, System.currentTimeMillis(), "image");
evictIfNeeded();
}
// 获取缓存(乐观锁检查与数据校验)
Object get(String key) {
CacheEntry entry = cacheMap.get(key);
if (entry != null && !isExpired(entry)) {
entry.lastAccess = System.currentTimeMillis();
return entry.data;
}
byte[] data = db.load(key);
if (data != null) {
String dbMd5 = db.getMd5(key);
if (!dbMd5.equals(entry.md5)) { // 数据校验失败,从服务器重新下载
data = downloadFromServer(key);
db.update(key, MD5Util.md5(data), serverVersion, data);
}
CacheEntry newEntry = new CacheEntry(data, db.getVersion(key), System.currentTimeMillis(), "image");
cacheMap.put(key, newEntry);
}
return data;
}
// 本地修改(标记待同步)
void updateLocal(String key, byte[] newData) {
String newMd5 = MD5Util.md5(newData);
CacheEntry entry = cacheMap.get(key);
if (entry != null) {
entry.data = newData;
entry.md5 = newMd5;
cacheMap.put(key, entry);
db.markPending(key, "update", newMd5, db.getVersion(key));
}
}
// 淘汰策略(LRU)
void evictIfNeeded() {
if (cacheMap.size() > MAX_CACHE_SIZE) {
String keyToRemove = findLeastRecentlyUsedKey();
cacheMap.remove(keyToRemove);
db.delete(keyToRemove);
}
}
// 网络恢复后增量同步(断点续传)
void onNetworkRecovery() {
List<String> pending = db.getPendingChanges();
if (!pending.isEmpty()) {
syncManager.performIncrementalSync(pending, 0);
}
}
// 同步处理(断点续传与冲突检测)
void syncIncremental(List<String> keys, int offset) {
for (int i = offset; i < keys.size(); i++) {
String key = keys.get(i);
PendingEntry pending = db.getPending(key);
if (pending != null) {
if (pending.operationType.equals("update")) {
byte[] serverData = downloadFromServer(key);
String serverMd5 = MD5Util.md5(serverData);
if (serverMd5.equals(pending.dataMd5)) {
db.update(key, serverMd5, pending.dataVersion, serverData);
cacheMap.put(key, new CacheEntry(serverData, serverMd5, pending.dataVersion, System.currentTimeMillis(), "image"));
} else {
// 冲突:服务器数据变化,回滚本地修改
byte[] localData = db.load(key);
db.markConflict(key, localData, serverMd5);
// 通知用户选择保留哪个版本
showConflictDialog(key, localData, serverData);
}
} else if (pending.operationType.equals("delete")) {
db.delete(key);
cacheMap.remove(key);
}
}
}
}
// 数据加密(示例)
private byte[] encryptData(byte[] data) {
return AES.encrypt(data, keyStore.getKey());
}
private byte[] decryptData(byte[] encrypted) {
return AES.decrypt(encrypted, keyStore.getKey());
}
}
class CacheEntry {
byte[] data;
String md5;
long serverVersion;
long lastAccess;
String fileType;
}
5) 【面试口播版答案】
“面试官您好,针对万兴喵库的数据备份工具,我设计了一个离线缓存系统,核心是分层架构:存储层(SQLite持久化,带版本与MD5校验)、缓存层(LRU/LFU动态策略,图片用LRU,文档用LFU)、同步层(增量同步与断点续传)。数据更新时,本地修改标记为待同步并附带哈希与版本号,网络恢复后通过增量同步(比较哈希和版本号,仅传变化数据)。安全存储用AES-256加密,密钥存设备安全区域,定期轮换。淘汰策略按时间(7天未访问)、按大小(100MB容量)、按访问频率,结合文件类型。并发控制用乐观锁(版本号),冲突时回滚本地数据并提示用户。网络恢复时断点续传,记录进度,失败后指数退避重试。这样确保离线操作的一致性、安全性和高效性,满足万兴喵库的备份需求。”
6) 【追问清单】
7) 【常见坑/雷区】