Redis word bak

@font-face { font-family: "Arial"; }@font-face { font-family: "Courier New"; }@font-face { font-family: "Times"; }@font-face { font-family: "Geneva"; }@font-face { font-family: "Tms Rmn"; }@font-face { font-family: "Helv"; }@font-face { font-family: "MS Serif"; }@font-face { font-family: "MS Sans Serif"; }@font-face { font-family: "New York"; }@font-face { font-family: "System"; }@font-face { font-family: "Wingdings"; }@font-face { font-family: "MS 明朝"; }@font-face { font-family: "바탕"; }@font-face { font-family: "宋體"; }@font-face { font-family: "新細明體"; }@font-face { font-family: "MS ゴシック"; }@font-face { font-family: "Century"; }@font-face { font-family: "Verdana"; }@font-face { font-family: "Angsana New"; }@font-face { font-family: "Cordia New"; }@font-face { font-family: "Mangal"; }@font-face { font-family: "Latha"; }@font-face { font-family: "Sylfaen"; }@font-face { font-family: "Vrinda"; }@font-face { font-family: "Raavi"; }@font-face { font-family: "Shruti"; }@font-face { font-family: "Sendnya"; }@font-face { font-family: "Gautami"; }@font-face { font-family: "Tunga"; }@font-face { font-family: "Estrangelo Edessa"; }@font-face { font-family: "Cambria Math"; }@font-face { font-family: "@宋體"; }@font-face { font-family: "Calibri Light"; }@font-face { font-family: "Calibri"; }@font-face { font-family: "@MS 明朝"; }@font-face { font-family: "@MS ゴシック"; }@font-face { font-family: "Microsoft YaHei"; }@font-face { font-family: "Consolas"; }@font-face { font-family: "Helvetica Neue"; }@font-face { font-family: "SimSun"; }@font-face { font-family: "@SimSun"; }@font-face { font-family: "@Microsoft YaHei"; }p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; text-align: justify; font-size: 12pt; font-family: Calibri; }h1 { margin: 17pt 0cm 16.5pt; text-align: justify; line-height: 240%; page-break-after: avoid; font-size: 22pt; font-family: Calibri; }h2 { margin: 13pt 0cm; text-align: justify; line-height: 173%; page-break-after: avoid; font-size: 16pt; font-family: "Calibri Light"; }h3 { margin: 13pt 0cm; text-align: justify; line-height: 173%; page-break-after: avoid; font-size: 16pt; font-family: Calibri; }p.MsoDocumentMap, li.MsoDocumentMap, div.MsoDocumentMap { margin: 0cm 0cm 0.0001pt; text-align: justify; font-size: 12pt; font-family: "Times New Roman"; }span.a { font-family: "Times New Roman"; }span.msoIns { text-decoration: underline; color: teal; }span.msoDel { text-decoration: line-through; color: red; }.MsoChpDefault { font-family: Calibri; }div.WordSection1 { }ol { margin-bottom: 0cm; }ul { margin-bottom: 0cm; }html

概述

簡介

Redis 是徹底開源免費的,遵照BSD協議,是一個高性能的key-value數據庫。java

 

Redis 與其餘 key - value 緩存產品有如下三個特色:node

Redis支持數據的持久化,能夠將內存中的數據保持在磁盤中,重啓的時候能夠再次加載進行使用。mysql

Redis不只僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。程序員

Redis支持數據的備份,即master-slave模式的數據備份。redis

 

 

優點

性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。算法

豐富的數據類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數據類型操做。spring

原子 – Redis的全部操做都是原子性的,同時Redis還支持對幾個操做全並後的原子性執行。sql

豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過時等等特性。mongodb

 

與其餘key-value存儲的不一樣

Redis有着更爲複雜的數據結構而且提供對他們的原子性操做,這是一個不一樣於其餘數據庫的進化路徑。Redis的數據類型都是基於基本數據結構的同時對程序員透明,無需進行額外的抽象。

Redis運行在內存中可是能夠持久化到磁盤,因此在對不一樣數據集進行高速讀寫時須要權衡內存,應爲數據量不能大於硬件內存。在內存數據庫方面的另外一個優勢是,相比在磁盤上相同的複雜的數據結構,在內存中操做起來很是簡單,這樣Redis能夠作不少內部複雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產生的,由於他們並不須要進行隨機訪問。

 

安裝

一、下載安裝包

二、解壓

三、安裝

make && make install

make是編譯,make install是安裝,能夠指定安裝路徑

make PREFIX=/use/local/redis install

PREFIX用於指定安裝路徑

四、驗證

除了執行PATH路徑下的命令外,也能夠去 src 目錄下(推薦這個)

在:/usr/local/bin 下,會有 redis-server 通常此目錄已經加入PATH了

redis-server 使用默認配置啓動refis服務

指定配置文件的方式啓動:

    redis-server redis.conf

    配置文件默認在安裝目錄下

新開一個窗口,redis-cli 使用默認配置鏈接Redis服務

執行ping,顯示PONG,說明成功了

四、關閉服務

在進入 redis-cli 的狀況下,直接shutdown命令,

或者使用kill命令

 

登錄服務器

redis-cli  或者  redis-cli -h 127.0.0.1 -p 6379

 

配置:redis.conf

設置配置信息

一、去修改配置文件

二、經過config set命令修改

config set key value 

三、獲取配信息

config get key

 

詳細配置項

redis.conf 配置項說明以下:

1. Redis默認不是以守護進程的方式運行,能夠經過該配置項修改,使用yes啓用守護進程

    daemonize no

2. 當Redis以守護進程方式運行時,Redis默認會把pid寫入/var/run/redis.pid文件,能夠經過pidfile指定

    pidfile /var/run/redis.pid

3. 指定Redis監聽端口,默認端口爲6379,做者在本身的一篇博文中解釋了爲何選用6379做爲默認端口,由於6379在手機按鍵上MERZ對應的號碼,而MERZ取自意大利歌女Alessia Merz的名字

    port 6379

4. 綁定的主機地址

    bind 127.0.0.1

5.當 客戶端閒置多長時間後關閉鏈接,若是指定爲0,表示關閉該功能

    timeout 300

6. 指定日誌記錄級別,Redis總共支持四個級別:debug、verbose、notice、warning,默認爲verbose

    loglevel verbose

7. 日誌記錄方式,默認爲標準輸出,若是配置Redis爲守護進程方式運行,而這裏又配置爲日誌記錄方式爲標準輸出,則日誌將會發送給/dev/null

    logfile stdout

8. 設置數據庫的數量,默認數據庫爲0,可使用SELECT <dbid>命令在鏈接上指定數據庫id

    databases 16

9. 指定在多長時間內,有多少次更新操做,就將數據同步到數據文件,能夠多個條件配合

    save <seconds> <changes>

    Redis默認配置文件中提供了三個條件:

    save 900 1

    save 300 10

    save 60 10000

    分別表示900秒(15分鐘)內有1個更改,300秒(5分鐘)內有10個更改以及60秒內有10000個更改。

 

10. 指定存儲至本地數據庫時是否壓縮數據,默認爲yes,Redis採用LZF壓縮,若是爲了節省CPU時間,能夠關閉該選項,但會致使數據庫文件變的巨大

    rdbcompression yes

11. 指定本地數據庫文件名,默認值爲dump.rdb

    dbfilename dump.rdb

12. 指定本地數據庫存放目錄

    dir ./

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

    slaveof <masterip> <masterport>

14. 當master服務設置了密碼保護時,slav服務鏈接master的密碼

    masterauth <master-password>

15. 設置Redis鏈接密碼,若是配置了鏈接密碼,客戶端在鏈接Redis時須要經過AUTH <password>命令提供密碼,默認關閉

    requirepass foobared

16. 設置同一時間最大客戶端鏈接數,默認無限制,Redis能夠同時打開的客戶端鏈接數爲Redis進程能夠打開的最大文件描述符數,若是設置 maxclients 0,表示不做限制。當客戶端鏈接數到達限制時,Redis會關閉新的鏈接並向客戶端返回max number of clients reached錯誤信息

    maxclients 128

17. 指定Redis最大內存限制,Redis在啓動時會把數據加載到內存中,達到最大內存後,Redis會先嚐試清除已到期或即將到期的Key,當此方法處理 後,仍然到達最大內存設置,將沒法再進行寫入操做,但仍然能夠進行讀取操做。Redis新的vm機制,會把Key存放內存,Value會存放在swap區

    maxmemory <bytes>

18. 指定是否在每次更新操做後進行日誌記錄,Redis在默認狀況下是異步的把數據寫入磁盤,若是不開啓,可能會在斷電時致使一段時間內的數據丟失。由於 redis自己同步數據文件是按上面save條件來同步的,因此有的數據會在一段時間內只存在於內存中。默認爲no

    appendonly no

19. 指定更新日誌文件名,默認爲appendonly.aof

     appendfilename appendonly.aof

20. 指定更新日誌條件,共有3個可選值: 

    no:表示等操做系統進行數據緩存同步到磁盤(快) 

    always:表示每次更新操做後手動調用fsync()將數據寫到磁盤(慢,安全) 

    everysec:表示每秒同步一次(折衷,默認值)

    appendfsync everysec

 

21. 指定是否啓用虛擬內存機制,默認值爲no,簡單的介紹一下,VM機制將數據分頁存放,由Redis將訪問量較少的頁即冷數據swap到磁盤上,訪問多的頁面由磁盤自動換出到內存中(在後面的文章我會仔細分析Redis的VM機制)

     vm-enabled no

22. 虛擬內存文件路徑,默認值爲/tmp/redis.swap,不可多個Redis實例共享

     vm-swap-file /tmp/redis.swap

23. 將全部大於vm-max-memory的數據存入虛擬內存,不管vm-max-memory設置多小,全部索引數據都是內存存儲的(Redis的索引數據 就是keys),也就是說,當vm-max-memory設置爲0的時候,實際上是全部value都存在於磁盤。默認值爲0

     vm-max-memory 0

24. Redis swap文件分紅了不少的page,一個對象能夠保存在多個page上面,但一個page上不能被多個對象共享,vm-page-size是要根據存儲的 數據大小來設定的,做者建議若是存儲不少小對象,page大小最好設置爲32或者64bytes;若是存儲很大大對象,則可使用更大的page,若是不 肯定,就使用默認值

     vm-page-size 32

25. 設置swap文件中的page數量,因爲頁表(一種表示頁面空閒或使用的bitmap)是在放在內存中的,,在磁盤上每8個pages將消耗1byte的內存。

     vm-pages 134217728

26. 設置訪問swap文件的線程數,最好不要超過機器的核數,若是設置爲0,那麼全部對swap文件的操做都是串行的,可能會形成比較長時間的延遲。默認值爲4

     vm-max-threads 4

27. 設置在向客戶端應答時,是否把較小的包合併爲一個包發送,默認爲開啓

    glueoutputbuf yes

28. 指定在超過必定的數量或者最大的元素超過某一臨界值時,採用一種特殊的哈希算法

    hash-max-zipmap-entries 64

    hash-max-zipmap-value 512

29. 指定是否激活重置哈希,默認爲開啓(後面在介紹Redis的哈希算法時具體介紹)

    activerehashing yes

30. 指定包含其它的配置文件,能夠在同一主機上多個Redis實例之間使用同一份配置文件,而同時各個實例又擁有本身的特定配置文件

    include /path/to/local.conf

 

 

 

數據類型

Redis數據類型

Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

 

String(字符串)

string是redis最基本的類型,你能夠理解成與Memcached如出一轍的類型,一個key對應一個value。

string類型是二進制安全的。意思是redis的string能夠包含任何數據。好比jpg圖片或者序列化的對象 。

string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。

 

redis 127.0.0.1:6379> SET name "w3cschool.cc"

OK

redis 127.0.0.1:6379> GET name

"w3cschool.cc"

 

Hash(哈希)

Redis hash 是一個鍵值對集合。

Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。

 

 

redis 127.0.0.1:6379> HMSET user:1 username w3cschool.cc password w3cschool.cc points 200

 

OK

 

