redis 基礎總結

redis簡介:

官方鏈接:跳轉地址;中文官方鏈接:跳轉地址

Redis 是一個開源(BSD許可)的,內存中的數據結構存儲系統,它可以用作數據庫、緩存和消息中間件。 它支持多種類型的數據結構,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與范圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內置了 復制(replication),LUA腳本(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁盤持久化(persistence), 并通過 Redis哨兵(Sentinel)和自動 分區(Cluster)提供高可用性(high availability)。

可以對這些類型運行原子操作,例如附加到字符串;遞增哈希值;將元素推送到列表中;計算集合交集,并集和差異;或者在排序集中獲得排名最高的成員。

為了實現其出色的性能,Redis使用內存數據集。根據您的使用情況,您可以通過每隔一段時間將數據集轉儲到磁盤或通過將每個命令附加到日志來保留它。如果您只需要功能豐富的網絡內存緩存,則可以選擇禁用持久性。

Redis還支持簡單到設置的主從異步復制,具有非常快速的非阻塞第一次同步,自動重新連接以及在網絡分割上的部分重新同步。

其他功能包括:

  • 事物
  • 發布/訂閱
  • Lua腳本
  • 設置key的生存時間
  • LRU驅逐key(更新緩存)
  • 自動故障轉移

Redis是用ANSI C編寫的,適用于大多數POSIX系統,如Linux,* BSD,OS X,沒有外部依賴性。Linux和OS X是Redis開發和測試的兩個操作系統,我們建議使用Linux進行部署。Windows版本沒有官方支持,但Microsoft開發并維護了Redis的Win-64端口。

redis單機版使用

下載鏈接:跳轉地址

下載以及安裝

1.安裝單機版參考redis官網

$ wget http://download.redis.io/releases/redis-5.0.0.tar.gz
$ tar xzf redis-5.0.0.tar.gz
$ cd redis-5.0.0
$ make

2.啟動默認安裝好的redis服務

$ src/redis-server

3.查看redis默認配置信息:

$ src/redis-cli info

添加認證以及后臺啟動模式

修改redis配置redis.conf文件,修改以下內容即可

daemonize yes
requirepass YouPassword

重啟redis服務并指定配置文件,即生效

$ src/redis-server redis.conf

查看redis信息

$ src/redis-cli -a admin -p 6379 info
# Server
redis_version:4.0.11
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:1d679a1d2d6b6fc8
**redis_mode:standalone**
os:Darwin 16.7.0 x86_64
arch_bits:64
multiplexing_api:kqueue
atomicvar_api:atomic-builtin
gcc_version:4.2.1
process_id:27355
run_id:15e44fc5b4b0da7a879fabdb0e4fdccf3d514389
**tcp_port:6379**
uptime_in_seconds:23
uptime_in_days:0
hz:10
lru_clock:13288401
executable:/Users/xiaodongsun/Downloads/redis-4.0.11/src/redis-server
**config_file:/Users/xiaodongsun/Downloads/redis-4.0.11/redis.conf**

# Clients
**connected_clients:1**
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
**used_memory:1032992**
used_memory_human:1008.78K
**used_memory_rss:1601536**
used_memory_rss_human:1.53M
**used_memory_peak:1032992**
used_memory_peak_human:1008.78K
used_memory_peak_perc:105.32%
used_memory_overhead:1030478
used_memory_startup:980848
used_memory_dataset:2514
used_memory_dataset_perc:4.82%
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
**maxmemory:0**
maxmemory_human:0B
maxmemory_policy:noeviction
**mem_fragmentation_ratio:1.55**
mem_allocator:libc
active_defrag_running:0
lazyfree_pending_objects:0

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1540015034
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
**aof_enabled:0**
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0

# Stats
total_connections_received:2
total_commands_processed:1
instantaneous_ops_per_sec:0
total_net_input_bytes:53
total_net_output_bytes:39
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0

# Replication
**role:master**
connected_slaves:0
master_replid:bb6813b6a6a62c3529b609fd154115da8a21d51a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:0.01
used_cpu_user:0.01
used_cpu_sys_children:0.00
used_cpu_user_children:0.00

# Cluster
**cluster_enabled:0**

# Keyspace

redis常用數據類型

redis最為常用的數據類型主要有以下:

- String 
- Hash
- List
- Set
- Sorted Set
- pub/sub
- Transactions

String

Strings 數據結構是簡單的key-value類型,value其實不僅是String,也可以是數字.
常用命令: set,get,decr,incr(原子遞增),mget,mset,getset等。

127.0.0.1:6379> KEYS *
(empty list or set)
127.0.0.1:6379>
127.0.0.1:6379> SET string root
OK
127.0.0.1:6379> GET string
"root"
127.0.0.1:6379> SET string admin #重新覆蓋相同key的value
OK
127.0.0.1:6379> GET string
"admin"
127.0.0.1:6379> SET count 1
OK
127.0.0.1:6379> INCR count #原子遞增
(integer) 2
127.0.0.1:6379> GET count
"2"
127.0.0.1:6379> DECR count #原子遞減
(integer) 1
127.0.0.1:6379> GET count
"1"
127.0.0.1:6379> GETSET test getset #將key對應的值重新賦值,并返回key對應的原有值
"1"
127.0.0.1:6379> MGET test count string #MEGT/MSET一次性獲取或存儲多個key對應的值
1) "getset"
2) "1"
3) "admin"

