許多web停用都將數(shù)據(jù)保存到RDBMS(關(guān)系型數(shù)據(jù)庫(kù))中,應(yīng)用服務(wù)器中讀取數(shù)據(jù)并在瀏覽器中顯示。但隨著數(shù)據(jù)量增大、訪問的集中,就會(huì)出現(xiàn)RDBMS的負(fù)擔(dān)加重,數(shù)據(jù)庫(kù)響應(yīng)惡化,網(wǎng)站顯示延遲等重大影響。
Memcahe/redis是高性能的分布式內(nèi)存緩存服務(wù)器,通過緩存數(shù)據(jù)庫(kù)查詢結(jié)果,減少數(shù)據(jù)庫(kù)訪問次數(shù),以提高動(dòng)態(tài)web等應(yīng)用速度,提高可擴(kuò)展性。
簡(jiǎn)而言之:緩存數(shù)據(jù)庫(kù)查詢結(jié)果,加快訪問速度,緩解數(shù)據(jù)庫(kù)壓力。
Nosql
非關(guān)系型數(shù)據(jù)庫(kù)(not only sql)
為彌補(bǔ)關(guān)系型數(shù)據(jù)庫(kù)的不足
以鍵值方式存儲(chǔ)數(shù)據(jù)
緩存數(shù)據(jù)庫(kù)
產(chǎn)品有redis、memcached、mongoDB
Memcache
特點(diǎn)
內(nèi)置內(nèi)存存儲(chǔ)方式(重啟操作系統(tǒng)會(huì)導(dǎo)致全部數(shù)據(jù)消失)
簡(jiǎn)單的key/value存儲(chǔ)
不互相通信的分布式
緩存原理
檢查用戶請(qǐng)求的數(shù)據(jù)時(shí)緩存中是否存在,若存在直接返回,無需查詢數(shù)據(jù)庫(kù)。
若請(qǐng)求數(shù)據(jù)在緩存中查詢不到,去查詢數(shù)據(jù)庫(kù),返回?cái)?shù)據(jù),同時(shí)把數(shù)據(jù)存儲(chǔ)到緩存中一份。
保持緩存的“新鮮性”,每當(dāng)數(shù)據(jù)發(fā)生變化的時(shí)候,要同步更新緩存的信息,確保用戶不會(huì)在緩存取到舊的數(shù)據(jù)。
Redis
redis是一個(gè)開源的,使用C語言編寫的,支持網(wǎng)絡(luò)交互的,可基于內(nèi)存也可持久化的key-Value數(shù)據(jù)庫(kù)。
官網(wǎng):redis.io
特點(diǎn)
豐富的數(shù)據(jù)結(jié)構(gòu)
支持持久化
支持事物(事物:一個(gè)完整的動(dòng)作,要么全部執(zhí)行,要么什么都沒做。)
支持主從
安裝
從reids.io下載最新版redis-X.Y.Z.tar.gz后解壓。然后進(jìn)入redis-X.Y.Z文件夾make即可。
# wget http://download.redis.io/releases/redis-4.0.9.tar.gz
# tar xzf redis-4.0.9.tar.gz -C /
# cd redis-4.0.9
# make
若因缺包報(bào)錯(cuò),在安裝完缺失的包之后需重新解壓新包進(jìn)行make安裝,若沒有編譯工具需要先安裝yum -y install gcc make
啟動(dòng)redis(默認(rèn)非daemon形式啟動(dòng))
# ./src/redis-server
指定配置文件啟動(dòng)
# ./src/redis-server ../redis.conf
設(shè)置開機(jī)啟動(dòng)
1.# mkdir /etc/redis
2.# cp /redis-4.0.9/redis.conf /etc/redis/6379.conf
啟動(dòng)腳本
# vim /etc/init.d/redis
#!/bin/sh
# chkconfig: 2345 10 90
# description: Start and Stop redis
REDISPORT=6379
EXEC=/redis-4.0.9/src/redis-server
#(可更改)
CLIEXEC=/redis-4.0.9/src/redis-cli
#(可更改)
PIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/${REDISPORT}.conf"
case "$1" in
start)
if [ -f $PIDFILE ]
then
echo "$PIDFILE exists, process is already running or crashed"
else
echo "Starting Redis server..."
$EXEC $CONF & #(增加)
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo "$PIDFILE does not exist, process is not running"
else
PID=$(cat $PIDFILE)
echo "Stopping ..."
$CLIEXEC -p $REDISPORT shutdown
while [ -x /proc/${PID} ]
do
echo "Waiting for Redis to shutdown ..."
sleep 1
done
echo "Redis stopped"
fi
;;
restart)
"$0" stop
sleep 3
"$0" start
;;
*)
echo "Please use start or stop as first argument"
;;syst
esac
授權(quán)
# chmod 777 /etc/init.d/redis
加入開機(jī)啟動(dòng)
# chkconfig --add redis
# chkconfig redis on
# systemctl daemon-reload //重新加載自啟動(dòng)系統(tǒng)
啟動(dòng)方式
# /etc/init.d/redis start 6
# systemctl start redis
端口
默認(rèn)服務(wù)端口為6379
測(cè)試
# ./src/redis-cli
127.0.0.1:6379> set name hello
OK
127.0.0.1:6379> get name
"hello"
127.0.0.1:6379> save //保存數(shù)據(jù)到磁盤
127.0.0.1:6379> shutdown //通過客戶端來關(guān)閉redis服務(wù)端 禁用
數(shù)據(jù)結(jié)構(gòu)
redis 是一種高級(jí)的key:value存儲(chǔ)系統(tǒng),它的value支持五種數(shù)據(jù)類型:
字符串(strings)
字符串列表(lists)
字符串集合(sets)
有序字符串集合(sorted sets)
哈希(hashes)
注意:
key不可太長(zhǎng),盡量不要超過1024字節(jié),這樣不僅會(huì)小孩內(nèi)存,而且會(huì)降低查找效率。
key也不要太短,太短的話,key的可讀性會(huì)降低。
在項(xiàng)目中,建議key使用統(tǒng)一的命名格式。
redis持久化
開啟持久化功能后,重啟redis,數(shù)據(jù)會(huì)自動(dòng)通過持久化文件恢復(fù)。
RDB(默認(rèn)開啟)
在不同的時(shí)間點(diǎn),將redis存儲(chǔ)的數(shù)據(jù)生成快照并存儲(chǔ)到磁盤等介質(zhì)上。RDB方式,是將redis某一時(shí)刻的數(shù)據(jù)持久化到磁盤中,是一種快照式的持久化方法。
redis在進(jìn)行數(shù)據(jù)持久化的過程中,會(huì)先將數(shù)據(jù)寫入到一個(gè)臨時(shí)文件中,待持久化過程都結(jié)束,才會(huì)用這個(gè)臨時(shí)文件替換上次持久換文件。這種特性可讓我們隨時(shí)備份文件,因?yàn)榭煺瘴募偸峭暾捎玫摹?/p>
特點(diǎn)
周期性
不影響數(shù)據(jù)寫入
RDB會(huì)啟動(dòng)子進(jìn)程,備份所有數(shù)據(jù)。當(dāng)前進(jìn)程繼續(xù)提供數(shù)據(jù)讀寫,當(dāng)備份完成替換老的備份文件。
高效,一次性還原所有數(shù)據(jù)
完美性較差
故障點(diǎn)到上一次備份之間的數(shù)據(jù)無法恢復(fù)。
查看RDB開啟狀態(tài)
vim /redis-4.0.9/redis.conf
dbfilename dump.rdb
#dbfilename:持久化數(shù)據(jù)存儲(chǔ)在本地的文件
dir ./
#dir:持久化數(shù)據(jù)存儲(chǔ)在本地的路徑,如果是在/redis/redis-3.0.6/src下啟動(dòng)的redis-cli,則數(shù)據(jù)會(huì)存儲(chǔ)在當(dāng)前src目錄下
save 900 1
save 300 10
save 60 10000
##snapshot觸發(fā)的時(shí)機(jī),save <seconds> <changes>
##如下為900秒后,至少有一個(gè)變更操作,才會(huì)snapshot
##對(duì)于此值的設(shè)置,需要謹(jǐn)慎,評(píng)估系統(tǒng)的變更操作密集程度
##可以通過“save “””來關(guān)閉snapshot功能
#save時(shí)間,以下分別表示更改了1個(gè)key時(shí)間隔900s進(jìn)行持久化存儲(chǔ);更改了10個(gè)key300s進(jìn)行存儲(chǔ);更改10000個(gè)key60s進(jìn)行存儲(chǔ)。
stop-writes-on-bgsave-error yes
##當(dāng)snapshot時(shí)出現(xiàn)錯(cuò)誤無法繼續(xù)時(shí),是否阻塞客戶端“變更操作”,“錯(cuò)誤”可能因?yàn)榇疟P已滿/磁盤故障/OS級(jí)別異常等
rdbcompression yes
##是否啟用rdb文件壓縮,默認(rèn)為“yes”,壓縮往往意味著“額外的cpu消耗”,同時(shí)也意味這較小的文件尺寸以及較短的網(wǎng)絡(luò)傳輸時(shí)間
AOF
AOF,英文是Append Only File ,即只允許追加不允許改寫的文件。
AOF,將redis執(zhí)行過得所有寫指令(每秒鐘),記錄在日志里,再次redis重新啟動(dòng)時(shí)只要把這些寫指令從前到后再重復(fù)執(zhí)行一遍,就可實(shí)現(xiàn)數(shù)據(jù)恢復(fù)。
特點(diǎn)
實(shí)時(shí)性
完整性較好
體積大
記錄/刪除數(shù)據(jù)的指令,都會(huì)被記錄?;謴?fù)速度慢于RDB。
開啟AOF
vim /redis-4.0.9/redis.conf
appendonly yes
##此選項(xiàng)為aof功能的開關(guān),默認(rèn)為“no”,可以通過“yes”來開啟aof功能
##只有在“yes”下,aof重寫/文件同步等特性才會(huì)生效
appendfilename appendonly.aof
##指定aof文件名稱
appendfsync everysec
##指定aof操作中文件同步策略,有三個(gè)合法值:always everysec no,默認(rèn)為everysec
no-appendfsync-on-rewrite no
##在aof-rewrite期間,appendfsync是否暫緩文件同步,"no"表示“不暫緩”,“yes”表示“暫緩”,默認(rèn)為“no”
auto-aof-rewrite-min-size 64mb
##aof文件rewrite觸發(fā)的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才會(huì)觸發(fā)rewrite,默認(rèn)“64mb”,建議“512mb”
auto-aof-rewrite-percentage 100
##相對(duì)于“上一次”rewrite,本次rewrite觸發(fā)時(shí)aof文件應(yīng)該增長(zhǎng)的百分比。
##每一次rewrite之后,redis都會(huì)記錄下此時(shí)“新aof”文件的大小(例如A),那么當(dāng)aof文件增長(zhǎng)到A*(1 + p)之后
##觸發(fā)下一次rewrite,每一次aof記錄的添加,都會(huì)檢測(cè)當(dāng)前aof文件的尺寸。
默認(rèn)的AOF持久化策略
每秒鐘fsync(把緩存中的寫指令記錄到磁盤中)一次,在這種情況下,redis,仍可以保持良好的處理性能,即使redis故障也只會(huì)丟失最近一秒的數(shù)據(jù)。
AOF日志修復(fù)
若在追加日志時(shí),恰好遇到磁盤空間滿,inode滿或斷電等情況導(dǎo)致日志寫入不完整,redis并不會(huì)貿(mào)然加載這個(gè)有問題的AOF文件,而是報(bào)錯(cuò)退出。
可使用redis的提供的redis-check-aof工具,可以用來進(jìn)行日志修復(fù)。
1.備份被寫壞的AOF文件
2.運(yùn)行redis-check-aof –fix進(jìn)行修復(fù)
3.用diff -u來看下兩個(gè)文件的差異,確認(rèn)問題點(diǎn)
4.重啟redis,加載修復(fù)后的AOF文件
AOF重寫
AOF使用追加模式,若不做任何處理,AOF文件會(huì)越來越大,因此,redis提供了重寫機(jī)制(rewrite)機(jī)制。
文件重寫機(jī)制(rewrite):當(dāng)AOF文件大小超過所設(shè)定的閾值時(shí),redis會(huì)啟動(dòng)AOF的內(nèi)容壓縮,只保留可以恢復(fù)數(shù)據(jù)的最小指令集。
原理:
重寫即將開始之際,redis會(huì)創(chuàng)建(fork)一個(gè)“重寫子進(jìn)程”,這個(gè)子進(jìn)程會(huì)首先讀取現(xiàn)有的AOF文件,并將其包含的指令進(jìn)行分析壓縮并寫入到一個(gè)臨時(shí)文件中。
與此同時(shí),主工作進(jìn)程會(huì)將新接收到的寫指令一邊累積到內(nèi)存緩沖區(qū)中,一邊繼續(xù)寫入到原有的AOF文件中,這樣做是保證原有的AOF文件的可用性,避免在重寫過程中出現(xiàn)意外。
當(dāng)“重寫子進(jìn)程”完成重寫工作后,它會(huì)給父進(jìn)程發(fā)一個(gè)信號(hào),父進(jìn)程收到信號(hào)后就會(huì)將內(nèi)存中緩存的寫指令追加到新AOF文件中。
當(dāng)追加結(jié)束后,redis就會(huì)用新AOF文件來代替舊AOF文件,之后再有新的寫指令,就都會(huì)追加到新的AOF文件中了。
通過AOF恢復(fù)數(shù)據(jù)
若意外執(zhí)行了FLUSHALL,導(dǎo)致redis內(nèi)存中數(shù)據(jù)被清空。只要redis配置了AOF持久化方式,且AOF文件還沒被重寫,可以執(zhí)行以下操作恢復(fù)。
暫停redis
編輯AOF文件將最后一行的FLUSHALL刪除
重啟redis
持久化選擇RDB和AOF的選擇方式
官方建議兩個(gè)同時(shí)使用這樣可以提供更可靠的持久化方案。
這種情況下redis重啟的話,會(huì)優(yōu)先采用AOF方式來進(jìn)行數(shù)據(jù)恢復(fù)(AOF恢復(fù)數(shù)據(jù)完整度更高。)
AOF寫入數(shù)據(jù)快,RDB寫入速度慢
如果沒有數(shù)據(jù)持久化需求,可以關(guān)閉RDB和AOF方式,這樣的話redis將變成一個(gè)純內(nèi)存數(shù)據(jù)庫(kù),就像memcache一樣。
redis主從、哨兵`
主從同步
redis同mysql一樣支持主從同步(同時(shí)也支持一主多從以及多級(jí)從結(jié)構(gòu))
redis的主從同步是異步進(jìn)行的,這種模式的優(yōu)點(diǎn)是主從同步不會(huì)影響主邏輯,也不會(huì)降低redis的處理性能。
使用主從結(jié)構(gòu)的原因
純碎的冗余備份
提升讀性能,比如很小號(hào)性能的SORT就可以有從服務(wù)器來承擔(dān)。
優(yōu)化
可以考慮關(guān)閉主服務(wù)器的數(shù)據(jù)持久化功能,只讓從服務(wù)器持久化,這樣可以提高主服務(wù)器的處理性能。
將從服務(wù)器設(shè)置為只讀模式,這樣可以避免從服務(wù)器數(shù)據(jù)被誤修改,但從服務(wù)器仍然可以接受CONRG指令,因此不應(yīng)將從服務(wù)器直接暴露到不安全的網(wǎng)絡(luò)環(huán)境中。(如必須如此,那可以考慮給重要指令進(jìn)行重命名。)
原理
1.如果設(shè)置了一個(gè)Slave,無論是第一次連接還是重連到Master,它都會(huì)發(fā)出一個(gè)SYNC命令;
2.當(dāng)Master收到SYNC命令之后,會(huì)做兩件事:
a) Master執(zhí)行BGSAVE,即在后臺(tái)保存數(shù)據(jù)到磁盤(rdb快照文件);
b) Master同時(shí)將新收到的寫入和修改數(shù)據(jù)集的命令存入緩沖區(qū)(非查詢類);
3.當(dāng)Master在后臺(tái)把數(shù)據(jù)保存到快照文件完成之后,Master會(huì)把這個(gè)快照文件傳送給Slave,而Slave則把內(nèi)存清空后,加載該文件到內(nèi)存中;
4.而Master也會(huì)把此前收集到緩沖區(qū)中的命令,通過Reids命令協(xié)議形式轉(zhuǎn)發(fā)給Slave,Slave執(zhí)行這些命令,實(shí)現(xiàn)和Master的同步;
5.Master/Slave此后會(huì)不斷通過異步方式進(jìn)行命令的同步,達(dá)到最終數(shù)據(jù)的同步一致;
6.需要注意的是Master和Slave之間一旦發(fā)生重連都會(huì)引發(fā)全量同步操作。但在2.8之后版本,也可能是部分同步操作。
部分復(fù)制
2.8開始,當(dāng)Master和Slave之間的連接斷開之后,他們之間可以采用持續(xù)復(fù)制處理方式代替采用全量同步。
Master端為復(fù)制流維護(hù)一個(gè)內(nèi)存緩沖區(qū)(in-memory backlog),記錄最近發(fā)送的復(fù)制流命令;同時(shí),Master和Slave之間都維護(hù)一個(gè)復(fù)制偏移量(replication offset)和當(dāng)前Master服務(wù)器ID(Masterrun id)。當(dāng)網(wǎng)絡(luò)斷開,Slave嘗試重連時(shí):
a. 如果MasterID相同(即仍是斷網(wǎng)前的Master服務(wù)器),并且從斷開時(shí)到當(dāng)前時(shí)刻的歷史命令依然在Master的內(nèi)存緩沖區(qū)中存在,則Master會(huì)將缺失的這段時(shí)間的所有命令發(fā)送給Slave執(zhí)行,然后復(fù)制工作就可以繼續(xù)執(zhí)行了;
b. 否則,依然需要全量復(fù)制操作;
sentinel
sentinel(哨兵)
Sentinel(哨兵)是用于監(jiān)控redis集群中Master狀態(tài)的工具,其已經(jīng)被集成在redis2.4+的版本中
setinel作用
1.Master狀態(tài)檢測(cè)
2.如果Master異常,則會(huì)進(jìn)行Master-Slave切換,將其中一個(gè)Slave作為Master,將之前的Master作為Slave
3.Master-Slave切換后,master_redis.conf、slave_redis.conf和sentinel.conf的內(nèi)容都會(huì)發(fā)生改變,即master_redis.conf中會(huì)多一行slaveof的配置,sentinel.conf的監(jiān)控目標(biāo)會(huì)隨之調(diào)換
sentinel工作方式
1.每個(gè)Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其他 Sentinel 實(shí)例發(fā)送一個(gè) PING 命令
2.如果一個(gè)實(shí)例(instance)距離最后一次有效回復(fù) PING 命令的時(shí)間超過 down-after-milliseconds 選項(xiàng)所指定的值, 則這個(gè)實(shí)例會(huì)被 Sentinel 標(biāo)記為主觀下線。
3.如果一個(gè)Master被標(biāo)記為主觀下線,則正在監(jiān)視這個(gè)Master的所有 Sentinel 要以每秒一次的頻率確認(rèn)Master的確進(jìn)入了主觀下線狀態(tài)。 an>
4.當(dāng)有足夠數(shù)量的 Sentinel(大于等于配置文件指定的值)在指定的時(shí)間范圍內(nèi)確認(rèn)Master的確進(jìn)入了主觀下線狀態(tài), 則Master會(huì)被標(biāo)記為客觀下線
5.在一般情況下, 每個(gè) Sentinel 會(huì)以每 10 秒一次的頻率向它已知的所有Master,Slave發(fā)送 INFO 命令
6.當(dāng)Master被 Sentinel 標(biāo)記為客觀下線時(shí),Sentinel 向下線的 Master 的所有 Slave 發(fā)送 INFO 命令的頻率會(huì)從 10 秒一次改為每秒一次
7.若沒有足夠數(shù)量的 Sentinel 同意 Master 已經(jīng)下線, Master 的客觀下線狀態(tài)就會(huì)被移除。 若 Master 重新向 Sentinel 的 PING 命令返回有效回復(fù), Master 的主觀下線狀態(tài)就會(huì)被移除。
主觀下線和客觀下線
主觀下線:Subjectively Down,簡(jiǎn)稱 SDOWN,指的是當(dāng)前 Sentinel 實(shí)例對(duì)某個(gè)redis服務(wù)器做出的下線判斷。
客觀下線:Objectively Down, 簡(jiǎn)稱 ODOWN,指的是多個(gè) Sentinel 實(shí)例在對(duì)Master Server做出 SDOWN 判斷,并且通過 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下線判斷,然后開啟failover.
舉個(gè)栗子
環(huán)境
三臺(tái)服務(wù)器保持通訊暢通,并部署redis。
master slave1 slave2
配置主從
master
# vim /etc/redis/6379.conf
master:
bind 0.0.0.0 //監(jiān)控本地所有網(wǎng)卡IP
protected-mode no
slave1/2
# vim /etc/redis/6379.conf
bind 0.0.0.0
slaveof master_ip master_port //修改master_ip和port
protected-mode no
測(cè)試
# /redis-4.0.9/src/redis-cli
127.0.0.1:6379> info replication
master結(jié)果
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.0.113,port=6379,state=online,offset=2212,lag=1
slave1:ip=192.168.0.112,port=6379,state=online,offset=2212,lag=0
slave結(jié)果
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.0.109
master_port:6379
master_link_status:up
配置sentienl
1.每臺(tái)機(jī)器上修改redis主配置文件設(shè)置:bind 0.0.0.0
2.每臺(tái)機(jī)器上修改sentinel配置文件:添加如下配置
# vim /redis-4.0.9/sentinel.conf
sentinel monitor mymaster MASTERIP 6379 2
//當(dāng)集群中有2個(gè)sentinel認(rèn)為master死了時(shí),才能真正認(rèn)為該master已經(jīng)不可用了。
sentinel down-after-milliseconds mymaster 3000 //單位毫秒
sentinel failover-timeout mymaster 10000
protected-mode no
3.每臺(tái)機(jī)器啟動(dòng)服務(wù)
# ./src/redis-sentinel sentinel.conf
4.關(guān)閉主服務(wù)器,觀察從服務(wù)器狀態(tài)
# /redis-4.0.9/src/redis-cli
#info replication