Redis筆記整理(三):進階操作與高級部分

[TOC]

創(chuàng)新互聯(lián)是一家專業(yè)提供平泉企業(yè)網(wǎng)站建設,專注與成都網(wǎng)站制作、成都網(wǎng)站設計、H5場景定制、小程序制作等業(yè)務。10年已為平泉眾多企業(yè)、政府機構等服務。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進行中。


redis發(fā)布訂閱

Redis發(fā)布訂閱(pub/sub)是一種消息通信模式:發(fā)送者(pub)發(fā)送消息,訂閱者(sub)接收消息。
Redis客戶端可以訂閱任意數(shù)量的頻道。
下圖展示了頻道channel1,以及訂閱這個頻道的三個客戶端——client1,client2,client5之間的關系。
當有新消息通過PUBLISH命令發(fā)送給頻道channel1時,這個消息就會被發(fā)送給訂閱它的三個客戶端:

Redis筆記整理(三):進階操作與高級部分

相關操作命令如下:

命令描述
PSUBSCRIBE pattern [pattern ...] 訂閱一個或多個符合給定模式的頻道
PUSBSUB subcommand [argument [argument...]] 查看訂閱與發(fā)布系統(tǒng)狀態(tài)
PUBLISH channel message 將消息發(fā)送到指定的頻道
PUNSUBSCRIBE [ pattern [pattern ...]] 退訂所有給定模式的頻道
SUBSCRIBE channel [channel ...] 訂閱給定的一個或多個頻道的信息
UNSUBSCRIBE [channel [channel ...]] 指退訂給定的頻道

舉例如下:

創(chuàng)建的訂閱頻道名為redisChat
localhost:6379> SUBSCRIBE redisChat
1) "subscribe"
2) "redisChat
   重新打開一個新的redis客戶端,然后在同一個頻道redisChat發(fā)布兩次消息,訂閱者就能接收到相關消息。
127.0.0.1:6379> PUBLISH redisChat "jack is handsome boy"
這時在訂閱端中很快就可以看到該消息。

Redis事務

  Redis事務可以一次執(zhí)行多個命令,并且?guī)в幸韵聝蓚€重要的保證:
   事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執(zhí)行。
                          事務在執(zhí)行的過程中,不會被其他客戶端發(fā)送來的命令請求所打斷。
   事務是一個原子操作:事務中的命令要么全部被執(zhí)行,要么全部都不執(zhí)行。

   一個事務從開始到執(zhí)行會經(jīng)歷三個階段:
      開始事務。
      命令入隊。
      執(zhí)行事務。

其相關操作命令如下:

命令描述
DISCARD 取消事務,放棄執(zhí)行事務塊內(nèi)的所有命令
EXEC 執(zhí)行所有事務塊內(nèi)的命令
MULTI 標記一個事務塊的開始
UNWATCH 取消WATCH命令對所有key的監(jiān)視
WATCH key [key ...] 監(jiān)視一個或多個key,如果在事務執(zhí)行之前這些key被其它命令所改動,那么事務將被打斷

舉例如下:

uplooking01:7001> get name
"xpleaf"
uplooking01:7001> MULTI
OK
uplooking01:7001> get name
QUEUED
uplooking01:7001> set name yyh
QUEUED
uplooking01:7001> get name
QUEUED
uplooking01:7001> EXEC
1) "xpleaf"
2) OK
3) "yyh"

Redis命令總結

Redis的常用命令主要分為兩個方面、一個是鍵值相關命令、一個是服務器相關命令
1、鍵值相關命令
      keys * 取出當前所有的key
      exists name 查看redis是否有name這個key
      del name 刪除key name
      expire confirm 100 設置confirm這個key100秒過期
      ttl confirm 獲取confirm 這個key的有效時長
      select 0 選擇到0數(shù)據(jù)庫 redis默認的數(shù)據(jù)庫是0~15一共16個數(shù)據(jù)庫
      move confirm 1 將當前數(shù)據(jù)庫中的key移動到其他的數(shù)據(jù)庫中,
      persist confirm 移除confirm這個key的過期時間
      randomkey 隨機返回數(shù)據(jù)庫里面的一個key
      rename key2 key3 重命名key2 為key3
      type key2 返回key的數(shù)據(jù)類型
