全面瞭解 Redis 高階特性,實現高效能、高可靠的資料儲存和處理

2023-03-25 12:00:20


Redis 是一種高效能、高可靠的記憶體資料儲存和處理系統,它支援多種資料結構和協定,可以用於各種不同的應用場景。本文將介紹 Redis 的高階特性,包括持久化、事務、Lua 指令碼等方面,以及如何使用這些特性實現高效能、高可靠的資料儲存和處理。

高效能、高可用、高可延伸性的原理

  1. 基於記憶體的資料結構:Redis將資料儲存在記憶體中,而不是硬碟中,因此可以實現非常高速的讀寫操作。
  2. 單執行緒的模型:Redis採用單執行緒的模型,避免了多執行緒之間的競爭問題,也減少了執行緒切換的開銷。
  3. 高效的網路通訊:Redis採用自己設計的簡單協定進行通訊,協定本身非常輕量級,減少了網路傳輸的開銷。
  4. 非同步非阻塞式IO:Redis採用非同步非阻塞的IO模型,當IO操作完成後才會通知應用程式,避免了IO阻塞對效能的影響。
  5. 高效的持久化機制:Redis支援多種持久化機制,包括快照和AOF,可以滿足不同的業務需求,同時也可以提高資料的安全性。
學會與人相處,建立良好的人際關係,
這是在職場中獲得成功的關鍵。

持久化

Redis是一種記憶體資料庫,它將資料儲存在記憶體中,因此它非常快速。但是,如果Redis程序意外終止,所有資料將丟失。為了解決這個問題,Redis提供了持久化功能,它可以將記憶體中的資料非同步寫入磁碟,以便在Redis重啟後可以恢復資料。

RDB持久化

RDB持久化是將Redis在某個時間點上的資料儲存到硬碟上,可以看作是對Redis記憶體中的資料做一個快照。RDB持久化可以通過設定Redis伺服器的時間間隔來自動觸發,也可以手動執行。

AOF持久化

AOF持久化是將Redis的寫操作以文字形式追加到檔案中。AOF檔案中的每個寫操作都是一個Redis命令,當Redis伺服器重啟時,可以通過執行AOF檔案中的所有命令來恢復資料。

持久化的設定

RDB設定

RDB持久化的組態檔為redis.conf。在組態檔中,可以通過以下設定項來控制RDB持久化的行為:

  • save:指定Redis自動觸發RDB持久化的條件,格式為 save ,其中seconds表示時間間隔,changes表示資料變化的次數。例如,save 900 1 表示如果900秒內有至少1個鍵被修改,則觸發RDB持久化。
  • stop-writes-on-bgsave-error:如果設定為yes,則如果RDB持久化失敗,Redis伺服器將停止接受寫請求,直到RDB持久化成功為止。
    Redis還提供了以下與RDB持久化相關的命令:
  • save:手動觸發RDB持久化。
  • bgsave:在後臺非同步執行RDB持久化。

AOF設定

AOF持久化的組態檔為redis.conf。在組態檔中,可以通過以下設定項來控制AOF持久化的行為:

  • appendonly:如果設定為yes,則開啟AOF持久化。
  • appendfsync:指定AOF緩衝區何時將資料同步到硬碟,有以下三個選項:
    • always:每個Redis命令都會立即同步到硬碟。
    • everysec:每秒將AOF緩衝區中的資料同步到硬碟。
    • no:完全依賴作業系統將資料同步到硬碟。
  • no-appendfsync-on-rewrite:如果設定為yes,則當Redis執行AOF重寫時,不將資料同步到硬碟。
    Redis還提供了以下與AOF持久化相關的命令:
  • bgrewriteaof:在後臺非同步執行AOF重寫。
  • bgappendonly:在後臺非同步執行AOF緩衝區的資料同步到硬碟。

持久化的恢復

RDB的恢復

RDB持久化的恢復比較簡單,只需將RDB檔案複製到Redis伺服器的工作目錄,並在redis.conf檔案中指定RDB檔案的路徑即可。Redis伺服器啟動時會自動載入RDB檔案,並恢復資料。

人生如一場旅程,不要只看到目的地,
更要享受旅途中的美好。

AOF的恢復

AOF持久化的恢復相對複雜。首先,需要將AOF檔案載入到Redis伺服器中:

plaintextCopy code
redis-cli
CONFIG SET appendonly yes
BGREWRITEAOF

然後,需要清空Redis伺服器中的資料:

plaintextCopy code
redis-cli
FLUSHALL

最後,執行AOF檔案中的所有命令,恢復資料:

plaintextCopy code
redis-cli
CONFIG SET appendonly yes
BGREWRITEAOF

RDB和AOF的選擇

在選擇持久化方式時,需要根據實際的業務場景和需求來選擇RDB或AOF持久化。如果對資料完整性要求較高,可以選擇AOF持久化;如果對資料完整性要求不高,可以選擇RDB持久化。

持久化對效能的影響

持久化會對Redis伺服器的效能產生一定的影響,特別是在執行RDB持久化時,由於需要fork出子程序,會佔用一定的CPU和記憶體資源。因此,在設定持久化時,需要根據實際情況來平衡資料安全和效能的需求。

資料的丟失問題

由於Redis的持久化是非同步的,因此在Redis意外終止時,可能會丟失部分資料。為了最小化資料丟失的風險,可以使用AOF持久化,並將appendfsync設定為always。這將確保每個寫操作都同步到磁碟上的AOF檔案中。