應用場景:String是最常用的一種數據類型,普通的key/ value 存儲都可以歸為此類.即可以完全實現目前 Memcached 的功能,并且效率更高。還可以享受Redis的定時持久化,操作日志及 Replication等功能。除了提供與 Memcached 一樣的get、set、incr、decr 等操作外,Redis還提供了下面一些操作:

  • 獲取字符串長度
  • 往字符串append內容
  • 設置和獲取字符串的某一段內容
  • 設置及獲取字符串的某一位(bit)
  • 批量設置一系列字符串的內容

實現方式:

String在redis內部存儲默認就是一個字符串,被redisObject所引用,當遇到incr,decr等操作時會轉成數值型進行計算,此時redisObject的encoding字段為int。

修改或查詢鍵空間

有些指令不是針對任何具體的類型定義的,而是用于和整個鍵空間交互的。因此,它們可被用于任何類型的鍵。

使用EXISTS命令返回1或0標識給定key的值是否存在,使用DEL命令可以刪除key對應的值,DEL命令返回1或0標識值是被刪除(值存在)或者沒被刪除(key對應的值不存在)。

127.0.0.1:6379> EXISTS count #判斷是否存在該key
(integer) 1
127.0.0.1:6379> DEL count #刪除鍵值對
(integer) 1
127.0.0.1:6379> TYPE string #key對應的值的存儲類型
string

redis超時:數據在限定時間內存活

127.0.0.1:6379> EXPIRE string 20 #為已經存在的key設置存活時間
(integer) 1
127.0.0.1:6379> TTL string #TTL命令用來查看key對應的值剩余存活時間。
(integer) 14
127.0.0.1:6379> SET expire 10ms ex 60 #設置鍵值對的時候,指定存活時間
OK
127.0.0.1:6379> TTL expire
(integer) 53

Lists

Redis lists基于Linked Lists實現。這意味著即使在一個list中有數百萬個元素,在頭部或尾部添加一個元素的操作,其時間復雜度也是常數級別的。用LPUSH 命令在十個元素的list頭部添加新元素,和在千萬元素list頭部添加新元素的速度相同。

那么,壞消息是什么?在數組實現的list中利用索引訪問元素的速度極快,而同樣的操作在linked list實現的list上沒有那么快。
Redis Lists用linked list實現的原因是:對于數據庫系統來說,至關重要的特性是:能非常快的在很大的列表上添加元素。另一個重要因素是,正如你將要看到的:Redis lists能在常數時間取得常數長度。

如果快速訪問集合元素很重要,建議使用可排序集合(sorted sets)。可排序集合我們會隨后介紹。

常用命令:lpush,rpush,lpop,rpop,lrange等。

