Redis 入門

Luson發表於2019-12-23

Redis

1 Redis 介紹

Nosql 基本概念

為了解決高併發、高可用、高可擴充套件,大資料儲存等一系列問題而產生的資料庫解決方案,就是NoSql。

NoSql,叫非關係型資料庫,它的全名Not only sql。它不能替代關係型資料庫,只能作為關係型資料庫的一個良好補充。

Nosql 分類

  • 鍵值(Key-Value)儲存資料庫 相關產品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB 典型應用: 內容快取,主要用於處理大量資料的高訪問負載。 資料模型: 一系列鍵值對 優勢: 快速查詢 劣勢: 儲存的資料缺少結構化

  • 列儲存資料庫 相關產品:Cassandra, HBase, Riak 典型應用:分散式的檔案系統 資料模型:以列簇式儲存,將同一列資料存在一起 優勢:查詢速度快,可擴充套件性強,更容易進行分散式擴充套件 劣勢:功能相對侷限

  • 文件型資料庫 相關產品:CouchDB、MongoDB 典型應用:Web應用(與Key-Value類似,Value是結構化的) 資料模型: 一系列鍵值對 優勢:資料結構要求不嚴格 劣勢: 查詢效能不高,而且缺乏統一的查詢語法

  • 圖形(Graph)資料庫 相關資料庫:Neo4J、InfoGrid、Infinite Graph 典型應用:社交網路 資料模型:圖結構 優勢:利用圖結構相關演算法。 劣勢:需要對整個圖做計算才能得出結果,不容易做分散式的叢集方案。

Redis 基本概念

Redis是使用c語言開發的一個高效能鍵值資料庫。Redis可以通過一些鍵值型別來儲存資料。 鍵值型別: String字元型別 map雜湊型別 list列表型別 set集合型別 sortedset有序集合型別

發展歷史

2008年,義大利的一家創業公司Merzia推出了一款基於MySQL的網站實時統計系統LLOOGG,然而沒過多久該公司的創始人 Salvatore Sanfilippo便 對MySQL的效能感到失望,於是他決定親自為LLOOGG量身定做一個資料庫,並於2009年開發完成,這個資料庫就是Redis。 不過Salvatore Sanfilippo並不滿足只將Redis用於LLOOGG這一款產品,而是希望更多的人使用它,於是在同一年Salvatore Sanfilippo將Redis開源釋出,並開始和Redis的另一名主要的程式碼貢獻者Pieter Noordhuis一起繼續著Redis的開發,直到今天。

Salvatore Sanfilippo自己也沒有想到,短短的幾年時間,Redis就擁有了龐大的使用者群體。Hacker News在2012年釋出了一份資料庫的使用情況調查,結果顯示有近12%的公司在使用Redis。國內如新浪微博、街旁網、知乎網,國外如GitHub、Stack Overflow、Flickr等都是Redis的使用者。

VMware公司從2010年開始贊助Redis的開發, Salvatore Sanfilippo和Pieter Noordhuis也分別在3月和5月加入VMware,全職開發Redis。

應用場景

快取(資料查詢、短連線、新聞內容、商品內容等等)。(最多使用) 分散式叢集架構中的session分離。 聊天室的線上好友列表。 任務佇列。(秒殺、搶購、12306等等) 應用排行榜。 網站訪問統計。 資料過期處理(可以精確到毫秒)

2 Redis 安裝

下載

官網地址:http://redis.io/ 下載地址:http://download.redis.io/releases/redis-3.0.0.tar.gz

安裝

#sftp 上傳安裝包到linux
#解壓
tar -zxvf redis.3.0.0.tar.gz
#安裝c語言環境
sudo apt-get install gcc-c++
#編譯
cd redis-3.0.0
make
#安裝
make install PREFIX = /usr/local/redis
# 檢視
cd /usr/local/redis
ls
複製程式碼

redis 啟動

前端啟動

  • 前端啟動命令 ./redis-server
  • 前端啟動的關閉 強制關閉 ctrl+c 正常關閉 ./redis-cli shutdown

**tips:**一旦客戶端關閉,則redis服務也會停掉

後端啟動

  • 將 redis 原始碼包中的 redis.conf 檔案拷貝至 bin 目錄下 cp /root/redis-3.0.0/redis.conf
  • 修改 redis.conf 檔案,將 daemonize 改為 yes vim redis.conf
  • 使用後端命令啟動 redis ./redis-server redis.conf
  • 檢視是否啟動成功 ps -aux | grep redis
  • 關閉後端啟動的方式 強制關閉: kill -9 程式號 正常關閉:./redis-cli shutdown

3 Redis 客戶端

