Java架構之Redis企業級開發與運維從入門

介紹
Redis:Remote DIctionary Server(遠程字典服務器),是徹底開源免費的,用C語言編寫的,遵照BSD協議,
是一個高性能的(key/value)分佈式內存數據庫,基於內存運行並支持持久化的NoSQL數據庫,是當前最熱門的NoSql數據庫之一,也被人們稱爲數據結構服務器。html

優勢:java

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

(2)Redis不只僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲算法

(3)Redis支持數據的備份,即master-slave模式的數據備份數據庫

相關應用:centos

(1)內存存儲和持久化:redis支持異步將內存中的數據寫到硬盤上,同時不影響繼續服務數組

(2)取最新N個數據的操做,如:能夠將最新的10條評論的ID放在Redis的List集合裏面安全

(3)模擬相似於HttpSession這種須要設定過時時間的功能服務器

(4)發佈、訂閱消息系統數據結構

(5)定時器、計數器

Redis的安裝
下載
下載[redis-5.0.0][http://download.redis.io/releases/redis-5.0.0.tar.gz]放到centos系統中

安裝
解壓redis壓縮文件,在解壓目錄執行make && make install

安裝目錄查看
查看默認安裝目錄:usr/local/bin

redis-benchmark:性能測試工具

redis-check-aof:修復有問題的AOF文件

redis-check-dump:修復有問題的dump.rdb文件

redis-cli:客戶端,操做入口

redis-sentinel:redis集羣使用

redis-server:Redis服務器啓動命令

啓動服務
(1)修改redis.conf文件將裏面的daemonize no 改爲 yes,讓服務在後臺啓動

(2)將默認的redis.conf拷貝到本身定義好的一個路徑下,好比/myconf

(3)經過命令redis-server /myconf啓動服務

(4)redis-cli 鏈接測試

服務關閉
單實例關閉:redis-cli shutdown

多實例關閉,指定端口關閉:redis-cli -p 6379 shutdown

Redis服務
服務核心
單進程

單進程模型來處理客戶端的請求。對讀寫等事件的響應是經過對epoll函數的包裝來作到的。Redis的實際處理速度徹底依靠主進程的執行效率。

epoll是Linux內核爲處理大批量文件描述符而做了改進的epoll,是Linux下多路複用IO接口select/poll的加強版本,它能顯著提升程序在大量併發鏈接中只有少許活躍的狀況下的系統CPU利用率。

服務端操做
默認16個數據庫,相似數組下表從零開始,初始默認使用零號庫。

設置數據庫的數量,默認數據庫爲0,可使用SELECT 命令在鏈接上指定數據庫id databases 16。

默認端口是6379

數據庫操做

select命令切換數據庫:select [index]

dbsize查看當前數據庫的key的數量

flushdb:清空當前庫

flushall:清空所有庫

統一密碼管理,16個庫都是一樣密碼,要麼都OK要麼一個也鏈接不上

Redis索引都是從零開始

更多操做

http://redisdoc.com/

Redis數據類型
Redis的五大數據類型:

(1)string(字符串)
(2)hash(哈希,相似java裏的Map)
(3)list(列表)
(4)set(集合)
(5)zset(sorted set:有序集合)

Redis 鍵(key)
key值查看:

(1)keys * 顯示全部的key
(2)exists key 判斷某個key是否存在
(3)move key db 將當前庫的key移至db庫
(4)expire key 秒鐘 爲給定的key設置過時時間
(5)ttl key 查看還有多少秒過時,-1表示永不過時,-2表示已過時
(6)type key 查看你的key是什麼類型
(7)del key刪除key
更多操做:http://redisdoc.com/database/index.html

Redis字符串(String)
string是redis最基本的類型,一個key對應一個value。

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

string類型是Redis最基本的數據類型,一個redis中字符串value最多能夠是512M。

相關操做:
set/get/del/append/strlen 設置/獲取/刪除/追加/字符串長度
Incr/decr/incrby/decrby 數字操做,必定要是數字才能進行加減
getrange/setrange 返回指定範圍內的字符串/指定範圍字符串替換
setex(set with expire)鍵秒值/setnx(set if not exist)
mset/mget/msetnx
getset(先get再set)

全部字符串類型操做:http://redisdoc.com/string/index.html

Redis列表(List)
Redis 列表是簡單的字符串列表,按照插入順序排序。能夠添加一個元素導列表的頭部(左邊)或者尾部(右邊)。它的底層實際是個鏈表。

相關操做:
lpush/rpush/lrange 插入表頭/插入表尾/區間值返回
lpop/rpop 移除並返回表頭元素/移除並返回表尾元素
lindex 按照索引下標得到元素(從上到下)
llen 長度獲取
lrem 移除
ltrim key 開始index 結束index,截取指定範圍的值後再賦值給key
rpoplpush 源列表 目的列表
lset key index value
linsert key before/after 值1 值2

全部列表操做:http://redisdoc.com/list/index.html

Redis集合(Set)
Redis的Set是string類型的無序集合。它是經過HashTable實現實現的。

相關操做:

sadd/smembers/sismember
scard,獲取集合裏面的元素個數
srem key value 刪除集合中元素
srandmember key 某個整數(隨機出幾個數)
spop key 隨機出棧
smove key1 key2 在key1裏某個值 做用是將key1裏的某個值賦給key2
差集:sdiff
交集:sinter
並集:sunion

全部Set集合操做:http://redisdoc.com/set/index.html

Redis哈希(Hash)
相關操做:

hset/hget/hmset/hmget/hgetall/hdel
hlen
hexists key 在key裏面的某個值的key
hkeys/hvals
hincrby/hincrbyfloat
hsetnx

全部Hash操做:http://redisdoc.com/hash/index.html

Redis有序集合Zset(sorted set)
相關操做:

zadd/zrange
zrangebyscore key 開始score 結束score
zrem key 某score下對應的value值,做用是刪除元素
zcard/zcount key score區間/zrank key values值,做用是得到下標值/zscore key 對應值,得到分數
zrevrank key values值,做用是逆序得到下標值
zrevrange
zrevrangebyscore key 結束score 開始score

全部操做:http://redisdoc.com/sorted_set/index.html

redis配置文件
https://www.cnblogs.com/zhang-ke/p/5981108.html

#配置大小單位,開頭定義了一些基本的度量單位,只支持bytes,不支持bit
#單位大小寫不敏感

###################################GENERAL通用###################################
#包含其它配置文件
include /path/to/local.conf
#是否在後臺執行,yes:後臺運行;no:不是後臺運行
daemonize yes
#redis的進程文件
pidfile /var/run/redis_6379.pid
#指定 redis 只接收來自於該 IP 地址的請求,若是不進行設置,那麼將處理全部請求
bind 127.0.0.1
#redis監聽的端口號。
port 6379
# 此參數爲設置客戶端空閒超過timeout,服務端會斷開鏈接,爲0則服務端不會主動斷開鏈接,不能小於0。
timeout 0
#指定了服務端日誌的級別。級別包括:debug(不少信息,方便開發、測試),verbose(許多有用的信息,可是沒有debug級別信息多),notice(適當的日誌級別,適合生產環境),warn(只有很是重要的信息)
loglevel notice
#指定了記錄日誌的文件。空字符串的話,日誌會打印到標準輸出設備。後臺運行的redis標準輸出是/dev/null。
logfile /var/log/redis/redis-server.log
#數據庫的數量,默認使用的數據庫是DB 0。能夠經過」SELECT 「命令選擇一個db
databases 16
#設置tcp的backlog,backlog實際上是一個鏈接隊列,backlog隊列總和=未完成三次握手隊列 + 已經完成三次握手隊列。在高併發環境下你須要一個高backlog值來避免客戶端鏈接問題。注意Linux內核會將這個值減少到/proc/sys/net/core/somaxconn的值,因此須要確認增大somaxconn和tcp_max_syn_backlog兩個值來達到想要的效果
tcp-backlog 511
#單位爲秒,若是設置爲0,則不會進行Keepalive檢測,建議設置成60 
tcp-keepalive 60
#是否把日誌輸出到syslog中
syslog-enabled
#指定syslog裏的日誌標誌
syslog-ident
#指定syslog設備,值能夠是USER或LOCAL0-LOCAL7
syslog-facility

###################################SNAPSHOTTING快照###################################
# RDB是整個內存的壓縮過的Snapshot
# 快照配置
# 註釋掉「save」這一行配置項就可讓保存數據庫功能失效
# 設置sedis進行數據庫鏡像的頻率。
# 900秒(15分鐘)內至少1個key值改變(則進行數據庫保存--持久化) 
# 300秒(5分鐘)內至少10個key值改變(則進行數據庫保存--持久化) 
# 60秒(1分鐘)內至少10000個key值改變(則進行數據庫保存--持久化)
# 若是想禁用RDB持久化的策略,只要不設置任何save指令,或者給save傳入一個空字符串參數也能夠
save 900 1
save 300 10
save 60 10000

#當RDB持久化出現錯誤後,是否依然進行繼續進行工做,yes:不能進行工做,no:能夠繼續進行工做,能夠經過info中的rdb_last_bgsave_status瞭解RDB持久化是否有錯誤
stop-writes-on-bgsave-error yes
# 對於存儲到磁盤中的快照,能夠設置是否進行壓縮存儲。若是是的話,redis會採用LZF算法進行壓縮。若是你不想消耗CPU來進行壓縮的話,能夠設置爲關閉此功能
rdbcompression yes
#是否校驗rdb文件。從rdb格式的第五個版本開始,在rdb文件的末尾會帶上CRC64的校驗和。這跟有利於文件的容錯性,可是在保存rdb文件的時候,會有大概10%的性能損耗,因此若是你追求高性能,能夠關閉該配置。
rdbchecksum yes
#rdb文件的名稱
dbfilename dump.rdb
#數據目錄,數據庫的寫入會在這個目錄。rdb、aof文件也會寫在這個目錄
dir /var/lib/redis

################################### LIMITS ####################################

# 設置能連上redis的最大客戶端鏈接數量。默認是10000個客戶端鏈接。因爲redis不區分鏈接是客戶端鏈接仍是內部打開文件或者和slave鏈接等,因此maxclients最小建議設置到32。若是超過了maxclients,redis會給新的鏈接發送’max number of clients reached’,並關閉鏈接。
# maxclients 10000
#redis配置的最大內存容量。當內存滿了,須要配合maxmemory-policy策略進行處理。注意slave的輸出緩衝區是不計算在maxmemory內的。因此爲了防止主機內存使用完,建議設置的maxmemory須要更小一些。
# maxmemory <bytes>

#內存容量超過maxmemory後的處理策略。
#volatile-lru:利用LRU算法移除設置過過時時間的key。
#volatile-random:隨機移除設置過過時時間的key。
#volatile-ttl:移除即將過時的key,根據最近過時時間來刪除(輔以TTL)
#allkeys-lru:利用LRU算法移除任何key。
#allkeys-random:隨機移除任何key。
#noeviction:不移除任何key,只是返回一個寫錯誤。
#上面的這些驅逐策略,若是redis沒有合適的key驅逐,對於寫命令,仍是會返回錯誤。redis將再也不接收寫請求,只接收get請求。寫命令包括:set setnx setex append incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby getset mset msetnx exec sort。
# maxmemory-policy noeviction

#lru檢測的樣本數。使用lru或者ttl淘汰算法,從須要淘汰的列表中隨機選擇sample個key,選出閒置時間最長的key移除。
# maxmemory-samples 5

############################## APPEND ONLY MODE ###############################
#默認redis使用的是rdb方式持久化,這種方式在許多應用中已經足夠用了。可是redis若是中途宕機,會致使可能有幾分鐘的數據丟失,根據save來策略進行持久化,Append Only File是另外一種持久化方式,能夠提供更好的持久化特性。Redis會把每次寫入的數據在接收後都寫入 appendonly.aof 文件,每次啓動時Redis都會先把這個文件的數據讀入內存裏,先忽略RDB文件。
appendonly yes
#aof文件名
appendfilename "appendonly.aof"

#aof持久化策略的配置
#no表示不執行fsync,由操做系統保證數據同步到磁盤,速度最快。
#always表示每次寫入都執行fsync,以保證數據同步到磁盤。
#everysec表示每秒執行一次fsync,可能會致使丟失這1s數據。
appendfsync everysec
# 重寫時是否能夠運用Appendfsync,用默認no便可,保證數據安全性。
no-appendfsync-on-rewrite no

#設置容許重寫的最小aof文件大小,避免了達到約定百分比但尺寸仍然很小的狀況還要重寫
auto-aof-rewrite-min-size 64mb
#aof自動重寫配置。當目前aof文件大小超過上一次重寫的aof文件大小的百分之多少進行重寫,即當aof文件增加到必定大小的時候Redis可以調用bgrewriteaof對日誌文件進行重寫。當前AOF文件大小是上第二天志重寫獲得AOF文件大小的二倍(設置爲100)時,自動啓動新的日誌重寫過程。
auto-aof-rewrite-percentage 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
redis持久化
RDB
原理
在指定的時間間隔內將內存中的數據集快照寫入磁盤,也就是行話講的Snapshot快照,它恢復時是將快照文件直接讀到內存裏。

Redis會單首創建(fork)一個子進程來進行持久化,會先將數據寫入到一個臨時文件中,待持久化過程都結束了,再用這個臨時文件替換上次持久化好的文件。整個過程當中,主進程是不進行任何IO操做的,這就確保了極高的性能若是須要進行大規模數據的恢復,且對於數據恢復的完整性不是很是敏感,那RDB方式要比AOF方式更加的高效。RDB的缺點是最後一次持久化後的數據可能丟失。

fork的做用是複製一個與當前進程同樣的進程。新進程的全部數據(變量、環境變量、程序計數器等)數值都和原進程一致,可是是一個全新的進程,並做爲原進程的子進程。

保存方案
rdb 保存的是dump.rdb文件。

save命令只管保存,其它無論,所有阻塞。

Redis會在後臺異步進行快照操做,快照同時還能夠響應客戶端請求。能夠經過lastsave命令獲取最後一次成功執行快照的時間。

RDB持久化恢復方案
將備份文件 (dump.rdb) 移動到 redis 安裝目錄並啓動服務便可,CONFIG GET dir獲取目錄,指定配置文件的dir 路徑,dir默認當前目錄。

優點與劣勢
優點:

(1)適合大規模的數據恢復

(2)對數據完整性和一致性要求不高

劣勢:

(1)在必定間隔時間作一次備份,因此若是redis意外down掉的話,就會丟失最後一次快照後的全部修改。

(2)fork的時候,內存中的數據被克隆了一份,大體2倍的膨脹性須要考慮

動態中止保存方法:

動態全部中止RDB保存規則的方法:redis-cli config set save 「」

AOF(Append Only File)
原理
以日誌的形式來記錄每一個寫操做,將Redis執行過的全部寫指令記錄下來(讀操做不記錄),只許追加文件但不能夠改寫文件,redis啓動之初會讀取該文件從新構建數據,換言之,redis重啓的話就根據日誌文件的內容將寫指令從前到後執行一次以完成數據的恢復工做。

配置文件
Aof保存的是appendonly.aof文件,能夠在redis.conf修改文件名。

修改默認的appendonly no,改成yes

appendonly yes
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
#always表示每次寫入都執行fsync,以保證數據同步到磁盤。
# appendfsync always
#everysec表示每秒執行一次fsync,可能會致使丟失這1s數據。
appendfsync everysec
#no表示不執行fsync,由操做系統保證數據同步到磁盤,速度最快。
# appendfsync no
1
2
3
4
5
6
7
8
9
AOF啓動/修復/恢復
將有數據的aof文件複製一份保存到對應目錄(config get dir),而後重啓redis進行加載而恢復數據。

若是AOP文件存在數據異常,可使用redis-check-aof --fix進行修復。

rewrite
AOF採用文件追加方式,文件會愈來愈大爲避免出現此種狀況,新增了重寫機制,當AOF文件的大小超過所設定的閾值時,Redis就會啓動AOF文件的內容壓縮,只保留能夠恢復數據的最小指令集.可使用命令bgrewriteaof

重寫原理:

AOF文件持續增加而過大時,會fork出一條新進程來將文件重寫(也是先寫臨時文件最後再rename),遍歷新進程的內存中數據,每條記錄有一條的Set語句。重寫aof文件的操做,並無讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,這點和快照有點相似。

觸發機制:

Redis會記錄上次重寫時的AOF大小,默認配置是當AOF文件大小是上次rewrite後大小的一倍且文件大於64M時觸發。

AOP優點與劣勢
優點:

(1)每修改同步:appendfsync always 同步持久化 每次發生數據變動會被當即記錄到磁盤 性能較差但數據完整性比較好.
(2)每秒同步:appendfsync everysec 異步操做,每秒記錄 若是一秒內宕機,有數據丟失,但數據丟失小。
(3)不一樣步:appendfsync no 從不一樣步,性能好。

劣勢:

(1)相同數據集的數據而言aof文件要遠大於rdb文件,恢復速度慢於rdb
(2)aof運行效率要慢於rdb,每秒同步策略效率較好,不一樣步效率和rdb相同

持久化方案總結
若是隻但願數據在服務器運行的時候存在,能夠不使用任何持久化方式.

方案對比:

RDB持久化方式可以在指定的時間間隔能對你的數據進行快照存儲。
AOF持久化方式記錄每次對服務器寫的操做,當服務器重啓的時候會從新執行這些命令來恢復原始的數據,AOF命令以redis協議追加保存每次寫的操做到文件末尾.Redis還能對AOF文件進行後臺重寫,使得AOF文件的體積不至於過大

同時開啓兩種持久化方式:

在這種狀況下,當redis重啓的時候會優先載入AOF文件來恢復原始的數據,由於在一般狀況下AOF文件保存的數據集要比RDB文件保存的數據集要完整.
RDB的數據不實時,同時使用二者時服務器重啓也只會找AOF文件。那要不要只使用AOF呢?
做者建議不要,由於RDB更適合用於備份數據庫(AOF在不斷變化很差備份),快速重啓,並且不會有AOF可能潛在的bug,留着做爲一個萬一的手段。

Redis事務
簡介
能夠一次執行多個命令,本質是一組命令的集合。一個事務中的全部命令都會序列化,按順序地串行化執行而不會被其它命令插入,不準加塞。一個隊列中,一次性、順序性、排他性的執行一系列命令。

操做流程
(1)開啓:以MULTI開始一個事務
(2)入隊:將多個命令入隊到事務中,接到這些命令並不會當即執行,而是放到等待執行的事務隊列裏面
(3)執行:由EXEC命令觸發事務

事務
基本命令
http://redisdoc.com/transaction/index.html

DISCARD:取消事務,放棄執行事務塊內的全部命令。
EXEC:執行全部事務塊內的命令
MULTI :標記一個事務塊的開始。
WATCH :監視一個(或多個) key ,若是在事務執行以前這個(或這些) key 被其餘命令所改動,那麼事務將被打斷。
UNWATCH:取消 WATCH 命令對全部 key 的監視。

執行狀況
基本操做
(1)所有正常執行,即事務中的命令所有執行成功

(2)放棄事務,即放棄在事務中的全部操做

(3)所有執行失敗(事務中隊列中的執行操做,有語法錯誤)。

(4)部分執行(若隊列中命令無語法錯誤,則所有執行,執行過程報錯的不影響其它命令,例如:一個字符串k1=「vvsdf」,執行操做 incr k1不會報語法錯誤,但會報執行錯誤)

watch監控
悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖。

樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣能夠提升吞吐量,

樂觀鎖策略:提交版本必須大於記錄當前版本才能執行更新。

Watch原理:

Watch指令,相似樂觀鎖,事務提交時,若是Key的值已被別的客戶端改變,好比某個list已被別的客戶端push/pop過了,整個事務隊列都不會被執行。
經過WATCH命令在事務執行以前監控了多個Keys,假若在WATCH以後有任何Key的值發生了變化,EXEC命令執行的事務都將被放棄,同時返回Nullmulti-bulk應答以通知調用者事務執行失敗。

Watch執行流程:

(1)WATCH 監視一個(或多個) key

(2)MULTI標記一個事務塊的開始

(3)執行操做

(4)狀況一:監控了key,若是key被修改了,後面一個事務的執行失效, WATCH 取消對全部 key 的監視

狀況二:執行exec 把MULTI隊列中的命令所有執行完成,而且WATCH監控鎖也會被取消掉。

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

沒有隔離級別的概念:隊列中的命令沒有提交以前都不會實際的被執行,由於事務提交前任何指令都不會被實際執行,也就不存在」事務內的查詢要看到事務裏的更新,在事務外查詢不能看到」這個讓人萬分頭痛的問題。

不保證原子性:redis同一個事務中若是有一條命令執行失敗,其後的命令仍然會被執行,沒有回滾。

Redis的發佈訂閱
簡介
進程間的一種消息通訊模式:發送者(pub)發送消息,訂閱者(sub)接收消息。

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

訂閱發佈消息圖
例:頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關係圖

 

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

 

操做命令
http://redisdoc.com/pubsub/index.html

PSUBSCRIBE pattern [pattern …] 訂閱一個或多個符合給定模式的頻道。
PUBSUB subcommand [argument [argument …]] 查看訂閱與發佈系統狀態。
PUBLISH channel message 將信息發送到指定的頻道。
PUNSUBSCRIBE [pattern [pattern …]] 退訂全部給定模式的頻道。
SUBSCRIBE channel [channel …] 訂閱給定的一個或多個頻道的信息。
UNSUBSCRIBE [channel [channel …]] 指退訂給定的頻道。

操做實例:

在redis客服端建立訂閱頻道channel1:

127.0.0.1:6379[1]> SUBSCRIBE channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "hello channel1" //收到的第一條消息
1) "message"
2) "channel1"
3) "come here" //收到的第二條消息
1
2
3
4
5
6
7
8
9
10
11
從新開啓一個redis客服端,而後在同一個頻道 redisChat 發佈消息,訂閱者就能接收到消息。

