花了一週左右,全面的學習redis的知識,並記錄學習筆記php
原文請訪問個人技術博客番茄技術小棧java
Redis是一個使用ANSI C編寫的開源、支持網絡、基於內存、可選持久性的鍵值對存儲數據庫node
10w QPSpython
緣由mysql
$ wget http://download.redis.io/releases/redis-4.0.8.tar.gz
$ tar xzf redis-4.0.8.tar.gz
$ cd redis-4.0.8
$ make
複製代碼
命令名 | 命令說明 |
---|---|
redis-server | redis服務器 |
redis-cli | redis命令行客戶端 |
redis-benchmark | redis性能測試工具 |
redis-check-aof | aof文件修復工具 |
redis-check-dump | RDB文件檢查工具 |
redis-sentinel | sentinel服務器(2.8之後) |
redis-server
複製代碼
驗證linux
ps aux | grep redis
複製代碼
redis-cli -h 127.0.0.1 -p 6379 ping
複製代碼
redis-server configPath
複製代碼
redis-server --port 6380
複製代碼
三種啓動方式比較git
redis-cli -h 127.0.0.1 -p 6379
複製代碼
返回值 | 返回值說明 |
---|---|
狀態回覆 | ping -> pong |
錯誤回覆 | hget hello field -> (error) ERR wrong number of arguments for 'hget' command |
整數回覆 | incr hello -> (integer) 1 |
字符串回覆 | get hello -> "1" |
多行字符串回覆 | mget hello foo -> 1) "1" 2) (nil) |
配置名 | 說明 |
---|---|
daemonize | 是不是守護進程(no/yes) |
port | redis對外端口號 |
logfile | redis系統日誌 |
dir | redis工做目錄 |
配置方式github
vim redis-6382.conf
port 6382
daemonize yes
logfile "6382.log"
dir ./workdata/
複製代碼
redis-server redis-6382.conf
複製代碼
ps -aux | grep -v redis-server | grep 6382
複製代碼
vim workdata/6382.log
複製代碼
命令 | 說明 | 時間複雜度 |
---|---|---|
keys [pattern] | 遍歷全部key | O(N) |
dbsize | 遍歷全部key | O(1) |
exists | 檢查key是否存在 | O(1) |
del key | 刪除指定的key-value | O(1) |
expire key seconds | key在seconds秒後過時 | O(1) |
ttl key | 查看key剩餘的過時時間 | O(1) |
persist key | 去掉key的過時時間 | O(1) |
type key | 返回key的類型 | O(1) |
注意 keys命令通常再也不生產環境使用redis
** 演示**sql
➜ redis-4.0.8 redis-cli -h 127.0.0.1 -p 6382
127.0.0.1:6382> set hello word
OK
127.0.0.1:6382> set php good
OK
127.0.0.1:6382> set java best
OK
127.0.0.1:6382> keys *
1) "java"
2) "hello"
3) "php"
127.0.0.1:6382> dbsize
(integer) 3
127.0.0.1:6382> exists php
(integer) 1
127.0.0.1:6382> del php java
(integer) 2
127.0.0.1:6382> keys *
1) "hello"
127.0.0.1:6382> expire hello 20
(integer) 1
127.0.0.1:6382> ttl hello
(integer) 16
127.0.0.1:6382> ttl hello
(integer) 12
127.0.0.1:6382> persist hello
(integer) 1
127.0.0.1:6382> ttl hello
(integer) -1
127.0.0.1:6382> type hello
string
複製代碼
單線程在程序執行時,所走的程序路徑按照連續順序排下來,前面的必須處理好,後面的纔會執行。
key | value |
---|---|
hello | world |
counter | 1 |
bits | 101111101110 |
能夠是字符串(json);數字,以及二進制
命令 | 說明 | 時間複雜度 |
---|---|---|
get key | 獲取key對應的value | O(1) |
set key value | 設置key value | O(1) |
del key | 刪除key-value | O(1) |
incr | key自增1, 若是key不存在,自增後get(key) = 1 | O(1) |
decr | key自減1, 若是key不存在,自增後get(key) = -1 | O(1) |
incrby key k | key自增k, 若是key不存在,自增後get(key) = k | O(1) |
decr key k | key自減k, 若是key不存在,自增後get(key) = -k | O(1) |
set key value | 無論能夠是否存在 | O(1) |
setnx key value | key不存在,才設置 | O(1) |
set key value xx | key存在,才設置 | O(1) |
mget key1 key2 key3 | 批量獲取key,原子操做 | O(N) |
mset key1 value1 key2 value2 | 批量設置key-value | O(1) |
getset key newvalue | set key newvalue並返回舊的value | O(1) |
append key value | 將value追加到舊的value | O(1) |
strlen key | 返回字符串的長度(注意中文,utf8下一個中文佔用3個字符) | O(1) |
incrbyfloat key 3.5 | 增長key對應的值3.5 | O(1) |
getrange key start end | 獲取字符串指定下標全部的值 | O(1) |
setrange key index value | 設置指定下標全部對應的值 | O(1) |
練習
127.0.0.1:6382> set hello "world"
OK
127.0.0.1:6382> get hell
(nil)
127.0.0.1:6382> get hello
"world"
127.0.0.1:6382> del hello
(integer) 1
127.0.0.1:6382> get hello
(nil)
127.0.0.1:6382> get counter
(nil)
127.0.0.1:6382> incr counter
(integer) 1
127.0.0.1:6382> get counter
"1"
127.0.0.1:6382> incrby counter 99
(integer) 100
127.0.0.1:6382> get counter
"100"
127.0.0.1:6382> decr counter
(integer) 99
127.0.0.1:6382> get counter
"99"
127.0.0.1:6382> decrby counter 100
(integer) -1
127.0.0.1:6382> get counter
"-1"
127.0.0.1:6382> exists php
(integer) 0
127.0.0.1:6382> set php good
OK
127.0.0.1:6382> setnx php bad
(integer) 0
127.0.0.1:6382> set php best xx
OK
127.0.0.1:6382> get php
"best"
127.0.0.1:6382> exists java
(integer) 0
127.0.0.1:6382> setnx java best
(integer) 1
127.0.0.1:6382> set java easy xx
OK
127.0.0.1:6382> get java
"easy"
127.0.0.1:6382> set hello world
OK
127.0.0.1:6382> getset hello php
"world"
127.0.0.1:6382> get hello
"php"
127.0.0.1:6382> append hell ",php"
(integer) 4
127.0.0.1:6382> get hello
"php"
127.0.0.1:6382> append hello ",php"
(integer) 7
127.0.0.1:6382> get hello
"php,php"
127.0.0.1:6382> strlen hello
(integer) 7
127.0.0.1:6382> set hello "吳軍旗"
OK
127.0.0.1:6382> strlen hello
(integer) 9
複製代碼
n次get操做
** 1次mget操做**
incr userid: pageview (**主要的是:單線程,因此無競爭)**)
複製代碼
incr id
複製代碼
命令 | 說明 | 時間複雜度 |
---|---|---|
hget key field | 獲取hash key對應field的value | O(1) |
hset key field value | 設置has key 對應的field的value | O(1) |
hexists key field | 判斷hash key 是否有field | O(1) |
hlen key | 獲取hash key field的數量 | O(1) |
hmget key field1 field2...fieldN | 批量獲取hash key的一批field對應的值 | O(N) |
hset key field1 value1 field2 value2...fieldN valueN | 批量設置hash key的一批field value | O(1) |
hgetall key | 返回hash key對應全部的field和value | O(N) |
hvals key | 返回hash key對應全部的field的value | O(N) |
hkeys key | 返回hash key對應全部的field | O(N) |
hsetnx key field value | 設置has key 對應的field的value(若是field已經存在,則失敗) | O(1) |
hincrby key field intCounter | hash key對應的field的value自增intCounter | O(1) |
hincrbyfloat key field floatCounter | 浮點數版本 | O(1) |
注意 當心使用hgetall(牢記單線程)
練習
127.0.0.1:6382> hset user1 age 26
(integer) 1
127.0.0.1:6382> hset user1 name wujunqi
(integer) 1
127.0.0.1:6382> hget all user1
(nil)
127.0.0.1:6382> hgetall user1
1) "age"
2) "26"
3) "name"
4) "wujunqi"
127.0.0.1:6382> hdel user1 age
(integer) 1
127.0.0.1:6382> hgetall user1
1) "name"
2) "wujunqi"
127.0.0.1:6382> hget user1 name
"wujunqi"
127.0.0.1:6382> hexists user1 name
(integer) 1
127.0.0.1:6382> hlen user1
(integer) 1
127.0.0.1:6382> hmset user2 name xiaofang age 26
OK
127.0.0.1:6382> hmget user2 name age
1) "xiaofang"
2) "26"
127.0.0.1:6382> hgetall user2
1) "name"
2) "xiaofang"
3) "age"
4) "26"
127.0.0.1:6382> hvals user2
1) "xiaofang"
2) "26"
127.0.0.1:6382> hkeys user2
1) "name"
2) "age"
127.0.0.1:6382> hincrby user age 2
(integer) 2
127.0.0.1:6382> hgetall user2
1) "name"
2) "xiaofang"
3) "age"
4) "26"
127.0.0.1:6382> hincrby user2 age 2
(integer) 28
127.0.0.1:6382> hgetall user2
1) "name"
2) "xiaofang"
3) "age"
4) "28"
127.0.0.1:6382> hincrbyfloat user2 age 2.0
"30"
127.0.0.1:6382> hincrbyfloat user2 age 2.5
"32.5"
127.0.0.1:6382> hgetall user2
1) "name"
2) "xiaofang"
3) "age"
4) "32.5"
複製代碼
練習
127.0.0.1:6382> rpush list1 a b c d
(integer) 4
127.0.0.1:6382> lpush list1 e f g h i
(integer) 9
127.0.0.1:6382> lrange list1 0 -1
1) "i"
2) "h"
3) "g"
4) "f"
5) "e"
6) "a"
7) "b"
8) "c"
9) "d"
127.0.0.1:6382> linsert list1 before i wu
(integer) 10
127.0.0.1:6382> lrange list1 0 -1
1) "wu"
2) "i"
3) "h"
4) "g"
5) "f"
6) "e"
7) "a"
8) "b"
9) "c"
10) "d"
127.0.0.1:6382> linsert list1 after i jun
(integer) 11
127.0.0.1:6382> lrange list1 0 -1
1) "wu"
2) "i"
3) "jun"
4) "h"
5) "g"
6) "f"
7) "e"
8) "a"
9) "b"
10) "c"
11) "d"
127.0.0.1:6382> lpop list1
"wu"
127.0.0.1:6382> rpop list1
"d"
127.0.0.1:6382> lrange list1 0 -1
1) "i"
2) "jun"
3) "h"
4) "g"
5) "f"
6) "e"
7) "a"
8) "b"
9) "c"
127.0.0.1:6382> lrem list1 1 i
(integer) 1
127.0.0.1:6382> lrange list1 0 -1
1) "jun"
2) "h"
3) "g"
4) "f"
5) "e"
6) "a"
7) "b"
8) "c"
127.0.0.1:6382> rpush list1 c c c c c
(integer) 13
127.0.0.1:6382> ltrem list1 -3 c
(error) ERR unknown command 'ltrem'
127.0.0.1:6382> lrem list1 -3 c
(integer) 3
127.0.0.1:6382> lrange list1 0 -1
1) "jun"
2) "h"
3) "g"
4) "f"
5) "e"
6) "a"
7) "b"
8) "c"
9) "c"
10) "c"
127.0.0.1:6382> lindex list 0
(nil)
127.0.0.1:6382> lindex list1 0
"jun"
127.0.0.1:6382> llen list1
(integer) 10
127.0.0.1:6382> lset list 0 wu
(error) ERR no such key
127.0.0.1:6382> lset list1 0 wu
OK
127.0.0.1:6382> lrange list1 0 -1
1) "wu"
2) "h"
3) "g"
4) "f"
5) "e"
6) "a"
7) "b"
8) "c"
9) "c"
10) "c"
複製代碼
Redis 的 Set 是 String 類型的無序集合。集合成員是惟一的,這就意味着集合中不能出現重複的數據。 Redis 中集合是經過哈希表實現的,因此添加,刪除,查找的複雜度都是 O(1)。
命令 | 說明 | 時間複雜度 |
---|---|---|
sadd key element | 向集合key添加element(若是element已經存在,添加失敗) | O(1) |
srem key element | 將集合key中的element移除掉 | O(1) |
scard key | 計算集合大小 | O(1) |
sismember key element | 判斷element 是否在集合中 | O(1) |
srandmember key count | 從集合中隨機挑count個元素 | O(1) |
spop key | 從集合中隨機彈出一個元素 | O(1) |
smembers key | 獲取集合全部元素 | O(1) |
srem key element | 將集合key中的element移除掉 | O(1) |
命令 | 說明 | 時間複雜度 |
---|---|---|
sdiff key1 key2 | 差集 | O(1) |
sinter key1 key2 | 交集 | O(1) |
sunion key1 key2 | 並集 | O(1) |
sidff/sinter/suion + store destkey | 將差集、交集、並集保存在destkey中 | O(1) |
注意
練習
127.0.0.1:6382> sadd set1 a b c d
(integer) 4
127.0.0.1:6382> srem set1 a
(integer) 1
127.0.0.1:6382> smembers set1
1) "d"
2) "c"
3) "b"
127.0.0.1:6382> scard set1
(integer) 3
127.0.0.1:6382> sismember set1 d
(integer) 1
127.0.0.1:6382> srandmember set1 2
1) "d"
2) "b"
127.0.0.1:6382> srandmember set1 2
1) "b"
2) "c"
127.0.0.1:6382> spop set1
"c"
127.0.0.1:6382> smembers set1
1) "d"
2) "b"
127.0.0.1:6382> srem set1 d
(integer) 1
127.0.0.1:6382> smembers set1
1) "b"
127.0.0.1:6382> sadd set1 1 2 3 4 5
(integer) 5
127.0.0.1:6382> sadd set2 a b c 12 8 9 1 2
(integer) 8
127.0.0.1:6382> sdiff set1 set2
1) "3"
2) "4"
3) "5"
127.0.0.1:6382> sinter set1 set2
1) "2"
2) "b"
3) "1"
127.0.0.1:6382> sunion set1 set2
1) "5"
2) "2"
3) "4"
4) "1"
5) "a"
6) "8"
7) "3"
8) "b"
9) "9"
10) "12"
11) "c"
127.0.0.1:6382>
複製代碼
總結
Redis 有序集合和集合同樣也是string類型元素的集合,且不容許重複的成員。不一樣的是每一個元素都會關聯一個double類型的分數。redis正是經過分數來爲集合中的成員進行從小到大的排序。有序集合的成員是惟一的,但分數(score)卻能夠重複。
命令 | 說明 | 時間複雜度 |
---|---|---|
zadd key score element | 添加score和element | O(logN) |
zrem key element(能夠是多個) | 將集合key中的element移除掉 | O(1) |
zscore key element | 返回元素的分數 | O(1) |
zincrby key increScore element | 增長或減小元素的分數 | O(1) |
zcard key | 返回元素的總個數 | O(1) |
zrank(zrevrank) key member | 返回元素的排名 | O(1) |
zrange(zrevrank) key start end [WITHSCORES] | 返回指定索引範圍內的升序元素[分值] | O(logN + m) |
zrangebyscore(zrevrangebyscore) key minScore maxScore | 返回指定分數範圍內的升序元素 | O(logN + m) |
zcount key minScore maxScore | 返回有序集合內在指定分數範圍內的個數 | O(logN + m) |
zremrangebyrank key start end | 刪除指定排名內的升序元素 | O(logN + m) |
zremrangebyscore key minScore maxScore | 刪除指定分數內的升序元素 | O(logN + m) |
ZINTERSTORE destination numkeys(表示key的個數) key [key ...] | 計算給定的一個或多個有序集的交集並將結果集存儲在新的有序集合 key 中 | |
ZUNIONSTORE destination numkeys key [key ...] | 計算給定的一個或多個有序集的並集,並存儲在新的 key 中 |
找相應語言的下載(通常選擇有笑臉和星星的)
https://redis.io/clients#php
複製代碼
兩點說明
如何配置
什麼是流水線
流水線的做用
兩點注意
publish channel message
subscribe [channel] 一個或者多個
unsubscribe [channel] 一個或者多個
練習
127.0.0.1:6382> publish weibomovie "hello world"
(integer) 1
127.0.0.1:6382> publish weibomovie "hello world2"
(integer) 1
複製代碼
另一個cli
127.0.0.1:6382> SUBSCRIBE weibomovie
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "weibomovie"
3) (integer) 1
1) "message"
2) "weibomovie"
3) "hello world"
1) "message"
2) "weibomovie"
3) "hello world2"
複製代碼
命令 | 說明 | 時間複雜度 |
---|---|---|
setbit key offset value | 給位圖指定索引設置值 | O(1) |
getbit key offset | 獲取位圖指定索引的值 | O(1) |
bitcount key start end | 獲取位圖指定範圍(start 到end,單位爲字節,若是不指定就獲取所有)位值爲1的個數 | O(1) |
bitop op destkey key [key...] | 作多個bitmap的and,or,not,xor操做並將結果保存在destkey中 | O(1) |
bitpos key targetBit [start][end | 計算位圖指定範圍(start到end,單位爲字節,若是不指定就是獲取所有)第一個偏移量對應的值等於targetBit的位置 | O(1) |
練習
127.0.0.1:6382> set hello big
OK
127.0.0.1:6382> getbit hello
(error) ERR wrong number of arguments for 'getbit' command
127.0.0.1:6382> getbit hello 0
(integer) 0
127.0.0.1:6382> setbit hello 0 1
(integer) 0
127.0.0.1:6382> get hello
"\xe2ig"
127.0.0.1:6382> set hell a
OK
127.0.0.1:6382> bitcount hell
(integer) 3
127.0.0.1:6382> bitop and hell hello
(integer) 3
127.0.0.1:6382> set a a
OK
127.0.0.1:6382> set b b
OK
127.0.0.1:6382> bitop and c a b
(integer) 1
127.0.0.1:6382> get c
"`"
127.0.0.1:6382> bitpos a 1
(integer) 1
127.0.0.1:6382> bitpos a 0
(integer) 0
127.0.0.1:6382> set user2 100
OK
複製代碼
重要理解 使用位圖去記錄用戶uid,其實就是記錄索引值,好比userid=100表明位圖下標100的值爲1
命令 | 說明 |
---|---|
pfaddd key element [element...] | 向hyperloglog添加元素 |
pfcount key [key...] | 計算hyperloglog的獨立總數 |
pfmerge destkey sourceKey [sourcekey...] | 合併多個hyperloglog |
練習
127.0.0.1:6382> pfadd puser1 "u1" "u2" "u3"
(integer) 1
127.0.0.1:6382> pfcount puser1
(integer) 3
127.0.0.1:6382> pfadd puser2 "u3" "u4" "u5"
(integer) 1
127.0.0.1:6382> pfmerge puser puser1 puser2
OK
127.0.0.1:6382> pfcount puser
(integer) 5
複製代碼
是否能容忍錯誤(錯誤率:0.81%)
是否須要單條數據(沒有辦法取出)
命令 | 說明 |
---|---|
geoadd key longitude latitude member [longitude latitude member ...] | 增長地理位置信息 |
geopos key member[member... | 獲取地理位置信息 |
geodist key member1 member2[unit] | 獲取兩個地理位置的距離,unit:m,km,mi,ft |
georadius | 獲取指定位置範圍內的地理位置信息集合 |
練習
127.0.0.1:6382> geoadd beijing 116.28 39.55
(error) ERR wrong number of arguments for 'geoadd' command
127.0.0.1:6382> geoadd geo 116.28 39.55 beijing 117.12 39.08 tianjin
(integer) 2
127.0.0.1:6382> geopos geo beijing
1) 1) "116.28000229597091675"
2) "39.5500007245470826"
127.0.0.1:6382> geodist geo beijing tianjin
"89206.0576"
127.0.0.1:6382>
複製代碼
redis全部數據保存在內存中, 對數據的更新將異步地保存到磁盤上
* 文件策略:如存在老的RDB文件,新替換老
* 複雜度:O(N)
複製代碼
**相關配置
配置參數 | 值 |
---|---|
save | 900 1 |
save | 300 10 |
save | 60 10000 |
dbfilename | dump-${port}.rdb |
dir | /bigdishpath |
stop-writes-on-bgsav-error | yes |
rdbcompression | yes |
其餘的方式也會觸發生成RDB文件
三種策略比較
-------------------------華麗的分割線--------------------
看完的朋友能夠點個喜歡/關注,您的支持是對我最大的鼓勵。
想了解更多,歡迎關注個人微信公衆號:番茄技術小棧