自帶客戶端

  • 啟動 ./redis-cli -h 127.0.0.1 -p 6379 -h 指定訪問 redis 伺服器的 ip 地址 -p 指定訪問的 redis 伺服器的 port 埠 還可以寫成 ./redis-cli 使用預設配置,預設ip 127.0.0.1,預設埠 6379
  • 關閉 ctrl + c 127.0.0.1:6379>quit

圖形介面客戶端

redis-desktop-manager 開啟如下:

Redis 入門

Redis 入門

選擇資料庫方式: select 加上資料庫的下標,就可以選擇指定的資料庫使用,下標從0開始。

127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]>
複製程式碼

jedis 客戶端

介紹

Redis不僅是使用命令來操作,現在基本上主流的語言都有客戶端支援,比如java、C、C#、C++、php、Node.js、Go等。

在官方網站裡列一些Java的客戶端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推薦使用Jedis和Redisson。 在企業中用的最多的就是Jedis,下面我們就重點學習下Jedis。

Jedis同樣也是託管在github上,地址:https://github.com/xetorthio/jedis

工程搭建

  • 新增 jar commons-pool2-2.3.jar jedis-2.7.0.jar
單例連線redis

Redis 入門

使用連線池連線 redis

Redis 入門

Spring 整合 jedisPool

新增 spring 的 jar 包 配置 spring 配置檔案 applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">

    <!-- 連線池配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大連線數 -->
        <property name="maxTotal" value="30" />
        <!-- 最大空閒連線數 -->
        <property name="maxIdle" value="10" />
        <!-- 每次釋放連線的最大數目 -->
        <property name="numTestsPerEvictionRun" value="1024" />
        <!-- 釋放連線的掃描間隔(毫秒) -->
        <property name="timeBetweenEvictionRunsMillis" value="30000" />
        <!-- 連線最小空閒時間 -->
        <property name="minEvictableIdleTimeMillis" value="1800000" />
        <!-- 連線空閒多久後釋放, 當空閒時間>該值 且 空閒連線>最大空閒連線數 時直接釋放 -->
        <property name="softMinEvictableIdleTimeMillis" value="10000" />
        <!-- 獲取連線時的最大等待毫秒數,小於零:阻塞不確定的時間,預設-1 -->
        <property name="maxWaitMillis" value="1500" />
        <!-- 在獲取連線的時候檢查有效性, 預設false -->
        <property name="testOnBorrow" value="false" />
        <!-- 在空閒時檢查有效性, 預設false -->
        <property name="testWhileIdle" value="true" />
        <!-- 連線耗盡時是否阻塞, false報異常,ture阻塞直到超時, 預設true -->
        <property name="blockWhenExhausted" value="false" />
    </bean>

    <!-- redis單機 通過連線池 -->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool"
        destroy-method="close">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <constructor-arg name="host" value="192.168.242.130" />
        <constructor-arg name="port" value="6379" />
    </bean>
</beans>
複製程式碼

測試程式碼

@Test
    public void testJedisPool() {
        JedisPool pool = (JedisPool) applicationContext.getBean("jedisPool");
        Jedis jedis = null;
        try {
            jedis = pool.getResource();

            jedis.set("name", "lisi");
            String name = jedis.get("name");
            System.out.println(name);
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (jedis != null) {
                // 關閉連線
                jedis.close();
            }
        }
    }
複製程式碼

4 資料型別

String 型別

賦值 set key value

127.0.0.1:6379> set test 123
OK
複製程式碼

取值 get key

127.0.0.1:6379> get test
"123"
複製程式碼

取值並賦值 getset key value

127.0.0.1:6379> getset test 321
"123"
127.0.0.1:6379> get test
"321"
複製程式碼

設定獲取多個鍵值 mset key value [key value...] mget key [key...]

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> mget k1 k2
1) "v1"
2) "v2"
複製程式碼

刪除 del key

127.0.0.1:6379> del test
(integer) 1
複製程式碼

數值增減

  • 遞增數字 當儲存的字串是整數時,Redis提供了一個實用的命令INCR,其作用是讓當前鍵值遞增,並返回遞增後的值。 語法:incr key
    127.0.0.1:6379> set num 1
    OK
    127.0.0.1:6379> incr num
    (integer) 2
    127.0.0.1:6379> incr num
    (integer) 3
    127.0.0.1:6379> incr num
    (integer) 4
    複製程式碼
  • 增加指定的整數 incrby key increment
    127.0.0.1:6379> incrby num 2
    (integer) 8
    127.0.0.1:6379> incrby num 2
    (integer) 10
    複製程式碼
  • 遞減數值 decr key
    127.0.0.1:6379> decr num
    (integer) 9
    127.0.0.1:6379> decr num
    (integer) 8
    複製程式碼
  • 減少指定的數值 decryby key decrement
    127.0.0.1:6379> decrby num 2
    (integer) 6
    127.0.0.1:6379> decrby num 2
    (integer) 4
    複製程式碼