127.0.0.1:6379[1]> PUBLISH channel1 "hello channel1"
(integer) 1
127.0.0.1:6379[1]> PUBLISH channel1 "come here"
(integer) 1
1
2
3
4
Redis的複製(Master/Slave)
簡介
Redis支持簡單的主從(master-slave)複製功能,當主Redis服務器更新數據時能將數據自動同步到從Redis服務器 ,Master以寫爲主,Slave以讀爲主。

主要用途
讀寫分離、容災恢復

配置搭建
原則
配從(庫)不配主(庫),從庫是不能進行修改操做的。

模式
http://redisdoc.com/replication/slaveof.html

每次與master斷開以後,都須要從新鏈接,除非你配置進redis.conf文件

例若有3臺redis服務器,分別是A、B、C。

一主二從
以A爲主(master)庫,B、C爲從庫。

在B、C上分別執行slaveof 127.0.0.1 6379,而後A庫上全部的更新操做都能在B、C中存在。

A:

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=70,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=70,lag=1
.....
127.0.0.1:6379> set k1 v1
OK
1
2
3
4
5
6
7
8
9
B:

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
...
127.0.0.1:6380> get k1
"v1"
1
2
3
4
5
6
7
8
9
10
C:

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
...
127.0.0.1:6381> get k1
"v1"
1
2
3
4
5
6
7
8
9
10
薪火相傳
上一個Slave能夠是下一個slave的Master,Slave一樣能夠接收其餘slaves的鏈接和同步請求,那麼該slave做爲了鏈條中下一個的master,能夠有效減輕master的寫壓力。
中途變動轉向:會清除以前的數據,從新創建拷貝最新的。
A(master)爲主庫
B做爲A庫的slave,做爲C庫的master
C爲B庫的slave

