Redis 從搭建到集羣實踐

 

第一章 安裝

1.1.windows 安裝

1.1.1下載

   下載地址: https://github.com/MSOpenTech/redis/releases

    Redis 支持 32 位和 64 位。這個需要根據你係統平臺的實際情況選擇,這裏我們下載 Redis-x64-xxx.zip壓縮包到 C 盤,解壓後,將文件夾重新命名爲 redis

     打開一個 cmd 窗口 使用cd命令切換目錄到 C:\redis 運行 redis-server.exe redis.windows.conf 。

     如果想方便的話,可以把 redis 的路徑加到系統的環境變量裏,這樣就省得再輸路徑了,後面的那個 redis.windows.conf 可以省略,如果省略,會啓用默認的。輸入之後,會顯示如下界面:

這時候另啓一個cmd窗口,原來的不要關閉,不然就無法訪問服務端了。

切換到redis目錄下運行 redis-cli.exe -h 127.0.0.1 -p 6379 。

設置鍵值對 set myKey abc 取出鍵值對 get myKey

1.2 Linux安裝

1.2.1下載: 

      從官網http://download.redis.io/releases/readis-3.0.6.tar.gz 下載,         

1.2.2.安裝:

      將下載的redis傳送到虛擬機中,因爲比較小,通過xshell傳輸 cd /usr/local/src

      mkdir redis    

 (1) 傳輸:rz   -E

 (2) 解壓: tar -xzvf redis...

 (3) 進入 cd  redis-3.2.6

    (4) 編譯: make

    (5) 安裝:make install

    (6) 查看  ll / ls

 

1.2.3 啓動 redis-server

 

在命令裏面不能退出來,所以得在開啓一個窗口

  查看進程 ps -ef |grep redis

1.2.4 開啓redis客戶端口

SUCCESS!

啓動配置

1.3 Redis配置 

  redis實例配置配置文件:redis.conf

       redis最多啓用6個實例

1.3.1 單機多實例配置  

   (1)在redis目錄下,cp一份redis.conf

             

   (2) 編輯redis2.config即可

             

   (3) port修改,如果設爲0,redis將不在socket上監聽任何客戶端連接。

                      

   (4) 守護進程模式: 默認情況下redis不是作爲守護進程運行的,如果想改爲後臺運行,就需要改成yes.

                           

   (5) 設置最大內存空間,默認情況下整個物理內存就是默認內存空間,風險太大

 必須帶上單位,通常是 1k 1gb  4m等這樣,不區分大小寫。

 

    (6) 默認情況下,redis在server上所有有效的網絡接口上監聽客戶端連接。如果只想讓它在一個網絡接口上監聽,那就綁定一個IP或者多個IP.

             

     (7) 可以設置密碼

 

     (8) 啓動實例

    (9) redis客戶端服務關閉

            redis-cli -h 127.0.0.1 -p 6380 shutdown     / kill 進程號

    (10) 插入數據

                

    (11) 讀取緩存數據

                      

     (12) 可以設置密碼,在配置文件(redis*.conf)

                       

     (13) 訪問需要密碼:auth 密碼

                         

1.3.2註釋:

(1) 設置模式,修改redis.conf

daemonize yes #默認爲no

(2) 端口配置:

   默認6379

 (3) 配置數據庫數量:

Redis默認開啓16個數據庫,不能像mysql自定義數據庫名稱,只能是數值,不能修改。

 (4) 配置內存大小:

會生成一個和內存大小一樣的文件。maxmemory 200mb #在真實環境必須部署,否則物理內存會被耗盡。一般配置200mb/500mb/1gb/2gb。可以分散到多臺服務器,和其它業務共享服務器,以充分利用資源。同時因爲分散,防止單點故障,造成大量緩存失效。

maxmemory 200mb

1.3.3啓動

redis-server #默認找redis.conf配置文件

(1)  redis-server redis6380.conf #指定配置文件,這樣可以啓動多個實例

(2)  redis-cli的使用之發送命令  redis-cli 默認連接:IP 127.0.0.1 端口 6379

(3)  指定IP端口:redis-cli -h 實例ip -p 實例端口

eg:  redis-cli –h 127.0.0.1 –p 6379

(4) 使用ping命令測試與客戶端和服務器鏈接是否正常

redis-cli ping或redis-cli

redis 127.0.0.1:6379>ping

PONG

redis-cli的使用之命令返回值,狀態回覆(最簡單的回覆-redis提供的測試命令)

錯誤回覆(以error開頭,後面跟着錯誤信息)

eg:127.0.0.1:6379>TEST

(error) ERR unknown command 'TEST'

  a. 整數回覆

    127.0.0.1:6379>INCR test_incr

    (integer) 1

  b. 字符串回覆(最長久的一種回覆,雙引號包裹)

    127.0.0.1:6379>get test

    “123”

  c. 多行字符串回覆

    127.0.0.1:6379>KEYS *

   1) "test_incr"

   2) "test"

(5)  redis數據庫切換SELECT

redis默認支持16個數據庫,對外都是以一個從0開始的遞增數字命名,可以通過參數database來修改默認數據庫個數。客戶端連接redis服務後會自動選擇0號數據庫,可以通過select命令更換數據庫,例如選擇1號數據庫:

127.0.0.1:6379>SELECT 1

OK

127.0.0.1:6379>GET test

(nil)

說明:

Redis不支持自定義數據庫名稱。

Redis不支持爲每個數據庫設置訪問密碼。

Redis的多個數據庫之間不是安全隔離的,FLUSHALL命令會清空所有數據庫的數據

1.3.4 安裝兩個服務

複製改端口無需再次安裝

只需要複製配置文件,啓動時選擇配置文件即可。

#cd  /usr/local/src/redis/redis.2.8.17