向尾部追加值 APPEND的作用是向鍵值的末尾追加value。如果鍵不存在則將該鍵的值設定為value,即相當於 SET key value。返回值是追加後字串的總長度。 語法:append key value

127.0.0.1:6379> set str hello
OK
127.0.0.1:6379> append str "world"
(integer) 10
127.0.0.1:6379> get str
"helloworld"
複製程式碼

獲取字串長度 STRLEN命令返回鍵值的長度,如果鍵不存在則返回0。 語法:strlen key

127.0.0.1:6379> strlen str
(integer) 10
複製程式碼

應用

  • 自增主鍵 商品編號、訂單號採用 string 的遞增數字特性生成

Hash 雜湊型別

使用 string 的問題

假設有User物件以JSON序列化的形式儲存到Redis中,User物件有id,username、password、age、name等屬性,儲存的過程如下: 儲存、更新:User物件 json(string) redis

如果在業務上只是更新age屬性,其他的屬性並不做更新我應該怎麼做呢? 如果仍然採用上邊的方法在傳輸、處理時會造成資源浪費,下邊講的hash可以很好的解決這個問題。

介紹

hash叫雜湊型別,它提供了欄位和欄位值的對映。欄位值只能是字串型別,不支援雜湊型別、集合型別等其它型別。如下:

Redis 入門

命令

賦值 HSET命令不區分插入和更新操作,當執行插入操作時HSET命令返回1,當執行更新操作時返回0。

  • 一次只設定一個欄位值 語法:hset key field value
    127.0.0.1:6379> hset user username zhangsan
    (integer) 1
    複製程式碼
  • 一次設定多個欄位值 語法:hmset key field value [field value...]
    127.0.0.1:6379> hmset user age 20 username lisi
    OK
    複製程式碼
  • 當欄位不存在時賦值,類似hset,區別在於如果欄位存在,該命令不執行任何操作。 語法:hsetnx key field value
    127.0.0.1:6379> hsetnx user age 30
    (integer) 0
    複製程式碼

取值

  • 一次獲取一個欄位值 語法:hget key field
    127.0.0.1:6379> hget user username
    "lisi"
    複製程式碼
  • 一次可以獲取多個欄位值 語法:hmget key field [field...]
    127.0.0.1:6379> hmget user age username
    1) "20"
    2) "lisi"
    複製程式碼
  • 獲取所有欄位值 語法:hgetall key
    127.0.0.1:6379> hgetall user
    1) "username"
    2) "lisi"
    3) "age"
    4) "20"
    複製程式碼

刪除欄位 可以刪除一個或多個欄位,返回值是被刪除的欄位的個數。 語法:hdel key field [field...]

127.0.0.1:6379> hdel user age
(integer) 1
127.0.0.1:6379> hdel user age username
(integer) 1
複製程式碼

增加數字 語法:hincrby key field increment

127.0.0.1:6379> hincrby user age 2
(integer) 2
複製程式碼

判斷欄位是否存在 語法:hexists key field

127.0.0.1:6379> hexists user age
(integer) 1
複製程式碼

只獲取欄位名或欄位值 語法: hkeys key hvals key

127.0.0.1:6379> hkeys user
1) "age"
複製程式碼

獲取欄位數量 語法:hlen key

127.0.0.1:6379> hlen user
(integer) 1
複製程式碼

應用 儲存商品資訊

127.0.0.1:6379> hlen user
(integer) 1
複製程式碼

獲取商品資訊

127.0.0.1:6379> hgetall items:1001
1) "id"
2) "3"
3) "name"
4) "apple"
5) "price"
6) "5.00"
複製程式碼

List 型別

ArrayList 和 LinkedList 的區別

Arraylist是使用陣列來儲存資料,特點:查詢快、增刪慢

Linkedlist是使用雙向連結串列儲存資料,特點:增刪快、查詢慢,但是查詢連結串列兩端的資料也很快。

Redis的list是採用來連結串列來儲存的,所以對於redis的list資料型別的操作,是操作list的兩端資料來操作的。

命令

向列表兩端增加元素

  • 向列表左邊增加元素 語法:lpush key value [value...]
127.0.0.1:6379> lpush list:1 1 2 3
(integer) 3
複製程式碼
  • 向列表右邊增加元素 語法:rpush key value [value...]