redis 127.0.0.1:6379> HGETALL user:1

 

1) "username"

 

2) "w3cschool.cc"

 

3) "password"

 

4) "w3cschool.cc"

 

5) "points"

 

6) "200"

 

redis 127.0.0.1:6379>

 

 

 

以上實例中 hash 數據類型存儲了包含用戶腳本信息的用戶對象。 實例中咱們使用了 Redis HMSET, HGETALL 命令,user:1 爲鍵值。

每一個 hash 能夠存儲 232 - 1 鍵值對(40多億)。

 

List(列表)

Redis 列表是簡單的字符串列表,按照插入順序排序。你能夠添加一個元素到列表的頭部(左邊)或者尾部(右邊)。

 

 

redis 127.0.0.1:6379> lpush w3cschool.cc redis

 

(integer) 1

 

redis 127.0.0.1:6379> lpush w3cschool.cc mongodb

 

(integer) 2

 

redis 127.0.0.1:6379> lpush w3cschool.cc rabitmq

 

(integer) 3

 

redis 127.0.0.1:6379> lrange w3cschool.cc 0 10

 

1) "rabitmq"

 

2) "mongodb"

 

3) "redis"

 

redis 127.0.0.1:6379>

 

 

 

列表最多可存儲 232 - 1 元素 (4294967295, 每一個列表可存儲40多億)。

 

Set(集合)

Redis的Set是string類型的無序集合。

集合是經過哈希表實現的,因此添加,刪除,查找的複雜度都是O(1)。

sadd 命令

添加一個string元素到,key對應的set集合中,成功返回1,若是元素已經在集合中返回0,key對應的set不存在返回錯誤。

 

 

redis 127.0.0.1:6379> sadd w3cschool.cc redis

 

(integer) 1

 

redis 127.0.0.1:6379> sadd w3cschool.cc mongodb

 

(integer) 1

 

redis 127.0.0.1:6379> sadd w3cschool.cc rabitmq

 

(integer) 1

 

redis 127.0.0.1:6379> sadd w3cschool.cc rabitmq

 

(integer) 0

 

redis 127.0.0.1:6379> smembers w3cschool.cc

 

 

 

1) "rabitmq"

 

2) "mongodb"

 

3) "redis"

 

 

 

注意:以上實例中 rabitmq 添加了兩次,但根據集合內元素的惟一性,第二次插入的元素將被忽略。

集合中最大的成員數爲 232 - 1 (4294967295, 每一個集合可存儲40多億個成員)。

 

zset(sorted set:有序集合)

Redis zset 和 set 同樣也是string類型元素的集合,且不容許重複的成員。

 

不一樣的是每一個元素都會關聯一個double類型的分數。redis正是經過分數來爲集合中的成員進行從小到大的排序。

zset的成員是惟一的,但分數(score)卻能夠重複。

zadd 命令

添加元素到集合,元素在集合中存在則更新對應score

 

 

redis 127.0.0.1:6379> zadd w3cschool.cc 0 redis

 

(integer) 1

 

redis 127.0.0.1:6379> zadd w3cschool.cc 0 mongodb

 

(integer) 1

 

redis 127.0.0.1:6379> zadd w3cschool.cc 0 rabitmq

 

(integer) 1

 

redis 127.0.0.1:6379> zadd w3cschool.cc 0 rabitmq

 

(integer) 0

 

redis 127.0.0.1:6379> ZRANGEBYSCORE w3cschool.cc 0 1000

 

 

 

1) "redis"

 

2) "mongodb"

 

3) "rabitmq"

 

 

 

客戶端命令

Redis客戶端命令

 

Redis 命令用於在 redis 服務上執行操做。

要在 redis 服務上執行命令須要一個 redis 客戶端。Redis 客戶端在咱們以前下載的的 redis 的安裝包中。

語法

Redis 客戶端的基本語法爲:

 

$ redis-cli

 

啓動 redis 客戶端,打開終端並輸入命令 redis-cli。該命令會鏈接本地的 redis 服務。

 

 

$redis-cli

 

redis 127.0.0.1:6379>

 

redis 127.0.0.1:6379> PING

 

 

 

PONG

 

 

 

在以上實例中咱們鏈接到本地的 redis 服務並執行 PING 命令,該命令用於檢測 redis 服務是否啓動。

 

在遠程服務上執行命令

$ redis-cli -h host -p port -a password

 

如下實例演示瞭如何鏈接到主機爲 127.0.0.1,端口爲 6379 ,密碼爲 mypass 的 redis 服務上。

 

 

$redis-cli -h 127.0.0.1 -p 6379 -a "mypass"

 

redis 127.0.0.1:6379>

 

redis 127.0.0.1:6379> PING

 

 

 

PONG

 

 

 

基本操做

http://www.runoob.com/redis/redis-tutorial.html

這裏就不累述了

 

 

 

集羣安裝

全部的 Redis 節點在集羣中互聯,內部使用二進制協議優化速度和帶寬

節點的 fail,是經過集羣中超過半數的節點檢測失效時才生效。也就是說,集羣中有半數以上的節點沒法鏈接上某個節點,那麼這個節點就被斷定 fail

 

客戶端鏈接集羣中的任意一臺機器,均可以訪問整個集羣的數據,由於節點之間會跳轉

 

新的數據,怎麼肯定添加到集羣中的哪臺機器呢?

答:Redis 內置了16384個哈希槽,當須要在集羣中添加數據的時候,對 Key使用 CRC16算法計算出一個結果,而後將結果對16384取餘。

這樣,每一個 Key 都對應到了0~16383中的一個數字,Redis根據節點數量,大體均等的將哈希槽映射到節點上。

能夠理解成集羣中的每臺 Redis 服務器,都均勻分配了一些槽,Key 的計算結果屬於哪一個槽,那個槽屬於哪臺服務器,就將數據存儲在哪臺服務器上

 

安裝集羣須要 ruby 支持

須要 redis 第三方接口支持:Mac 下執行一遍 sudo gem install redis 

 

下面經過一個實例演示Redis 集羣的安裝

這裏在同一臺服務器用不一樣的端口表示不一樣的redis服務器,以下:

主節點:

192.168.101.3:7001 

192.168.101.3:7002 

192.168.101.3:7003

從節點:

192.168.101.3:7004 

192.168.101.3:7005 

192.168.101.3:7006

 

 

我這裏在一臺機器上,經過端口,模擬不一樣的 Redis 服務器,實際環境中,通常是經過不一樣機器,也就是 ip 來肯定的

一、安裝單機版 Redis

二、建立一個文件夾 - redis-cluster

這個文件夾保存全部經過端口區分的集羣中的 Redis服務器

 

建立redis-cluster目錄,其下建立700一、7002......7006目錄,

 

將redis安裝目錄bin下的文件拷貝到每一個700X目錄內,同時將redis源碼目錄src下的redis-trib.rb拷貝到redis-cluster目錄下。

修改每一個700X目錄下的redis.conf配置文件:

 

port XXXX

#bind 192.168.101.3

cluster-enabled yes 

 

 

三、若是是真實的集羣環境,則不須要步驟二。直接啓動每一個節點

分別進入700一、700二、...7006目錄,執行:

./redis-server ./redis.conf

 

查看redis進程:

 

四、啓動集羣

./redis-trib.rb create --replicas 1 192.168.101.3:7001 192.168.101.3:7002 192.168.101.3:7003 192.168.101.3:7004 192.168.101.3:7005  192.168.101.3:7006

 

 

說明:

redis集羣至少須要3個主節點,每一個主節點有一個從節點總共6個節點

replicas指定爲1表示每一個主節點有一個從節點

 

注意:

若是執行時報以下錯誤:

[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0

解決方法是刪除生成的配置文件nodes.conf,若是不行則說明如今建立的結點包括了舊集羣的結點信息,須要刪除redis的持久化文件後再重啓redis,好比:appendonly.aof、dump.rdb

 

五、查詢集羣信息

 

./redis-cli -c -h 192.168.101.3 -p 7001 ,其中-c表示以集羣方式鏈接redis-h指定ip地址,-p指定端口號

 

cluster nodes 查詢集羣結點信息

 

cluster info 查詢集羣狀態信息

 

其餘集羣中的操做

一、添加主節點

集羣建立成功後能夠向集羣中添加節點,下面是添加一個master主節點 

添加7007結點,參考集羣結點規劃章節添加一個「7007」目錄做爲新節點。

 

./redis-trib.rb add-node  192.168.101.3:7007 192.168.101.3:7001

查看集羣結點發現7007已添加到集羣中:

cluster nodes

 

 

 

二、Hash槽從新分配

添加完主節點須要對主節點進行hash槽分配這樣該主節才能夠存儲數據。

redis集羣有16384個槽,集羣中的每一個結點分配自已槽,經過查看集羣結點能夠看到槽佔用狀況。

 

給剛添加的7007結點分配槽:

 

 

第一步:鏈接上集羣

./redis-trib.rb reshard 192.168.101.3:7001(鏈接集羣中任意一個可用結點都行)

 

第二步:輸入要分配的槽數量

 

輸入 500表示要分配500個槽

 

第三步:輸入接收槽的結點id

 

這裏準備給7007分配槽,經過cluster nodes查看7007結點id爲15b809eadae88955e36bcdbb8144f61bbbaf38fb

輸入:15b809eadae88955e36bcdbb8144f61bbbaf38fb

 

 

第四步:輸入源結點id

 

這裏輸入all

 

 

第五步:輸入yes開始移動槽到目標結點id

 

三、添加從節點

集羣建立成功後能夠向集羣中添加節點,下面是添加一個slave從節點。

添加7008從結點,將7008做爲7007的從結點。

 

./redis-trib.rb add-node --slave --master-id 主節點id 添加節點的ip和端口集羣中已存在節點ip和端口

 

 

執行以下命令:

./redis-trib.rb add-node --slave --master-id cad9f7413ec6842c971dbcc2c48b4ca959eb5db4  192.168.101.3:7008 192.168.101.3:7001

cad9f7413ec6842c971dbcc2c48b4ca959eb5db4  是7007結點的id,可經過cluster nodes查看。

 

注意:若是原來該結點在集羣中的配置信息已經生成cluster-config-file指定的配置文件中(若是cluster-config-file沒有指定則默認爲nodes.conf),這時可能會報錯:

[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0

解決方法是刪除生成的配置文件nodes.conf,刪除後再執行./redis-trib.rb add-node指令

查看集羣中的結點,剛添加的7008爲7007的從節點:

 

四、刪除節點

./redis-trib.rb del-node 127.0.0.1:7005 4b45eb75c8b428fbd77ab979b85080146a9bc017

 

刪除已經佔有hash槽的結點會失敗,報錯以下:

[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again.

 

須要將該結點佔用的hash槽分配出去(參考hash槽從新分配章節)。

 

 

Java操做Redis

 

// 鏈接redis集羣

    @Test

    public void testJedisCluster() {

 

        JedisPoolConfig config = new JedisPoolConfig();

        // 最大鏈接數

        config.setMaxTotal(30);

        // 最大鏈接空閒數

        config.setMaxIdle(2);

 

        //集羣結點

        Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();

        jedisClusterNode.add(new HostAndPort("192.168.101.3", 7001));

        jedisClusterNode.add(new HostAndPort("192.168.101.3", 7002));

        jedisClusterNode.add(new HostAndPort("192.168.101.3", 7003));

        jedisClusterNode.add(new HostAndPort("192.168.101.3", 7004));

        jedisClusterNode.add(new HostAndPort("192.168.101.3", 7005));

        jedisClusterNode.add(new HostAndPort("192.168.101.3", 7006));

        JedisCluster jc = new JedisCluster(jedisClusterNode, config);

       

        JedisCluster jcd = new JedisCluster(jedisClusterNode);

        jcd.set("name", "zhangsan");

        String value = jcd.get("name");

        System.out.println(value);

    }

 

 

 

 

 

 

/Users/sherry/WorkPath/Git/Web/redisDemo/src/main/java/org/zln/utils/JedisUtils.java

 

package org.zln.utils;

 

import org.apache.commons.lang3.StringUtils;

import org.apache.logging.log4j.LogManager;

import org.apache.logging.log4j.Logger;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;

 

 

/**

 * Created by sherry on 16/9/13.

 */

public class JedisUtils {

 

 

    private static Logger logger = LogManager.getLogger();

    private static JedisPool pool = null;

 

    private static final String URL = "127.0.0.1";

    private static final int PORT = 6379;

 

    private static Jedis jedis = null;

    static {

        pool = new JedisPool(new JedisPoolConfig(), URL,PORT);

 

 

    }

 

    public static Jedis getRedisCon(String password){

        jedis = pool.getResource();

        if (StringUtils.isNotEmpty(password)){

            logger.info("以密碼:"+password+" 登錄 redis");

            jedis.auth(password);

        }

        logger.info(jedis.ping());

        return jedis;

    }

 

    public static void closeRedisCon(Jedis jedis){

        if (jedis!=null){

            jedis.close();

        }

    }

 

 

    public static void closeApp(){

        //關閉應用程序的時候執行

        pool.destroy();

    }

 

 

}

 

 

/Users/sherry/WorkPath/Git/Web/redisDemo/src/main/java/org/zln/main/JedisMain.java

 

package org.zln.main;

 

import org.apache.logging.log4j.LogManager;

import org.apache.logging.log4j.Logger;

import org.zln.utils.JedisUtils;

import redis.clients.jedis.Jedis;

 

import java.io.*;

import java.util.*;

 

/**

 * Created by sherry on 16/9/13.

 */

public class JedisMain {

 

    private static Logger logger = LogManager.getLogger();

 

    public static void main(String[] args) {

        Jedis jedis = JedisUtils.getRedisCon("");

//        stringTest(jedis);

//

//        listTest(jedis);

//

//        mapTest(jedis);

//

//        objTest(jedis);

 

        objListTest(jedis);

//        將這個Jedis實例歸還給JedisPool。

        JedisUtils.closeRedisCon(jedis);

 

    }

 

    /**

     * 對象列表

     * @param jedis

     */

    private static void objListTest(Jedis jedis) {

        Person person1 = new Person("name1",1);

        Person person2 = new Person("name2",2);

        Person person3 = new Person("name3",3);

        Person person4 = new Person("name4",4);

 

        List<Person> persons = new ArrayList<>();

        persons.add(person1);

        persons.add(person2);

        persons.add(person3);

        persons.add(person4);

 

        try {

            for (Person person:persons){

                ByteArrayOutputStream bos =  new ByteArrayOutputStream();

                ObjectOutputStream oos =  new ObjectOutputStream(bos);

                oos.writeObject(person);

                byte [] byteArray = bos.toByteArray();

                oos.close();

                bos.close();

 

                logger.info("寫入對象:"+person);

                jedis.lpush("persons".getBytes(),byteArray);

            }

 

            List<byte[]> personsBytes = jedis.lrange("persons".getBytes(),0,10);

            for (byte[] bs:personsBytes){

                ByteArrayInputStream bis =  new ByteArrayInputStream(bs);

 

                ObjectInputStream inputStream =  new ObjectInputStream(bis);

 

                Person readObject = (Person) inputStream.readObject();

 

                logger.info( " 讀取對象 \t" + readObject.toString());

 

                inputStream.close();

 

                bis.close();

            }

 

        } catch (IOException|ClassNotFoundException e) {

            e.printStackTrace();

        }

 

        jedis.del("persons".getBytes());

 

 

    }

 

    /**

     * 存儲對象

     * @param jedis

     */

    private static void objTest(Jedis jedis) {

 

        Person person = new Person();

        person.setAge(27);

        person.setName("卡卡卡");

 

        ByteArrayOutputStream bos =  new ByteArrayOutputStream();

 

        try {

            ObjectOutputStream oos =  new ObjectOutputStream(bos);

            oos.writeObject(person);

 

            byte [] byteArray = bos.toByteArray();

            oos.close();

            bos.close();

 

            String setObjectRet = jedis.set(person.getName().getBytes(), byteArray);

 

            logger.info( " set object return \t" + setObjectRet);

 

            byte [] bs = jedis.get( person.getName().getBytes());

 

            ByteArrayInputStream bis =  new ByteArrayInputStream(bs);

 

            ObjectInputStream inputStream =  new ObjectInputStream(bis);

 

            Person readObject = (Person) inputStream.readObject();

 

            logger.info( " read object \t" + readObject.toString());

 

            inputStream.close();

 

            bis.close();

 

        } catch (IOException|ClassNotFoundException e) {

            e.printStackTrace();

        }

 

        jedis.del(person.getName());

    }

 

    /**

     * 存儲 Map

     * @param jedis

     */

    private static void mapTest(Jedis jedis) {

        Map<String,String> user =  new HashMap<String,String>();

        user.put( "name" ,  "cd" );

        user.put( "password" ,  "123456" );

 

        jedis.hmset("user",user);

        // mapkey 個數

        System.out.println(String.format ( "len:%d" , jedis.hlen( "user" )));

//map中的全部鍵值

        System.out.println(String.format ( "keys: %s" , jedis.hkeys( "user" ) ));

//map中的全部value

        System.out.println(String.format ( "values: %s" , jedis.hvals( "user" ) ));

//取出map中的name字段值

        List<String> rsmap = jedis.hmget( "user" ,  "name" , "password" );

        System.out.println(rsmap);

//刪除map中的某一個鍵值 password

        jedis.hdel( "user" ,  "password" );

        System.out.println(jedis.hmget( "user" ,  "name" ,  "password" ));

 

        jedis.del("user");

    }

 

    /**

     * 存儲列表

     * @param jedis

     */

    private static void listTest(Jedis jedis) {

        jedis.lpush("tutorial-list", "Redis");

        jedis.lpush("tutorial-list", "Mongodb");

        jedis.lpush("tutorial-list", "Mysql");

        // 獲取存儲的數據並輸出

        List<String> list = jedis.lrange("tutorial-list", 0 ,5);

        for(int i=0; i<list.size(); i++) {

            System.out.println("Stored string in redis:: "+list.get(i));

        }

        jedis.del("tutorial-list");

    }

 

    /**

     * 存儲字符串

     * @param jedis

     */

    private static void stringTest(Jedis jedis) {

        //一次次添加

        jedis.set("string1","一號字符串");

        jedis.set("string2","二號字符串");

        jedis.set("string3","三號字符串");

        jedis.set("string4","四號字符串");

 

        logger.info("獲取string1:"+jedis.get("string1"));

        //在已有 key 上,對 value 進行新增

        jedis.append("string1","添加新字符串");

        logger.info("獲取string1:"+jedis.get("string1"));

 

 

        //一次性添加多個鍵值對

        jedis.mset("s1","v1","s2","v2","s3","v3");

        logger.info("獲取s1:"+jedis.get("s1"));

 

        for (Iterator<String> iterator = jedis.keys("*").iterator();iterator.hasNext();){

            String key = iterator.next();

            logger.info(key+":"+jedis.get(key));

            jedis.del(key);

        }

 

    }

}

 

 

 

與Spring集成

pom構建:

 

[html] view plain copy

 

print?

1 <modelVersion>4.0.0</modelVersion>  

2 <groupId>com.x.redis</groupId>  

3 <artifactId>springredis</artifactId>  

4 <version>0.0.1-SNAPSHOT</version>  

5   

6 <dependencies>  

7     <dependency>  

8         <groupId>org.springframework.data</groupId>  

9         <artifactId>spring-data-redis</artifactId>  

10              <version>1.0.2.RELEASE</version>  

11          </dependency>  

12          <dependency>  

13              <groupId>org.springframework</groupId>  

14              <artifactId>spring-test</artifactId>  

15              <version>3.1.2.RELEASE</version>  

16              <scope>test</scope>  

17          </dependency>  

18            

19          <dependency>  

20              <groupId>redis.clients</groupId>  

21              <artifactId>jedis</artifactId>  

22              <version>2.1.0</version>  

23          </dependency>  

24            

25           <dependency>  

26              <groupId>junit</groupId>  

27              <artifactId>junit</artifactId>  

28              <version>4.8.2</version>  

29              <scope>test</scope>  

30          </dependency>  

31      </dependencies>  

 

spring配置文件(applicationContext.xml):

 

[html] view plain copy

 

print?

1 <?xml version="1.0" encoding="UTF-8"?>  

2 <beans xmlns="http://www.springframework.org/schema/beans"  

3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  

4     xmlns:context="http://www.springframework.org/schema/context"  

5     xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"  

6     xmlns:aop="http://www.springframework.org/schema/aop"  

7     xsi:schemaLocation="  

8             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  

9             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">  

10        

11          <context:property-placeholder location="classpath:redis.properties" />  

12        

13          <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">  

14              <property name="maxIdle" value="${redis.maxIdle}" />  

15              <property name="maxActive" value="${redis.maxActive}" />  

16              <property name="maxWait" value="${redis.maxWait}" />  

17              <property name="testOnBorrow" value="${redis.testOnBorrow}" />  

18          </bean>  

19            

20          <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"  

21              p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"  p:pool-config-ref="poolConfig"/>  

22            

23          <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">  

24              <property name="connectionFactory"   ref="connectionFactory" />  

25          </bean>         

26            

27          <bean id="userDao" class="com.x.dao.impl.UserDao" />   

28      </beans>  

redis.properties

 

 

[html] view plain copy

 

print?

1 # Redis settings  

2 redis.host=localhost  

3 redis.port=6379  

4 redis.pass=java2000_wl  

5   

6   

7 redis.maxIdle=300  

8 redis.maxActive=600  

9 redis.maxWait=1000  

10      redis.testOnBorrow=true  

 

java代碼:

 

[java] view plain copy

 

print?

1 package com.x.entity;  

2   

3 import java.io.Serializable;  

4   

5 /**  

6  * @author http://blog.csdn.net/java2000_wl  

7  * @version <b>1.0</b>  

8  */   

9 public class User implements Serializable {  

10            

11          private static final long serialVersionUID = -6011241820070393952L;  

12        

13          private String id;  

14            

15          private String name;  

16            

17          private String password;  

18        

19          /** 

20           * <br>------------------------------<br> 

21           */  

22          public User() {  

23                

24          }  

25            

26          /** 

27           * <br>------------------------------<br> 

28           */  

29          public User(String id, String name, String password) {  

30              super();  

31              this.id = id;  

32              this.name = name;  

33              this.password = password;  

34          }  

35        

36          /** 

37           * 得到id 

38           * @return the id 

39           */  

40          public String getId() {  

41              return id;  

42          }  

43        

44          /** 

45           * 設置id 

46           * @param id the id to set 

47           */  

48          public void setId(String id) {  

49              this.id = id;  

50          }  

51        

52          /** 

53           * 得到name 

54           * @return the name 

55           */  

56          public String getName() {  

57              return name;  

58          }  

59        

60          /** 

61           * 設置name 

62           * @param name the name to set 

63           */  

64          public void setName(String name) {  

65              this.name = name;  

66          }  

67        

68          /** 

69           * 得到password 

70           * @return the password 

71           */  

72          public String getPassword() {  

73              return password;  

74          }  

75        

76          /** 

77           * 設置password 

78           * @param password the password to set 

79           */  

80          public void setPassword(String password) {  

81              this.password = password;  

82          }  

83      }  

[java] view plain copy

 

print?

1 package com.x.dao;  

2   

3 import org.springframework.beans.factory.annotation.Autowired;  

4 import org.springframework.data.redis.core.RedisTemplate;  

5 import org.springframework.data.redis.serializer.RedisSerializer;  

6   

7 /**  

8  * AbstractBaseRedisDao 

9  * @author http://blog.csdn.net/java2000_wl  

10       * @version <b>1.0</b>  

11       */   

12      public abstract class AbstractBaseRedisDao<K, V> {  

13            

14          @Autowired  

15          protected RedisTemplate<K, V> redisTemplate;  

16        

17          /** 

18           * 設置redisTemplate 

19           * @param redisTemplate the redisTemplate to set 

20           */  

21          public void setRedisTemplate(RedisTemplate<K, V> redisTemplate) {  

22              this.redisTemplate = redisTemplate;  

23          }  

24            

25          /** 

26           * 獲取 RedisSerializer 

27           * <br>------------------------------<br> 

28           */  

29          protected RedisSerializer<String> getRedisSerializer() {  

30              return redisTemplate.getStringSerializer();  

31          }  

32      }  

[java] view plain copy

 

print?

1 package com.x.dao;  

2   

3 import java.util.List;  

4   

5 import com.x.entity.User;  

6   

7 /**  

8  * @author http://blog.csdn.net/java2000_wl  

9  * @version <b>1.0</b>  

10       */   

11      public interface IUserDao {  

12            

13          /** 

14           * 新增 

15           * <br>------------------------------<br> 

16           * @param user 

17           * @return 

18           */  

19          boolean add(User user);  

20            

21          /** 

22           * 批量新增 使用pipeline方式 

23           * <br>------------------------------<br> 

24           * @param list 

25           * @return 

26           */  

27          boolean add(List<User> list);  

28            

29          /** 

30           * 刪除 

31           * <br>------------------------------<br> 

32           * @param key 

33           */  

34          void delete(String key);  

35            

36          /** 

37           * 刪除多個 

38           * <br>------------------------------<br> 

39           * @param keys 

40           */  

41          void delete(List<String> keys);  

42            

43          /** 

44           * 修改 

45           * <br>------------------------------<br> 

46           * @param user 

47           * @return  

48           */  

49          boolean update(User user);  

50        

51          /** 

52           * 經過key獲取 

53           * <br>------------------------------<br> 

54           * @param keyId 

55           * @return  

56           */  

57          User get(String keyId);  

58      }  

[java] view plain copy

 

print?

1 package com.x.dao.impl;  

2   

3 import java.util.ArrayList;  

4 import java.util.List;  

5   

6 import org.springframework.dao.DataAccessException;  

7 import org.springframework.data.redis.connection.RedisConnection;  

8 import org.springframework.data.redis.core.RedisCallback;  

9 import org.springframework.data.redis.serializer.RedisSerializer;  

10      import org.springframework.util.Assert;  

11        

12      import com.x.dao.AbstractBaseRedisDao;  

13      import com.x.dao.IUserDao;  

14      import com.x.entity.User;  

15        

16      /**  

17       * Dao 

18       * @author http://blog.csdn.net/java2000_wl  

19       * @version <b>1.0</b>  

20       */   

21      public class UserDao extends AbstractBaseRedisDao<String, User> implements IUserDao {  

22        

23          /**  

24           * 新增 

25           *<br>------------------------------<br> 

26           * @param user 

27           * @return 

28           */  

29          public boolean add(final User user) {  

30              boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {  

31                  public Boolean doInRedis(RedisConnection connection)  

32                          throws DataAccessException {  

33                      RedisSerializer<String> serializer = getRedisSerializer();  

34                      byte[] key  = serializer.serialize(user.getId());  

35                      byte[] name = serializer.serialize(user.getName());  

36                      return connection.setNX(key, name);  

37                  }  

38              });  

39              return result;  

40          }  

41            

42          /** 

43           * 批量新增 使用pipeline方式   

44           *<br>------------------------------<br> 

45           *@param list 

46           *@return 

47           */  

48          public boolean add(final List<User> list) {  

49              Assert.notEmpty(list);  

50              boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {  

51                  public Boolean doInRedis(RedisConnection connection)  

52                          throws DataAccessException {  

53                      RedisSerializer<String> serializer = getRedisSerializer();  

54                      for (User user : list) {  

55                          byte[] key  = serializer.serialize(user.getId());  

56                          byte[] name = serializer.serialize(user.getName());  

57                          connection.setNX(key, name);  

58                      }  

59                      return true;  

60                  }  

61              }, falsetrue);  

62              return result;  

63          }  

64            

65          /**  

66           * 刪除 

67           * <br>------------------------------<br> 

68           * @param key 

69           */  

70          public void delete(String key) {  

71              List<String> list = new ArrayList<String>();  

72              list.add(key);  

73              delete(list);  

74          }  

75        

76          /** 

77           * 刪除多個 

78           * <br>------------------------------<br> 

79           * @param keys 

80           */  

81          public void delete(List<String> keys) {  

82              redisTemplate.delete(keys);  

83          }  

84        

85          /** 

86           * 修改  

87           * <br>------------------------------<br> 

88           * @param user 

89           * @return  

90           */  

91          public boolean update(final User user) {  

92              String key = user.getId();  

93              if (get(key) == null) {  

94                  throw new NullPointerException("數據行不存在, key = " + key);  

95              }  

96              boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {  

97                  public Boolean doInRedis(RedisConnection connection)  

98                          throws DataAccessException {  

99                      RedisSerializer<String> serializer = getRedisSerializer();  

100                    byte[] key  = serializer.serialize(user.getId());  

101                    byte[] name = serializer.serialize(user.getName());  

102                    connection.set(key, name);  

103                    return true;  

104                }  

105            });  

106            return result;  

107        }  

108      

109        /**  

110         * 經過key獲取 

111         * <br>------------------------------<br> 

112         * @param keyId 

113         * @return 

114         */  

115        public User get(final String keyId) {  

116            User result = redisTemplate.execute(new RedisCallback<User>() {  

117                public User doInRedis(RedisConnection connection)  

118                        throws DataAccessException {  

119                    RedisSerializer<String> serializer = getRedisSerializer();  

120                    byte[] key = serializer.serialize(keyId);  

121                    byte[] value = connection.get(key);  

122                    if (value == null) {  

123                        return null;  

124                    }  

125                    String name = serializer.deserialize(value);  

126                    return new User(keyId, name, null);  

127                }  

128            });  

129            return result;  

130        }  

131    }  