2、服務器相關命令
      ping PONG返回響應是否連接成功
      echo 在命令行打印一些內(nèi)容
      select 0~15 編號的數(shù)據(jù)庫
      quit  /exit 退出客戶端
      dbsize 返回當前數(shù)據(jù)庫中所有key的數(shù)量
      info 返回redis的相關信息
      config get dir/* 實時傳儲收到的請求
      flushdb 刪除當前選擇數(shù)據(jù)庫中的所有key
      flushall 刪除所有數(shù)據(jù)庫中的數(shù)據(jù)庫

Redis安全

我們可以通過redis的配置文件設置密碼參數(shù),這樣客戶端連接到redis服務就需要密碼驗證,這樣可以讓你的redis服務更安全。

我們可以通過以下命令查看是否設置了密碼驗證:

uplooking01:7001> config get requirepass
1) "requirepass"
2) ""

默認情況下requirepass參數(shù)是空的,這就意味著無需密碼驗證就可以連接到redis服務。如果設置密碼,客戶端連接redis服務就需要密碼驗證。否則無法執(zhí)行命令,有兩方式完成認證:

可以在連接時就指定密碼:redis-cli -h uplooking03 -a uplooking
也可以先連接,到終端后再認證:auth uplooking

Redis管道與性能測試

   Redis是一種基于客戶端-服務端模型以及請求/響應協(xié)議的TCP服務。這意味著通常情況下一個請求會遵循以下步驟:
   客戶端向服務端發(fā)送一個查詢請求,并監(jiān)聽scoket返回,通常是以阻塞模式,等待服務端響應。
   服務端處理命令,并將結果返回給客戶端。
   Redis管道技術可以在服務端末響應時,客戶端可以繼續(xù)想服務端發(fā)送請求,并最終一次性讀取所有服務端的相應。

下面使用Java代碼來進行測試:

package com.uplooking.bigdata;

import com.uplooking.bigdata.common.util.redis.JedisUtil;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;

/**
 * 使用管道和不使用管道的性能測試對比
 */
public class PipelineTest {

    @Test
    public void testPipeline() {
        int count = 10000;
        // 標記不使用管道操作時的開始時間
        long start = System.currentTimeMillis();
        // 不使用管道執(zhí)行操作
        withoutPipeline(count);
        // 標記不使用管道操作時的結束時間
        long end = System.currentTimeMillis();
        // 輸出不使用管道進行操作時所消耗的時間
        System.out.println("withoutPipeline: " + (end-start));
        // 標記使用管道操作時的開始時間
        start = System.currentTimeMillis();
        // 使用管道執(zhí)行操作
        usePipeline(count);
        // 標記使用管道操作時的結束時間
        end = System.currentTimeMillis();
        // 輸出使用管道進行操作時所消耗的時間
        System.out.println("usePipeline: " + (end-start));
    }

    private void withoutPipeline(int count) {
        JedisUtil.getJedis();
        Jedis jedis = JedisUtil.getJedis();
        for(int i =0; i < count; i++) {
            jedis.incr("testKey1");
        }
        cleanUp(jedis);
    }

    private void usePipeline(int count) {
        Jedis jedis = JedisUtil.getJedis();
        Pipeline pl = jedis.pipelined();
        for(int i =0; i < count; i++) {
            pl.incr("testKey1");
        }
        pl.sync();
        cleanUp(jedis);
    }

    public void cleanUp(Jedis jedis) {
        JedisUtil.returnJedis(jedis);
    }
}

JedisUtil可以查看前面的代碼,這里就不再給出。

輸出結果如下:

withoutPipeline: 1935
usePipeline: 60

測試結果還是有明顯的差距,所以多次操作使用pipeline還是有明顯的優(yōu)勢。

Redis性能測試:讀寫能力查看

 Redis性能測試是通過同時執(zhí)行多個命令實現(xiàn)的。
語法
  redis-benchmark [option] [option-value]
實例
  以下實例同時執(zhí)行10000個請求來檢測性能:
  1)、redis-benchmark -n 100000
  2)、redis-benchmark -h localhost -p 6379 -t set,lpush -n 100000 -q

其常見的命令選項如下:

選項描述默認值
-h 指定服務器主機名 127.0.0.1
-p 指定服務器端口 6379
-s 指定服務器socket
-c 指定并發(fā)連接數(shù) 50
-n 指定請求數(shù) 10000
-d 以字節(jié)的形式指定set/get值的數(shù)據(jù)大小 2
-k 1=keep alive 0=reconnect 1
-r set/get/incr使用隨機key,sadd使用隨機值
-P 通過管道傳輸<numreq>請求 1
-q 強制退出redis。僅顯示query/sec值
-csv 以CSV格式輸出
-l 生產(chǎn)循環(huán),永久執(zhí)行測試
-t 僅運行以逗號分割的測試命令列表
-I Idle模式。僅打開N個idle連接并等待

完整測試案例

[uplooking@uplooking01 ~]$ redis-benchmark -h uplooking01 -p 6379 -n 100000 -c 20
====== PING_INLINE ======
  100000 requests completed in 1.29 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.96% <= 1 milliseconds
100.00% <= 1 milliseconds
77459.34 requests per second

====== PING_BULK ======
  100000 requests completed in 1.33 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.95% <= 1 milliseconds
99.96% <= 2 milliseconds
100.00% <= 2 milliseconds
75187.97 requests per second

====== SET ======
  100000 requests completed in 1.29 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.96% <= 1 milliseconds
99.98% <= 2 milliseconds
99.98% <= 4 milliseconds
99.99% <= 5 milliseconds
100.00% <= 5 milliseconds
77339.52 requests per second

====== GET ======
  100000 requests completed in 1.35 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.98% <= 1 milliseconds
100.00% <= 1 milliseconds
74239.05 requests per second

====== INCR ======
  100000 requests completed in 1.29 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.98% <= 1 milliseconds
100.00% <= 1 milliseconds
77279.75 requests per second

====== LPUSH ======
  100000 requests completed in 1.28 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.98% <= 1 milliseconds
100.00% <= 1 milliseconds
77821.02 requests per second

====== RPUSH ======
  100000 requests completed in 1.28 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.94% <= 1 milliseconds
100.00% <= 1 milliseconds
77881.62 requests per second

====== LPOP ======
  100000 requests completed in 1.27 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.99% <= 1 milliseconds
100.00% <= 1 milliseconds
78616.35 requests per second

====== RPOP ======
  100000 requests completed in 1.27 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.92% <= 1 milliseconds
100.00% <= 1 milliseconds
78678.20 requests per second

====== SADD ======
  100000 requests completed in 1.34 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.99% <= 1 milliseconds
100.00% <= 1 milliseconds
74404.77 requests per second

====== SPOP ======
  100000 requests completed in 1.34 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.96% <= 1 milliseconds
100.00% <= 1 milliseconds
74738.41 requests per second

====== LPUSH (needed to benchmark LRANGE) ======
  100000 requests completed in 1.27 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.96% <= 1 milliseconds
100.00% <= 1 milliseconds
78492.93 requests per second

====== LRANGE_100 (first 100 elements) ======
  100000 requests completed in 2.81 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.87% <= 1 milliseconds
99.98% <= 2 milliseconds
100.00% <= 3 milliseconds
35536.61 requests per second

====== LRANGE_300 (first 300 elements) ======
  100000 requests completed in 7.59 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

97.91% <= 1 milliseconds
99.83% <= 2 milliseconds
99.96% <= 3 milliseconds
100.00% <= 4 milliseconds
100.00% <= 4 milliseconds
13166.56 requests per second

====== LRANGE_500 (first 450 elements) ======
  100000 requests completed in 10.27 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

37.79% <= 1 milliseconds
99.54% <= 2 milliseconds
99.91% <= 3 milliseconds
99.97% <= 4 milliseconds
99.99% <= 5 milliseconds
100.00% <= 6 milliseconds
100.00% <= 6 milliseconds
9734.25 requests per second

====== LRANGE_600 (first 600 elements) ======
  100000 requests completed in 13.01 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

0.72% <= 1 milliseconds
98.59% <= 2 milliseconds
99.76% <= 3 milliseconds
99.94% <= 4 milliseconds
99.98% <= 5 milliseconds
100.00% <= 6 milliseconds
7689.35 requests per second

====== MSET (10 keys) ======
  100000 requests completed in 1.69 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1