127.0.0.1:6379> LSET lists 0 a #當key不存在報錯
(error) ERR no such key
127.0.0.1:6379> RPUSH lists a #向list左邊添加一個新元素,若key不存在則新建一個key
(integer) 1
127.0.0.1:6379> keys *
1) "lists"
127.0.0.1:6379> LPUSH lists A
(integer) 2
127.0.0.1:6379> LINDEX lists 0
"A"
127.0.0.1:6379> LINDEX lists 1
"a"
127.0.0.1:6379> LRANGE lists 0 -1 #LRANGE 帶有兩個索引,一定范圍的第一個和最后一個元素。這兩個索引都可以為負來告知Redis從尾部開始計數,因此-1表示最后一個元素,-2表示list中的倒數第二個元素,以此類推。
1) "A"
2) "a"
27.0.0.1:6379> RPUSH lists b c d e f #一次向list存入多個值
(integer) 7
127.0.0.1:6379> LRANGE lists 0 -1
1) "A"
2) "a"
3) "b"
4) "c"
5) "d"
6) "e"
7) "f"
127.0.0.1:6379> RPOP lists #它從list中刪除元素并同時返回刪除的值。可以在左邊或右邊操作。(抽獎)
"f"
127.0.0.1:6379> RPOP lists
"d"
127.0.0.1:6379> LPOP lists
"A"
127.0.0.1:6379> LPOP lists
"a"
127.0.0.1:6379> LPOP lists #在這最后 列表中的命令序列是空的,沒有更多的元素可以被彈出。
(nil)
127.0.0.1:6379> LTRIM list 0 2 #可以使用LTRIM把list從左邊截取指定長度
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "b"
2) "c"
3) "d"
127.0.0.1:6379> LLEN list #list長度
(integer) 3

應用場景:
Redis list的應用場景非常多,也是Redis最重要的數據結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現。

Lists 就是鏈表,相信略有數據結構知識的人都應該能理解其結構。使用Lists結構,我們可以輕松地實現最新消息排行等功能。Lists的另一個應用就是消息隊列,
可以利用Lists的PUSH操作,將任務存在Lists中,然后工作線程再用POP操作將任務取出進行執行。Redis還提供了操作Lists中某一段的api,你可以直接查詢,刪除Lists中某一段的元素。

實現方式:

Redis list的實現為一個雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內存開銷,Redis內部的很多實現,包括發送緩沖隊列等也都是用的這個數據結構。

Hash

Redis hash 看起來就像一個 “hash” 的樣子,由鍵值對組成,Hash 便于表示 objects,實際上,你可以放入一個 hash 的域數量實際上沒有限制(除了可用內存以外)。所以,你可以在你的應用中以不同的方式使用 hash。值得注意的是,小的 hash 被用特殊方式編碼,非常節約內存。hash指令的完整列表,常用命令:hget,hset,hgetall 等。

127.0.0.1:6379> HMSET user:01 username admin birthyear 1995 verified 1 #設置 hash 中的多個域
OK
127.0.0.1:6379> HGET user:01 username #取回單個域
"admin"
127.0.0.1:6379> HGET user:01 birthyear
"1995"
127.0.0.1:6379> HMGET user:01 username verified #取回指定的多個域,類似MGET
1) "admin"
2) "1"
127.0.0.1:6379> HGETALL user:01 #返回一系列值
1) "username"
2) "admin"
3) "birthyear"
4) "1995"
5) "verified"
6) "1"
127.0.0.1:6379> HEXISTS user:01 username #是否存在
(integer) 1
127.0.0.1:6379> HKEYS user:01 #所有key
1) "username"
2) "birthyear"
3) "verified"
127.0.0.1:6379> HSTRLEN user:01 username #字符長度
(integer) 5
127.0.0.1:6379> HVALS user:01 #所有值
1) "admin"
2) "1995"
3) "1"
127.0.0.1:6379> HSETNX user:01 sex man #增加鍵值域
(integer) 1
127.0.0.1:6379> HLEN user:01 #key中存儲的哈希中包含的字段數
(integer) 4
127.0.0.1:6379> HINCRBY user:01 birthyear -1 #執行遞增和遞減操作
(integer) 1994
127.0.0.1:6379> HINCRBYFLOAT user:01 birthyear 0.5 #執行浮點遞增和遞減操作
"1994.5"
127.0.0.1:6379> HSCAN user:01 0 #迭代集合
1) "0"
2) 1) "username"
   2) "admin"
   3) "birthyear"
   4) "1994.5"
   5) "verified"
   6) "1"
   7) "sex"
   8) "man"