127.0.0.1:6379> rpush list:1 4 5 6
(integer) 6
複製程式碼

檢視列表 LRANGE命令是列表型別最常用的命令之一,獲取列表中的某一片段,將返回start、stop之間的所有元素(包含兩端的元素),索引從0開始。索引可以是負數,如:“-1”代表最後邊的一個元素。

語法:lrange key start stop

127.0.0.1:6379> lrange list:1 0 2
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> lrange list:1 0 -1
1) "3"
2) "2"
3) "1"
4) "4"
5) "5"
6) "6"
複製程式碼

從列表兩端彈出元素 LPOP命令從列表左邊彈出一個元素,會分兩步完成:

  • 第一步是將列表左邊的元素從列表中移除
  • 第二步是返回被移除的元素值。 語法: lpop key rpop key
    127.0.0.1:6379> lpop list:1
    "3"
    127.0.0.1:6379> rpop list:1
    "6"
    複製程式碼

獲取列表中元素的個數 語法:llen key

127.0.0.1:6379> llen list:1
(integer) 4
複製程式碼

刪除列表中指定的值 LREM命令會刪除列表中前count個值為value的元素,返回實際刪除的元素個數。根據count值的不同,該命令的執行方式會有所不同:

  • 當count>0時, LREM會從列表左邊開始刪除。
  • 當count<0時, LREM會從列表後邊開始刪除。
  • 當count=0時, LREM刪除所有值為value的元素。

語法:lrem key count value

獲得/設定指定索引的元素值

  • 獲得指定索引的元素值 語法:lindex key index
    127.0.0.1:6379> lindex list:1 2
    "4"
    複製程式碼
  • 設定指定索引的元素值 語法:lset key index value
    127.0.0.1:6379> lset list:1 2 2
    OK
    複製程式碼

只保留列表指定片段 指定範圍和 lrange 一致 語法:ltrim key start stop

127.0.0.1:6379> lrange list:1 0 -1
1) "2"
2) "1"
3) "2"
4) "5"
127.0.0.1:6379> ltrim list:1 0 2
OK
127.0.0.1:6379> lrange list:1 0 -1
1) "2"
2) "1"
3) "2"
複製程式碼

向列表中插入元素 該命令首先會在列表中從左到右查詢值為pivot的元素,然後根據第二個引數是BEFORE還是AFTER來決定將value插入到該元素的前面還是後面。 語法:linsert key before | after pivot value

127.0.0.1:6379> lrange list:1 0 -1
1) "2"
2) "1"
3) "2"
127.0.0.1:6379> linsert list:1 after 1 9
(integer) 4
127.0.0.1:6379> lrange list:1 0 -1
1) "2"
2) "1"
3) "9"
4) "2"
複製程式碼

將元素從一個列表轉移到另一個列表 語法:rpoplpush source destination

127.0.0.1:6379> lrange list:1 0 -1
1) "2"
2) "1"
3) "9"
4) "2"
127.0.0.1:6379> rpoplpush list:1 newlist
"2"
127.0.0.1:6379> lrange newlist 0 -1
1) "2"
127.0.0.1:6379> lrange list:1 0 -1
1) "2"
2) "1"
3) "9"
複製程式碼

應用 在Redis中建立商品評論列表 使用者釋出商品評論,將評論資訊轉成json儲存到list中。 使用者在頁面查詢評論列表,從redis中取出json資料展示到頁面。

定義商品評論列表key: 商品編號為1001的商品評論key【items: comment:1001】

Set 型別

集合型別:無序、不可重複 列表型別:有序、可重複

命令

增加/刪除元素 語法:sadd key member [member...]

127.0.0.1:6379> sadd set a b c
(integer) 3
127.0.0.1:6379> sadd set a
(integer) 0
複製程式碼

語法:srem key member [member...]

127.0.0.1:6379> srem set c
(integer) 1
複製程式碼

獲得集合中的所有元素 語法:smembers key

127.0.0.1:6379> smembers set
1) "b"
2) "a"
複製程式碼

判斷元素是否在集合中 語法:sismember key member

127.0.0.1:6379> sismember set a
(integer) 1
127.0.0.1:6379> sismember set h
(integer) 0
複製程式碼

運算命令

集合的差集運算 A-B 屬於 A 並且 不屬於 B 的元素構成的集合

Redis 入門
語法:sdiff key [key...]

127.0.0.1:6379> sadd setA 1 2 3
(integer) 3
127.0.0.1:6379> sadd setB 2 3 4
(integer) 3
127.0.0.1:6379> sdiff setA setB 
1) "1"
127.0.0.1:6379> sdiff setB setA
1) "4"
複製程式碼

集合的交集運算 屬於A且屬於B的元素構成的集合