#cp  redis.conf redis6380.conf

#vi  redis6380.conf    #修改端口爲6380

#redis-server redis6380.conf

注意:啓動後,會殘留些數據,不完全,必須flushall清除掉。

1.4 外部編碼訪問配置

1.4.1 多機多實例配置

     克隆redis虛擬機1,配置redis1的三個redis實例

 

1.4.2 pom依賴

  <!-- jedis -->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.9.0</version>
</dependency>

1.4.3 連接測試

1.4.4 與外界java連接

(1) 需要開放端口

a . 打開6379端口(Centeros 7之前版本)

/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT

/etc/rc.d/init.d/iptables save #修改生效

/etc/init.d/iptables status #查看配置

 b. CenterOS 7版本,本次所有測試均使用CenterOS 7

systemctl start firewalld   開啓防火牆

firewall-cmd --zone=public --add-port=6379/tcp --permanent 開啓6379端口(permanent永久生效,沒有此參數,重啓後失效)

firewall-cmd --reload 重新載入

firewall-cmd --zone=public --query-port=6379/tcp 查看

(1)  錯誤處理:

解決:redis服務沒啓動。。。。

                 

 (2) 進入redis中,設置保護模式no.

                   

 (3) 訪問redis的驅動包。

 

使用最爲廣泛的是Jedis和Redisson(官方推薦),在企業中採用最多的是Jedis。 Jedis官網地址:https://github.com/xetorthio/jedis

 

(5)  Jedis測試

@Test
public void jedis() {
    Jedis jedis = new Jedis("192.168.88.110", 6379);
    jedis.set("test", "456789"); //設置值
    System.out.println(jedis.get("test")); //獲取值
    /*設置多個值*/
    jedis.mset("test1", "1", "test2", "2");
    List<String> olist = jedis.mget("test1", "test2");
    for (String s : olist) {
        System.out.println(s);
    }
    jedis.close();  //關閉
}

Jedis連接池示例:

public static void main(String[] args) {
    /*構建連接池配置信息*/
    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    /*設置最大連接數*/
    jedisPoolConfig.setMaxTotal(200);
    /*構建連接池*/
    JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.88.110",
        6379);
    /*從池中獲取連接*/
    Jedis jedis = jedisPool.getResource();
    /*讀取數據*/
    System.out.println(jedis.get("name"));
    /*將連接還回池中*/
    //jedisPool.returnResource(jedis); //被廢棄了,重寫了close()
    jedis.close();
    jedisPool.close();
}

1.5 Reids分片:集羣搭建

1.5.1分片代碼示例

/**
 * 集羣式連接池配置
 */
public class ShardedJedisPoolDemo {
    public static void main(String[] args) {
        /*構建連接池的配置信息*/
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        /*設置最大連接數*/
        jedisPoolConfig.setMaxTotal(200);
        /*定義集羣信息*/
        List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
        shards.add(new JedisShardInfo("192.168.88.110", 6379));
        shards.add(new JedisShardInfo("192.168.88.110", 6380));
        shards.add(new JedisShardInfo("192.168.88.110", 6381));
        /*定義集羣連接池*/
        ShardedJedisPool shardedJedisPool = new ShardedJedisPool(
            jedisPoolConfig, shards);
        ShardedJedis shardedJedis = null;

        try {
            /*從連接池中獲取分片對象*/
            shardedJedis = shardedJedisPool.getResource();
            /*存數據*/
            for (int i = 0; i < 100; i++) {
                shardedJedis.set("name_" + i, "tom_" + i);
            }
            /*從池中獲取數據*/
            String value = shardedJedis.get("name_32");
            System.out.println(value);
            value = shardedJedis.get("name_88");
            System.out.println(value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != shardedJedis) {
                /*關閉,檢測連接是否有效,有效放回連接池中,無效則重置*/
                shardedJedis.close();
            }
        }
        /*關閉連接池*/
        shardedJedisPool.close();
    }
}

1.5.2 Redis多個節點的透明訪問:

在6379上執行:

redis-cli -h 192.168.88.110 -p 6379

192.168.88.110:6379> keys *

 1) "name_53"

 2) "name_7"

 3) "name_99"

 4) "name_87"

 5) "name_18

.........

在6380上執行:

redis-cli -h 192.168.88.110 -p 6379

192.168.88.110:6380> keys *

  1) "name_75"

  2) "name_14"

  3) "name_89"

  4) "name_56"

  5) "name_0"

   ......

1.6  Redis 主從複製

1.6.1  查看全部信息

        

1.6.2  默認是主

        

1.6.3 配置從服務器,掛載到從服務器上

         

 

1.7  哨兵

Sentinel 總結

 

1.7.1 Sentinel的作用:

A、Master 狀態監測

B、如果Master 異常,則會進行Master-slave 轉換,將其中一個Slave作爲Master,將之前的Master作爲Slave 

C、Master-Slave切換後,master_redis.conf、slave_redis.conf和sentinel.conf的內容都會發生改變,即master_redis.conf中會多一行slaveof的配置,sentinel.conf的監控目標會隨之調換 

 

 

1.7.2 Sentinel的工作方式:

1):每個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其他 Sentinel 實例發送一個 PING 命令 
2):如果一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel 標記爲主觀下線。 
3):如果一個Master被標記爲主觀下線,則正在監視這個Master的所有 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態。 
4):當有足夠數量的 Sentinel(大於等於配置文件指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態, 則Master會被標記爲客觀下線 
5):在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有Master,Slave發送 INFO 命令 
6):當Master被 Sentinel 標記爲客觀下線時,Sentinel 向下線的 Master 的所有 Slave 發送 INFO 命令的頻率會從 10 秒一次改爲每秒一次 
7):若沒有足夠數量的 Sentinel 同意 Master 已經下線, Master 的客觀下線狀態就會被移除。 
若 Master 重新向 Sentinel 的 PING 命令返回有效回覆, Master 的主觀下線狀態就會被移除。