應用場景:在Memcached中,我們經常將一些結構化的信息打包成HashMap,在客戶端序列化后存儲為一個字符串的值,比如用戶的昵稱、年齡、性別、積分等,這時候在需要修改其中某一項時,通常需要將所有值取出反序列化后,修改某一項的值,再序列化存儲回去。這樣不僅增大了開銷,也不適用于一些可能并發操作的場合(比如兩個并發的操作都需要修改積分)。而Redis的Hash結構可以使你像在數據庫中Update一個屬性一樣只修改某一項屬性值。

簡單舉個實例來描述下Hash的應用場景,比如我們要存儲一個用戶信息對象數據,包含以下信息:

用戶ID為查找的key,存儲的value用戶對象包含姓名,年齡,生日等信息,如果用普通的key/value結構來存儲,主要有以下2種存儲方式:

第一種方式將用戶ID作為查找key,把其他信息封裝成一個對象以序列化的方式存儲,這種方式的缺點是,增加了序列化/反序列化的開銷,并且在需要修改其中一項信息時,需要把整個對象取回,并且修改操作需要對并發進行保護,引入CAS等復雜問題。

第二種方法是這個用戶信息對象有多少成員就存成多少個key-value對兒,用用戶ID+對應屬性的名稱作為唯一標識來取得對應屬性的值,雖然省去了序列化開銷和并發問題,但是用戶ID為重復存儲,如果存在大量這樣的數據,內存浪費還是非常可觀的。

那么Redis提供的Hash很好的解決了這個問題,Redis的Hash實際是內部存儲的Value為一個HashMap,并提供了直接存取這個Map成員的接口。也就是說,Key仍然是用戶ID, value是一個Map,這個Map的key是成員的屬性名,value是屬性值,這樣對數據的修改和存取都可以直接通過其內部Map的Key(Redis里稱內部Map的key為field), 也就是通過 key(用戶ID) + field(屬性標簽) 就可以操作對應屬性數據了,既不需要重復存儲數據,也不會帶來序列化和并發修改控制的問題。很好的解決了問題。

這里同時需要注意,Redis提供了接口(hgetall)可以直接取到全部的屬性數據,但是如果內部Map的成員很多,那么涉及到遍歷整個內部Map的操作,由于Redis單線程模型的緣故,這個遍歷操作可能會比較耗時,而另其它客戶端的請求完全不響應,這點需要格外注意。

實現方式:

Redis Hash對應Value內部實際就是一個HashMap,實際這里會有2種不同實現,這個Hash的成員比較少時Redis為了節省內存會采用類似一維數組的方式來緊湊存儲,而不會采用真正的HashMap結構,對應的value redisObject的encoding為zipmap,當成員數量增大時會自動轉成真正的HashMap,此時encoding為ht。

Set

Redis Set 是 String 的無序排列。SADD 指令把新的元素添加到 set 中。對 set 也可做一些其他的操作,比如測試一個給定的元素是否存在,對不同 set 取交集,并集或差,等等。常用命令:
sadd,spop,smembers,sunion 等。更多命令參考

