1、NoSQL簡介
- NoSQL:Not Only SQL
Key Value / Tuple Store:DynamoDB, redis
Wide Column Store / Column Families:列式數據庫, hbase
Document Store:文檔數據庫,mongodb,Elastic
Graph Databases:圖式數據庫,Neo4j
Multimodel Databases:
Object Databases:
Time Series / Streaming Databases:時間序列存儲
mysql是關系型數據庫,是屬于SQL而不是NoSQL - ACID:原子性、一致性、隔離性、持久性,事物性存儲必須滿足ACID
- 特性:數據量大、數據變化非常快(數據增長快、流量分布變化大、數據間耦合結構變化快)、數據源很多
- CAP、BASE
CAP:
Consistency、Availablity、Partition tolerence分區容錯性
C:多個數據節點上的數據一致;
A:用戶發出請求后的有限時間范圍內返回結果;
P:network partition,網絡發生分區后,服務是否依然可用;
CAP理論:一個分布式系統不可能同時滿足C、A、P三個特性,最多可同時滿足其中兩者;對于分布式系統滿足分區容錯性幾乎是必須的。
AP:
C:弱一致性;
CP:
BASE:BA,S,E,基于CAP演化而來
BA:Basically Available,基本可用;
S:Soft state,軟狀態/柔性事務,即狀態可以在一個時間窗口內是不同步的;
E:Eventually consistency,最終一致性;
2、Redis介紹
- REmote DIctionary Server:遠程字典服務器或數據結構服務器,k/v,數據結構;
內存存儲:in-memroy,鍵和值都在內存中存儲
持久化:為了保證數據的持久化,redis會將內存中的數據以快照或AOF的方式存儲到磁盤上
主從(sentinel)
Cluster(shard) - 程序環境:
安裝:yum install redis 在epel源里
配置文件:/etc/redis.conf
主程序:/usr/bin/redis-server
端口:6379/tcp
客戶端:/usr/bin/redis-cli
Unit File:/usr/lib/systemd/system/redis.service
數據目錄:/var/lib/redis - redis:k/v
key:直接ASCII字符串;
value:strings(字符串), lists(數組), hashes(含有子健和值), sets(集合), sorted sets(有序集合), bitmaps(位圖), hyperloglogs,geo(基于位置經緯度做搜索) - 客戶端redis-cli命令:
Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
-h HOST
-p PORT
-a PASSWORD
-n DBID ---redis也有數據庫,用數字表示,默認有0-15號數據庫,共16個,可以在配置文件中修改數據庫的數量 - 與Connection相關命令:
help @connection
AUTH <password> ---輸入密碼進行認證
ECHO <message>
PING ---ping服務器是否存活,如果是好的會回應pang
QUIT ---客戶端退出連接
SELECT dbid ---切換數據庫 - 清空數據庫:
FLUSHDB:清空當前數據庫;
FLUSHALL:清空所有數據庫;
3、Redis數據結構舉例
1、安裝、啟動、客戶端連接和切庫
[root@centos7 .ssh]#redis-cli -h 172.18.21.107 -p 6379 ---可以連接到本機的某個地址和端口
172.18.21.107:6379> quit
[root@centos7 .ssh]#redis-cli ---不加默認連接到本機的127.0.0.1地址的6379端口
127.0.0.1:6379> select 0 ---默認連接后進入的是0號數據庫
OK
127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]> select 1 ---可以進行切庫
OK
2、字符串string數據結構
127.0.0.1:6379[1]> help @string ---可以查看幫助
127.0.0.1:6379[1]> set mykey 'hello redis' ---增加一個鍵和值
OK
127.0.0.1:6379[1]> get mykey ---獲取鍵和值
"hello redis"
127.0.0.1:6379[1]> append mykey ' ,how old are you' ---在存在的鍵的后面追加值
(integer) 28
127.0.0.1:6379[1]> get mykey
"hello redis ,how old are you"
127.0.0.1:6379[1]> strlen mykey ---查看面mykey鍵的值的長度
(integer) 28
127.0.0.1:6379[1]> set mykey 'hi redis' EX 100 ---修改鍵的值,并設定過期時間為100s
OK
127.0.0.1:6379[1]> get mykey
"hi redis"
127.0.0.1:6379[1]> set mykey 'hello' NX ---如果mykey 這個鍵不存在才創建,存在就不創建出現nil
(nil)
127.0.0.1:6379[1]> set mykey 'hello' XX ---如果存在這個鍵才修改
OK
127.0.0.1:6379[1]> get mykey
"hello"
127.0.0.1:6379[1]> set mykeytwo value EX 100 XX ---XX表示如果存在才創建,不存在就不創建
(nil)
127.0.0.1:6379[1]> set count 0 ---創建一個鍵值為整數
OK
127.0.0.1:6379[1]> incr count ---自增
(integer) 1
127.0.0.1:6379[1]> incrby count 2
(integer) 3
127.0.0.1:6379[1]> incrby count 2 ---以多少進行自增
(integer) 5
127.0.0.1:6379[1]> decr count
(integer) 4
127.0.0.1:6379[1]> decrby count 2 ---以多少進行自減
(integer) 2
127.0.0.1:6379[1]> del count ---刪除鍵
(integer) 1
127.0.0.1:6379[1]> get count
(nil)
3、數組list數據結構
127.0.0.1:6379[1]> help @list
127.0.0.1:6379[1]> lpush weekdays sat ---在weekdays數組中增加一個元素為sat,并且是左側入站,rpush表示右側入站,也就是在數組中加入元素的時候是從左側加還是從右側加入的
(integer) 1
127.0.0.1:6379[1]> lpush weekdays fri
(integer) 2
127.0.0.1:6379[1]> lpush weekdays thu ---數組的名字是鍵,數組中的元素是值
(integer) 3
127.0.0.1:6379[1]> lindex weekdays 0 ---查看數組的索引為0的元素
"thu"
127.0.0.1:6379[1]> lindex weekdays 1
"fri"
127.0.0.1:6379[1]> lindex weekdays 3
(nil)
127.0.0.1:6379[1]> lindex weekdays 2
"sat"
127.0.0.1:6379[1]> lpush weekdays tue
(integer) 4
127.0.0.1:6379[1]> linsert weekdays after tue wed ---在tue元素之后插入wed元素
(integer) 5
127.0.0.1:6379[1]> lrange weekdays 0 4 ---查看數組的索引下標為0-4的元素
1) "tue"
2) "wed"
3) "thu"
4) "fri"
5) "sat"
127.0.0.1:6379[1]> rpop weekdays ---從右側出站
"sat"
127.0.0.1:6379[1]> lrange weekdays 0 4 ---查看一下上面的元素已經沒有了
1) "tue"
2) "wed"
3) "thu"
4) "fri"
127.0.0.1:6379[1]> lrem weekdays 2 wed ---從中間刪除某個元素
(integer) 1
127.0.0.1:6379[1]> lrange weekdays 0 4
1) "tue"
2) "thu"
3) "fri"
127.0.0.1:6379[1]> llen weekdays ---查看數組中元素的個數
(integer) 3
127.0.0.1:6379[1]> lpush weekdays sun
(integer) 4
127.0.0.1:6379[1]> lrange weekdays 0 4
1) "sun"
2) "tue"
3) "thu"
4) "fri"
127.0.0.1:6379[1]> lindex weekdays 0
"sun"
127.0.0.1:6379[1]> lindex weekdays 1
"tue"
127.0.0.1:6379[1]> lindex weekdays 2
"thu"
127.0.0.1:6379[1]> lindex weekdays 3
"fri"
127.0.0.1:6379[1]> lindex weekdays 4
(nil)
3、hash數據結構
127.0.0.1:6379[1]> help @hash
127.0.0.1:6379[1]> HMSET member name jerry age 17 gender female ---member為鍵,name、age、gender為它的子健,jerry、17、female為子健的值
OK
127.0.0.1:6379[1]> hkeys member ---查看所有的子健
1) "name"
2) "age"
3) "gender"
127.0.0.1:6379[1]> HVALS member ---查看所有子健的值
1) "jerry"
2) "17"
3) "female"
127.0.0.1:6379[1]> HSTRLEN member name ---查看name子健的值的長度
(integer) 5
127.0.0.1:6379[1]> HSTRLEN member age
(integer) 2
127.0.0.1:6379[1]> HGETALL member ---查看所有子健和值
1) "name"
2) "jerry"
3) "age"
4) "17"
5) "gender"
6) "female"
127.0.0.1:6379[1]> HDEL member gender ---刪除某個子健
(integer) 1
127.0.0.1:6379[1]> HGETALL member
1) "name"
2) "jerry"
3) "age"
4) "17"
4、集合set數據結構
127.0.0.1:6379[1]> help @set
127.0.0.1:6379[1]> SADD animals elephant wolf tiger monkey fox dog cat ---添加一個集合
(integer) 7
127.0.0.1:6379[1]> SADD jiaqin pig dog chiken duck fish
(integer) 5
127.0.0.1:6379[1]> SMEMBERS animals ---查看集合中的成員
1) "monkey"
2) "tiger"
3) "cat"
4) "elephant"
5) "fox"
6) "dog"
7) "wolf"
127.0.0.1:6379[1]> SMEMBERS jiaqin
1) "pig"
2) "chiken"
3) "duck"
4) "dog"
5) "fish"
127.0.0.1:6379[1]> SCARD animals ---查看集合中成員的數量
(integer) 7
127.0.0.1:6379[1]> SPOP animals ---隨機的扇出一個成員
"monkey"
127.0.0.1:6379[1]> SREM jiaqin fish ---刪除某個集合中的指定成員
(integer) 1
127.0.0.1:6379[1]> SINTER animals jiaqin ---求交集
1) "dog"
127.0.0.1:6379[1]> SDIFF animals jiaqin ---求差集,表示animals中有而jiaqin中沒有的成員
1) "wolf"
2) "cat"
3) "fox"
4) "elephant"
5) "tiger"
127.0.0.1:6379[1]> SDIFF jiaqin animals ---和上面的正好相反
1) "pig"
2) "chiken"
3) "duck"
127.0.0.1:6379[1]> SUNION animals jiaqin ---求并集
1) "cat"
2) "chiken"
3) "elephant"
4) "fox"
5) "duck"
6) "dog"
7) "wolf"
8) "tiger"
9) "pig"
5、有序集合sorted_set數據結構
127.0.0.1:6379[1]> help @sorted_set
127.0.0.1:6379[1]> ZADD name 1 tom 3 jerry 9 obama 7 trump 4 bush ---添加鍵和值,name是鍵,后面名字是值,數字是給值打的分數,根據這個分數才能進行排序,變成有序集合
(integer) 5
127.0.0.1:6379[1]> ZSCORE name trump ---查找trump的分數
"7"
127.0.0.1:6379[1]> ZRANK name trump ---查找trump的索引,索引是按照分數從低到高進行排序的,從0開始
(integer) 3
127.0.0.1:6379[1]> ZRANK name tom
(integer) 0
127.0.0.1:6379[1]> ZRANK name jerry
(integer) 1
127.0.0.1:6379[1]> ZRANK name obama
(integer) 4
127.0.0.1:6379[1]> ZRANGE name 1 3 根據索引進行查找
1) "jerry"
2) "bush"
3) "trump"
127.0.0.1:6379[1]> ZRANGEBYSCORE name 3 10 ---根據分數進行查找
1) "jerry"
2) "bush"
3) "trump"
4) "obama"
6、發布訂閱隊列pubsub數據結構
127.0.0.1:6379[1]> help @pubsub
127.0.0.1:6379[1]> PUBLISH ops 'rhel 8.0 is coming'
(integer) 0 ---發布一個頻道為ops,內容為rhel 8.0 is coming
復制打開另外一個終端
[root@centos7 app]#redis-cli
127.0.0.1:6379> SUBSCRIBE ops ---在另外一個終端訂閱這個頻道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "ops"
3) (integer) 1
在第一終端的ops頻道再發布一個消息
127.0.0.1:6379[1]> PUBLISH ops 'good morning'
(integer) 1
在另外一個終端可以看到這個消息,因為這個終端訂閱了這個頻道,所有訂閱了這個頻道的終端都可以看到這個消息
1) "message"
2) "ops"
3) "good morning"
4、配置和使用redis
vim /etc/redis.conf
- 通用配置項:
daemonize:設置為no,如果設置為yes以守護進程的方式運行就不受systemd的控制了,設置成no時以systmectl啟動時會以守護進程的方式運行
supervised:一般設置為no,意思是受不受upstart(centos6)和systemd(centos7)的監督,這一項設置成yes和no都可以,因為即使受他們的監督,redis運行出問題了也不會將結果反饋給他們
loglevel, pidfile, logfile,
databases:設定數據庫數量,默認為16個,每個數據庫的名字均為整數,從0開始編號,默認操作的數據庫為0;
切換數據庫的方法:
SELECT <dbid>
- 網絡配置項:
bind IP ---bind 0.0.0.0表示監聽在本機的所有ip
port PORT
protected-mode ---表示啟動保護模式,當bind后面沒有寫ip地址并且配置文件中沒有設置連接到redis主機的密碼時會啟動保護模式,用戶連接的時候將會失敗
tcp-backlog ---tcp的后援隊列長度
unixsocket
timeout:在客戶端空閑幾秒鐘后關閉連接
- 安全配置:
requirepass <PASSWORD> ---設置連接到redis服務器的密碼
[root@centos7 .ssh]#systemctl restart redis
[root@centos7 .ssh]#redis-cli
127.0.0.1:6379> KEYS * ---連入后如果不輸入密碼是看不到數據庫的
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH centos ---輸入密碼后可以看到了
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> KEYS *
1) "member"
2) "mykey"
3) "name"
4) "jiaqin"
5) "weekdays"
6) "animals"
[root@centos7 .ssh]#redis-cli -a centos ---也可以連接的時候直接指明密碼
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> KEYS *
1) "member"
2) "mykey"
3) "name"
4) "jiaqin"
5) "weekdays"
6) "animals"
rename-command <COMMAND> <NEW_CMND_NAME> ---
對config命令進行重命名,客戶端連接到redis后,使用config命令
可以改變redis在運行時的服務特性,這個命令比較危險,最好別
人不知道這個命令叫什么,但在AOF或Replication環境中,為了
管理方便,使從服務器也知道這個命令的名字,不建議重命名
- Limits相關的配置:
maxclients:最大并發連接數,默認是1000
maxmemory <bytes>:最大內存,單位是字節
maxmemory-policy noeviction:定義淘汰策略,默認是noeviction表示不淘汰,當內存空間被占滿時,不允許寫數據,會返回錯誤信息
一般volatile-ttl策略比較好,表示當內存空間要滿了時,會淘汰馬上要到期的鍵
淘汰策略:volatile-lru, allkeys-lru, volatile-random, allkeys-random, volatile-ttl, noeviction
maxmemory-samples 5:淘汰算法運行時的采樣樣本數,樣本數越多越精確,但出于性能考慮設置成5就可以了
- SlowLog相關的配置:
slowlog-log-slower-than 10000 單位是微秒;查詢時間超過10毫秒的就認為是慢查詢,就記錄到慢查詢日志中
slowlog-max-len 128:設置慢查詢日志最多記錄多少條記錄;
- ADVANCED配置:
hash-max-ziplist-entries 512:一個hash內部最多能容納多少個子健
hash-max-ziplist-value 64:每個子健的值最大不能超過多少個字節
list-max-ziplist-size -2:每個子健的值允許占的最大空間;
client-output-buffer-limit normal 0 0 0 正常客戶端
client-output-buffer-limit slave 256mb 64mb 60 從服務器的客戶端
client-output-buffer-limit pubsub 32mb 8mb 60 連接到隊列服務器的客戶端
redis的數據先存到內存緩沖區,客戶端連接時通過內存緩沖不區
輸出給客戶端,以上三項是用來定義發送給客戶端的緩沖區的大
小, 比如:256mb 64mb 60分別表示硬限制、軟限制和軟限制
的寬限期
- 配置參數可運行時修改
127.0.0.1:6379> INFO ----服務器狀態信息查看,分為多個段
127.0.0.1:6379> INFO memory
127.0.0.1:6379> INFO replication ---只查看某個段
127.0.0.1:6379> INFO stats
127.0.0.1:6379> CONFIG RESETSTAT ----重新計數
127.0.0.1:6379> CONFIG GET requirepass ---可以查看密碼
1) "requirepass"
2) "centos"
127.0.0.1:6379> CONFIG GET maxclients
1) "maxclients"
2) "10000"
127.0.0.1:6379> CONFIG SET maxclients 10200 ---修改最大并發連接
OK
127.0.0.1:6379> CONFIG GET maxclients
1) "maxclients"
2) "10200"
127.0.0.1:6379> CONFIG REWRITE ---寫到配置文件里
OK
vim /etc/redis.conf
maxclients 10200 ---發現配置文件里已經修改,運用config set
可以修改運行時的參數并寫到配置文件里,所以說config這個命令
很危險,不能讓別人知道。
- 查看客戶端的連接
127.0.0.1:6379> CLIENT list ---查看有幾個客戶端連接到本機
id=3 addr=127.0.0.1:45178 fd=5 name= age=613 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
id=4 addr=127.0.0.1:45180 fd=6 name= age=3 idle=3 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=command
127.0.0.1:6379> CLIENT SETNAME n1 ---給客戶端命名
OK
127.0.0.1:6379> CLIENT list
id=3 addr=127.0.0.1:45178 fd=5 name=n1 age=628 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
id=4 addr=127.0.0.1:45180 fd=6 name= age=18 idle=18 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=command
127.0.0.1:6379[1]> CLIENT KILL id 4 ---殺死某個客戶端
(integer) 1
127.0.0.1:6379[1]> CLIENT list ---發現id為4的客戶端沒有了
id=3 addr=127.0.0.1:45178 fd=5 name=n1 age=725 idle=0 flags=N db=1 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
5、redis的持久化
- RDB:snapshotting, 二進制格式;按事先定制的策略,周期性地將數據從內存同步至磁盤;數據文件默認為dump.rdb;
客戶端顯式使用SAVE或BGSAVE命令來手動啟動快照保存機制;
SAVE:同步,即在主線程中保存快照,此時會阻塞所有客戶端請求;不會丟失數據
BGSAVE:異步;backgroud,啟動一個子進程去保存快照并在后臺運行,不會阻塞客戶端的請求,但有可能丟失數據,因為同步的時候客戶端可能正在寫數據
[root@centos7 ~]#cd /var/lib/redis/
[root@centos7 redis]#ls
dump.rdb
- AOF:Append Only File, fsync(aof文件重寫)
記錄每次寫操作至指定的文件尾部實現的持久化;當redis重啟時,可通過重新執行文件中的命令在內存中重建出數據庫;相當于mysql的二進制日志,可以進行時間點還原
BGREWRITEAOF:AOF文件重寫;
不會讀取正在使用AOF文件,而是通過將內存中的數據以命令的方式保存至臨時文件中,完成之后替換原來的AOF文件; - RDB相關的配置:
*save <seconds> <changes>
save 900 1
save 300 10
save 60 10000
表示:三個策略滿足其中任意一個均會觸發SNAPSHOTTING操作;900s內至少有一個key有變化,300s內至少有10個key有變化,60s內至少有1W個key發生變化;
stop-writes-on-bgsave-error yes
持久功能,也就是保存到磁盤操作出現錯誤時,是否禁止新的寫入操作請求;
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb:指定rdb文件名
dir /var/lib/redis:rdb文件的存儲路徑
- AOF相關的配置
appendonly no ---如果改成yes表示啟用AOF持久化功能,RDB和AOF持久化功能可以同時啟用是沒有問題的
[root@centos7 redis]#ls /var/lib/redis/ ---啟用之后會發現數據目錄有兩個文件了
appendonly.aof dump.rdb
appendfilename "appendonly.aof"
appendfsync :AOF重寫有以下三種模式
no:redis不執行主動同步操作,而是由操作系統自行決定;
everysec:每秒一次; 默認
always:每語句一次;
no-appendfsync-on-rewrite no:是否在執行aof重寫期間開啟一個后端的子進程,默認為no,表示啟用;但如果重寫的模式為no,則不建議開啟,因為不知道什么時候會重寫
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
上述兩個條件同時滿足時,方會觸發重寫AOF;與上次aof文件大小相比,其增長量超過100%,且大小不少于64MB;
aof-load-truncated yes :AOF開啟時要不要重新清理一下aof文件
注意:持久機制本身不能取代備份;應該制訂備份策略,對redis庫定期備份;
RDB與AOF同時啟用:
(1) BGSAVE和BGREWRITEAOF不會同時進行;
(2) Redis服務器啟動時用持久化的數據文件恢復數據,會優先使用AOF;
6、redis的主從復制
特點:一個Master可以有多個slave主機,支持鏈式復制;
Master以非阻塞方式同步數據至slave主機;
配置slave節點:
redis-cli> SLAVEOF <MASTER_IP> <MASTER_PORT>
redis-cli> CONFIG SET masterauth <PASSWORD>
配置參數:
slaveof :指明主節點redis監聽的ip地址和端口號,只在從上設置
masterauth:指明主節點的密碼,只在從節點的設置
slave-serve-stale-data yes:是否可以用過期的數據響應客戶端的請求
slave-read-only yes:從節點只允許讀操作
repl-diskless-sync no :要不要啟用無磁盤的復制,新的從節點或某較長時間未能與主節點進行同步的從節點重新與主節點通信,需要做“full synchronization",此時其同步方式有兩種style:
Disk-backend:主節點新創建快照文件于磁盤中,而后將其發送給從節點;
Diskless:主節點新創建快照后直接通過網絡套接字文件發送給從節點;為了實現并行復制,通常需要在復制啟動前延遲一個時間段;
repl-diskless-sync-delay 5 :發送快照時是否延遲發送
repl-ping-slave-period 10 主節點多長時間探測一下從節點是否存活
repl-timeout 60:主從復制的超時時長
repl-disable-tcp-nodelay no :發送tcp響應時是否延遲
repl-backlog-size 1mb從服務器后援隊列的大小
slave-priority 100:復制集群中,主節點故障時,sentinel應用場景中的主節點選舉時使用的優先級;數字越小優先級越高,但0表示不參與選舉;
min-slaves-to-write 3:主節點僅允許其能夠通信的從節點數量大于等于此處的值時接受寫操作;
min-slaves-max-lag 10:從節點延遲時長超出此處指定的時長時,主節點會拒絕寫入操作;
示例
1、同步所有節點的時間
2、在node2上的設置
vim /etc/redis.conf
bind 0.0.0.0
requirepass centos ---設置客戶端連接本節點的密碼
slaveof 172.18.21.107 6379 ---指明主的地址和端口
masterauth centos ---指明主的密碼
systemctl start redis
redis-cli -a centos
127.0.0.1:6379[1]> INFO replication ---查看一下主從復制的相關信息,發現角色是從
測試
在主節點node1上創建一個鍵和值
127.0.0.1:6379[1]> set mykey 'hello redis'
在從節點node2上
127.0.0.1:6379[1]> get mykey ---可以看到,說明主從復制成功
"hello redis"
3、在node3上采用config命令在運行時創建主從復制
vim /etc/redis.conf
bind 0.0.0.0
requirepass centos
systemctl start redis
ss -nlt
[root@node3 ~]#redis-cli -a centos ---連接到此服務器
127.0.0.1:6379> CONFIG GET slaveof
1) "slaveof"
2) ""
127.0.0.1:6379> slaveof 172.18.21.107 6379 ---指明主節點的ip和端口
OK
127.0.0.1:6379> CONFIG GET slaveof
1) "slaveof"
2) "172.18.21.107 6379"
127.0.0.1:6379> CONFIG set masterauth centos ---指明主節點的密碼
OK
127.0.0.1:6379> CONFIG GET masterauth
1) "masterauth"
2) "centos"
127.0.0.1:6379> CONFIG REWRITE ---寫到配置文件里
OK
[root@node3 ~]#tail -n 3 /etc/redis.conf ---發現已經追加到配置文件的最后
# Generated by CONFIG REWRITE
slaveof 172.18.21.107 6379
masterauth "centos"
127.0.0.1:6379> INFO replication
# Replication
role:slave ---角色已經變成從
master_host:172.18.21.107
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:1704
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> KEYS * ---可以看到前面創建的鍵
1) "mykey"
127.0.0.1:6379[1]> get mykey
"hello slave 2"
7、redis的故障轉移
redis的故障轉移通過sentinel完成:主要完成三個功能:監控、通知、自動故障轉移,主節點蕩機了,會自動提升一個從節點為新的主節點
選舉機制:流言協議、投票協議
流言協議:不能主觀的判斷某一個節點不可用,而是問其他節點能不能找到主節點,如果其他的也找不到主幾點才證明主節點真的蕩機了
投票協議:with quorum > total/2,without quorum <=total/2,quorum表示sentinel集群的quorum機制,比如有三個sentinel節點,至少有2個節點同時判定主節點故障時,才認為其真的故障,才會進行故障轉移
配置參數
sentinel monitor <master-name> <ip> <redis-port> <quorum>:監控的主節點的名字、ip地址、端口、法定人數
sentinel auth-pass <master-name> <password>:監控的主節點的名字和密碼
<quorum>表示sentinel集群的quorum機制,即至少有quorum個sentinel節點同時判定主節點故障時,才認為其真的故障;
s_down: subjectively down ---主觀判斷其故障
o_down: objectively down ----客觀判斷其故障
sentinel down-after-milliseconds <master-name> <milliseconds>:監控到指定的集群的主節點異常狀態持續多久方才將標記為“故障”;單位是毫秒
sentinel parallel-syncs <master-name> <numslaves>:指在failover故障轉移過程中,能夠被sentinel并行配置的從節點的數量;
sentinel failover-timeout <master-name> <milliseconds>:sentinel必須在此指定的時長內完成故障轉移操作,否則,將視為故障轉移操作失敗;
sentinel notification-script <master-name> <script-path>:通知腳本,此腳本被自動傳遞多個參數;
示例:本實驗是在6主從復制的基礎上完成的
1、在node1節點上的設置
vim /etc/redis-sentinel.conf
bind 0.0.0.0 ---注意一定要加上監聽的ip地址,不然會啟動保護模式,此行配置文件中沒有,需要后加上
sentinel monitor mymaster 172.18.21.107 6379 2 ---只監控主節點就可以,給主節點起個名字叫mymaster
sentinel auth-pass mymaster centos ---監控的主節點的名字和密碼
sentinel down-after-milliseconds mymaster 5000 ---主節點故障5秒后標記為故障狀態
sentinel parallel-syncs mymaster 3 ---故障轉移過程中能夠被sentinel并行配置的從節點的數量是3
sentinel failover-timeout mymaster 60000 ---故障轉移時間超過1分鐘認為失敗
將此配置拷貝到node2和node3節點上
scp /etc/redis-sentinel.conf node2:/etc/
scp /etc/redis-sentinel.conf node3:/etc/
2、在三個節點上都啟動redis-sentinel
systemctl start redis-sentinel.service
ss -nlt ---發現26379端口已經打開
3、在node1上連接到redis-sentinel
redis-cli -h 172.18.21.107 -p 26379
172.18.21.107:26379> sentinel masters ---查看主節點的信息
172.18.21.107:26379> sentinel slaves mymaster -=--查看從節點的信息,查看從節點時要指明查看哪個主節點的從節點,后面要加上mymaster,指明主節點的名字
4、測試
停止node1節點的redis服務
systemctl stop redis
redis-cli -h 172.18.21.107 -p 26379
172.18.21.107:26379> sentinel masters ---查看主節點發現主節
點變成了node3,這里因為沒有設置優先級,所以會根據ip地址自
動提升一個從為主節點,可以通過修改配置文件中slave-priority
100來設置優先級,數字越小優先級越高
172.18.21.107:26379> sentinel slaves mymaster ---從節點變成node1和node2,并且node1的狀態為 "s_down,slave,disconnected"主觀故障
5、恢復node1節點,使其成為正常工作的從節點
在node1上的操作
vim /etc/redis.conf
slaveof 172.18.21.7 6379
masterauth centos
repl-diskless-sync no ---將此項改為no,如果前面當主的時候改成了Diskless或者Disk-backend
systemctl start redis
6、測試
redis-cli -h 172.18.21.107 -p 26379
172.18.21.107:26379> sentinel masters
172.18.21.107:26379> sentinel slaves mymaste ---查看到node1為slave,而不是"s_down,slave,disconnected"
備注:
SENTINEL failover <MASTER_NAME> ---手動觸發故障轉移 failover故障轉移
SENTINEL get-master-addr-by-name <MASTER_NAME>
172.18.21.107:26379> SENTINEL get-master-addr-by-name mymaster ---可以獲得主的地址和端口
1) "172.18.21.7"
2) "6379"
8、redis集群
redis集群會在所有redis節點上分配很多個槽,一共16384個槽,范圍是0-16383,每個節點上分配一定數量的槽,當客戶端創建 一個鍵和值時,會對鍵進行哈希計算,將計算的結果對16384取模,也會生成0-16383之間的數字,這個數字和哪個節點上的哪個槽位對上,此鍵就必須創建在這個節點上,因此需要客戶端的人工智能,也就是客戶端在創建一個鍵時如果和某個節點的某個槽位對上,就必須在這個節點上創建這個鍵,redis集群是將數據分別存儲在不同的redis節點的槽位上,每個節點的數據只是一部分。
集群相關的配置:
cluster-enabled 是否開啟集群配置
cluster-config-file 集群節點集群信息配置文件,每個節點都有一個,由redis生成和更新
cluster-node-timeout 集群節點互連超時的閾值,單位毫秒
cluster-slave-validity-factor 集群服務中每個節點也應該有從節點來避免單點,這就需要設置故障轉移,進行故障轉移時,salve會 申請成為master。有時slave會和master失聯很久導致數據較舊,這樣的slave不應該成為master。這個配置是用來設置失聯多久的從節點不能提升為主節點
cluster-require-full-coverage yes:如果任何一個節點故障了,并且沒有設置從節點,導致槽不完整了,還能否接受客戶端的請求,此配置是要求有完整的槽才能接受請求,因此設置為yes
配置過程:
(1) 設置配置文件,啟用集群功能;
(2) 啟動redis后為每個節點分配slots;
CLUSTER ADDSLOTS
注意:每個slot要獨立創建;可用范圍是0-16383,共16384個
(3) 設定集群成員關系;
CLUSTE MEET
示例:設置redis的三個集群服務,此實驗沒有設置從節點,三個節點都是主節點
1、在node1上的設置
vim /etc/redis.conf
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
cluster-require-full-coverage yes
scp /etc/redis.conf node2:/etc
scp /etc/redis.conf node1:/etc
min-slaves-to-write 0 ----在這里要注意要把這一項改為0,或者注釋掉,此項是定義主節點有幾個從節點時才允許寫,此實驗沒有從節點
2、重新啟動所有節點的redis服務
systemctl restart redis
3、給每個節點分配槽位,在node1上設置
[root@node1 ~]#echo $[16384/3] ---一般都是平均分配
5461
[root@node1 ~]#echo $[5461*2]
10922
[root@node1 ~]#redis-cli -a centos cluster addslots {0..5461}
OK
[root@node1 ~]#redis-cli -a centos -h 172.18.21.100 cluster addslots {5462..10922}
OK
[root@node1 ~]#redis-cli -a centos -h 172.18.21.7 cluster addslots {10923..16383}
OK
[root@node1 ~]#redis-cli -a centos
127.0.0.1:6379> CLUSTER INFO
cluster_state:fail ---可以看到此時的狀態還是失敗的
cluster_slots_assigned:5463 ---槽位已經分配成功了
cluster_slots_ok:5463
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:1
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0
4、讓集群內的成員會面
127.0.0.1:6379> CLUSTER MEET 172.18.21.100 6379
OK
127.0.0.1:6379> CLUSTER MEET 172.18.21.7 6379
OK
127.0.0.1:6379> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384 ---見面之后發現槽位一共是16384個了
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:3
cluster_current_epoch:2
cluster_my_epoch:1
cluster_stats_messages_sent:25
cluster_stats_messages_received:23
5、測試
在node1上的操作
[root@node1 ~]#redis-cli -a centos
127.0.0.1:6379> set test1key hi
OK
127.0.0.1:6379> get test1key
"hi"
127.0.0.1:6379> set testkey2 hello ---告訴我們要到node3節點上設置才可以,因為對testkey2這個鍵進行哈希計算后,對16384取模會落到node3節點的槽上
(error) MOVED 14758 172.18.21.7:6379
127.0.0.1:6379>
在node3節點上的操作
[root@node3 ~]#redis-cli -a centos
127.0.0.1:6379> set testkey2 hello ---在node3節點上就可以設置了
OK
127.0.0.1:6379> get testkey2
"hello"
127.0.0.1:6379> set testkey3 sayhello
(error) MOVED 10631 172.18.21.100:6379
在node2節點上的操作
[root@node2 .ssh]#redis-cli -a centos
127.0.0.1:6379> set testkey3 sayhello
OK