[java] view plain copy

 

print?

1 import java.util.ArrayList;  

2 import java.util.List;  

3   

4 import junit.framework.Assert;  

5   

6 import org.junit.Test;  

7 import org.springframework.beans.factory.annotation.Autowired;  

8 import org.springframework.test.context.ContextConfiguration;  

9 import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;  

10        

11      import com.x.dao.IUserDao;  

12      import com.x.entity.User;  

13        

14      /**  

15       * 測試 

16       * @author http://blog.csdn.net/java2000_wl  

17       * @version <b>1.0</b>  

18       */    

19      @ContextConfiguration(locations = {"classpath*:applicationContext.xml"})  

20      public class RedisTest extends AbstractJUnit4SpringContextTests {  

21            

22          @Autowired  

23          private IUserDao userDao;  

24            

25          /** 

26           * 新增 

27           * <br>------------------------------<br> 

28           */  

29          @Test  

30          public void testAddUser() {  

31              User user = new User();  

32              user.setId("user1");  

33              user.setName("java2000_wl");  

34              boolean result = userDao.add(user);  

35              Assert.assertTrue(result);  

36          }  

37            

38          /** 

39           * 批量新增 普通方式 

40           * <br>------------------------------<br> 

41           */  

42          @Test  

43          public void testAddUsers1() {  

44              List<User> list = new ArrayList<User>();  

45              for (int i = 10; i < 50000; i++) {  

46                  User user = new User();  

47                  user.setId("user" + i);  

48                  user.setName("java2000_wl" + i);  

49                  list.add(user);  

50              }  

51              long begin = System.currentTimeMillis();  

52              for (User user : list) {  

53                  userDao.add(user);  

54              }  

55              System.out.println(System.currentTimeMillis() -  begin);  

56          }  

57            

58          /** 

59           * 批量新增 pipeline方式 

60           * <br>------------------------------<br> 

61           */  

62          @Test  

63          public void testAddUsers2() {  

64              List<User> list = new ArrayList<User>();  

65              for (int i = 10; i < 1500000; i++) {  

66                  User user = new User();  

67                  user.setId("user" + i);  

68                  user.setName("java2000_wl" + i);  

69                  list.add(user);  

70              }  

71              long begin = System.currentTimeMillis();  

72              boolean result = userDao.add(list);  

73              System.out.println(System.currentTimeMillis() - begin);  

74              Assert.assertTrue(result);  

75          }  

76            

77          /** 

78           * 修改 

79           * <br>------------------------------<br> 

80           */  

81          @Test  

82          public void testUpdate() {  

83              User user = new User();  

84              user.setId("user1");  

85              user.setName("new_password");  

86              boolean result = userDao.update(user);  

87              Assert.assertTrue(result);  

88          }  

89            

90          /** 

91           * 經過key刪除單個 

92           * <br>------------------------------<br> 

93           */  

94          @Test  

95          public void testDelete() {  

96              String key = "user1";  

97              userDao.delete(key);  

98          }  

99            

100        /** 

101         * 批量刪除 

102         * <br>------------------------------<br> 

103         */  

104        @Test  

105        public void testDeletes() {  

106            List<String> list = new ArrayList<String>();  

107            for (int i = 0; i < 10; i++) {  

108                list.add("user" + i);  

109            }  

110            userDao.delete(list);  

111        }  

112          

113        /** 

114         * 獲取 

115         * <br>------------------------------<br> 

116         */  

117        @Test  

118        public void testGetUser() {  

119            String id = "user1";  

120            User user = userDao.get(id);  

121            Assert.assertNotNull(user);  

122            Assert.assertEquals(user.getName(), "java2000_wl");  

123        }  

124      

125        /** 

126         * 設置userDao 

127         * @param userDao the userDao to set 

128         */  

129        public void setUserDao(IUserDao userDao) {  

130            this.userDao = userDao;  

131        }  

132    }  

 

 

-----------------------上述有點混亂,下面記錄重要的Redis信息----------------------------

一、什麼是Redis?

       Redis是數據庫,不是簡單的緩存

      

二、如何安裝Redis?

       見上

       默認狀況下安裝完畢後,在/usr/local/bin/目錄下和安裝目錄的src目錄下,會產生幾個命令文件,分別是

       redis-server:Redis的服務器操做命令,用於Redis服務器的啓停

       redis-cli:Redis的客戶端命令,用於鏈接Redis服務器,並進行各項操做

       redis-benchmark:Redis的性能測試工具

       redis-check-aof:檢查aof日誌的工具

       redis-check-dump:檢查rdb日誌的工具

 

三、如何啓動Redis服務?

       使用redis-server命令,指定一個redis.conf配置文件進行啓動便可

       如:redis-server redis.conf

 

四、如何鏈接Redis服務器?

       使用redis-cli命令

       例如:redis-cli -h ip -p port

       如何直接  redis-cli,則默認鏈接127.0.0.1的6379端口

 

五、如何添加/獲取數據?

可以操做的數據類型包括  字符串、列表、集合、有序集合、哈希、位圖、超重對數

Redis的鍵是二進制安全的,可使用任何的二進制序列做爲鍵

鍵的最大值是512MB

       String(字符串)

string是redis最基本的類型,你能夠理解成與Memcached如出一轍的類型,一個key對應一個value。

string類型是二進制安全的。意思是redis的string能夠包含任何數據。好比jpg圖片或者序列化的對象 。

string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。

實例

redis 127.0.0.1:6379> SET name "runoob"

OK

redis 127.0.0.1:6379> GET name

"runoob"

在以上實例中咱們使用了 Redis 的 SET 和 GET 命令。鍵爲 name,對應的值爲 runoob。

注意:一個鍵最大能存儲512MB。

 

    Hash(哈希)

Redis hash 是一個鍵值對集合。

Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。

實例

127.0.0.1:6379> HMSET user:1 username runoob password runoob points 200

OK

127.0.0.1:6379> HGETALL user:1

1) "username"

2) "runoob"

3) "password"

4) "runoob"

5) "points"

6) "200"

以上實例中 hash 數據類型存儲了包含用戶腳本信息的用戶對象。 實例中咱們使用了 Redis HMSET, HGETALL 命令,user:1 爲鍵值。

每一個 hash 能夠存儲 232 -1 鍵值對(40多億)。

 

 

    List(列表)