127.0.0.1:6379> SADD array 1 a a b #新的元素添加到 set 中
(integer) 3
127.0.0.1:6379> SMEMBERS array #顯示set成員,去重并且無序排列
1) "1"
2) "b"
3) "a"
127.0.0.1:6379> SISMEMBER array a #檢測特定的元素是否存在
(integer) 1
127.0.0.1:6379
127.0.0.1:6379> SADD news:1000:tags 1 2 5 77
(integer) 4
127.0.0.1:6379> SADD tag:1:news 1000
(integer) 1
127.0.0.1:6379> SADD tag:2:news 1000
(integer) 1
127.0.0.1:6379> SADD tag:5:news 1000
(integer) 1
127.0.0.1:6379> SADD tag:77:news 1000
(integer) 1
127.0.0.1:6379> SMEMBERS news:1000:tags
1) "1"
2) "2"
3) "5"
4) "77"
127.0.0.1:6379> SINTER tag:1:news tag:2:news #獲取不同 set 的交集
1) "1000"
127.0.0.1:6379> SDIFF tag:2:news tag:77:news #交集
(empty list or set)
127.0.0.1:6379> SUNION array tag:2:news #并集
1) "1"
2) "a"
3) "1000"
4) "2"
5) "3"
6) "b"
127.0.0.1:6379> SSCAN array 0 #迭代集合中的元素
1) "0"
2) 1) "1"
   2) "2"
   3) "3"
   4) "a"
   5) "b"
127.0.0.1:6379> sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 SJ SQ SK #模擬撲克牌
(integer) 52
127.0.0.1:6379> sunionstore game:1:deck deck #對多個集合取并集,并把結果存入另一個 set 中
(integer) 52
127.0.0.1:6379> keys *
1) "news:1000:tags"
2) "tag:2:news"
3) "tag:5:news"
4) "array"
5) "tag:1:news"
6) "game:1:deck"
7) "deck"
8) "tag:77:news"
127.0.0.1:6379> SPOP game:1:deck #隨機從set集合中獲取一個值(發牌)
"S5"
127.0.0.1:6379> SPOP game:1:deck
"H9"
127.0.0.1:6379> SCARD game:1:deck #set里剩余元素數量
(integer) 50
127.0.0.1:6379> SRANDMEMBER game:1:deck #獲取隨機元素而不從集合中刪除它
"D5"

應用場景:Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在于set是可以自動排重的,當你需要存儲一個列表數據,又不希望出現重復數據時,set是一個很好的選擇,并且set提供了判斷某個成員是否在一個set集合內的重要接口,這個也是list所不能提供的。

Sets 集合的概念就是一堆不重復值的組合。利用Redis提供的Sets數據結構,可以存儲一些集合性的數據,比如在微博應用中,可以將一個用戶所有的關注人存在一個集合中,將其所有粉絲存在一個集合。Redis還為集合提供了求交集、并集、差集等操作,可以非常方便的實現如共同關注、共同喜好、二度好友等功能,對上面的所有集合操作,你還可以使用不同的命令選擇將結果返回給客戶端還是存集到一個新的集合中。

實現方式:

set 的內部實現是一個value永遠為null的HashMap,實際就是通過計算hash的方式來快速排重的,這也是set能提供判斷一個成員是否在集合內的原因。

Sorted Set

Sorted sets是一種數據類型,類似于Set和Hash之間的混合。與集合一樣,有序集合由唯一的,非重復的字符串元素組成,因此在某種意義上,有序集合也是一個集合。

排序集合中的元素按順序排列(因此它們不是根據請求排序的,順序是用于表示排序集合的數據結構的特性)。它們按照以下規則訂購:

  • 如果A和B是兩個具有不同分數的元素,那么A> B,如果A.score是> B.score。
  • 如果A和B具有完全相同的score,那么如果A字符串在字典上大于B字符串,則A> B.A和B字符串不能相等,因為有序集只有唯一元素。