Redis 入門
語法:sinter key [key...]

127.0.0.1:6379> sinter setA setB
1) "2"
2) "3"
複製程式碼

集合的並集運算 屬於 A 或者 屬於 B 的元素構成的集合

Redis 入門
語法:sunion key [key...]

127.0.0.1:6379> sunion setA setB
1) "1"
2) "2"
3) "3"
4) "4"
複製程式碼

獲得集合中元素的個數 語法:scard key

127.0.0.1:6379> smembers setA
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> scard setA
(integer) 3
複製程式碼

從集合中彈出一個元素 注意:由於集合是無序的,所有spop命令會從集合中隨機選擇一個元素彈出。 語法:spop key

127.0.0.1:6379> spop setA
"2"
複製程式碼

Sortedset 型別

Sortedset 又叫 zset Sortedset 是有序集合,可排序的,但是唯一。 Sortedset 和 set 的不同之處,會給 set 中元素新增一個分數,然後通過這個分數進行排序。

命令

增加元素

向有序集合中加入一個元素和該元素的分數,如果該元素已經存在則會用新的分數替換原有的分數。返回值是新加入到集合中的元素個數,不包含之前已經存在的元素。 語法:zadd key score member [score member...]

127.0.0.1:6379> zadd scoreboard 80 zhangsan 89 lisi 94 wangwu
(integer) 3
127.0.0.1:6379> zadd scoreboard 97 lisi
(integer) 0
複製程式碼
獲取元素分數

語法:zscore key member

127.0.0.1:6379> zscore scoreboard lisi
"97"
複製程式碼
刪除元素

移除有序集key中的一個或多個成員,不存在的成員將被忽略。 當key存在但不是有序集型別時,返回一個錯誤。

語法:zrem key member [member...]

127.0.0.1:6379> zrem scoreboard lisi
(integer) 1
複製程式碼
獲得排名在某個範圍的元素列表

獲得排名在某個範圍的元素列表

  • 按照元素分數從小到大的順序返回索引從start到stop之間的所有元素(包含兩端的元素) 語法:zrange key start stop [withscores]
    127.0.0.1:6379> zrange scoreboard 0 2
    1) "zhangsan"
    2) "wangwu"
    複製程式碼
  • 按照元素分數從大到小的順序返回索引從start到stop之間的所有元素(包含兩端的元素) 語法:zrevrange key start stop [withscores]
    127.0.0.1:6379> zrevrange scoreboard 0 2
    1) "wangwu"
    2) "zhangsan"
    複製程式碼
    如果需要獲得元素的分數可以在命令末尾加上 withscores 引數 ··· 127.0.0.1:6379> zrevrange scoreboard 0 2 withscores
    1. "wangwu"
    2. "94"
    3. "zhangsan"
    4. "80" ···
獲取元素的排名
  • 從小到大 語法:zrank key member
127.0.0.1:6379> zrank scoreboard zhangsan
(integer) 0
複製程式碼
  • 從大到小 語法:zrevrank key member
127.0.0.1:6379> zrevrank scoreboard zhangsan
(integer) 1
複製程式碼
獲得指定分數範圍的元素

語法:zrangebyscore key min max [withscores] [limit offset count]

127.0.0.1:6379> ZRANGEBYSCORE scoreboard 90 97 WITHSCORES
1) "wangwu"
2) "94"
3) "lisi"
4) "97"
127.0.0.1:6379> ZRANGEBYSCORE scoreboard 70 100 limit 1 2
1) "wangwu"
2) "lisi"
複製程式碼
增加某個元素的分數

返回值是更改後的分數 語法:zincrby key increment member

127.0.0.1:6379> ZINCRBY scoreboard 4 lisi 
"101“
複製程式碼
獲得集合中元素的數量

語法:zcard key

127.0.0.1:6379> zcard scoreboard
(integer) 3
複製程式碼
獲得指定分數範圍內的元素個數

語法:zcount key min max

127.0.0.1:6379> zcount scoreboard 80 90
(integer) 1
複製程式碼
按照排名範圍刪除元素

語法:zremrangebyrank key start stop

127.0.0.1:6379> zremrangebyrank scoreboard 0 1
(integer) 2
127.0.0.1:6379> zrange scoreboard 0 -1
1) "wangwu"
複製程式碼
按照分數範圍刪除元素

語法:zremrangebyscore key min max

127.0.0.1:6379> zadd scoreboard 84 zhangsan    
(integer) 1
127.0.0.1:6379> ZREMRANGEBYSCORE scoreboard 80 100
(integer) 1
複製程式碼
應用
商品銷售排行榜