99.98% <= 1 milliseconds
100.00% <= 1 milliseconds
59241.71 requests per second

可以看到執(zhí)行了多個命令進行測試,如果只是希望測試部分命令的性能情況,可以參考下面的部分測試案例。

部分測試案例

[uplooking@uplooking01 ~]$ redis-benchmark -h uplooking01 -p 6379 -t set,lpush -n 100000 -q
SET: 75301.21 requests per second
LPUSH: 77101.00 requests per second

通過上面的測試,我們就可以知道我們的Redis環(huán)境的讀寫能力究竟如何。

Redis數(shù)據(jù)持久化

RDB(默認)

rdb方式的持久化是通過快照完成的,當符合一定條件時redis會自動將內(nèi)存中的所有數(shù)據(jù)執(zhí)行快照操作并存儲到硬盤上。
默認存儲在dump.rdb文件中。(文件名在配置文件中dbfilename)
redis進行快照的時機(在配置文件redis.conf中)
save 900 1:表示900秒內(nèi)至少一個鍵被更改則進行快照。
save 300 10
save 60 10000
(redis自動實現(xiàn)快照的過程,見下面的文檔內(nèi)容)

手動執(zhí)行save或者bgsave命令讓redis執(zhí)行快照。
兩個命令的區(qū)別在于,save是由主進程進行快照操作,會阻塞其它請求。bgsave是由redis執(zhí)行fork函數(shù)復制出一個子進程來進行快照操作。
文件修復:redis-check-dump

rdb的優(yōu)缺點
優(yōu)點:由于存儲的有數(shù)據(jù)快照文件,恢復數(shù)據(jù)很方便。
缺點:會丟失最后一次快照以后更改的所有數(shù)據(jù)。

redis實現(xiàn)快照的過程:

1:redis使用fork函數(shù)復制一份當前進程的副本(子進程)
2:父進程繼續(xù)接收并處理客戶端發(fā)來的命令,而子進程開始將內(nèi)存中的數(shù)據(jù)寫入硬盤中的臨時文件
3:當子進程寫入完所有數(shù)據(jù)后會用該臨時文件替換舊的RDB文件,至此,一次快照操作完成。

注意:redis在進行快照的過程中不會修改RDB文件,只有快照結束后才會將舊的文件替換成新的,也就是說任何時候RDB文件都是完整的。
這就使得我們可以通過定時備份RDB文件來實現(xiàn)redis數(shù)據(jù)庫的備份
RDB文件是經(jīng)過壓縮的二進制文件,占用的空間會小于內(nèi)存中的數(shù)據(jù),更加利于傳輸。

AOF

AOF基本配置
aof方式的持久化是通過日志文件的方式。默認情況下redis沒有開啟aof,可以通過參數(shù)appendonly參數(shù)開啟。
    appendonly yes

aof文件的保存位置和rdb文件的位置相同,都是dir參數(shù)設置的,默認的文件名是appendonly.aof,可以通過         appendfilename參數(shù)修改
    appendfilename appendonly.aof

redis寫命令同步的時機:

#appendfsync always 每次都會執(zhí)行
appendfsync everysec 默認 每秒執(zhí)行一次同步操作(推薦,默認)
#appendfsync no不主動進行同步,由操作系統(tǒng)來做,30秒一次

另外查看aof日志文件,它的內(nèi)容如下:

[uplooking@uplooking01 redis]$ tail -f appendonly.aof
single
$2
no
*3
$3
SET
$3
age
$2
18

其相關符號的說明如下:

*<參數(shù)數(shù)量>
$<參數(shù) 1 的字節(jié)數(shù)量> 
<參數(shù) 1 的數(shù)據(jù)> 
...
$<參數(shù) N 的字節(jié)數(shù)量> 
<參數(shù) N 的數(shù)據(jù)> 
aof日志文件重寫
  auto-aof-rewrite-percentage 100(當目前aof文件大小超過上一次重寫時的aof文件大小的百分之多少時會再次進行重寫,如果之前沒有重寫,則以啟動時的aof文件大小為依據(jù))
  auto-aof-rewrite-min-size 64mb
  手動執(zhí)行bgrewriteaof進行重寫
  重寫的過程只和內(nèi)存中的數(shù)據(jù)有關,和之前的aof文件無關。
  所謂的“重寫”其實是一個有歧義的詞語, 實際上, 
  AOF 重寫并不需要對原有的 AOF 文件進行任何寫入和讀取, 它針對的是數(shù)據(jù)庫中鍵的當前值。