127.0.0.1:6379> zadd hackers 1940 "Alan Kay"
(integer) 1
127.0.0.1:6379> zadd hackers 1957 "Sophie Wilson"
(integer) 1
127.0.0.1:6379> zadd hackers 1953 "Richard Stallman"
(integer) 1
127.0.0.1:6379> ZRANGE hackers 0 -1 #通過索引區間返回有序集合成指定區間內的成員;返回按出生年份排序的黑客列表,0和-1表示從元素索引0到最后一個元素
1) "Alan Kay"
2) "Richard Stallman"
3) "Sophie Wilson"
127.0.0.1:6379> ZREVRANGE hackers 0 -1 #以相反的方式
1) "Sophie Wilson"
2) "Richard Stallman"
3) "Alan Kay"
127.0.0.1:6379> ZRANGE hackers 0 -1 WITHSCORES #通過索引區間返回有序集合成指定區間內的成員以及scores
1) "Alan Kay"
2) "1940"
3) "Richard Stallman"
4) "1953"
5) "Sophie Wilson"
6) "1957"
127.0.0.1:6379> ZRANGEBYSCORE hackers -inf 1950 #所有出生到1950年的人
1) "Alan Kay"
127.0.0.1:6379> ZREMRANGEBYSCORE hackers 1940 1960 #從排序集中刪除1940年到1960年間出生的所有黑客,并返回已刪除元素的數量。
(integer) 3
127.0.0.1:6379> ZRANK hackers "Alan Kay" #詢問有序元素集中元素的位置
(integer) 0
127.0.0.1:6379> ZRANK hackers "Sophie Wilson"
(integer) 1
127.0.0.1:6379> zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0 "Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon" 0 "Linus Torvalds" 0 "Alan Turing" #插入了相同的相同分數,按字典順序獲取,
(integer) 9
127.0.0.1:6379> ZRANGE hackers 0 -1 #由于排序集排序規則,它們已經按字典順序排序:
1) "Alan Kay"
2) "Alan Turing"
3) "Anita Borg"
4) "Claude Shannon"
5) "Hedy Lamarr"
6) "Linus Torvalds"
7) "Richard Stallman"
8) "Sophie Wilson"
9) "Yukihiro Matsumoto"
127.0.0.1:6379> ZRANGEBYLEX hackers [B [P #使用ZRANGEBYLEX我們可以要求詞典范圍
1) "Claude Shannon"
2) "Hedy Lamarr"
3) "Linus Torvalds"

使用場景:Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先級(score)的參數來為成員排序,并且是插入有序的,即自動排序。當你需要一個有序的并且不重復的集合列表,那么可以選擇sorted set數據結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。

另外還可以用Sorted Sets來做帶權重的隊列,比如普通消息的score為1,重要消息的score為2,然后工作線程可以選擇按score的倒序來獲取工作任務。讓重要的任務優先執行。

實現方式:

Redis sorted set的內部使用HashMap和跳躍表(SkipList)來保證數據的存儲和有序,HashMap里放的是成員到score的映射,而跳躍表里存放的是所有的成員,排序依據是HashMap里存的score,使用跳躍表的結構可以獲得比較高的查找效率,并且在實現上比較簡單。

Pub/Sub

Pub/Sub 從字面上理解就是發布(Publish)與訂閱(Subscribe),在Redis中,你可以設定對某一個key值進行消息發布及消息訂閱,當一個key值上進行了消息發布后,所有訂閱它的客戶端都會收到相應的消息。這一功能最明顯的用法就是用作實時消息系統,比如普通的即時聊天,群聊等功能。

客戶端1:

127.0.0.1:6379> SUBSCRIBE redisChat #創建了訂閱頻道名為 redisChat,訂閱者就能接收到消息。
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
# 訂閱者的客戶端會顯示如下消息
3) (integer) 1
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "hello redis"

客戶端2:

127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique" #在同一個頻道 redisChat 發布兩次消息
(integer) 1
127.0.0.1:6379> PUBLISH redisChat "hello redis"
(integer) 1

Transactions

MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事務相關的命令。事務可以一次執行多個命令, 并且帶有以下兩個重要的保證:

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

Redis還提供了一個Watch功能,你可以對一個key進行Watch,然后再執行Transactions,在這過程中,如果這個Watched的值進行了修改,那么這個Transactions會發現并拒絕執行。 參考地址鏈接

127.0.0.1:6379> MULTI #開啟了一個事務
OK
127.0.0.1:6379> SET book-name "Mastering C++ in 21 days" #將命令放入隊列中
QUEUED
127.0.0.1:6379> GET book-name
QUEUED
127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED
127.0.0.1:6379> SMEMBERS tag
QUEUED
127.0.0.1:6379> EXEC #開啟事務之后執行
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "C++"
   2) "Mastering Series"
   3) "Programming"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a 1
QUEUED
127.0.0.1:6379> set b 2
QUEUED
127.0.0.1:6379> DISCARD #清空事務隊列,并放棄執行事
OK