Redis 列表是簡單的字符串列表,按照插入順序排序。你能夠添加一個元素到列表的頭部(左邊)或者尾部(右邊)。

實例

redis 127.0.0.1:6379> lpush runoob redis

(integer) 1

redis 127.0.0.1:6379> lpush runoob mongodb

(integer) 2

redis 127.0.0.1:6379> lpush runoob rabitmq

(integer) 3

redis 127.0.0.1:6379> lrange runoob 0 10

1) "rabitmq"

2) "mongodb"

3) "redis"

redis 127.0.0.1:6379>

列表最多可存儲 232 - 1 元素 (4294967295, 每一個列表可存儲40多億)。

 

    Set(集合)

Redis的Set是string類型的無序集合。

集合是經過哈希表實現的,因此添加,刪除,查找的複雜度都是O(1)。

sadd 命令

添加一個string元素到,key對應的set集合中,成功返回1,若是元素已經在集合中返回0,key對應的set不存在返回錯誤。

sadd key member

實例

redis 127.0.0.1:6379> sadd runoob redis

(integer) 1

redis 127.0.0.1:6379> sadd runoob mongodb

(integer) 1

redis 127.0.0.1:6379> sadd runoob rabitmq

(integer) 1

redis 127.0.0.1:6379> sadd runoob rabitmq

(integer) 0

redis 127.0.0.1:6379> smembers runoob

 

1) "rabitmq"

2) "mongodb"

3) "redis"

注意:以上實例中 rabitmq 添加了兩次,但根據集合內元素的惟一性,第二次插入的元素將被忽略。

集合中最大的成員數爲 232 - 1(4294967295, 每一個集合可存儲40多億個成員)。

 

    zset(sorted set:有序集合)

Redis zset 和 set 同樣也是string類型元素的集合,且不容許重複的成員。

 

不一樣的是每一個元素都會關聯一個double類型的分數。redis正是經過分數來爲集合中的成員進行從小到大的排序。

zset的成員是惟一的,但分數(score)卻能夠重複。

zadd 命令

添加元素到集合,元素在集合中存在則更新對應score

zadd key score member

實例

redis 127.0.0.1:6379> zadd runoob 0 redis

(integer) 1

redis 127.0.0.1:6379> zadd runoob 0 mongodb

(integer) 1

redis 127.0.0.1:6379> zadd runoob 0 rabitmq

(integer) 1

redis 127.0.0.1:6379> zadd runoob 0 rabitmq

(integer) 0

redis 127.0.0.1:6379> ZRANGEBYSCORE runoob 0 1000

 

1) "redis"

2) "mongodb"

3) "rabitmq"

 

六、如何操做Key?

序號

命令及描述

1

DEL key

該命令用於在 key 存在時刪除 key。

2

DUMP key

序列化給定 key ,並返回被序列化的值。

3

EXISTS key

檢查給定 key 是否存在。

4

EXPIRE key seconds

爲給定 key 設置過時時間。

5

EXPIREAT key timestamp

EXPIREAT 的做用和 EXPIRE 相似,都用於爲 key 設置過時時間。 不一樣在於 EXPIREAT 命令接受的時間參數是 UNIX 時間戳(unix timestamp)。

6

PEXPIRE key milliseconds

設置 key 的過時時間以毫秒計。

7

PEXPIREAT key milliseconds-timestamp

設置 key 過時時間的時間戳(unix timestamp) 以毫秒計

8

KEYS pattern

查找全部符合給定模式( pattern)的 key 。

9

MOVE key db

將當前數據庫的 key 移動到給定的數據庫 db 當中。

10

PERSIST key

移除 key 的過時時間,key 將持久保持。

11

PTTL key

以毫秒爲單位返回 key 的剩餘的過時時間。

12

TTL key

以秒爲單位,返回給定 key 的剩餘生存時間(TTL, time to live)。

13

RANDOMKEY

從當前數據庫中隨機返回一個 key 。

14

RENAME key newkey

修改 key 的名稱

15

RENAMENX key newkey

僅當 newkey 不存在時,將 key 更名爲 newkey 。

16

TYPE key

返回 key 所儲存的值的類型。

 

命令詳解

exists

檢查執行的key是否存在

127.0.0.1:6379> exists k1

(integer) 1

127.0.0.1:6379> exists k5

(integer) 0

del

刪除指定的key

127.0.0.1:6379> del name

(integer) 1

 

返回值爲刪除的鍵的個數。若是被刪除的鍵自己就不存在,就返回0

type

查詢鍵的類型

127.0.0.1:6379> type k1

string

expire

設置鍵的生存時間。單位是秒

超過咱們的設置時間後,key會失效,等同於執行了del操做

127.0.0.1:6379> expire mk 5

(integer) 1

127.0.0.1:6379> get mk

"wahaha"

127.0.0.1:6379> get mk

(nil)

pexpire

設置鍵的生存時間。單位是毫秒

超過咱們的設置時間後,key會失效,等同於執行了del操做

 

persist

移除key的過時時間設置。至關於此key會永久保持

127.0.0.1:6379> persist mk

(integer) 1

 

ttl

key的剩餘生存時間,單位是秒

127.0.0.1:6379> ttl k4

(integer) 3498

pttl

key的剩餘生存時間,單位是毫秒

127.0.0.1:6379> pttl k4

(integer) 3558506

七、如何關閉服務?

       有兩種方法

              一、找到對應的進程號,直接kill

              二、使用redis-cli登錄後,執行shutdown命令

 

八、如何後臺啓動?

       默認狀況下啓動的redis-server,並非後臺運行的

       修改redis.conf文件的  daemonize yes

 

九、如何設置Redis參數?

   有兩種方式

      一、直接修改redis.conf 文件

      二、使用CONFIG命令

         CONFIG GET * ;獲取當前設置的所有參數

         CONFIG GET KEY ;獲取指定key設置的值

         CONFIG SET KEY VALUE ;設置某個參數

 

十、Redis有哪些參數能夠設置?

       redis.conf 配置項說明以下:

1. Redis默認不是以守護進程的方式運行,能夠經過該配置項修改,使用yes啓用守護進程

    daemonize no

2. 當Redis以守護進程方式運行時,Redis默認會把pid寫入/var/run/redis.pid文件,能夠經過pidfile指定

    pidfile /var/run/redis.pid

3. 指定Redis監聽端口,默認端口爲6379,做者在本身的一篇博文中解釋了爲何選用6379做爲默認端口,由於6379在手機按鍵上MERZ對應的號碼,而MERZ取自意大利歌女Alessia Merz的名字

    port 6379

4. 綁定的主機地址

    bind 127.0.0.1

5.當 客戶端閒置多長時間後關閉鏈接,若是指定爲0,表示關閉該功能

    timeout 300

6. 指定日誌記錄級別,Redis總共支持四個級別:debug、verbose、notice、warning,默認爲verbose

    loglevel verbose

7. 日誌記錄方式,默認爲標準輸出,若是配置Redis爲守護進程方式運行,而這裏又配置爲日誌記錄方式爲標準輸出,則日誌將會發送給/dev/null

    logfile stdout

8. 設置數據庫的數量,默認數據庫爲0,可使用SELECT <dbid>命令在鏈接上指定數據庫id

    databases 16

9. 指定在多長時間內,有多少次更新操做,就將數據同步到數據文件,能夠多個條件配合

    save <seconds> <changes>

    Redis默認配置文件中提供了三個條件:

    save 900 1

    save 300 10

    save 60 10000

    分別表示900秒(15分鐘)內有1個更改,300秒(5分鐘)內有10個更改以及60秒內有10000個更改。

 

10. 指定存儲至本地數據庫時是否壓縮數據,默認爲yes,Redis採用LZF壓縮,若是爲了節省CPU時間,能夠關閉該選項,但會致使數據庫文件變的巨大

    rdbcompression yes

11. 指定本地數據庫文件名,默認值爲dump.rdb

    dbfilename dump.rdb

12. 指定本地數據庫存放目錄

    dir ./

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

    slaveof <masterip> <masterport>

14. 當master服務設置了密碼保護時,slav服務鏈接master的密碼

    masterauth <master-password>

15. 設置Redis鏈接密碼,若是配置了鏈接密碼,客戶端在鏈接Redis時須要經過AUTH <password>命令提供密碼,默認關閉

    requirepass foobared

16. 設置同一時間最大客戶端鏈接數,默認無限制,Redis能夠同時打開的客戶端鏈接數爲Redis進程能夠打開的最大文件描述符數,若是設置 maxclients 0,表示不做限制。當客戶端鏈接數到達限制時,Redis會關閉新的鏈接並向客戶端返回max number of clients reached錯誤信息

    maxclients 128

17. 指定Redis最大內存限制,Redis在啓動時會把數據加載到內存中,達到最大內存後,Redis會先嚐試清除已到期或即將到期的Key,當此方法處理 後,仍然到達最大內存設置,將沒法再進行寫入操做,但仍然能夠進行讀取操做。Redis新的vm機制,會把Key存放內存,Value會存放在swap區

    maxmemory <bytes>

18. 指定是否在每次更新操做後進行日誌記錄,Redis在默認狀況下是異步的把數據寫入磁盤,若是不開啓,可能會在斷電時致使一段時間內的數據丟失。由於 redis自己同步數據文件是按上面save條件來同步的,因此有的數據會在一段時間內只存在於內存中。默認爲no

    appendonly no

19. 指定更新日誌文件名,默認爲appendonly.aof

     appendfilename appendonly.aof

20. 指定更新日誌條件,共有3個可選值:

    no:表示等操做系統進行數據緩存同步到磁盤(快)

    always:表示每次更新操做後手動調用fsync()將數據寫到磁盤(慢,安全)

    everysec:表示每秒同步一次(折衷,默認值)

    appendfsync everysec

 

21. 指定是否啓用虛擬內存機制,默認值爲no,簡單的介紹一下,VM機制將數據分頁存放,由Redis將訪問量較少的頁即冷數據swap到磁盤上,訪問多的頁面由磁盤自動換出到內存中(在後面的文章我會仔細分析Redis的VM機制)

     vm-enabled no

22. 虛擬內存文件路徑,默認值爲/tmp/redis.swap,不可多個Redis實例共享

     vm-swap-file /tmp/redis.swap

23. 將全部大於vm-max-memory的數據存入虛擬內存,不管vm-max-memory設置多小,全部索引數據都是內存存儲的(Redis的索引數據 就是keys),也就是說,當vm-max-memory設置爲0的時候,實際上是全部value都存在於磁盤。默認值爲0

     vm-max-memory 0

24. Redis swap文件分紅了不少的page,一個對象能夠保存在多個page上面,但一個page上不能被多個對象共享,vm-page-size是要根據存儲的 數據大小來設定的,做者建議若是存儲不少小對象,page大小最好設置爲32或者64bytes;若是存儲很大大對象,則可使用更大的page,若是不 肯定,就使用默認值

     vm-page-size 32

25. 設置swap文件中的page數量,因爲頁表(一種表示頁面空閒或使用的bitmap)是在放在內存中的,,在磁盤上每8個pages將消耗1byte的內存。

     vm-pages 134217728

26. 設置訪問swap文件的線程數,最好不要超過機器的核數,若是設置爲0,那麼全部對swap文件的操做都是串行的,可能會形成比較長時間的延遲。默認值爲4

     vm-max-threads 4

27. 設置在向客戶端應答時,是否把較小的包合併爲一個包發送,默認爲開啓

    glueoutputbuf yes

28. 指定在超過必定的數量或者最大的元素超過某一臨界值時,採用一種特殊的哈希算法

    hash-max-zipmap-entries 64

    hash-max-zipmap-value 512

29. 指定是否激活重置哈希,默認爲開啓(後面在介紹Redis的哈希算法時具體介紹)

    activerehashing yes

30. 指定包含其它的配置文件,能夠在同一主機上多個Redis實例之間使用同一份配置文件,而同時各個實例又擁有本身的特定配置文件

    include /path/to/local.conf

 

十一、如何操做字符串類型的數據?

命令列表