需求:根據商品銷售量對商品進行排行顯示 思路:定義商品銷售排行榜(sorted set集合),Key為items:sellsort,分數為商品銷售量。

寫入商品銷售量:

  • 商品編號1001的銷量是9,商品編號1002的銷量是10 192.168.101.3:7007> ZADD items:sellsort 9 1001 10 1002

  • 商品編號1001的銷量加1 192.168.101.3:7001> ZINCRBY items:sellsort 1 1001

  • 商品銷量前10名: 192.168.101.3:7001> ZRANGE items:sellsort 0 9 withscores

keys 命令

常用命令

  • keys 返回滿足給定pattern 的所有key redis 127.0.0.1:6379> keys mylist*

    1. "mylist"
    2. "mylist5"
    3. "mylist6"
    4. "mylist7"
    5. "mylist8"
  • exists 確認一個key 是否存在 示例:從結果來看,資料庫中不存在HongWan 這個key,但是age 這個key 是存在的 redis 127.0.0.1:6379> exists HongWan (integer) 0 redis 127.0.0.1:6379> exists age (integer) 1 redis 127.0.0.1:6379>

  • del 刪除一個key redis 127.0.0.1:6379> del age (integer) 1 redis 127.0.0.1:6379> exists age (integer) 0

  • rename 重新命名key 示例:age 成功的被我們改名為age_new 了 redis 127.0.0.1:6379[1]> keys *

    1. "age" redis 127.0.0.1:6379[1]> rename age age_new OK redis 127.0.0.1:6379[1]> keys *
    2. "age_new" redis 127.0.0.1:6379[1]>
  • type 返回值的型別 示例:這個方法可以非常簡單的判斷出值的型別 redis 127.0.0.1:6379> type addr string redis 127.0.0.1:6379> type myzset2 zset redis 127.0.0.1:6379> type mylist list redis 127.0.0.1:6379>

設定 key 的生存時間

Redis在實際使用過程中更多的用作快取,然而快取的資料一般都是需要設定生存時間的,即:到期後資料銷燬。

EXPIRE key seconds 設定key的生存時間(單位:秒)key在多少秒後會自動刪除
TTL key 檢視key剩餘的生存時間
PERSIST key 清除生存時間
PEXPIRE key milliseconds 生存時間設定單位為:毫秒

例子:

192.168.101.3:7002> set test 1        設定test的值為1
OK
192.168.101.3:7002> get test            獲取test的值
"1"
192.168.101.3:7002> EXPIRE test 5    設定test的生存時間為5秒
(integer) 1
192.168.101.3:7002> TTL test            檢視test的生於生成時間還有1秒刪除
(integer) 1
192.168.101.3:7002> TTL test
(integer) -2
192.168.101.3:7002> get test            獲取test的值,已經刪除
(nil)
複製程式碼

Redis 持久化方案

Rdb 方式

Redis 預設的方式,redis 通過快照方式將資料持久化到磁碟中。

設定持久化快照的條件

在 redis.conf 中修改持久化快照的條件:

Redis 入門

持久化檔案的儲存目錄

在 redis.conf 中可以指定持久化檔案的儲存目錄

Redis 入門

Rdb 的問題

一旦redis非法關閉,那麼會丟失最後一次持久化之後的資料。

如果資料不重要,則不必要關心。 如果資料不能允許丟失,那麼要使用 aof 方式。

Aof 方式

Redis 預設是不使用該方式持久化的。Aof 方式的持久化,是操作一次 redis 資料庫,則將操作的記錄儲存到 aof 持久化檔案中。

  • 第一步:開啟 aof 方式持久化方案。 將redis.conf中的appendonly改為yes,即開啟aof方式的持久化方案。

    Redis 入門

  • Aof檔案儲存的目錄和rdb方式的一樣。 Aof檔案儲存的名稱

    Redis 入門

在使用aof和rdb方式時,如果redis重啟,則資料從aof檔案載入。

Redis 的主從複製

什麼是主從複製

持久化保證了即使redis服務重啟也不會丟失資料,因為redis服務重啟後會將硬碟上持久化的資料恢復到記憶體中,但是當redis伺服器的硬碟損壞了可能會導致資料丟失,如果通過redis的主從複製機制就可以避免這種單點故障,如下圖:

Redis 入門
說明:

  • 主redis中的資料有兩個副本(replication)即從redis1和從redis2,即使一臺redis伺服器當機其它兩臺redis服務也可以繼續提供服務。
  • 主redis中的資料和從redis上的資料保持實時同步,當主redis寫入資料時通過主從複製機制會複製到兩個從redis服務上。
  • 只有一個主redis,可以有多個從redis。
  • 主從複製不會阻塞master,在同步資料時,master 可以繼續處理client 請求
  • 一個redis可以即是主又是從,如下圖:
    Redis 入門

