日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

redis重启会清除数据吗_从零开始手写 redis(三)内存数据重启后如何不丢失?...

發布時間:2025/6/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis重启会清除数据吗_从零开始手写 redis(三)内存数据重启后如何不丢失?... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

我們在 從零手寫 cache 框架(一)實現固定大小的緩存 中已經初步實現了我們的 cache。

我們在 從零手寫 cache 框架(一)實現過期特性 中實現了 key 的過期特性。

本節,讓我們來一起學習一下如何實現類似 redis 中的 rdb 的持久化模式。

持久化的目的

我們存儲的信息都是直接放在內存中的,如果斷電或者應用重啟,那么內容就全部丟失了。

有時候我們希望這些信息重啟之后還在,就像 redis 重啟一樣。

load 加載

說明

在實現持久化之前,我們來看一下一個簡單的需求:

如何在緩存啟動的時候,指定初始化加載的信息。

實現思路

這個也不難,我們在 cache 初始化的時候,直接設置對應的信息即可。

api

為了便于后期拓展,定義 ICacheLoad 接口。

public interface ICacheLoad<K, V> {/*** 加載緩存信息* @param cache 緩存* @since 0.0.7*/void load(final ICache<K,V> cache);}

自定義初始化策略

我們在初始化的時候,放入 2 個固定的信息。

public class MyCacheLoad implements ICacheLoad<String,String> {@Overridepublic void load(ICache<String, String> cache) {cache.put("1", "1");cache.put("2", "2");}}

測試

只需要在緩存初始化的時候,指定對應的加載實現類即可。

ICache<String, String> cache = CacheBs.<String,String>newInstance().load(new MyCacheLoad()).build();Assert.assertEquals(2, cache.size());

持久化

說明

上面先介紹初始化加載,其實已經完成了 cache 持久化的一半。

我們要做的另一件事,就是將 cache 的內容持久化到文件或者數據庫,便于初始化的時候加載。

接口定義

為了便于靈活替換,我們定義一個持久化的接口。

public interface ICachePersist<K, V> {/*** 持久化緩存信息* @param cache 緩存* @since 0.0.7*/void persist(final ICache<K, V> cache);}

簡單實現

我們實現一個最簡單的基于 json 的持久化,當然后期可以添加類似于 AOF 的持久化模式。

public class CachePersistDbJson<K,V> implements ICachePersist<K,V> {/*** 數據庫路徑* @since 0.0.8*/private final String dbPath;public CachePersistDbJson(String dbPath) {this.dbPath = dbPath;}/*** 持久化* key長度 key+value* 第一個空格,獲取 key 的長度,然后截取* @param cache 緩存*/@Overridepublic void persist(ICache<K, V> cache) {Set<Map.Entry<K,V>> entrySet = cache.entrySet();// 創建文件FileUtil.createFile(dbPath);// 清空文件FileUtil.truncate(dbPath);for(Map.Entry<K,V> entry : entrySet) {K key = entry.getKey();Long expireTime = cache.expire().expireTime(key);PersistEntry<K,V> persistEntry = new PersistEntry<>();persistEntry.setKey(key);persistEntry.setValue(entry.getValue());persistEntry.setExpire(expireTime);String line = JSON.toJSONString(persistEntry);FileUtil.write(dbPath, line, StandardOpenOption.APPEND);}}}

定時執行

上面定義好了一種持久化的策略,但是沒有提供對應的觸發方式。

我們就采用對用戶透明的設計方式:定時執行。

public class InnerCachePersist<K,V> {private static final Log log = LogFactory.getLog(InnerCachePersist.class);/*** 緩存信息* @since 0.0.8*/private final ICache<K,V> cache;/*** 緩存持久化策略* @since 0.0.8*/private final ICachePersist<K,V> persist;/*** 線程執行類* @since 0.0.3*/private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();public InnerCachePersist(ICache<K, V> cache, ICachePersist<K, V> persist) {this.cache = cache;this.persist = persist;// 初始化this.init();}/*** 初始化* @since 0.0.8*/private void init() {EXECUTOR_SERVICE.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {try {log.info("開始持久化緩存信息");persist.persist(cache);log.info("完成持久化緩存信息");} catch (Exception exception) {log.error("文件持久化異常", exception);}}}, 0, 10, TimeUnit.MINUTES);}}

定時執行的時間間隔為 10min。

測試

我們只需要在創建 cache 時,指定我們的持久化策略即可。

ICache<String, String> cache = CacheBs.<String,String>newInstance().load(new MyCacheLoad()).persist(CachePersists.<String, String>dbJson("1.rdb")).build(); Assert.assertEquals(2, cache.size()); TimeUnit.SECONDS.sleep(5);

為了確保文件持久化完成,我們沉睡了一會兒。

文件效果

  • 1.rdb

生成的文件內容如下:

{"key":"2","value":"2"} {"key":"1","value":"1"}

對應的緩存加載

我們只需要實現以下對應的加載即可,解析文件,然后初始化 cache。

/*** 加載策略-文件路徑* @author binbin.hou* @since 0.0.8*/ public class CacheLoadDbJson<K,V> implements ICacheLoad<K,V> {private static final Log log = LogFactory.getLog(CacheLoadDbJson.class);/*** 文件路徑* @since 0.0.8*/private final String dbPath;public CacheLoadDbJson(String dbPath) {this.dbPath = dbPath;}@Overridepublic void load(ICache<K, V> cache) {List<String> lines = FileUtil.readAllLines(dbPath);log.info("[load] 開始處理 path: {}", dbPath);if(CollectionUtil.isEmpty(lines)) {log.info("[load] path: {} 文件內容為空,直接返回", dbPath);return;}for(String line : lines) {if(StringUtil.isEmpty(line)) {continue;}// 執行// 簡單的類型還行,復雜的這種反序列化會失敗PersistEntry<K,V> entry = JSON.parseObject(line, PersistEntry.class);K key = entry.getKey();V value = entry.getValue();Long expire = entry.getExpire();cache.put(key, value);if(ObjectUtil.isNotNull(expire)) {cache.expireAt(key, expire);}}//nothing...} }

然后在初始化時使用即可。

小結

到這里,我們一個類似于 redis rdb 的持久化就簡單模擬完成了。

但是對于 rdb 這里還有需要可優化點,比如 rdb 文件的壓縮、格式的定義、CRC 校驗等等。

redis 考慮到性能問題,還有 AOF 的持久化模式,二者相輔相成,才能達到企業級別的緩存效果。

我們后續將陸續引入這些特性。

對你有幫助的話,歡迎點贊評論收藏關注一波~

你的鼓勵,是我最大的動力~

總結

以上是生活随笔為你收集整理的redis重启会清除数据吗_从零开始手写 redis(三)内存数据重启后如何不丢失?...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。