事務

Redis事務是指在一次操作中執行多個命令,並且這些命令要麼全部被執行,要麼全部不執行。Redis事務可以保證一系列命令的原子性執行。

職場中最重要的能力並不是技術或知識,
而是溝通和共同作業的能力。

事務的優點

  • 原子性:Redis事務可以保證多個命令的原子性執行,即要麼全部執行,要麼全部不執行。
  • 效能:Redis事務可以將多個命令打包成一個批次操作,從而減少網路通訊的開銷,提高效能。
  • 一致性:Redis事務可以保證多個命令的一致性,即在執行事務期間,其他使用者端不會對這些命令進行修改。

實現方式

  • MULTI:開始一個事務。
  • EXEC:執行事務中的所有命令。
  • DISCARD:取消事務。
  • WATCH:監視一個或多個鍵,如果在事務執行期間這些鍵被修改,事務將被取消。

範例:

/**
     * 事務操作
     * @param isOpenError 是否開啟異常
     */
    public void transactionalMethod(boolean isOpenError) {
        redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations operations) {
                operations.multi(); // 開啟事務
                ValueOperations<String, String> valueOps = operations.opsForValue();
                valueOps.set("key1", "value1");
                if(isOpenError){
                    int i = 1 / 0;
                }
                valueOps.set("key2", "value2");
                List exec = operations.exec();//提交事務
                return exec;
            }
        });
    }

注意事項

  • Redis事務不支援回滾操作。
  • 如果在執行事務期間,鍵被其他使用者端修改,那麼事務將被取消。
  • Redis事務不支援巢狀事務。
  • Redis事務中的命令不能使用事務外的資料。
  • Redis事務中的命令不支援樂觀鎖。

應用場景

  • 批次操作:將多個命令打包成一個事務,從而減少網路通訊的開銷,提高效能。
  • 保證資料一致性:在需要保證資料一致性的場景中使用Redis事務可以避免因為並行操作導致資料不一致的問題。

釋出訂閱

釋出和訂閱是 Redis 的一種訊息傳遞機制,它可以實現多個使用者端之間的訊息通訊。下面是一個簡單的 Redis 釋出和訂閱的範例

實現訊息訂閱者

public class RedisMessageListener implements MessageListener {
    @Override
    public void onMessage(Message message, byte[] bytes) {
        System.out.println("收到訊息: " + message.toString());
    }
}

註冊訊息訂閱者

@Bean
    public RedisMessageListenerContainer redisContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisTemplate().getConnectionFactory());
        container.addMessageListener(new RedisMessageListener(), new ChannelTopic("pubsub:example"));
        return container;
    }

傳送訊息

public void publish(String message) {
        redisTemplate.convertAndSend("pubsub:example", message);
    }

lua指令碼

永遠保持謙虛和學習的心態,
才能不斷提升自己,贏得更多的機會和尊重。

Redis 支援 Lua 指令碼,可以通過編寫 Lua 指令碼來實現複雜的資料操作和處理。Redis 的 Lua 指令碼可以存取 Redis 資料庫,Redis 提供的各種命令和函數。

下面是一個使用lua指令碼實現redis自增計數器的範例

public Long increment(String key) {
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/increment.lua")));
        script.setResultType(Long.class);
        List<String> keys = Collections.singletonList(key);
        return redisTemplate.execute(script, keys);
    }

lua指令碼

local key = KEYS[1]
local value = redis.call('INCR', key)
return value

使用 Lua 指令碼可以將多個 Redis 命令封裝在一個指令碼中,減少網路開銷和伺服器負載。此外,Lua 指令碼還可以實現 Redis 不支援的資料結構和演演算法,可以擴充套件 Redis 的功能和應用範圍。

管道操作

管道(pipeline)是一種高效的Redis命令執行方式,它可以在一次通訊中傳送多個Redis命令,並一次性獲取所有命令的響應結果。這種方式可以有效地降低Redis伺服器的網路延遲和通訊開銷,提高Redis的效能。

下面是一個使用管道操作的範例

/**
     * 管道操作
     * 注意管道操作不支援事務和watch命令,需要謹慎使用。
     * 管道操作會將多個命令打包成一個請求傳送給Redis伺服器,
     * 如果其中一個命令執行失敗,那麼整個管道操作都會失敗
     */
    public void pipelineExample() {
        List<Object> results = redisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                connection.stringCommands().set("key1".getBytes(), "value1".getBytes());
                connection.stringCommands().set("key2".getBytes(), "value2".getBytes());
                connection.stringCommands().set("key3".getBytes(), "value3".getBytes());
                return null;
            }
        });
        System.out.println(results); // 列印結果
    }

完整程式碼地址

https://gitee.com/youlaiorg/youlai-learning.git

總結

本文介紹了Redis的高階特性,包括持久化、事務、釋出訂閱、lua指令碼和管道操作。其中,持久化可以實現資料的持久化儲存,事務可以保證一系列命令的原子性執行,釋出訂閱可以實現多個使用者端之間的訊息通訊,lua指令碼可以實現複雜的資料操作和處理,管道操作可以在一次通訊中傳送多個Redis命令。此外,本文還介紹了Redis高效能、高可用、高可延伸性的原理,包括基於記憶體的資料結構、單執行緒的模型、高效的網路通訊、非同步非阻塞式IO和高效的持久化機制。

做事要講求團隊合作,相互支援,共同進步。