主從複製設定

主機配置

無需配置

從機配置

  • 第一步:複製出一個從機 cp bin/ bin2 -r
  • 第二步:修改從機的 redis.conf 語法:slaveof masterip masterport slaveof 192.168.242.137 6379
    Redis 入門
  • 第三步:修改從機的 port 地址為 6380
    Redis 入門
  • 第四步:清除從機的持久化檔案 rm -rf appendonly.aof dump.rdb
  • 第五步:啟動從機 ./redis-server redis.conf
  • 第六步:啟動6380的客戶端 ./redis-cli -p 6380

注意: 主機一旦發生增刪改操作,那麼從機會將資料同步到從機中 從機不能執行寫操作

Redis 叢集

redis-cluster 架構圖

Redis 入門

架構細節: (1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進位制協議優化傳輸速度和頻寬. (2)節點的fail是通過叢集中超過半數的節點檢測失效時才生效. (3)客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連線叢集所有節點,連線叢集中任何一個可用節點即可 (4)redis-cluster把所有的物理節點對映到[0-16383]slot上,cluster 負責維護node<->slot<->value Redis 叢集中內建了 16384 個雜湊槽,當需要在 Redis 叢集中放置一個 key-value 時,redis 先對 key 使用 crc16 演算法算出一個結果,然後把結果對 16384 求餘數,這樣每個 key 都會對應一個編號在 0-16383 之間的雜湊槽,redis 會根據節點數量大致均等的將雜湊槽對映到不同的節點.

Redis 入門

redis-cluster 投票 容錯

Redis 入門

(1)叢集中所有master參與投票,如果半數以上master節點與其中一個master節點通訊超過(cluster-node-timeout),認為該master節點掛掉. (2):什麼時候整個叢集不可用(cluster_state:fail)?

  • 如果叢集任意master掛掉,且當前master沒有slave,則叢集進入fail狀態。也可以理解成叢集的[0-16383]slot對映不完全時進入fail狀態。
  • 如果叢集超過半數以上master掛掉,無論是否有slave,叢集進入fail狀態。

安裝 Ruby

叢集管理工具(redis-trib.rb)是使用 ruby 指令碼語言編寫的。

  • 安裝 ruby
sudo apt-get install ruby
複製程式碼
  • 上傳 redis-3.0.0.gem 到 linux
  • 安裝 ruby 和 redis 介面 gem install redis-3.0.0.gem
  • 將 redis-3.0.0 包下 src 目錄中的以下檔案拷貝到 redis/redis-cluster/
cd /usr/local/redis/
mkdir redis-cluster
cd /root/redis-3.0.0/src/
cp redis-trib.rb /usr/local/redis/redis-cluster
複製程式碼

搭建叢集

搭建叢集最少需要 3 臺主機,如果每臺主機再配置一臺從機的話,則最少需要6臺機器。 埠設計:7001-7006

  1. 複製出一個7001機器 cp bin ./redis-cluster/7001 -r
  2. 如果存在持久化檔案,則刪除 rm -rf appendonly.aof dump.rdb
  3. 設定叢集引數,修改redis.conf
    Redis 入門
  4. 修改埠
    Redis 入門
  5. 複製出7002-7006機器
cp 7001/ 7002-r
cp 7001/ 7003-r
cp 7001/ 7004-r
cp 7001/ 7005-r
cp 7001/ 7006-r
複製程式碼
  1. 修改7002-7006機器埠
  2. 建立檔案 start-all.sh
cd 7001
./redis-server redis.conf
cd ..
cd 7002
./redis-server redis.conf
cd ..
cd 7003
./redis-server redis.conf
cd ..
cd 7004
./redis-server redis.conf
cd ..
cd 7005
./redis-server redis.conf
cd ..
cd 7006
./redis-server redis.conf
cd ..
複製程式碼
  1. 修改檔案許可權
chmod u+x start-all.sh
複製程式碼
  1. 執行檔案,啟動六臺機器
./start-all.sh
複製程式碼
  1. 建立叢集 ./redis-trib.rb create --replicas 1 192.168.126.128:7001 192.168.126.128:7002 192.168.126.128:7003 192.168.126.128:7004 192.168.126.128:7005 192.168.126.128:7006

連線叢集

root@ubuntu:/usr/local/redis/redis-cluster/7001# ./redis-cli -p 7001 -c

-c 指定叢集連線

檢視叢集資訊

  • 檢視叢集資訊

    192.168.126.128:7002> cluster info
    cluster_state:ok
    cluster_slots_assigned:16384
    cluster_slots_ok:16384
    cluster_slots_pfail:0
    cluster_slots_fail:0
    cluster_known_nodes:6
    cluster_size:3
    cluster_current_epoch:6
    cluster_my_epoch:2
    cluster_stats_messages_sent:260
    cluster_stats_messages_received:260
    複製程式碼
  • 檢視叢集節點

    192.168.126.128:7002> cluster nodes
    3a15e73dacb512745156535ae7f959acf65ae12e 192.168.126.128:7005 slave 23e173cdc0b7673dc28cae70efaabbc41308bfdc 0 1531452321139 5 connected
    2a58a53a5b10f7bd91af04128a6ed439d534c0ee 192.168.126.128:7001 master - 0 1531452322145 1 connected 0-5460
    d0808388485dd08f1a2ecdfe3d2b213742d0050d 192.168.126.128:7004 slave 2a58a53a5b10f7bd91af04128a6ed439d534c0ee 0 1531452318117 4 connected
    23e173cdc0b7673dc28cae70efaabbc41308bfdc 192.168.126.128:7002 myself,master - 0 0 2 connected 5461-10922
    2af2312acc56552f9f73470f90d9a51973fc74d3 192.168.126.128:7006 slave 78faf92cfdbd12e1b27b270fb0798e67017f4d0b 0 1531452320132 6 connected
    78faf92cfdbd12e1b27b270fb0798e67017f4d0b 192.168.126.128:7007 master - 0 1531452319123 3 connected 10923-16383
    複製程式碼

jedis連線叢集

@Test
    public void jedisCluster() {
        // 建立jedisCluster
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("192.168.242.137", 7001));
        nodes.add(new HostAndPort("192.168.242.137", 7002));
        nodes.add(new HostAndPort("192.168.242.137", 7003));
        nodes.add(new HostAndPort("192.168.242.137", 7004));
        nodes.add(new HostAndPort("192.168.242.137", 7005));
        nodes.add(new HostAndPort("192.168.242.137", 7006));
        nodes.add(new HostAndPort("192.168.242.137", 7007));

        JedisCluster cluster = new JedisCluster(nodes);
    
        cluster.set("s4", "444");
    
        String result = cluster.get("s4");
        System.out.println(result);
    
        cluster.close();
    }