文件修復:redis-check-aof

對于aof日志文件重寫的概念再進一步說明:

所謂“重寫”其實是一個有歧義的詞語,實際上,AOF重寫并不需要對原有AOF文件進行任何寫入和讀取,
它針對的是數(shù)據(jù)庫中鍵的當前值。

假設服務器對鍵list執(zhí)行了以下四條命令:
127.0.0.1:6379[1]> RPUSH list 1 2 3 4    //[1,2,3,4]
127.0.0.1:6379[1]> RPOP list                    //[1,2,3]
127.0.0.1:6379[1]> LPOP list            //[2,3]
當前列表鍵list在數(shù)據(jù)庫中的值就為[2,3]。要保存這個列表的當前狀態(tài),并且盡量減少使用的命令數(shù),
最簡單的方式不是去AOF文件分析前面執(zhí)行的三條命令,而是直接讀取list鍵在數(shù)據(jù)庫中的當前值,
然后用一條RPUSH 2,3代替前面的三條命令。

根據(jù)鍵的類型,使用適當?shù)膶懭朊顏碇噩F(xiàn)鍵的當前值,這就是AOF重寫的實現(xiàn)原理
rdb切換到aof
動態(tài)切換redis持久方式,從RDB切換到AOF(支持Redis 2.2及以上)
  CONFIG SET appendonly yes
  CONFIG SET save ""(可選)

注意:當redis啟動時,如果rdb持久化和aof持久化都打開了,那么程序會使用aof方式來恢復數(shù)據(jù)集,
因為aof方式所保存的數(shù)據(jù)通常是最完整的。如果aof文件丟失了,則啟動之后數(shù)據(jù)庫內(nèi)容為空。

注意:如果想把正在運行的redis數(shù)據(jù)庫,從RDB切換到AOF,建議先使用動態(tài)切換方式,再修改配置文件,重啟數(shù)據(jù)庫。
(不能自己修改配置文件,重啟數(shù)據(jù)庫,否則數(shù)據(jù)庫中數(shù)據(jù)就為空了。因為此時會直接讀取aof文件的數(shù)據(jù),
rdb的數(shù)據(jù)文件還存在,但是redis只會加載aof日志文件。)

在實際測試時,效果跟上面的描述是一樣的:

1.先使用rdb的方式作為數(shù)據(jù)的持久化方式
2.向redis中添加數(shù)據(jù)
3.動態(tài)執(zhí)行CONFIG SET appendonly yes
然后會發(fā)現(xiàn)在redis目錄下動態(tài)生成一個aof文件,并且其數(shù)據(jù)就是當前redis內(nèi)存中的數(shù)據(jù)。

并且通過測試發(fā)現(xiàn),假如age這個key是原來rdb中存在的數(shù)據(jù),一旦動態(tài)切換,原來rdb的數(shù)據(jù)都會備份到aof日志文件中,
這樣也就驗證了,其實動態(tài)切換的過程,會把當前redis內(nèi)存中的數(shù)據(jù)都保存到aof日志文件中。

Redis優(yōu)化

Redis內(nèi)存占用情況

 100萬個鍵值對(鍵是0到999999值是字符串“hello world”)在32位操作系統(tǒng)的筆記本上用了100MB
使用64位的操作系統(tǒng)的話,相對來說占用的內(nèi)存會多一點,這是因為64位的系統(tǒng)里指針占用了8個字節(jié),
但是64位系統(tǒng)也能支持更大的內(nèi)存,所以運行大型的redis服務還是建議使用64位服務器

一個Redis實例最多能存放多少keys
   理論上Redis可以處理多達232-1的keys,并且在實際中進行了測試,每個實例至少存放了2億5千萬的keys
   也可以說Redis的存儲極限是系統(tǒng)中的可用內(nèi)存值。

Redis優(yōu)化1:基本優(yōu)化