WATCH 命令可以為 Redis 事務提供 check-and-set (CAS)行為(實現樂觀鎖):

客戶端1:

127.0.0.1:6379> set count 1
OK
127.0.0.1:6379> WATCH count #監視一個key
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a aa
QUEUED
127.0.0.1:6379> set b bb
QUEUED
127.0.0.1:6379> EXEC #在另一個客戶端修改了監視的key后,執行事務命令
(nil)
127.0.0.1:6379> keys *
1) "count"

客戶端2

127.0.0.1:6379> INCR count
(integer) 2
127.0.0.1:6379> get count
"2"

redis配置主從

  • 復制兩臺redis實例(6379,6380)
  • 實例6379(master) redis.conf配置信息如下:
daemonize yes
pidfile /var/run/redis_6379.pid
port 6379
  • 實例6380(slave) redis.conf配置信息如下:
daemonize yes
pidfile /var/run/redis_6379.pid
port 6379
slaveof 127.0.0.1 6379 #指向master的地址端口
  • 測試
127.0.0.1:6379> set name admin
OK
127.0.0.1:6380> get name
"admin"

redis 哨兵模式

Redis Sentinel 是一個分布式系統, 你可以在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來接收關于主服務器是否下線的信息, 并使用投票協議(agreement protocols)來決定是否執行自動故障遷移, 以及選擇哪個從服務器作為新的主服務器。 參考文檔鏈接地址

  1. 配置redis主從復制
  • 創建實例目錄


    Selection_001.png
  • 復制執行腳本


    Selection_002.png
  • 創建一個新的redis實例


    Selection_003.png
  • 主要修改redis.conf文件內容如下(master配置):

bind 127.0.0.1
port 7000
daemonize yes #啟動redis后臺運行
masterauth admin # master的密碼,如果redis設置了密碼,主從密碼要設置成一樣的
requirepass admin
data /home/xiaodongsun/Documents/redis-sentinel/7000/data
pidfile /var/run/redis_7000.pid
logfile /home/xiaodongsun/Documents/redis-sentinel/7000/data/redis_7000.log
  • 復制實例到7001,7002


    Selection_004.png
  • 修改實例7001和7002 redis.conf文件內容如下(slave配置):
vim ./7001/redis.conf #編輯配置文件
:%s/7000/7001/g #全局替換原實例配置
slaveof 127.0.0.1 7000 #指定master地址以及端口
  • 啟動redis服務:


    Selection_004.png
  • 測試主從復制


    Selection_005.png
  1. 搭建Sentinel系統
  • 修改7000 Sentinel實例的配置文件 sentinel.conf ,配置如下:
bind 127.0.0.1
port 26379
daemonize yes
dir /home/xiaodongsun/Documents/redis-sentinel/7000/data
logfile /home/xiaodongsun/Documents/redis-sentinel/7000/data/redis-sentinel.log
sentinel auth-pass mymaster admin
sentinel monitor mymaster 127.0.0.1 7000 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
  • 修改7001 Sentinel實例的配置文件 sentinel.conf ,配置如下:
bind 127.0.0.1
port 26380
daemonize yes
dir /home/xiaodongsun/Documents/redis-sentinel/7001/data
logfile /home/xiaodongsun/Documents/redis-sentinel/7001/data/redis-sentinel.log
sentinel auth-pass mymaster admin
sentinel monitor mymaster 127.0.0.1 7000 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
  • 修改7002 Sentinel實例的配置文件 sentinel.conf ,配置如下:
bind 127.0.0.1
port 26381
daemonize yes
dir /home/xiaodongsun/Documents/redis-sentinel/7002/data
logfile /home/xiaodongsun/Documents/redis-sentinel/7002/data/redis-sentinel.log
sentinel auth-pass mymaster admin
sentinel monitor mymaster 127.0.0.1 7000 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
  • 啟動各臺哨兵實例


    Selection_007.png

至此redis哨兵已初步搭建完成

  1. 測試
  • 查看redis主從信息


    master相關信息
slave相關信息
  • 故障轉移(在master上做下線操作在其他slave上查看新的信息)


    Selection_010.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374