複製程式碼

使用 spring

配置 applicationContext.xml

<!-- 連線池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <!-- 最大連線數 -->
    <property name="maxTotal" value="30" />
    <!-- 最大空閒連線數 -->
    <property name="maxIdle" value="10" />
    <!-- 每次釋放連線的最大數目 -->
    <property name="numTestsPerEvictionRun" value="1024" />
    <!-- 釋放連線的掃描間隔(毫秒) -->
    <property name="timeBetweenEvictionRunsMillis" value="30000" />
    <!-- 連線最小空閒時間 -->
    <property name="minEvictableIdleTimeMillis" value="1800000" />
    <!-- 連線空閒多久後釋放, 當空閒時間>該值 且 空閒連線>最大空閒連線數 時直接釋放 -->
    <property name="softMinEvictableIdleTimeMillis" value="10000" />
    <!-- 獲取連線時的最大等待毫秒數,小於零:阻塞不確定的時間,預設-1 -->
    <property name="maxWaitMillis" value="1500" />
    <!-- 在獲取連線的時候檢查有效性, 預設false -->
    <property name="testOnBorrow" value="true" />
    <!-- 在空閒時檢查有效性, 預設false -->
    <property name="testWhileIdle" value="true" />
    <!-- 連線耗盡時是否阻塞, false報異常,ture阻塞直到超時, 預設true -->
    <property name="blockWhenExhausted" value="false" />
</bean>
<!-- redis叢集 -->
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
    <constructor-arg index="0">
        <set>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7001"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7002"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7003"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7004"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7005"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="192.168.101.3"></constructor-arg>
                <constructor-arg index="1" value="7006"></constructor-arg>
            </bean>
        </set>
    </constructor-arg>
    <constructor-arg index="1" ref="jedisPoolConfig"></constructor-arg>
</bean>
複製程式碼

測試程式碼

private ApplicationContext applicationContext;
    @Before
    public void init() {
        applicationContext = new ClassPathXmlApplicationContext(
                "classpath:applicationContext.xml");
    }

    // redis叢集
    @Test
    public void testJedisCluster() {
        JedisCluster jedisCluster = (JedisCluster) applicationContext
                .getBean("jedisCluster");

        jedisCluster.set("name", "zhangsan");
        String value = jedisCluster.get("name");
        System.out.println(value);
    }
複製程式碼

相關文章