1.精簡鍵名和鍵值
  鍵名:盡量精簡,但是也不能單純?yōu)榱斯?jié)約空間而使用不易理解的鍵名。
  鍵值:對于鍵值的數(shù)量固定的話可以使用0和1這樣的數(shù)字來表示,(例如:male/female、right/wrong)

2.當業(yè)務場景不需要數(shù)據(jù)持久化時,關閉所有的持久化方式可以獲得最佳的性能

3.內(nèi)部編碼優(yōu)化(了解)
    redis為每種數(shù)據(jù)類型都提供了兩種內(nèi)部編碼方式,在不同的情況下redis會自動調整合適的編碼方式。(如圖所示)

4.SLOWLOG [get/reset/len]
  slowlog-log-slower-than 它決定要對執(zhí)行時間大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的命令進行記錄
  slowlog-max-len 它決定 slowlog 最多能保存多少條日志
  當發(fā)現(xiàn)redis性能下降的時候可以查看下是哪些命令導致的

Redis優(yōu)化2:內(nèi)存使用優(yōu)化

1.限制redis的內(nèi)存大小
  通過redis的info命令查看內(nèi)存使用情況
  如果不設置maxmemory或者設置為0,64位系統(tǒng)不限制內(nèi)存,32位系統(tǒng)最多使用3GB內(nèi)存。
  修改配置文件中的maxmemory和maxmemory-policy
  maxmemory:最大內(nèi)存
  maxmemory-policy:內(nèi)存不足時,數(shù)據(jù)清除策略

1.如果可以確定數(shù)據(jù)總量不大,并且內(nèi)存足夠的情況下不需要限制redis使用的內(nèi)存大小。
  如果數(shù)據(jù)量不可預估,并且內(nèi)存也有限的話,盡量限制下redis使用的內(nèi)存大小,這樣可以避免redis使用swap分區(qū)。

注意:如果不限制內(nèi)存,當物理內(nèi)存使用完之后,會使用swap分區(qū),這樣性能較低,如果限制了內(nèi)存,
     當?shù)竭_指定內(nèi)存之后就不能添加數(shù)據(jù)了,否則會報OOM錯誤。
     可以設置maxmemory-policy,內(nèi)存不足時刪除數(shù)據(jù)。

更詳細的說明如下:

在硬盤上進行讀寫操作要比在內(nèi)存上進行讀寫操作,時間上慢了近5個數(shù)量級,內(nèi)存是0.1μs(微秒)、而硬盤是10ms(毫秒)。如果Redis進程上發(fā)生內(nèi)存交換,那么Redis和依賴Redis上數(shù)據(jù)的應用會受到嚴重的性能影響。 通過查看used_memory指標可知道Redis正在使用的內(nèi)存情況,如果used_memory>可用最大內(nèi)存,那就說明Redis實例正在進行內(nèi)存交換或者已經(jīng)內(nèi)存交換完畢。管理員根據(jù)這個情況,執(zhí)行相對應的應急措施。

排查方案:若是在使用Redis期間沒有開啟rdb快照或aof持久化策略,那么緩存數(shù)據(jù)在Redis崩潰時就有丟失的危險。因為當Redis內(nèi)存使用率超過可用內(nèi)存的95%時,部分數(shù)據(jù)開始在內(nèi)存與swap空間來回交換,這時就可能有丟失數(shù)據(jù)的危險。當開啟并觸發(fā)快照功能時,Redis會fork一個子進程把當前內(nèi)存中的數(shù)據(jù)完全復制一份寫入到硬盤上。因此若是當前使用內(nèi)存超過可用內(nèi)存的45%時觸發(fā)快照功能,那么此時進行的內(nèi)存交換會變的非常危險(可能會丟失數(shù)據(jù))。 倘若在這個時候實例上有大量頻繁的更新操作,問題會變得更加嚴重。

通過減少Redis的內(nèi)存占用率,來避免這樣的問題,或者使用下面的技巧來避免內(nèi)存交換發(fā)生:1:盡可能的使用Hash數(shù)據(jù)結構。因為Redis在儲存小于100個字段的Hash結構上,其存儲效率是非常高的。所以在不需要集合(set)操作或list的push/pop操作的時候,盡可能的使用Hash結構。比如,在一個web應用程序中,需要存儲一個對象表示用戶信息,使用單個key表示一個用戶,其每個屬性存儲在Hash的字段里,這樣要比給每個屬性單獨設置一個key-value要高效的多。 通常情況下倘若有數(shù)據(jù)使用string結構,用多個key存儲時,那么應該轉換成單key多字段的Hash結構。 如上述例子中介紹的Hash結構應包含,單個對象的屬性或者單個用戶各種各樣的資料。Hash結構的操作命令是HSET(key, fields, value)和HGET(key, field),使用它可以存儲或從Hash中取出指定的字段。

