@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
設置配置信息
一、去修改配置文件
二、經過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槽從新分配章節)。
// 鏈接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);
}
}
}
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 }, false, true);
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是數據庫,不是簡單的緩存
見上
默認狀況下安裝完畢後,在/usr/local/bin/目錄下和安裝目錄的src目錄下,會產生幾個命令文件,分別是
redis-server:Redis的服務器操做命令,用於Redis服務器的啓停
redis-cli:Redis的客戶端命令,用於鏈接Redis服務器,並進行各項操做
redis-benchmark:Redis的性能測試工具
redis-check-aof:檢查aof日誌的工具
redis-check-dump:檢查rdb日誌的工具
使用redis-server命令,指定一個redis.conf配置文件進行啓動便可
如:redis-server redis.conf
使用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"
序號 |
命令及描述 |
1 |
該命令用於在 key 存在時刪除 key。 |
2 |
序列化給定 key ,並返回被序列化的值。 |
3 |
檢查給定 key 是否存在。 |
4 |
EXPIRE key seconds 爲給定 key 設置過時時間。 |
5 |
EXPIREAT 的做用和 EXPIRE 相似,都用於爲 key 設置過時時間。 不一樣在於 EXPIREAT 命令接受的時間參數是 UNIX 時間戳(unix timestamp)。 |
6 |
設置 key 的過時時間以毫秒計。 |
7 |
PEXPIREAT key milliseconds-timestamp 設置 key 過時時間的時間戳(unix timestamp) 以毫秒計 |
8 |
查找全部符合給定模式( pattern)的 key 。 |
9 |
將當前數據庫的 key 移動到給定的數據庫 db 當中。 |
10 |
移除 key 的過時時間,key 將持久保持。 |
11 |
以毫秒爲單位返回 key 的剩餘的過時時間。 |
12 |
以秒爲單位,返回給定 key 的剩餘生存時間(TTL, time to live)。 |
13 |
從當前數據庫中隨機返回一個 key 。 |
14 |
修改 key 的名稱 |
15 |
僅當 newkey 不存在時,將 key 更名爲 newkey 。 |
16 |
返回 key 所儲存的值的類型。 |
檢查執行的key是否存在
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> exists k5
(integer) 0
刪除指定的key
127.0.0.1:6379> del name
(integer) 1
返回值爲刪除的鍵的個數。若是被刪除的鍵自己就不存在,就返回0
查詢鍵的類型
127.0.0.1:6379> type k1
string
設置鍵的生存時間。單位是秒
超過咱們的設置時間後,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)
設置鍵的生存時間。單位是毫秒
超過咱們的設置時間後,key會失效,等同於執行了del操做
移除key的過時時間設置。至關於此key會永久保持
127.0.0.1:6379> persist mk
(integer) 1
key的剩餘生存時間,單位是秒
127.0.0.1:6379> ttl k4
(integer) 3498
key的剩餘生存時間,單位是毫秒
127.0.0.1:6379> pttl k4
(integer) 3558506
有兩種方法
一、找到對應的進程號,直接kill
二、使用redis-cli登錄後,執行shutdown命令
默認狀況下啓動的redis-server,並非後臺運行的
修改redis.conf文件的 daemonize yes
有兩種方式
一、直接修改redis.conf 文件
二、使用CONFIG命令
CONFIG GET * ;獲取當前設置的所有參數
CONFIG GET KEY ;獲取指定key設置的值
CONFIG SET KEY VALUE ;設置某個參數
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 |
設置指定 key 的值 |
2 |
獲取指定 key 的值。 |
3 |
返回 key 中字符串值的子字符 |
4 |
將給定 key 的值設爲 value ,並返回 key 的舊值(old value)。 |
5 |
對 key 所儲存的字符串值,獲取指定偏移量上的位(bit)。 |
6 |
獲取全部(一個或多個)給定 key 的值。 |
7 |
對 key 所儲存的字符串值,設置或清除指定偏移量上的位(bit)。 |
8 |
將值 value 關聯到 key ,並將 key 的過時時間設爲 seconds (以秒爲單位)。 |
9 |
只有在 key 不存在時設置 key 的值。 |
10 |
用 value 參數覆寫給定 key 所儲存的字符串值,從偏移量 offset 開始。 |
11 |
返回 key 所儲存的字符串值的長度。 |
12 |
MSET key value [key value ...] 同時設置一個或多個 key-value 對。 |
13 |
MSETNX key value [key value ...] 同時設置一個或多個 key-value 對,當且僅當全部給定 key 都不存在。 |
14 |
這個命令和 SETEX 命令類似,但它以毫秒爲單位設置 key 的生存時間,而不是像 SETEX 命令那樣,以秒爲單位。 |
15 |
將 key 中儲存的數字值增一。 |
16 |
將 key 所儲存的值加上給定的增量值(increment) 。 |
17 |
將 key 所儲存的值加上給定的浮點增量值(increment) 。 |
18 |
將 key 中儲存的數字值減一。 |
19 |
key 所儲存的值減去給定的減量值(decrement) 。 |
20 |
若是 key 已經存在而且是一個字符串, APPEND 命令將 value 追加到 key 原來的值的末尾。 |
Redis中的字符串是二進制安全的
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 單位是秒
127.0.0.1:6379> get mk
"wahaha"
對於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中的序列的概念有點像
同時設置多個k-v
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
同時獲取多個key的value
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
設置一個值,同時返回原先的值
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"
序號 |
命令及描述 |
1 |
刪除一個或多個哈希表字段 |
2 |
查看哈希表 key 中,指定的字段是否存在。 |
3 |
獲取存儲在哈希表中指定字段的值。 |
4 |
獲取在哈希表中指定 key 的全部字段和值 |
5 |
爲哈希表 key 中的指定字段的整數值加上增量 increment 。 |
6 |
HINCRBYFLOAT key field increment 爲哈希表 key 中的指定字段的浮點數值加上增量 increment 。 |
7 |
獲取全部哈希表中的字段 |
8 |
獲取哈希表中字段的數量 |
9 |
獲取全部給定字段的值 |
10 |
HMSET key field1 value1 [field2 value2 ] 同時將多個 field-value (域-值)對設置到哈希表 key 中。 |
11 |
將哈希表 key 中的字段 field 的值設爲 value 。 |
12 |
只有在字段 field 不存在時,設置哈希表字段的值。 |
13 |
獲取哈希表中全部值 |
14 |
HSCAN key cursor [MATCH pattern] [COUNT count] 迭代哈希表中的鍵值對。 |
添加/建立一個map類型的數據
127.0.0.1:6379> hmset person:zln name zln age 26
OK
其中 person:zln 是key。關於Map類型的Key,通常會使用:或-鏈接表達含義
獲取哈希對象中某個字段的值
127.0.0.1:6379> hget person:zln name
"zln"
獲取哈希對象中多個字段的值
127.0.0.1:6379> hmget person:zln name age
1) "zln"
2) "26"
獲取哈希對象所有字段的值-包括字段名
127.0.0.1:6379> hgetall person:zln
1) "name"
2) "zln"
3) "age"
4) "26"
序號 |
命令及描述 |
1 |
移出並獲取列表的第一個元素, 若是列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。 |
2 |
移出並獲取列表的最後一個元素, 若是列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。 |
3 |
BRPOPLPUSH source destination timeout 從列表中彈出一個值,將彈出的元素插入到另一個列表中並返回它; 若是列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。 |
4 |
經過索引獲取列表中的元素 |
5 |
LINSERT key BEFORE|AFTER pivot value 在列表的元素前或者後插入元素 |
6 |
獲取列表長度 |
7 |
移出並獲取列表的第一個元素 |
8 |
將一個或多個值插入到列表頭部 |
9 |
將一個或多個值插入到已存在的列表頭部 |
10 |
獲取列表指定範圍內的元素 |
11 |
移除列表元素 |
12 |
經過索引設置列表元素的值 |
13 |
對一個列表進行修剪(trim),就是說,讓列表只保留指定區間內的元素,不在指定區間以內的元素都將被刪除。 |
14 |
移除並獲取列表最後一個元素 |
15 |
移除列表的最後一個元素,並將該元素添加到另外一個列表並返回 |
16 |
在列表中添加一個或多個值 |
17 |
爲已存在的列表添加值 |
往列表的左側添加數據
127.0.0.1:6379> lpush list1 lv1
(integer) 1
能夠一次添加多個數據
lpush listKey v1 v2 v3 ...
若是列表不存在,會自動建立
往列表的右側添加數據
127.0.0.1:6379> rpush list1 lv3
(integer) 3
能夠一次添加多個數據
rpush listKey v1 v2 v3 ...
返回列表索引範圍內的子集
127.0.0.1:6379> lrange list1 0 -1
1) "lv2"
2) "lv1"
3) "lv3"
-1表示倒數第一個數據
返回最右側的元素,並將此元素從列表中刪除
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"
當彈出最後一個元素後,列表也就不存在了
返回最左側的元素,並將次元素從列表中刪除
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"
截取指定範圍內的列表
127.0.0.1:6379> ltrim list1 4 5
OK
一、記錄社交網絡中用戶最近提交的更新
二、設計生產者消費者模式,好比生產者使用rpush,消費者使用lpop。不過我以爲,消費者通常使用blpop key timeout比較好,當獲取不到數據的時候,等待直到超時。
序號 |
命令及描述 |
1 |
向集合添加一個或多個成員 |
2 |
獲取集合的成員數 |
3 |
返回給定全部集合的差集 |
4 |
SDIFFSTORE destination key1 [key2] 返回給定全部集合的差集並存儲在 destination 中 |
5 |
返回給定全部集合的交集 |
6 |
SINTERSTORE destination key1 [key2] 返回給定全部集合的交集並存儲在 destination 中 |
7 |
判斷 member 元素是不是集合 key 的成員 |
8 |
返回集合中的全部成員 |
9 |
SMOVE source destination member 將 member 元素從 source 集合移動到 destination 集合 |
10 |
移除並返回集合中的一個隨機元素 |
11 |
返回集合中一個或多個隨機數 |
12 |
移除集合中一個或多個成員 |
13 |
返回全部給定集合的並集 |
14 |
SUNIONSTORE destination key1 [key2] 全部給定集合的並集存儲在 destination 集合中 |
15 |
SSCAN key cursor [MATCH pattern] [COUNT count] 迭代集合中的元素 |
元素添加
127.0.0.1:6379> sadd sk 1
(integer) 1
查看當前Set的所有元素
127.0.0.1:6379> smembers sk
1) "1"
測試某個元素是否真實存在
127.0.0.1:6379> sismember sk 1
(integer) 1
127.0.0.1:6379> sismember sk 2
(integer) 0
其它命令注意是用來進行集合間操做的,詳見上面的命令列表
序號 |
命令及描述 |
1 |
ZADD key score1 member1 [score2 member2] 向有序集合添加一個或多個成員,或者更新已存在成員的分數 |
2 |
獲取有序集合的成員數 |
3 |
計算在有序集合中指定區間分數的成員數 |
4 |
有序集合中對指定成員的分數加上增量 increment |
5 |
ZINTERSTORE destination numkeys key [key ...] 計算給定的一個或多個有序集的交集並將結果集存儲在新的有序集合 key 中 |
6 |
在有序集合中計算指定字典區間內成員數量 |
7 |
ZRANGE key start stop [WITHSCORES] 經過索引區間返回有序集合成指定區間內的成員 |
8 |
ZRANGEBYLEX key min max [LIMIT offset count] 經過字典區間返回有序集合的成員 |
9 |
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 經過分數返回有序集合指定區間內的成員 |
10 |
返回有序集合中指定成員的索引 |
11 |
移除有序集合中的一個或多個成員 |
12 |
移除有序集合中給定的字典區間的全部成員 |
13 |
ZREMRANGEBYRANK key start stop 移除有序集合中給定的排名區間的全部成員 |
14 |
移除有序集合中給定的分數區間的全部成員 |
15 |
ZREVRANGE key start stop [WITHSCORES] 返回有序集中指定區間內的成員,經過索引,分數從高到底 |
16 |
ZREVRANGEBYSCORE key max min [WITHSCORES] 返回有序集中指定分數區間內的成員,分數從高到低排序 |
17 |
返回有序集合中指定成員的排名,有序集成員按分數值遞減(從大到小)排序 |
18 |
返回有序集中,成員的分數值 |
19 |
ZUNIONSTORE destination numkeys key [key ...] 計算給定的一個或多個有序集的並集,並存儲在新的 key 中 |
20 |
ZSCAN key cursor [MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成員和元素分值) |
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 |
返回給定 HyperLogLog 的基數估算值。 |
3 |
PFMERGE destkey sourcekey [sourcekey ...] 將多個 HyperLogLog 合併爲一個 HyperLogLog |
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 |
將信息發送到指定的頻道。 |
4 |
PUNSUBSCRIBE [pattern [pattern ...]] 退訂全部給定模式的頻道。 |
5 |
SUBSCRIBE channel [channel ...] 訂閱給定的一個或多個頻道的信息。 |
6 |
UNSUBSCRIBE [channel [channel ...]] 指退訂給定的頻道。 |
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 |
取消事務,放棄執行事務塊內的全部命令。 |
2 |
執行全部事務塊內的命令。 |
3 |
標記一個事務塊的開始。 |
4 |
取消 WATCH 命令對全部 key 的監視。 |
5 |
監視一個(或多個) key ,若是在事務執行以前這個(或這些) key 被其餘命令所改動,那麼事務將被打斷。 |
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 |
從腳本緩存中移除全部腳本。 |
5 |
殺死當前正在運行的 Lua 腳本。 |
6 |
將腳本 script 添加到腳本緩存中,但並不當即執行這個腳本。 |
序號 |
命令及描述 |
1 |
異步執行一個 AOF(AppendOnly File) 文件重寫操做 |
2 |
在後臺異步保存當前數據庫的數據到磁盤 |
3 |
CLIENT KILL [ip:port] [ID client-id] 關閉客戶端鏈接 |
4 |
獲取鏈接到服務器的客戶端鏈接列表 |
5 |
獲取鏈接的名稱 |
6 |
在指定時間內終止運行來自客戶端的命令 |
7 |
CLIENT SETNAME connection-name 設置當前鏈接的名稱 |
8 |
獲取集羣節點的映射數組 |
9 |
獲取 Redis 命令詳情數組 |
10 |
獲取 Redis 命令總數 |
11 |
獲取給定命令的全部鍵 |
12 |
返回當前服務器時間 |
13 |
COMMAND INFO command-name [command-name ...] 獲取指定 Redis 命令描述的數組 |
14 |
獲取指定配置參數的值 |
15 |
對啓動 Redis 服務器時所指定的 redis.conf 配置文件進行改寫 |
16 |
修改 redis 配置參數,無需重啓 |
17 |
重置 INFO 命令中的某些統計數據 |
18 |
返回當前數據庫的 key 的數量 |
19 |
獲取 key 的調試信息 |
20 |
讓 Redis 服務崩潰 |
21 |
刪除全部數據庫的全部key |
22 |
刪除當前數據庫的全部key |
23 |
獲取 Redis 服務器的各類信息和統計數值 |
24 |
返回最近一次 Redis 成功將數據保存到磁盤上的時間,以 UNIX 時間戳格式表示 |
25 |
實時打印出 Redis 服務器接收到的命令,調試用 |
26 |
返回主從實例所屬的角色 |
27 |
異步保存數據到硬盤 |
28 |
異步保存數據到硬盤,並關閉服務器 |
29 |
將當前服務器轉變爲指定服務器的從屬服務器(slave server) |
30 |
管理 redis 的慢日誌 |
31 |
用於複製功能(replication)的內部命令 |
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
咱們能夠經過 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"
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 參數讓結果只顯示每秒執行的請求數。
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 |
關閉客戶端鏈接 |
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倍。
分區是分割數據到多個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實例中。注意:取模操做是取除的餘數,一般在多種編程語言中用%操做符實現。
開始在 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
配置緩存大大小
在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
Redis的分片技術,容許在分佈式環境中,一個鍵的全部值分佈在不一樣的機器上。
分片技術突破了Redis可以承受的數據量,不然數據量受限於單機內存大小
計算能力也大大提高