A:

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=3290,lag=0
127.0.0.1:6379> set k2 v2
OK
1
2
3
4
5
6
7
B:

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
...
slave0:ip=127.0.0.1,port=6381,state=online,offset=3262,lag=1
127.0.0.1:6380> get k2
"v2
1
2
3
4
5
6
7
8
9
10
11
C:

127.0.0.1:6381> slaveof 127.0.0.1 6380
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
...
127.0.0.1:6381> get k2
"v2"
1
2
3
4
5
6
7
8
9
10
反客爲主
使當前數據庫中止與其餘數據庫的同步,轉成主數據庫。

SLAVEOF no one

哨兵模式(sentinel)
介紹
反客爲主的自動版,可以後臺監控主機是否故障,若是故障了根據投票數自動將從庫轉換爲主庫。
例如:當原有的master掛了,剩下的slave會投票選舉出新的master,若是以前的master庫從新啓動了,則會成爲同步新選舉出來的master的slave從庫。
一組sentinel能同時監控多個Master。

步驟
(1)在redis.conf對應目錄下新建sentinel.conf文件。而且配置哨兵:
sentinel monitor 自定義被監控redis庫 127.0.0.1 6379 1
上面最後一個數字1,表示主機掛掉後salve投票看讓誰接替成爲主機,得票數多少後成爲主機。
例如:監控A庫
sentinel.conf:

sentinel monitor host6379 127.0.0.1 6379 1
1
(2)啓動哨兵

redis-sentinel sentinel.conf 
1
複製原理
slave啓動成功鏈接到master後會發送一個sync命令
Master接到命令啓動後臺的存盤進程,同時收集全部接收到的用於修改數據集命令,
在後臺進程執行完畢以後,master將傳送整個數據文件到slave,以完成一次徹底同步
全量複製:而slave服務在接收到數據庫文件數據後,將其存盤並加載到內存中。
增量複製:Master繼續將新的全部收集到的修改命令依次傳給slave,完成同步
可是隻要是從新鏈接master,一次徹底同步(全量複製)將被自動執行

例:當slave第一次連上master會全量複製,後面進行的是增量複製

複製缺點
複製延時:

因爲全部的寫操做都是先在Master上操做,而後同步更新到Slave上,因此從Master同步到Slave機器有必定的延遲,當系統很繁忙的時候,延遲問題會更加嚴重,Slave機器數量的增長也會使這個問題更加嚴重。

Jedis
基礎
Jedis是 Redis 官方首選的 Java 客戶端開發包。

開發須要的jar包:commons-pool-1.6.jar、jedis-2.1.0.jar

maven:

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
經常使用操做
鏈接測試
Jedis jedis = new Jedis("192.168.10.206",6379);
System.out.println(jedis.ping());
1
2
基本類型操做
Jedis jedis = new Jedis("192.168.10.206",6379);
//獲取 keys * 結果
Set<String> keys = jedis.keys("*");
for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
System.out.println(key);
}
//查看k2是否存在
System.out.println("jedis.exists====>"+jedis.exists("k2"));
//查看k1還有多少秒過時
System.out.println(jedis.ttl("k1"));
//查看k1值
System.out.println(jedis.get("k1"));
//設置k4=k4_redis
jedis.set("k4","k4_redis");
//多個字符串同時設置值
jedis.mset("str1","v1","str2","v2","str3","v3");
//獲取多個字符串值
System.out.println(jedis.mget("str1","str2","str3"));