1.7.3 故障轉移

一次故障轉移操作由以下步驟組成:  

  1. 發現主服務器已經進入客觀下線狀態。  
  2. 對我們的當前紀元進行自增(詳情請參考 Raft leader election ), 並嘗試在這個紀元中當選。  
  3. 如果當選失敗, 那麼在設定的故障遷移超時時間的兩倍之後, 重新嘗試當選。 如果當選成功, 那麼執行以下步驟。  
  4. 選出一個從服務器,並將它升級爲主服務器。  
  5. 向被選中的從服務器發送 SLAVEOF NO ONE 命令,讓它轉變爲主服務器。  
  6. 通過發佈與訂閱功能, 將更新後的配置傳播給所有其他 Sentinel , 其他 Sentinel 對它們自己的配置進行更新。  
  7. 向已下線主服務器的從服務器發送 SLAVEOF 命令, 讓它們去複製新的主服務器。  
  8. 當所有從服務器都已經開始複製新的主服務器時, 領頭 Sentinel 終止這次故障遷移操作。    
  9. 故障轉移(failover)的第一步,就是選出新的master,大致的篩選流程爲:  
  10. 1. 刪除列表中所有處於下線或者斷線狀態的slave  
  11. 2. 刪除列表中所有最近五秒內沒有回覆過領頭sentinel的INFO命令的slave  
  12. 3. 刪除所有與已下線主服務器連接斷開超過down-after-milliseconds * 10毫秒的slave(確保slave沒有過早與master斷開,副本比較新)  
  13. 4. 根據slave優先級選擇  
  14. 5. 如果優先級相同,選擇複製偏移量最大的slave  
  15. 6. 如果都相同,按照run_id排序,選出run_id最小的slave  

 

哨兵監控主從redis,當master節點宕機,sentinel一直監控,如果發現master不能正常工作,sentinel從新選舉,從多個從節點中選舉出一個節點,把它改成主,其它slave節點,掛接到新的主上。舊的master進行修理,修理好,可以重新加入集羣中(動態),連接到新的master,它就變成一個slave。舊的主會自動全量從master上獲取數據(如果主的數據量很大,同步過程會稍長)

 

1.7.1 修改端口:

                           

1.7.2 配置監控的主服務器:

    

 

第一行配置指示 Sentinel 去監視一個名爲 mymaster 的主服務器, 這個主服務器的 IP 地址爲 127.0.0.1 , 端口號爲 6381 , 默認是2表示在sentinel集羣中只要有兩個節點檢測到redis主節點出故障就進行切換,單sentinel節點無效(自己測試發現的),改爲1,1表示宕機1個節點以後,就開始選舉  

 

1.7.3 其他配置使用默認配置,實際有需要再做相應配置,網上可以找到。

1.7.4 啓動:redis-sentinel sentinel.conf &

1.7.5 主節點掛掉,從節點自動選舉主節點,消息如下:

 

1.7.6  客戶端連接需要關閉保護模式(sentienl.conf)

  protected-mode no  

 

1.7.7 哨兵實例:

public class JedisSentinelDemo {
    public static void main(String[] args) {
        Set sentinels = new HashSet();
        sentinels.add(new HostAndPort("192.168.88.120", 26379).toString());
        sentinels.add(new HostAndPort("192.168.88.120", 26380).toString());
        JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster",
            sentinels);
        System.out.println("Current master: "
            + sentinelPool.getCurrentHostMaster().toString());
        Jedis master = sentinelPool.getResource();
        master.set("username", "wangqiulin");
        //sentinelPool.returnResource(master);
        Jedis master2 = sentinelPool.getResource();
        String value = master2.get("username");
        System.out.println("username: " + value);
        master2.close();
        sentinelPool.close();
        sentinelPool.destroy();
    }

}

1.8 Redis集羣官方推薦方案 Redis-Cluster 

Redis3.0版本之後,官方推薦集羣方案

1.8.1 redis使用中遇到的瓶頸

  我們日常在對於redis的使用中,經常會遇到一些問題

1、高可用問題,如何保證redis的持續高可用性。

2、容量問題,單實例redis內存無法無限擴充,達到32G後就進入了64位世界,性能下降。

3、併發性能問題,redis號稱單實例10萬併發,但也是有盡頭的。

1.8.2 redis-cluster的優勢  

1、官方推薦,毋庸置疑。

2、去中心化,集羣最大可增加1000個節點,性能隨節點增加而線性擴展。

3、管理方便,後續可自行增加或摘除節點,移動分槽等等。

4、簡單,易上手。

1.8.3 redis-cluster名詞介紹

1、master  主節點、

2、slave   從節點

3、slot    槽,一共有16384數據分槽,分佈在集羣的所有主節點中。=

1.8.4 redis-cluster簡介

 

圖中描述的是六個redis實例構成的集羣

6379端口爲客戶端通訊端口

16379端口爲集羣總線端口

集羣內部劃分爲16384個數據分槽,分佈在三個主redis中。

從redis中沒有分槽,不會參與集羣投票,也不會幫忙加快讀取數據,僅僅作爲主機的備份。

三個主節點中平均分佈着16384數據分槽的三分之一,每個節點中不會存有有重複數據,僅僅有自己的從機幫忙冗餘。

1.8.5 集羣部署

測試部署方式,一臺測試機多實例啓動部署。

(1) 安裝redis

$ wget http://download.redis.io/releases/redis-3.2.8.tar.gz

$ tar xzf redis-3.2.8.tar.gz

$ cd redis-3.2.8