序號

命令及描述

1

SET key value

設置指定 key 的值

2

GET key

獲取指定 key 的值。

3

GETRANGE key start end

返回 key 中字符串值的子字符

4

GETSET key value

將給定 key 的值設爲 value ,並返回 key 的舊值(old value)。

5

GETBIT key offset

對 key 所儲存的字符串值,獲取指定偏移量上的位(bit)。

6

MGET key1 [key2..]

獲取全部(一個或多個)給定 key 的值。

7

SETBIT key offset value

對 key 所儲存的字符串值,設置或清除指定偏移量上的位(bit)。

8

SETEX key seconds value

將值 value 關聯到 key ,並將 key 的過時時間設爲 seconds (以秒爲單位)。

9

SETNX key value

只有在 key 不存在時設置 key 的值。

10

SETRANGE key offset value

用 value 參數覆寫給定 key 所儲存的字符串值,從偏移量 offset 開始。

11

STRLEN key

返回 key 所儲存的字符串值的長度。

12

MSET key value [key value ...]

同時設置一個或多個 key-value 對。

13

MSETNX key value [key value ...]

同時設置一個或多個 key-value 對,當且僅當全部給定 key 都不存在。

14

PSETEX key milliseconds value

這個命令和 SETEX 命令類似,但它以毫秒爲單位設置 key 的生存時間,而不是像 SETEX 命令那樣,以秒爲單位。

15

INCR key

將 key 中儲存的數字值增一。

16

INCRBY key increment

將 key 所儲存的值加上給定的增量值(increment) 。

17

INCRBYFLOAT key increment

將 key 所儲存的值加上給定的浮點增量值(increment) 。

18

DECR key

將 key 中儲存的數字值減一。

19

DECRBY key decrement

key 所儲存的值減去給定的減量值(decrement) 。

20

APPEND key value

若是 key 已經存在而且是一個字符串, APPEND 命令將 value 追加到 key 原來的值的末尾。

Redis中的字符串是二進制安全的

命令詳解

set

127.0.0.1:6379> set mk wahaha

OK

若是key不存在,會建立,若是key存在,會覆蓋

 

127.0.0.1:6379> set mk mkv nx

(nil)

使用 nx 參數,若是key已經存在,就會set失敗

 

127.0.0.1:6379> set mnk kk xx

(nil)

使用 xx 參數,若是key不存在,就會set失敗

 

127.0.0.1:6379> set k4 v4 ex 3600

OK

能夠在設置的時候指定key的生存時間,ex  單位是秒

get

127.0.0.1:6379> get mk

"wahaha"

 

incr

對於value是整型數據的值進行自增

127.0.0.1:6379> set seq 1

OK

127.0.0.1:6379> incr seq

(integer) 2

127.0.0.1:6379> get seq

"2"

127.0.0.1:6379> incr seq

(integer) 3

127.0.0.1:6379> get seq

"3"

incr命令是原子的,也就是說,是多線程安全的。這個和Oracle中的序列的概念有點像

 

mset

同時設置多個k-v

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3

OK

mget

同時獲取多個key的value

127.0.0.1:6379> mget k1 k2 k3

1) "v1"

2) "v2"

3) "v3"

getset

設置一個值,同時返回原先的值

127.0.0.1:6379> get k1

"v1"

127.0.0.1:6379> getset k1 v2

"v1"

127.0.0.1:6379> get k1

"v2"

十二、如何操做Hash類型的數據

命令列表

序號

命令及描述

1

HDEL key field2 [field2]

刪除一個或多個哈希表字段

2

HEXISTS key field

查看哈希表 key 中,指定的字段是否存在。

3

HGET key field

獲取存儲在哈希表中指定字段的值。

4

HGETALL key

獲取在哈希表中指定 key 的全部字段和值

5

HINCRBY key field increment

爲哈希表 key 中的指定字段的整數值加上增量 increment 。

6

HINCRBYFLOAT key field increment

爲哈希表 key 中的指定字段的浮點數值加上增量 increment 。

7

HKEYS key

獲取全部哈希表中的字段

8

HLEN key

獲取哈希表中字段的數量

9

HMGET key field1 [field2]

獲取全部給定字段的值

10

HMSET key field1 value1 [field2 value2 ]

同時將多個 field-value (域-值)對設置到哈希表 key 中。

11

HSET key field value

將哈希表 key 中的字段 field 的值設爲 value 。

12

HSETNX key field value

只有在字段 field 不存在時,設置哈希表字段的值。

13

HVALS key

獲取哈希表中全部值

14

HSCAN key cursor [MATCH pattern] [COUNT count]

迭代哈希表中的鍵值對。

命令詳解

hmset

添加/建立一個map類型的數據

127.0.0.1:6379> hmset person:zln name zln age 26

OK

 

其中 person:zln 是key。關於Map類型的Key,通常會使用:或-鏈接表達含義

hget

獲取哈希對象中某個字段的值

127.0.0.1:6379> hget person:zln name

"zln"

 

hmget

獲取哈希對象中多個字段的值

127.0.0.1:6379> hmget person:zln name age

1) "zln"

2) "26"

 

hgetall

獲取哈希對象所有字段的值-包括字段名

127.0.0.1:6379> hgetall person:zln

1) "name"

2) "zln"

3) "age"

4) "26"

1三、如何操做List類型的數據

命令列表

序號

命令及描述

1

BLPOP key1 [key2 ] timeout

移出並獲取列表的第一個元素, 若是列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。

2

BRPOP key1 [key2 ] timeout

移出並獲取列表的最後一個元素, 若是列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。

3

BRPOPLPUSH source destination timeout

從列表中彈出一個值,將彈出的元素插入到另一個列表中並返回它; 若是列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。

4

LINDEX key index

經過索引獲取列表中的元素

5

LINSERT key BEFORE|AFTER pivot value

在列表的元素前或者後插入元素

6

LLEN key

獲取列表長度

7

LPOP key

移出並獲取列表的第一個元素

8

LPUSH key value1 [value2]

將一個或多個值插入到列表頭部

9

LPUSHX key value

將一個或多個值插入到已存在的列表頭部

10

LRANGE key start stop

獲取列表指定範圍內的元素

11

LREM key count value

移除列表元素

12

LSET key index value

經過索引設置列表元素的值

13

LTRIM key start stop

對一個列表進行修剪(trim),就是說,讓列表只保留指定區間內的元素,不在指定區間以內的元素都將被刪除。

14

RPOP key

移除並獲取列表最後一個元素

15

RPOPLPUSH source destination

移除列表的最後一個元素,並將該元素添加到另外一個列表並返回

16

RPUSH key value1 [value2]

在列表中添加一個或多個值

17

RPUSHX key value

爲已存在的列表添加值

命令詳解

lpush

往列表的左側添加數據

127.0.0.1:6379> lpush list1 lv1

(integer) 1

能夠一次添加多個數據

lpush listKey v1 v2 v3 ...

 

若是列表不存在,會自動建立

rpush

往列表的右側添加數據

127.0.0.1:6379> rpush list1 lv3

(integer) 3

 

能夠一次添加多個數據

rpush listKey v1 v2 v3 ...

lrange

返回列表索引範圍內的子集

127.0.0.1:6379> lrange  list1 0 -1

1) "lv2"

2) "lv1"

3) "lv3"

 

-1表示倒數第一個數據

rpop

返回最右側的元素,並將此元素從列表中刪除

127.0.0.1:6379> lrange  list1 0 -1

1) "lv2"

2) "lv1"

3) "lv3"

127.0.0.1:6379> rpop list1

"lv3"

127.0.0.1:6379> lrange  list1 0 -1

1) "lv2"

2) "lv1"

 

 

當彈出最後一個元素後,列表也就不存在了

lpop

返回最左側的元素,並將次元素從列表中刪除

127.0.0.1:6379> lrange  list1 0 -1

1) "lv2"

2) "lv1"

127.0.0.1:6379> lpop list1

"lv2"

127.0.0.1:6379> lpop list1

"lv1"

 

ltrim

截取指定範圍內的列表

127.0.0.1:6379> ltrim list1 4 5

OK

 

典型應用場景

一、記錄社交網絡中用戶最近提交的更新

二、設計生產者消費者模式,好比生產者使用rpush,消費者使用lpop。不過我以爲,消費者通常使用blpop key timeout比較好,當獲取不到數據的時候,等待直到超時。

 

1四、如何操做Set類型的數據

命令列表

序號

命令及描述

1

SADD key member1 [member2]

向集合添加一個或多個成員

2

SCARD key

獲取集合的成員數

3

SDIFF key1 [key2]

返回給定全部集合的差集

4

SDIFFSTORE destination key1 [key2]

返回給定全部集合的差集並存儲在 destination 中

5

SINTER key1 [key2]

返回給定全部集合的交集

6

SINTERSTORE destination key1 [key2]

返回給定全部集合的交集並存儲在 destination 中

7

SISMEMBER key member

判斷 member 元素是不是集合 key 的成員

8

SMEMBERS key

返回集合中的全部成員

9

SMOVE source destination member

將 member 元素從 source 集合移動到 destination 集合

10

SPOP key

移除並返回集合中的一個隨機元素

11

SRANDMEMBER key [count]

返回集合中一個或多個隨機數

12

SREM key member1 [member2]

移除集合中一個或多個成員

13

SUNION key1 [key2]

返回全部給定集合的並集

14

SUNIONSTORE destination key1 [key2]

全部給定集合的並集存儲在 destination 集合中

15

SSCAN key cursor [MATCH pattern] [COUNT count]

迭代集合中的元素

命令詳解

sadd

元素添加

127.0.0.1:6379> sadd sk 1

(integer) 1

smembers

查看當前Set的所有元素

127.0.0.1:6379> smembers sk

1) "1"

 

sismenber

測試某個元素是否真實存在

127.0.0.1:6379> sismember sk 1

(integer) 1

127.0.0.1:6379> sismember sk 2

(integer) 0

 

其它

其它命令注意是用來進行集合間操做的,詳見上面的命令列表

1五、如何操做有序集合類型的數據

命令列表

序號

命令及描述

1

ZADD key score1 member1 [score2 member2]

向有序集合添加一個或多個成員,或者更新已存在成員的分數

2

ZCARD key

獲取有序集合的成員數

3

ZCOUNT key min max

計算在有序集合中指定區間分數的成員數

4

ZINCRBY key increment member

有序集合中對指定成員的分數加上增量 increment

5

ZINTERSTORE destination numkeys key [key ...]

計算給定的一個或多個有序集的交集並將結果集存儲在新的有序集合 key 中

6

ZLEXCOUNT key min max

在有序集合中計算指定字典區間內成員數量

7

ZRANGE key start stop [WITHSCORES]

經過索引區間返回有序集合成指定區間內的成員

8

ZRANGEBYLEX key min max [LIMIT offset count]

經過字典區間返回有序集合的成員

9

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT]

經過分數返回有序集合指定區間內的成員

10

ZRANK key member

返回有序集合中指定成員的索引

11

ZREM key member [member ...]

移除有序集合中的一個或多個成員

12

ZREMRANGEBYLEX key min max

移除有序集合中給定的字典區間的全部成員

13

ZREMRANGEBYRANK key start stop

移除有序集合中給定的排名區間的全部成員

14

ZREMRANGEBYSCORE key min max

移除有序集合中給定的分數區間的全部成員

15

ZREVRANGE key start stop [WITHSCORES]

返回有序集中指定區間內的成員,經過索引,分數從高到底

16

ZREVRANGEBYSCORE key max min [WITHSCORES]

返回有序集中指定分數區間內的成員,分數從高到低排序

17

ZREVRANK key member

返回有序集合中指定成員的排名,有序集成員按分數值遞減(從大到小)排序

18

ZSCORE key member

返回有序集中,成員的分數值

19

ZUNIONSTORE destination numkeys key [key ...]

計算給定的一個或多個有序集的並集,並存儲在新的 key 中

20

ZSCAN key cursor [MATCH pattern] [COUNT count]

迭代有序集合中的元素(包括元素成員和元素分值)

 