2:設置key的過期時間。一個減少內(nèi)存使用率的簡單方法就是,每當存儲對象時確保設置key的過期時間。倘若key在明確的時間周期內(nèi)使用或者舊key不大可能被使用時,就可以用Redis過期時間命令(expire,expireat, pexpire, pexpireat)去設置過期時間,這樣Redis會在key過期時自動刪除key。 假如你知道每秒鐘有多少個新key-value被創(chuàng)建,那可以調整key的存活時間,并指定閥值去限制Redis使用的最大內(nèi)存。

3:回收key。在Redis配置文件中(一般叫Redis.conf),通過設置“maxmemory”屬性的值可以限制Redis最大使用的內(nèi)存,修改后重啟實例生效。也可以使用客戶端命令config set maxmemory 去修改值,這個命令是立即生效的,但會在重啟后會失效,需要使用config rewrite命令去刷新配置文件。 若是啟用了Redis快照功能,應該設置“maxmemory”值為系統(tǒng)可使用內(nèi)存的45%,因為快照時需要一倍的內(nèi)存來復制整個數(shù)據(jù)集,也就是說如果當前已使用45%,在快照期間會變成95%(45%+45%+5%),其中5%是預留給其他的開銷。 如果沒開啟快照功能,maxmemory最高能設置為系統(tǒng)可用內(nèi)存的95%。

當內(nèi)存使用達到設置的最大閥值時,需要選擇一種key的回收策略,可在Redis.conf配置文件中修改“maxmemory-policy”屬性值。 若是Redis數(shù)據(jù)集中的key都設置了過期時間,那么“volatile-ttl”策略是比較好的選擇。但如果key在達到最大內(nèi)存限制時沒能夠迅速過期,或者根本沒有設置過期時間。那么設置為“allkeys-lru”值比較合適,它允許Redis從整個數(shù)據(jù)集中挑選最近最少使用的key進行刪除(LRU淘汰算法)。Redis還提供了一些其他淘汰策略,如下:volatile-lru:使用LRU算法從已設置過期時間的數(shù)據(jù)集合中淘汰數(shù)據(jù)。volatile-ttl:從已設置過期時間的數(shù)據(jù)集合中挑選即將過期的數(shù)據(jù)淘汰。volatile-random:從已設置過期時間的數(shù)據(jù)集合中隨機挑選數(shù)據(jù)淘汰。allkeys-lru:使用LRU算法從所有數(shù)據(jù)集合中淘汰數(shù)據(jù)。allkeys-random:從數(shù)據(jù)集合中任意選擇數(shù)據(jù)淘汰no-enviction:禁止淘汰數(shù)據(jù)。

通過設置maxmemory為系統(tǒng)可用內(nèi)存的45%或95%(取決于持久化策略)和設置“maxmemory-policy”為“volatile-ttl”或“allkeys-lru”(取決于過期設置),可以比較準確的限制Redis最大內(nèi)存使用率,在絕大多數(shù)場景下使用這2種方式可確保Redis不會進行內(nèi)存交換。倘若你擔心由于限制了內(nèi)存使用率導致丟失數(shù)據(jù)的話,可以設置noneviction值禁止淘汰數(shù)據(jù)。

Redis優(yōu)化3

Redis是個單線程模型,客戶端過來的命令是按照順序執(zhí)行的,所以想要一次添加多條數(shù)據(jù)的時候可以使用管道(可以理解為批處理),或者使用一次可以添加多條數(shù)據(jù)的命令,例如:

setmset
get mget
lindex lrange
hset hmset
hget hmget

當前題目:Redis筆記整理(三):進階操作與高級部分
URL標題:http://muchs.cn/article2/pgohoc.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供關鍵詞優(yōu)化、微信小程序、App設計、Google定制開發(fā)、域名注冊

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站制作