$ make

(2) 修改配置文件 redis.conf

port 7000

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

cluster-enabled yes

cluster-config-file /opt/redis/7000/nodes.conf   #多實例情況下需要修改,例如/7000/

cluster-node-timeout 5000

首先, 讓我們進入一個新目錄, 並創建六個以端口號爲名字的子目錄, 稍後我們在將每個目錄中運行一個 Redis 實例: 命令如下:

mkdir cluster-test

cd cluster-test

mkdir 7000 7001 7002 7003 7004 7005

在文件夾 7000 至 7005 中, 各創建一個 redis.conf 文件, 文件的內容可以使用上面的示例配置文件, 但記得將配置中的端口號從 7000 改爲與文件夾名字相同的號碼。

(3)  啓動六個實例:

/編譯安裝目錄/src/redis-server redis.conf

注意,redis.conf應爲6個不同的修改過的多實例配置文件。 

注意,配置文件複製六分後,有許多需要你修改的地方。

(4) 創建redis-cluster

在src下運行集羣命令

redis-trib.rb命令與redis-cli命令放置在同一個目錄中,可全路徑執行或者創建別名。

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

1.8.6 安裝問題

注意:  redis的集羣,redis官方提供了redis-trib.rb工具,但是在使用之前 需要安裝ruby,以及redis和ruby連接:

yum -y install ruby ruby-devel rubygems rpm-build

gem install redis

其中 gem install redis命令執行時出現了:

 redis requires Ruby version >= 2.2.2的報錯,查了資料發現是Centos默認支持ruby到2.0.0,可gem 安裝redis需要最低是2.2.2

解決辦法是 先安裝rvm,再把ruby版本提升至2.3.3

1.安裝curl

sudo yum install curl

2. 安裝RVM

curl -L get.rvm.io | bash -s stable 

3. 

source /usr/local/rvm/scripts/rvm

4. 查看rvm庫中已知的ruby版本

rvm list known

5. 安裝一個ruby版本

rvm install 2.3.3

6. 使用一個ruby版本

rvm use 2.3.3

7. 設置默認版本

rvm remove 2.0.0

8. 卸載一個已知版本

ruby --version

9. 再安裝redis就可以了

gem install redis

10.在redis/src中編譯

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

11.爲了方便,可以寫腳本 start-cluster-all.sh

內容:

#!/bin/sh

#啓動實例

redis-server cluster/7000/redis.conf &

redis-server cluster/7001/redis.conf &

redis-server cluster/7002/redis.conf &

redis-server cluster/7003/redis.conf &

redis-server cluster/7004/redis.conf &

redis-server cluster/7005/redis.conf &

#創建集羣

cd  src

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

授權 chmod 777 start-cluster-all.sh

12. 運行

 

6個實例,默認配置3主3從,yes完成主從配置。

 

1.8.7 集羣命令

1.8.7.創建redis-cluster

./start-all.sh  

1.8.7.1移動槽

redis-trib.rb reshard 127.0.0.1:7000

執行集羣reshard操作,通過集羣中127.0.0.1:7000這一臺機器

[OK] All 16384 slots covered.

How many slots do you want to move (from 1 to 16384)? 2731

輸入需要移動的槽數量

What is the receiving node ID? 21c93aa709e10f7a9064faa04539b3ecd

輸入接收的節點的ID

How many slots do you want to move (from 1 to 16384)? 2731

What is the receiving node ID? 0abf4ca21c93aa709e10f7a9064faa04539b3ecd

Please enter all the source node IDs.

  Type 'all' to use all the nodes as source nodes for the hash slots.

  Type 'done' once you entered all the source nodes IDs.

Source node #1:0ddb4e430dda8778ac873dd169951c7d71b8235e

Source node #2:done

輸入所有被移動的節點ID,確認後輸入done

    Moving slot 5460 from 0ddb4e430dda8778ac873dd169951c7d71b8235e

    Moving slot 13653 from 0ddb4e430dda8778ac873dd169951c7d71b8235e

Do you want to proceed with the proposed reshard plan (yes/no)?

檢查後輸入yes進行移動分槽

至此,分槽移動完畢。

1.8.7.2 刪除節點 

redis-trib.rb del-node 127.0.0.1:6360 'f24c0c1ecf629b5413cbca632d389efcad7c8346'

最後跟着的是這個節點的ID,可在redis-cli終端中使用CLUSTER NODES查看

必要條件,此節點所有分槽均已移除。

1.8.7.3 添加master節點

redis-trib.rb add-node 127.0.0.1:6360 127.0.0.1:6350

新節點必須是空的,不能包含任何數據。請把之前aof和dump文件刪掉,並且若有nodes.conf也需要刪除。

add-node  將一個節點添加到集羣裏面, 第一個是新節點ip:port, 第二個是任意一個已存在節點ip:port

node:新節點沒有包含任何數據, 因爲它沒有包含任何slot。新加入的加點是一個主節點, 當集羣需要將某個從節點升級爲新的主節點時, 這個新節點不會被選中,同時新的主節點因爲沒有包含任何slot,不參加選舉和failover。

1.8.7.4 添加一個從節點

前三步操作同添加master一樣

第四步:redis-cli連接上新節點shell,輸入命令:cluster replicate 對應master的node-id

 

1.8.8 客戶端javaDemo

 @Test
public void testJedis() {
    String clusterNodes = "192.168.88.120:7000,192.168.88.120:7001,192.168.88.120:7002,192.168.88.120:7003,192.168.88.120:7004,192.168.88.120:7005";

    String[] nodelist = clusterNodes.split(",");
    Set<HostAndPort> nodes = new HashSet<>();
    for (String ipPort : nodelist) {
        String[] ipPortPair = ipPort.split(":");
        nodes.add(new HostAndPort(ipPortPair[0].trim(),
            Integer.valueOf(ipPortPair[1].trim())));
    }
    JedisCluster jedisCluster = new JedisCluster(nodes);
    jedisCluster.set("test_cluster", "7000");
    Assert.assertEquals("7000", jedisCluster.get("test_cluster"));
    jedisCluster.del("test_cluster");
   
} 