1六、什麼是HyperLogLog?

Redis 在 2.8.9 版本添加了 HyperLogLog 結構。

Redis HyperLogLog 是用來作基數統計的算法,HyperLogLog 的優勢是,在輸入元素的數量或者體積很是很是大時,計算基數所需的空間老是固定的、而且是很小的。

在 Redis 裏面,每一個 HyperLogLog 鍵只須要花費 12 KB 內存,就能夠計算接近 2^64 個不一樣元素的基 數。這和計算基數時,元素越多耗費內存就越多的集合造成鮮明對比。

可是,由於 HyperLogLog 只會根據輸入元素來計算基數,而不會儲存輸入元素自己,因此 HyperLogLog 不能像集合那樣,返回輸入的各個元素。

 

什麼是基數?

好比數據集 {1, 3, 5, 7, 5, 7, 8}, 那麼這個數據集的基數集爲 {1, 3, 5 ,7, 8}, 基數(不重複元素)爲5。 基數估計就是在偏差可接受的範圍內,快速計算基數。

 

實例

如下實例演示了 HyperLogLog 的工做過程:

redis 127.0.0.1:6379> PFADD runoobkey "redis"

 

1) (integer) 1

 

redis 127.0.0.1:6379> PFADD runoobkey "mongodb"

 

1) (integer) 1

 

redis 127.0.0.1:6379> PFADD runoobkey "mysql"

 

1) (integer) 1

 

redis 127.0.0.1:6379> PFCOUNT runoobkey

 

(integer) 3

 

Redis HyperLogLog 命令

下表列出了 redis HyperLogLog 的基本命令:

序號

命令及描述

1

PFADD key element [element ...]

添加指定元素到 HyperLogLog 中。

2

PFCOUNT key [key ...]

返回給定 HyperLogLog 的基數估算值。

3

PFMERGE destkey sourcekey [sourcekey ...]

將多個 HyperLogLog 合併爲一個 HyperLogLog

1七、Redis如何發佈/訂閱消息?

Redis 發佈訂閱(pub/sub)是一種消息通訊模式:發送者(pub)發送消息,訂閱者(sub)接收消息。

Redis 客戶端能夠訂閱任意數量的頻道。

下圖展現了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關係:

 

當有新消息經過 PUBLISH 命令發送給頻道 channel1 時, 這個消息就會被髮送給訂閱它的三個客戶端:

 

 

如下實例演示了發佈訂閱是如何工做的。在咱們實例中咱們建立了訂閱頻道名爲 redisChat:

redis 127.0.0.1:6379> SUBSCRIBE redisChat

 

Reading messages... (press Ctrl-C to quit)

1) "subscribe"

2) "redisChat"

3) (integer) 1

 

 

如今,咱們先從新開啓個 redis 客戶端,而後在同一個頻道 redisChat 發佈兩次消息,訂閱者就能接收到消息。

redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"

 

(integer) 1

 

redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com"

 

(integer) 1

 

# 訂閱者的客戶端會顯示以下消息

1) "message"

2) "redisChat"

3) "Redis is a great caching technique"

1) "message"

2) "redisChat"

3) "Learn redis by runoob.com"

 

 

序號

命令及描述

1

PSUBSCRIBE pattern [pattern ...]

訂閱一個或多個符合給定模式的頻道。

2

PUBSUB subcommand [argument [argument ...]]

查看訂閱與發佈系統狀態。

3

PUBLISH channel message

將信息發送到指定的頻道。

4

PUNSUBSCRIBE [pattern [pattern ...]]

退訂全部給定模式的頻道。

5

SUBSCRIBE channel [channel ...]

訂閱給定的一個或多個頻道的信息。

6

UNSUBSCRIBE [channel [channel ...]]

指退訂給定的頻道。

 

1八、Redis如何進行事務操做?

Redis 事務能夠一次執行多個命令, 而且帶有如下兩個重要的保證:

      事務是一個單獨的隔離操做:事務中的全部命令都會序列化、按順序地執行。事務在執行的過程當中,不會被其餘客戶端發送來的命令請求所打斷。

      事務是一個原子操做:事務中的命令要麼所有被執行,要麼所有都不執行。

一個事務從開始到執行會經歷如下三個階段:

           開始事務。

           命令入隊。

           執行事務。

 

如下是一個事務的例子, 它先以 MULTI 開始一個事務, 而後將多個命令入隊到事務中, 最後由 EXEC 命令觸發事務, 一併執行事務中的全部命令:

redis 127.0.0.1:6379> MULTI

OK

 

redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"

QUEUED

 

redis 127.0.0.1:6379> GET book-name

QUEUED

 

redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"

QUEUED

 

redis 127.0.0.1:6379> SMEMBERS tag

QUEUED

 

redis 127.0.0.1:6379> EXEC

1) OK

2) "Mastering C++ in 21 days"

3) (integer) 3

4) 1) "Mastering Series"

   2) "C++"

   3) "Programming"

 

 

 

序號

命令及描述

1

DISCARD

取消事務,放棄執行事務塊內的全部命令。

2

EXEC

執行全部事務塊內的命令。

3

MULTI

標記一個事務塊的開始。

4

UNWATCH

取消 WATCH 命令對全部 key 的監視。

5

WATCH key [key ...]

監視一個(或多個) key ,若是在事務執行以前這個(或這些) key 被其餘命令所改動,那麼事務將被打斷。

1九、Redis如何執行腳本?

Redis 腳本使用 Lua 解釋器來執行腳本。 Reids 2.6 版本經過內嵌支持 Lua 環境。執行腳本的經常使用命令爲 EVAL。

語法

Eval 命令的基本語法以下:

redis 127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]

實例

如下實例演示了 redis 腳本工做過程:

redis 127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second

 

1) "key1"

2) "key2"

3) "first"

4) "second"

 

Redis 腳本命令

下表列出了 redis 腳本經常使用命令:

序號

命令及描述

1

EVAL script numkeys key [key ...] arg [arg ...]

執行 Lua 腳本。

2

EVALSHA sha1 numkeys key [key ...] arg [arg ...]

執行 Lua 腳本。

3

SCRIPT EXISTS script [script ...]

查看指定的腳本是否已經被保存在緩存當中。

4

SCRIPT FLUSH

從腳本緩存中移除全部腳本。

5

SCRIPT KILL

殺死當前正在運行的 Lua 腳本。

6

SCRIPT LOAD script

將腳本 script 添加到腳本緩存中,但並不當即執行這個腳本。

20、如何切換數據庫?

SELECT index

2一、Redis服務端有哪些操做?

序號

命令及描述

1

BGREWRITEAOF

異步執行一個 AOF(AppendOnly File) 文件重寫操做

2

BGSAVE

在後臺異步保存當前數據庫的數據到磁盤

3

CLIENT KILL [ip:port] [ID client-id]

關閉客戶端鏈接

4

CLIENT LIST

獲取鏈接到服務器的客戶端鏈接列表

5

CLIENT GETNAME

獲取鏈接的名稱

6

CLIENT PAUSE timeout

在指定時間內終止運行來自客戶端的命令

7

CLIENT SETNAME connection-name

設置當前鏈接的名稱

8

CLUSTER SLOTS

獲取集羣節點的映射數組

9

COMMAND

獲取 Redis 命令詳情數組

10

COMMAND COUNT

獲取 Redis 命令總數

11

COMMAND GETKEYS

獲取給定命令的全部鍵

12

TIME

返回當前服務器時間

13

COMMAND INFO command-name [command-name ...]

獲取指定 Redis 命令描述的數組

14

CONFIG GET parameter

獲取指定配置參數的值

15

CONFIG REWRITE

對啓動 Redis 服務器時所指定的 redis.conf 配置文件進行改寫

16

CONFIG SET parameter value

修改 redis 配置參數,無需重啓

17

CONFIG RESETSTAT

重置 INFO 命令中的某些統計數據

18

DBSIZE

返回當前數據庫的 key 的數量

19

DEBUG OBJECT key

獲取 key 的調試信息

20

DEBUG SEGFAULT

讓 Redis 服務崩潰

21

FLUSHALL

刪除全部數據庫的全部key

22

FLUSHDB

刪除當前數據庫的全部key

23

INFO [section]

獲取 Redis 服務器的各類信息和統計數值

24

LASTSAVE

返回最近一次 Redis 成功將數據保存到磁盤上的時間,以 UNIX 時間戳格式表示

25

MONITOR

實時打印出 Redis 服務器接收到的命令,調試用

26

ROLE

返回主從實例所屬的角色

27

SAVE

異步保存數據到硬盤

28

SHUTDOWN [NOSAVE] [SAVE]

異步保存數據到硬盤,並關閉服務器

29

SLAVEOF host port

將當前服務器轉變爲指定服務器的從屬服務器(slave server)

30

SLOWLOG subcommand [argument]

管理 redis 的慢日誌

31

SYNC

用於複製功能(replication)的內部命令

2二、如何進行數據的備份與恢復?

Redis SAVE 命令用於建立當前數據庫的備份。

語法

redis Save 命令基本語法以下:

redis 127.0.0.1:6379> SAVE

實例

redis 127.0.0.1:6379> SAVE

OK

該命令將在 redis 安裝目錄中建立dump.rdb文件。

 

恢復數據

若是須要恢復數據,只需將備份文件 (dump.rdb) 移動到 redis 安裝目錄並啓動服務便可。獲取 redis 目錄可使用 CONFIG 命令,以下所示:

 

redis 127.0.0.1:6379> CONFIG GET dir

1) "dir"

2) "/usr/local/redis/bin"

以上命令 CONFIG GET dir 輸出的 redis 安裝目錄爲 /usr/local/redis/bin。

 

Bgsave

建立 redis 備份文件也可使用命令 BGSAVE,該命令在後臺執行。

實例

127.0.0.1:6379> BGSAVE

 

Background saving started

 

2三、如何設置密碼?

咱們能夠經過 redis 的配置文件設置密碼參數,這樣客戶端鏈接到 redis 服務就須要密碼驗證,這樣可讓你的 redis 服務更安全。

實例

咱們能夠經過如下命令查看是否設置了密碼驗證:

127.0.0.1:6379> CONFIG get requirepass

1) "requirepass"

2) ""

默認狀況下 requirepass 參數是空的,這就意味着你無需經過密碼驗證就能夠鏈接到 redis 服務。

你能夠經過如下命令來修改該參數:

127.0.0.1:6379> CONFIG set requirepass "runoob"

OK

127.0.0.1:6379> CONFIG get requirepass

1) "requirepass"

2) "runoob"

設置密碼後,客戶端鏈接 redis 服務就須要密碼驗證,不然沒法執行命令。

語法

AUTH 命令基本語法格式以下:

127.0.0.1:6379> AUTH password

實例

127.0.0.1:6379> AUTH "runoob"

OK

127.0.0.1:6379> SET mykey "Test value"

OK

127.0.0.1:6379> GET mykey

"Test value"

 

2四、Redis如何進行性能測試?

Redis 性能測試是經過同時執行多個命令實現的。

語法

redis 性能測試的基本命令以下:

redis-benchmark [option] [option value]

實例

如下實例同時執行 10000 個請求來檢測性能:

redis-benchmark -n 10000

 

PING_INLINE: 141043.72 requests per second

PING_BULK: 142857.14 requests per second

SET: 141442.72 requests per second

GET: 145348.83 requests per second

INCR: 137362.64 requests per second

LPUSH: 145348.83 requests per second

LPOP: 146198.83 requests per second

SADD: 146198.83 requests per second

SPOP: 149253.73 requests per second

LPUSH (needed to benchmark LRANGE): 148588.42 requests per second

LRANGE_100 (first 100 elements): 58411.21 requests per second

LRANGE_300 (first 300 elements): 21195.42 requests per second

LRANGE_500 (first 450 elements): 14539.11 requests per second

LRANGE_600 (first 600 elements): 10504.20 requests per second

MSET (10 keys): 93283.58 requests per second

redis 性能測試工具可選參數以下所示:

序號

選項

描述

默認值

1

-h