//list設置值 及獲取
jedis.lpush("mylist","v1","v2","v3","v4","v5");
List<String> list = jedis.lrange("mylist",0,-1);
for (String element : list) {
System.out.println(element);
}

//set設置值 及獲取
jedis.sadd("orders","jd001");
jedis.sadd("orders","jd002");
jedis.sadd("orders","jd003");
Set<String> set1 = jedis.smembers("orders");
for (Iterator iterator = set1.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
System.out.println(string);
}
//set移除值
jedis.srem("orders","jd002");
//hash設值及獲取
jedis.hset("hash1","userName","lisi");
System.out.println(jedis.hget("hash1","userName"));

//zset添加值
jedis.zadd("zset01",90d,"v4");
//zset獲取所有值
Set<String> s1 = jedis.zrange("zset01",0,-1);
for (Iterator iterator = s1.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
System.out.println(string);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
事務控制
Jedis jedis = new Jedis("127.0.0.1", 6379);
int balance;// 可用餘額
int amtToSubtract = 10;// 實刷額度
//watch監控
jedis.watch("balance");
balance = Integer.parseInt(jedis.get("balance"));
if (balance < amtToSubtract) {
//取消watch監控
jedis.unwatch();
System.out.println("modify");
} else {
//開啓事務
Transaction transaction = jedis.multi();
transaction.decrBy("balance", amtToSubtract);
transaction.incrBy("debt", amtToSubtract);
//執行並提交事務 watch監控也會取消
transaction.exec();
System.out.println("success");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
主從複製
Jedis jedis_M = new Jedis("127.0.0.1",6379);
Jedis jedis_S = new Jedis("127.0.0.1",6380);
jedis_S.slaveof("127.0.0.1",6379);
1
2
3
Jedis池
獲取Jedis實例須要從JedisPool中獲取,用完Jedis實例須要返還給JedisPool,若是Jedis在使用過程當中出錯,則也須要還給JedisPool

public class JedisPoolUtil {
private static volatile JedisPool jedisPool = null;

private JedisPoolUtil(){}

public static JedisPool getJedisPoolInstance(){
if(null == jedisPool){
synchronized (JedisPoolUtil.class){
if(null == jedisPool){
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxActive(1000);
poolConfig.setMaxIdle(32);
poolConfig.setMaxWait(100*1000);
poolConfig.setTestOnBorrow(true);

jedisPool = new JedisPool(poolConfig,"127.0.0.1",6379);
}
}
}
return jedisPool;
}

public static void release(JedisPool jedisPool,Jedis jedis){
if(null != jedis){
jedisPool.returnResourceObject(jedis);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
JedisPoolConfig配置
JedisPool的配置參數大部分是由JedisPoolConfig的對應項來賦值的。
maxActive:控制一個pool可分配多少個jedis實例,經過pool.getResource()來獲取;若是賦值爲-1,則表示不限制;若是pool已經分配了maxActive個jedis實例,則此時pool的狀態爲exhausted。
maxIdle:控制一個pool最多有多少個狀態爲idle(空閒)的jedis實例;
whenExhaustedAction:表示當pool中的jedis實例都被allocated完時,pool要採起的操做;默認有三種。
WHEN_EXHAUSTED_FAIL --> 表示無jedis實例時,直接拋出NoSuchElementException;
WHEN_EXHAUSTED_BLOCK --> 則表示阻塞住,或者達到maxWait時拋出JedisConnectionException;
WHEN_EXHAUSTED_GROW --> 則表示新建一個jedis實例,也就說設置的maxActive無用;
maxWait:表示當borrow一個jedis實例時,最大的等待時間,若是超過等待時間,則直接拋JedisConnectionException;
testOnBorrow:得到一個jedis實例的時候是否檢查鏈接可用性(ping());若是爲true,則獲得的jedis實例均是可用的;


testOnReturn:return 一個jedis實例給pool時,是否檢查鏈接可用性(ping());


testWhileIdle:若是爲true,表示有一個idle object evitor線程對idle object進行掃描,若是validate失敗,此object會被從pool中drop掉;這一項只有在timeBetweenEvictionRunsMillis大於0時纔有意義;


timeBetweenEvictionRunsMillis:表示idle object evitor兩次掃描之間要sleep的毫秒數;


numTestsPerEvictionRun:表示idle object evitor每次掃描的最多的對象數;


minEvictableIdleTimeMillis:表示一個對象至少停留在idle狀態的最短期,而後才能被idle object evitor掃描並驅逐;這一項只有在timeBetweenEvictionRunsMillis大於0時纔有意義;


softMinEvictableIdleTimeMillis:在minEvictableIdleTimeMillis基礎上,加入了至少minIdle個對象已經在pool裏面了。若是爲-1,evicted不會根據idle time驅逐任何對象。若是minEvictableIdleTimeMillis>0,則此項設置無心義,且只有在timeBetweenEvictionRunsMillis大於0時纔有意義;


lifo:borrowObject返回對象時,是採用DEFAULT_LIFO(last in first out,即相似cache的最頻繁使用隊列),若是爲False,則表示FIFO隊列;

其中JedisPoolConfig對一些參數的默認設置以下:testWhileIdle=trueminEvictableIdleTimeMills=60000timeBetweenEvictionRunsMillis=30000numTestsPerEvictionRun=-112345678910111213141516171819202122232425262728293031323334353637相關代碼:https://download.csdn.net/download/liu289747235/10972716

相關文章
相關標籤/搜索