問題1:

通過jedis連接redis單機成功,使用JedisCluster連接redis集羣一直報Could not get a resource from the pool,如下圖:

斷點調試:

 

解決:

   修改 start-cluster-all.sh

./redis-trib.rb create --replicas 1 192.168.88.120:7000 192.168.88.120:7001 192.168.88.120:7002 192.168.88.120:7003 192.168.88.120:7004 192.168.88.120:7005

   刪除 各個文件夾下所有nodes文件和dump文件,重啓即可。

   (1) 清空數據 redis-cli -c -p 7000   -> flushdb

   (2) rm -rf cluster/700*/nodes*

   (3) rm -rf dump.700*

   (4) ./start-cluster-all.sh

附錄一: Redis配置參數表

屬性

說明

daemonize no

# 默認值no,該參數用於定製redis服務是否以守護模式運行。

pidfile /var/run/redis.pid

# 默認值/var/run/redis.pid,指定redis服務的進程號文件路徑,以守護模式運行時需要配置本參數;

port 6379

# 默認值6379,指定redis服務的端口

tcp-backlog 511

# 在高併發的環境中,爲避免慢客戶端的連接問題,需要設置一個高速後臺日誌

timeout 0

設置客戶端連接時的超時時間,單位爲秒。當客戶端在這段時間內沒有發出任何指令,那麼關閉該連接

# 0是關閉此設置

tcp-keepalive 0

# TCP keepalive

 Linux上,指定值(秒)用於發送 ACKs的時間。注意關閉連接需要雙倍的時間。默認爲 0

loglevel notice

指定日誌記錄級別,生產環境推薦 notice

# Redis總共支持四個級別: debugverbosenoticewarning,默認爲 verbose

# debug    記錄很多信息,用於開發和測試

# varbose  有用的信息,不像 debug會記錄那麼多

# notice   普通的 verbose,常用於生產環境

# warning  只有非常重要或者嚴重的信息會記錄到日誌

logfile ""

配置 log文件地址

默認值爲 stdout,標準輸出,若後臺模式會輸出到 /dev/null

databases 16

# 可用數據庫數,默認值爲 16,默認數據庫爲 0,數據庫範圍在 0- database-1)之間

快照

stop-writes-on-bgsave-error yes

保存數據到磁盤,格式如下 :

#  save <seconds> <changes>

指出在多長時間內,有多少次更新操作,就將數據同步到數據文件rdb

相當於條件觸發抓取快照,這個可以多個條件配合

比如默認配置文件中的設置,就設置了三個條件

#   save 900 1  900秒內至少有 1 key被改變

#   save 300 10  300秒內至少有 300 key被改變

#   save 60 10000  60秒內至少有 10000 key被改變

#   save 900 1

#   save 300 10

#   save 60 10000

 

stop-writes-on-bgsave-error yes

後臺存儲錯誤停止寫。

rdbcompression yes

存儲至本地數據庫時(持久化到 rdb文件)是否壓縮數據,默認爲 yes

rdbchecksum yes

#  RDB文件的是否直接偶像 chcksum

dbfilename dump.rdb

本地持久化數據庫文件名,默認值爲 dump.rdb

dir /var/lib/redis-server/

工作目錄

數據庫鏡像備份的文件放置的路徑。

這裏的路徑跟文件名要分開配置是因爲 redis在進行備份時,先會將當前數據庫的狀態寫入到一個臨時文件中,等備份完成,

再把該該臨時文件替換爲上面所指定的文件,而這裏的臨時文件和上面所配置的備份文件都會放在這個指定的路徑當中。

# AOF文件也會存放在這個目錄下面

注意這裏必須制定一個目錄而不是文件

slave-serve-stale-data yes

主從複製 .設置該數據庫爲其他數據庫的從數據庫 .

設置當本機爲 slav服務時,設置 master服務的 IP地址及端口,在 Redis啓動時,它會自動從 master進行數據同步

# slaveof <masterip><masterport>

 master服務設置了密碼保護時 ( requirepass制定的密碼 )

# slave服務連接 master的密碼

# masterauth <master-password>

當從庫同主機失去連接或者複製正在進行,從機庫有兩種運行方式:

# 1) 如果 slave-serve-stale-data設置爲 yes(默認設置 ),從庫會繼續響應客戶端的請求

# 2) 如果 slave-serve-stale-data是指爲 no,出去 INFO SLAVOF命令之外的任何請求都會返回一個

#    錯誤 "SYNC with master in progress"

slaveread-only yes

配置 slave實例是否接受寫。寫 slave對存儲短暫數據(在同 master數據同步後可以很容易地被刪除)是有用的,但未配置的情況下,客戶端寫可能會發送問題。

 Redis2.6後,默認 slave read-only

repl-disable-tcp-nodelay no

從庫會按照一個時間間隔向主庫發送 PINGs.可以通過 repl-ping-slave-period設置這個時間間隔,默認是 10

# repl-ping-slave-period 10

# repl-timeout 設置主庫批量數據傳輸時間或者 ping回覆時間間隔,默認值是 60

一定要確保 repl-timeout大於 repl-ping-slave-period

# repl-timeout 60

slave socket SYNC後禁用 TCP_NODELAY

如果選擇“ yes ,Redis將使用一個較小的數字 TCP數據包和更少的帶寬將數據發送到 slave,但是這可能導致數據發送到 slave端會有延遲 ,如果是 Linux kernel的默認配置,會達到 40毫秒 .