指定服務器主機名

127.0.0.1

2

-p

指定服務器端口

6379

3

-s

指定服務器 socket

 

4

-c

指定併發鏈接數

50

5

-n

指定請求數

10000

6

-d

以字節的形式指定 SET/GET 值的數據大小

2

7

-k

1=keep alive 0=reconnect

1

8

-r

SET/GET/INCR 使用隨機 key, SADD 使用隨機值

 

9

-P

經過管道傳輸 <numreq> 請求

1

10

-q

強制退出 redis。僅顯示 query/sec 值

 

11

--csv

以 CSV 格式輸出

 

12

-l

生成循環,永久執行測試

 

13

-t

僅運行以逗號分隔的測試命令列表。

 

14

-I

Idle 模式。僅打開 N 個 idle 鏈接並等待。

 

實例

如下實例咱們使用了多個參數來測試 redis 性能:

redis-benchmark -h 127.0.0.1 -p 6379 -t set,lpush -n 10000 -q

 

SET: 146198.83 requests per second

LPUSH: 145560.41 requests per second

以上實例中主機爲 127.0.0.1,端口號爲 6379,執行的命令爲 set,lpush,請求數爲 10000,經過 -q 參數讓結果只顯示每秒執行的請求數。

 

2五、客戶端鏈接相關的操做

Redis 經過監聽一個 TCP 端口或者 Unix socket 的方式來接收來自客戶端的鏈接,當一個鏈接創建後,Redis 內部會進行如下一些操做:

32                  首先,客戶端 socket 會被設置爲非阻塞模式,由於 Redis 在網絡事件處理上採用的是非阻塞多路複用模型。

33                  而後爲這個 socket 設置 TCP_NODELAY 屬性,禁用 Nagle 算法

34                  而後建立一個可讀的文件事件用於監聽這個客戶端 socket 的數據發送

 

最大鏈接數

在 Redis2.4 中,最大鏈接數是被直接硬編碼在代碼裏面的,而在2.6版本中這個值變成可配置的。

maxclients 的默認值是 10000,你也能夠在 redis.conf 中對這個值進行修改。

config get maxclients

 

1) "maxclients"

2) "10000"

實例

如下實例咱們在服務啓動時設置最大鏈接數爲 100000:

redis-server --maxclients 100000

 

客戶端命令

S.N.

命令

描述

1

CLIENT LIST

返回鏈接到 redis 服務的客戶端列表

2

CLIENT SETNAME

設置當前鏈接的名稱

3

CLIENT GETNAME

獲取經過 CLIENT SETNAME 命令設置的服務名稱

4

CLIENT PAUSE

掛起客戶端鏈接,指定掛起的時間以毫秒計

5

CLIENT KILL

關閉客戶端鏈接

 

2六、管道技術

Redis是一種基於客戶端-服務端模型以及請求/響應協議的TCP服務。這意味着一般狀況下一個請求會遵循如下步驟:

35                  客戶端向服務端發送一個查詢請求,並監聽Socket返回,一般是以阻塞模式,等待服務端響應。

36                  服務端處理命令,並將結果返回給客戶端。

 

Redis 管道技術

Redis 管道技術能夠在服務端未響應時,客戶端能夠繼續向服務端發送請求,並最終一次性讀取全部服務端的響應。

實例

查看 redis 管道,只須要啓動 redis 實例並輸入如下命令:

$(echo -en "PING\r\n SET runoobkey redis\r\nGET runoobkey\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n"; sleep 10) | nc localhost 6379

 

+PONG

+OK

redis

:1

:2

:3

以上實例中咱們經過使用 PING 命令查看redis服務是否可用, 以後咱們們設置了 runoobkey 的值爲 redis,而後咱們獲取 runoobkey 的值並使得 visitor 自增 3 次。

在返回的結果中咱們能夠看到這些命令一次性向 redis 服務提交,並最終一次性讀取全部服務端的響應

 

管道技術的優點

管道技術最顯著的優點是提升了 redis 服務的性能。

一些測試數據

在下面的測試中,咱們將使用Redis的Ruby客戶端,支持管道技術特性,測試管道技術對速度的提高效果。

require 'rubygems'

require 'redis'

def bench(descr)

start = Time.now

yield

puts "#{descr} #{Time.now-start} seconds"

end

def without_pipelining

r = Redis.new

10000.times {

   r.ping

}

end

def with_pipelining

r = Redis.new

r.pipelined {

   10000.times {

      r.ping

   }

}

end

bench("without pipelining") {

   without_pipelining

}

bench("with pipelining") {

   with_pipelining

}

從處於局域網中的Mac OS X系統上執行上面這個簡單腳本的數據代表,開啓了管道操做後,往返時延已經被改善得至關低了。

without pipelining 1.185238 seconds

with pipelining 0.250783 seconds

如你所見,開啓管道後,咱們的速度效率提高了5倍。

 

2七、Redis分區

分區是分割數據到多個Redis實例的處理過程,所以每一個實例只保存key的一個子集。

分區的優點

      經過利用多臺計算機內存的和值,容許咱們構造更大的數據庫。

      經過多核和多臺計算機,容許咱們擴展計算能力;經過多臺計算機和網絡適配器,容許咱們擴展網絡帶寬。

分區的不足

redis的一些特性在分區方面表現的不是很好:

      涉及多個key的操做一般是不被支持的。舉例來講,當兩個set映射到不一樣的redis實例上時,你就不能對這兩個set執行交集操做。

      涉及多個key的redis事務不能使用。

      當使用分區時,數據處理較爲複雜,好比你須要處理多個rdb/aof文件,而且從多個實例和主機備份持久化文件。

      增長或刪除容量也比較複雜。redis集羣大多數支持在運行時增長、刪除節點的透明數據平衡的能力,可是相似於客戶端分區、代理等其餘系統則不支持這項特性。然而,一種叫作presharding的技術對此是有幫助的。

 

分區類型

Redis 有兩種類型分區。 假設有4個Redis實例 R0,R1,R2,R3,和相似user:1,user:2這樣的表示用戶的多個key,對既定的key有多種不一樣方式來選擇這個key存放在哪一個實例中。也就是說,有不一樣的系統來映射某個key到某個Redis服務。

範圍分區

最簡單的分區方式是按範圍分區,就是映射必定範圍的對象到特定的Redis實例。

好比,ID從0到10000的用戶會保存到實例R0,ID從10001到 20000的用戶會保存到R1,以此類推。

這種方式是可行的,而且在實際中使用,不足就是要有一個區間範圍到實例的映射表。這個表要被管理,同時還須要各 種對象的映射表,一般對Redis來講並不是是好的方法。

哈希分區

另一種分區方法是hash分區。這對任何key都適用,也無需是object_name:這種形式,像下面描述的同樣簡單:

      用一個hash函數將key轉換爲一個數字,好比使用crc32 hash函數。對key foobar執行crc32(foobar)會輸出相似93024922的整數。

           對這個整數取模,將其轉化爲0-3之間的數字,就能夠將這個整數映射到4個Redis實例中的一個了。93024922 % 4 = 2,就是說key foobar應該被存到R2實例中。注意:取模操做是取除的餘數,一般在多種編程語言中用%操做符實現。

 

2八、使用Java操做Redis

開始在 Java 中使用 Redis 前, 咱們須要確保已經安裝了 redis 服務及 Java redis 驅動,且你的機器上能正常使用 Java。 Java的安裝配置能夠參考咱們的 Java開發環境配置 接下來讓咱們安裝 Java redis 驅動:

      首先你須要下載驅動包,下載 jedis.jar,確保下載最新驅動包。

      在你的classpath中包含該驅動包。

 

鏈接到 redis 服務

import redis.clients.jedis.Jedis;

public class RedisJava {

   public static void main(String[] args) {

      //鏈接本地的 Redis 服務

      Jedis jedis = new Jedis("localhost");

      System.out.println("Connection to server sucessfully");

      //查看服務是否運行

      System.out.println("Server is running: "+jedis.ping());

 }

}

編譯以上 Java 程序,確保驅動包的路徑是正確的。

$javac RedisJava.java

$java RedisJava

Connection to server sucessfully

Server is running: PONG

 

Redis Java String Example

 

Redis Java String(字符串) 實例

import redis.clients.jedis.Jedis;

public class RedisStringJava {

   public static void main(String[] args) {

      //鏈接本地的 Redis 服務

      Jedis jedis = new Jedis("localhost");

      System.out.println("Connection to server sucessfully");

      //設置 redis 字符串數據

      jedis.set("runoobkey", "Redis tutorial");

     // 獲取存儲的數據並輸出

     System.out.println("Stored string in redis:: "+ jedis.get("runoobkey"));

 }

}

編譯以上程序。

$javac RedisStringJava.java

$java RedisStringJava

Connection to server sucessfully

Stored string in redis:: Redis tutorial

 

Redis Java List(列表) 實例

import redis.clients.jedis.Jedis;

public class RedisListJava {

   public static void main(String[] args) {

      //鏈接本地的 Redis 服務

      Jedis jedis = new Jedis("localhost");

      System.out.println("Connection to server sucessfully");

      //存儲數據到列表中

      jedis.lpush("tutorial-list", "Redis");

      jedis.lpush("tutorial-list", "Mongodb");

      jedis.lpush("tutorial-list", "Mysql");

     // 獲取存儲的數據並輸出

     List<String> list = jedis.lrange("tutorial-list", 0 ,5);

     for(int i=0; i<list.size(); i++) {

       System.out.println("Stored string in redis:: "+list.get(i));

     }

 }

}

編譯以上程序。

$javac RedisListJava.java

$java RedisListJava

Connection to server sucessfully

Stored string in redis:: Redis

Stored string in redis:: Mongodb

Stored string in redis:: Mysql

 

Redis Java Keys 實例

import redis.clients.jedis.Jedis;

public class RedisKeyJava {

   public static void main(String[] args) {

      //鏈接本地的 Redis 服務

      Jedis jedis = new Jedis("localhost");

      System.out.println("Connection to server sucessfully");

     

     // 獲取數據並輸出

     List<String> list = jedis.keys("*");

     for(int i=0; i<list.size(); i++) {

       System.out.println("List of stored keys:: "+list.get(i));

     }

   }

}

編譯以上程序。

$javac RedisKeyJava.java

$java RedisKeyJava

Connection to server sucessfully

List of stored keys:: tutorial-name

List of stored keys:: tutorial-list

 

 

2九、如何使用Redis做爲LRU緩存?

配置緩存大大小

在redis.conf 中 maxmemory 100mb

默認狀況下,64位操做系統爲0,即沒有限制,32位操做系統使用3G做爲隱含的內存大小限制

 

當內存到達指定大小後,須要選擇不一樣的行爲--->策略

由  maxmemory-policy  參數配置

 

如下策略可用:

 

noeviction:當到達內存限制時返回錯誤。當客戶端嘗試執行命令時會致使更多內存佔用(大多數寫命令,除了 DEL 和一些例外)。

allkeys-lru:回收最近最少使用(LRU)的鍵,爲新數據騰出空間。

volatile-lru:回收最近最少使用(LRU)的鍵,可是隻回收有設置過時的鍵,爲新數據騰出空間。

allkeys-random:回收隨機的鍵,爲新數據騰出空間。

volatile-random:回收隨機的鍵,可是隻回收有設置過時的鍵,爲新數據騰出空間。

volatile-ttl:回收有設置過時的鍵,嘗試先回收離 TTL 最短期的鍵,爲新數據騰出空間。

當沒有知足前提條件的話,volatile-lru,volatile-random 和 volatile-ttl 策略就表現得和 noeviction 同樣了。

 

127.0.0.1:6379> config get maxmemory-samples

1) "maxmemory-samples"

2) "5"

 

配置Redis 的 LRU算法的精度,1~10

30、什麼是Redis的分片?

Redis的分片技術,容許在分佈式環境中,一個鍵的全部值分佈在不一樣的機器上。

分片技術突破了Redis可以承受的數據量,不然數據量受限於單機內存大小

計算能力也大大提高

相關文章
相關標籤/搜索