如果選擇 "no",則發送數據到 slave端的延遲會降低,但將使用更多的帶寬用於複製 .

slave-priority 100

如果少於 N slave連接,且延遲時間 <=M秒,則 master可配置停止接受寫操作。

例如需要至少 3 slave連接,且延遲 <=10秒的配置:

#  min-slaves-to-write 3

#  min-slaves-max-lag 10

設置 0爲禁用

#  默認 min-slaves-to-write 0(禁用), min-slaves-max-lag 10

AOF數據備份

appendonly no

# AOF文件名稱  (默認 : "appendonly.aof")

# appendfilename appendonly.aof

# Redis支持三種同步 AOF文件的策略 :

# no: 不進行同步,系統去操作  . Faster.

# always: always表示每次有寫操作都進行同步 . Slow, Safest.

# everysec: 表示對寫操作進行累積,每秒同步一次 . Compromise.

默認是 "everysec",按照速度和安全折中這是最好的。

如果想讓 Redis能更高效的運行,你也可以設置爲 "no",讓操作系統決定什麼時候去執行

或者相反想讓數據更安全你也可以設置爲 "always"

如果不確定就用  "everysec".

# appendfsync always

appendfsync everysec

# appendfsync no

# AOF策略設置爲 always或者 everysec時,後臺處理進程 (後臺保存或者 AOF日誌重寫 )會執行大量的 I/O操作

在某些 Linux配置中會阻止過長的 fsync()請求。注意現在沒有任何修復,即使 fsync在另外一個線程進行處理

爲了減緩這個問題,可以設置下面這個參數 no-appendfsync-on-rewrite

no-appendfsync-on-rewrite no

# AOF 自動重寫

 AOF文件增長到一定大小的時候 Redis能夠調用  BGREWRITEAOF 對日誌文件進行重寫

它是這樣工作的: Redis會記住上次進行寫日誌後文件的大小 (如果從開機以來還沒進行過重寫,那日誌大小在開機的時候確定 )

基礎大小會同現在的大小進行比較。如果現在的大小比基礎大小大制定的百分比,重寫功能將啓動

同時需要指定一個最小大小用於 AOF重寫,這個用於阻止即使文件很小但是增長幅度很大也去重寫 AOF文件的情況

設置  percentage 0就關閉這個特性

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

aof-rewrite-incremental-fsync yes

當一個子節點重寫 AOF文件時,如果啓用下面的選項,則文件每生成 32M數據進行同步。

Lua腳本

lua-time-limit 5000

# 一個 Lua腳本最長的執行時間爲 5000毫秒( 5秒),如果爲 0或負數表示無限執行時間。

Log日誌

slowlog-log-slower-than 10000

# Redis Slow Log 記錄超過特定執行時間的命令。執行時間不包括 I/O計算比如連接客戶端,返回結果等,只是命令執行時間

可以通過兩個參數設置 slow log:一個是告訴 Redis執行超過多少時間被記錄的參數 slowlog-log-slower-than(微妙 )

另一個是 slow log的長度。當一個新命令被記錄的時候最早的命令將被從隊列中移除

下面的時間以微妙爲單位,因此 1000000代表一秒。

注意指定一個負數將關閉慢日誌,而設置爲 0將強制每個命令都會記錄

slowlog-max-len 128

對日誌長度沒有限制,只是要注意它會消耗內存

可以通過  SLOWLOG RESET回收被慢日誌消耗的內存

推薦使用默認值 128,當慢日誌超過 128時,最先進入隊列的記錄會被踢出

事件通知

notify-keyspace-events ""

當事件發生時, Redis可以通知 Pub/Sub客戶端。

可以在下表中選擇 Redis要通知的事件類型。事件類型由單個字符來標識:

# K     Keyspace事件,以 _keyspace@<db>_的前綴方式發佈

# E     Keyevent事件,以 _keysevent@<db>_的前綴方式發佈

# g    通用事件(不指定類型),像 DEL, EXPIRE, RENAME,

# $     String命令

# s     Set命令

# h     Hash命令

# z    有序集合命令

# x    過期事件(每次 key過期時生成)

# e    清除事件(當 key在內存被清除時生成)

# A     g$lshzxe的別稱,因此”AKE”意味着所有的事件

# notify-keyspace-events帶一個由 0到多個字符組成的字符串參數。空字符串意思是通知被禁用。

例子:啓用 list和通用事件:

# notify-keyspace-events Elg

默認所用的通知被禁用,因爲用戶通常不需要改特性,並且該特性會有性能損耗。

注意如果你不指定至少 K E之一,不會發送任何事件。

高級配置

 

hash-max-zipmap-entries 512

 

hash-max-zipmap-value 64 

 hash中包含超過指定元素個數並且最大的元素沒有超過臨界時,

# hash將以一種特殊的編碼方式(大大減少內存使用)來存儲,這裏可以設置這兩個臨界值

# Redis Hash對應 Value內部實際就是一個 HashMap,實際這裏會有 2種不同實現,

這個 Hash的成員比較少時 Redis爲了節省內存會採用類似一維數組的方式來緊湊存儲,而不會採用真正的 HashMap結構,對應的 valueredisObject encoding zipmap,

當成員數量增大時會自動轉成真正的 HashMap,此時 encoding ht

list-max-ziplist-entries 512

list-max-ziplist-value 64

 Hash一樣,多個小的 list以特定的方式編碼來節省空間。

#  list數據類型節點值大小小於多少字節會採用緊湊存儲格式。

set-max-intset-entries 512

# set數據類型內部數據如果全部是數值型,且包含多少節點以下會採用緊湊格式存儲。

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

 hashe list一樣 ,排序的 set在指定的長度內以指定編碼方式存儲以節省空間

#  zsort數據類型節點值大小小於多少字節會採用緊湊存儲格式。

activerehashing yes

# Redis將在每 100毫秒時使用 1毫秒的 CPU時間來對 redis hash表進行重新 hash,可以降低內存的使用

當你的使用場景中,有非常嚴格的實時性需要,不能夠接受 Redis時不時的對請求有 2毫秒的延遲的話,把這項配置爲 no

如果沒有這麼嚴格的實時性要求,可以設置爲 yes,以便能夠儘可能快的釋放內存。

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb60

client-output-buffer-limit pubsub 32mb 8mb60

# 客戶端的輸出緩衝區的限制,因爲某種原因客戶端從服務器讀取數據的速度不夠快,

# 可用於強制斷開連接(一個常見的原因是一個發佈 /訂閱客戶端消費消息的速度無法趕上生產它們的速度)。

可以三種不同客戶端的方式進行設置:

# normal -> 正常客戶端

# slave  -> slave MONITOR客戶端

# pubsub -> 至少訂閱了一個 pubsub channel pattern的客戶端

每個 client-output-buffer-limit語法 :

# client-output-buffer-limit <class><hard limit> <soft limit> <soft seconds>

一旦達到硬限制客戶端會立即斷開,或者達到軟限制並保持達成的指定秒數(連續)。

例如,如果硬限制爲 32兆字節和軟限制爲 16兆字節 /10秒,客戶端將會立即斷開

如果輸出緩衝區的大小達到 32兆字節,客戶端達到 16兆字節和連續超過了限制 10秒,也將斷開連接。

默認 normal客戶端不做限制,因爲他們在一個請求後未要求時(以推的方式)不接收數據,

只有異步客戶端可能會出現請求數據的速度比它可以讀取的速度快的場景。

把硬限制和軟限制都設置爲 0來禁用該特性

hz 10

# Redis調用內部函數來執行許多後臺任務,如關閉客戶端超時的連接,清除過期的 Key,等等。

不是所有的任務都以相同的頻率執行,但 Redis依照指定的“Hz”值來執行檢查任務。

默認情況下,“ Hz”的被設定爲 10

提高該值將在 Redis空閒時使用更多的 CPU時,但同時當有多個 key同時到期會使 Redis的反應更靈敏,以及超時可以更精確地處理。

範圍是 1 500之間,但是值超過 100通常不是一個好主意。

大多數用戶應該使用 10這個預設值,只有在非常低的延遲的情況下有必要提高最大到 100

附錄二: Redis命令

1. 對value操作的命令

exists(key):確認一個key是否存在

del(key):刪除一個key

type(key):返回值的類型

keys(pattern):返回滿足給定pattern的所有key

randomkey:隨機返回key空間的一個key

rename(oldname, newname):將key由oldname重命名爲newname,若newname存在則刪除newname表示的key

dbsize:返回當前數據庫中key的數目

expire:設定一個key的活動時間(s)

ttl:獲得一個key的活動時間

select(index):按索引查詢

move(key, dbindex):將當前數據庫中的key轉移到有dbindex索引的數據庫

flushdb:刪除當前選擇數據庫中的所有key

flushall:刪除所有數據庫中的所有key

2、對String操作的命令

set(key, value):給數據庫中名稱爲key的string賦予值value

get(key):返回數據庫中名稱爲key的string的value

getset(key, value):給名稱爲key的string賦予上一次的value

mget(key1, key2,…, key N):返回庫中多個string(它們的名稱爲key1,key2…)的value

setnx(key, value):如果不存在名稱爲key的string,則向庫中添加string,名稱爲key,值爲value

setex(key, time, value):向庫中添加string(名稱爲key,值爲value)同時,設定過期時間time

mset(key1, value1, key2, value2,…key N, value N):同時給多個string賦值,名稱爲key i的string賦值value i

msetnx(key1, value1, key2, value2,…key N, value N):如果所有名稱爲key i的string都不存在,則向庫中添加string,名稱key i賦值爲value i

incr(key):名稱爲key的string增1操作

incrby(key, integer):名稱爲key的string增加integer

decr(key):名稱爲key的string減1操作

decrby(key, integer):名稱爲key的string減少integer

append(key, value):名稱爲key的string的值附加value

substr(key, start, end):返回名稱爲key的string的value的子串

3、對List操作的命令

rpush(key, value):在名稱爲key的list尾添加一個值爲value的元素

lpush(key, value):在名稱爲key的list頭添加一個值爲value的 元素

llen(key):返回名稱爲key的list的長度

lrange(key, start, end):返回名稱爲key的list中start至end之間的元素(下標從0開始,下同)

ltrim(key, start, end):截取名稱爲key的list,保留start至end之間的元素

lindex(key, index):返回名稱爲key的list中index位置的元素

lset(key, index, value):給名稱爲key的list中index位置的元素賦值爲value

lrem(key, count, value):刪除count個名稱爲key的list中值爲value的元素。count爲0,刪除所有值爲value的元素,count>0從頭至尾刪除count個值爲value的元素,count<0從尾到頭刪除|count|個值爲value的元素。 lpop(key):返回並刪除名稱爲key的list中的首元素 rpop(key):返回並刪除名稱爲key的list中的尾元素 blpop(key1, key2,… key N, timeout):lpop命令的block版本。即當timeout爲0時,若遇到名稱爲key i的list不存在或該list爲空,則命令結束。如果timeout>0,則遇到上述情況時,等待timeout秒,如果問題沒有解決,則對keyi+1開始的list執行pop操作。

brpop(key1, key2,… key N, timeout):rpop的block版本。參考上一命令。

rpoplpush(srckey, dstkey):返回並刪除名稱爲srckey的list的尾元素,並將該元素添加到名稱爲dstkey的list的頭部

4、對Set操作的命令

sadd(key, member):向名稱爲key的set中添加元素member

srem(key, member) :刪除名稱爲key的set中的元素member

spop(key) :隨機返回並刪除名稱爲key的set中一個元素

smove(srckey, dstkey, member) :將member元素從名稱爲srckey的集合移到名稱爲dstkey的集合

scard(key) :返回名稱爲key的set的基數

sismember(key, member) :測試member是否是名稱爲key的set的元素

sinter(key1, key2,…key N) :求交集

sinterstore(dstkey, key1, key2,…key N) :求交集並將交集保存到dstkey的集合

sunion(key1, key2,…key N) :求並集

sunionstore(dstkey, key1, key2,…key N) :求並集並將並集保存到dstkey的集合

sdiff(key1, key2,…key N) :求差集

sdiffstore(dstkey, key1, key2,…key N) :求差集並將差集保存到dstkey的集合

smembers(key) :返回名稱爲key的set的所有元素

srandmember(key) :隨機返回名稱爲key的set的一個元素

5、對zset(sorted set)操作的命令

zadd(key, score, member):向名稱爲key的zset中添加元素member,score用於排序。如果該元素已經存在,則根據score更新該元素的順序。

zrem(key, member) :刪除名稱爲key的zset中的元素member

zincrby(key, increment, member) :如果在名稱爲key的zset中已經存在元素member,則該元素的score增加increment;否則向集合中添加該元素,其score的值爲increment

zrank(key, member) :返回名稱爲key的zset(元素已按score從小到大排序)中member元素的rank(即index,從0開始),若沒有member元素,返回“nil”

zrevrank(key, member) :返回名稱爲key的zset(元素已按score從大到小排序)中member元素的rank(即index,從0開始),若沒有member元素,返回“nil”

zrange(key, start, end):返回名稱爲key的zset(元素已按score從小到大排序)中的index從start到end的所有元素

zrevrange(key, start, end):返回名稱爲key的zset(元素已按score從大到小排序)中的index從start到end的所有元素

zrangebyscore(key, min, max):返回名稱爲key的zset中score >= min且score <= max的所有元素 zcard(key):返回名稱爲key的zset的基數 zscore(key, element):返回名稱爲key的zset中元素element的score zremrangebyrank(key, min, max):刪除名稱爲key的zset中rank >= min且rank <= max的所有元素 zremrangebyscore(key, min, max) :刪除名稱爲key的zset中score >= min且score <= max的所有元素

zunionstore / zinterstore(dstkeyN, key1,…,keyN, WEIGHTS w1,…wN, AGGREGATE SUM|MIN|MAX):對N個zset求並集和交集,並將最後的集合保存在dstkeyN中。對於集合中每一個元素的score,在進行AGGREGATE運算前,都要乘以對於的WEIGHT參數。如果沒有提供WEIGHT,默認爲1。默認的AGGREGATE是SUM,即結果集合中元素的score是所有集合對應元素進行SUM運算的值,而MIN和MAX是指,結果集合中元素的score是所有集合對應元素中最小值和最大值。

6、對Hash操作的命令

hset(key, field, value):向名稱爲key的hash中添加元素field<—>value

hget(key, field):返回名稱爲key的hash中field對應的value

hmget(key, field1, …,field N):返回名稱爲key的hash中field i對應的value

hmset(key, field1, value1,…,field N, value N):向名稱爲key的hash中添加元素field i<—>value i

hincrby(key, field, integer):將名稱爲key的hash中field的value增加integer

hexists(key, field):名稱爲key的hash中是否存在鍵爲field的域

hdel(key, field):刪除名稱爲key的hash中鍵爲field的域

hlen(key):返回名稱爲key的hash中元素個數

hkeys(key):返回名稱爲key的hash中所有鍵

hvals(key):返回名稱爲key的hash中所有鍵對應的value

hgetall(key):返回名稱爲key的hash中所有的鍵(field)及其對應的value

附錄三:集羣客戶端命令(redis-cli -c -p port)

集羣
cluster info :打印集羣的信息
cluster nodes :列出集羣當前已知的所有節點( node),以及這些節點的相關信息。
節點
cluster meet <ip> <port> :將 ip 和 port 所指定的節點添加到集羣當中,讓它成爲集羣的一份子。
cluster forget <node_id> :從集羣中移除 node_id 指定的節點。
cluster replicate <node_id> :將當前節點設置爲 node_id 指定的節點的從節點。
cluster saveconfig :將節點的配置文件保存到硬盤裏面。
槽(slot)
cluster addslots <slot> [slot ...] :將一個或多個槽( slot)指派( assign)給當前節點。
cluster delslots <slot> [slot ...] :移除一個或多個槽對當前節點的指派。
cluster flushslots :移除指派給當前節點的所有槽,讓當前節點變成一個沒有指派任何槽的節點。
cluster setslot <slot> node <node_id> :將槽 slot 指派給 node_id 指定的節點,如果槽已經指派給另一個節點,那麼先讓另一個節點刪除該槽>,然後再進行指派。
cluster setslot <slot> migrating <node_id> :將本節點的槽 slot 遷移到 node_id 指定的節點中。
cluster setslot <slot> importing <node_id> :從 node_id 指定的節點中導入槽 slot 到本節點。
cluster setslot <slot> stable :取消對槽 slot 的導入( import)或者遷移( migrate)。

cluster keyslot <key> :計算鍵 key 應該被放置在哪個槽上。
cluster countkeysinslot <slot> :返回槽 slot 目前包含的鍵值對數量。
cluster getkeysinslot <slot> <count> :返回 count 個 slot 槽中的鍵  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章