前言:數據庫讀取速度較慢一直是無法解決的問題,大型網站應對的方式主要是使用緩存服務器來緩解這種情況,減少數據庫訪問次數,以提高動態Web等應用的速度、提高可擴展性。
1、簡介
Memcached/redis是高性能的分布式內存緩存服務器,通過緩存數據庫查詢結果,減少數據庫訪問次數,以提高動態Web等應用的速度、 提高可擴展性。
2、memcache
2.1、memcache簡介
memcache特點如下:
- 內置內存存儲方式:數據完全不走硬盤,重啟操作系統會導致全部數據消失。
- 簡單key/value存儲:服務器不關心數據本身的意義及結構,只要是可序列化數據即可,所以極其方便讀取。 存儲項由“鍵、過期時間、可選的標志及數據”四個部分組成;
- 不互相通信的分布式:memcached盡管是“分布式”緩存服務器,但服務器端并沒有分布式功能。 各個memcached不會互相通信以共 享信息,由客戶端決策信息存放位置。
memcache工作流程:
- 檢查用戶請求的數據是緩存中是否有存在,如果有存在的話,只需要直接把請求的數據返回,無需查詢數據庫。
- 如果請求的數據在緩存中找不到,這時候再去查詢數據庫。返回請求數據的同時,把數據存儲到緩存中一份。
- 保持緩存的“新鮮性”,每當數據發生變化的時候(比如,數據有被修改,或被刪除的情況下),要同步的更新緩存信息,確保用戶不會在緩存取到舊的數據。
2.2、memcache部署
下述環境已提前更換阿里基礎倉房,epel源,關閉防火墻和selinux
[root@localhost ~]# yum install -y memcached
修改配置文件
[root@localhost ~]# vim /etc/sysconfig/memcached
[root@localhost ~]# cat /etc/sysconfig/memcached
PORT="11211" # Memcached服務監聽的端口號
USER="memcached" # 運行Memcached服務的用戶
MAXCONN="1024" # 允許的最大并發連接數
CACHESIZE="64" # Memcached的緩存大小,單位為MB,可以根據內存大小進行調整
OPTIONS="" # 其他啟動選項,例如可用于設置內存分配策略或其他配置
啟動memcache
[root@localhost ~]# systemctl start memcached[root@localhost ~]# ps aux | grep memcache
memcach+ 62086 0.0 0.1 344100 1688 ? Ssl 22:20 0:00 /usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024
root 62095 0.0 0.0 112824 988 pts/0 R+ 22:21 0:00 grep --color=auto memcache
嘗試簡單的memcache的使用(實際功能中此處為應用程序邏輯設計,和運維無關,此處僅為測試memcache功能使用)
[root@localhost ~]# yum install -y telnet
[root@localhost ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
set name 0 900 9
liumuquan
STORED
get name
VALUE name 0 9
liumuquan
END
^]
telnet> quit
Connection closed.# 此處set參數解釋# set key的名字 key的id號 緩存過期時間(0為無限) 字符串最大長度
memcache這里簡單整理了一下,主要重心還是放在redis上,redis對于memcache優勢太明顯了。
3、redis
3.1、redis簡介
redis是一個開源的、使用C語言編寫的、支持網絡交互的、可基于內存也可持久化的Key-Value數據庫。目前,Vmware在資助著redis項目的開發和維護。目前使用redis公司主要有暴雪、github、digg等。
redis特點:豐富的數據結構、支持持久化、支持事務(可以做集群分布式保證數據安全)、支持主從。
3.2、redis部署
基礎環境
IP | 角色 |
---|---|
192.168.188.128 | master1 |
安裝redis
[root@localhost ~]# wget http://download.redis.io/releases/redis-4.0.9.tar.gz -O /redis-
[root@localhost ~]# cd /
[root@localhost /]# tar zxf redis-4.0.9.tar.gz
[root@localhost /]# cd redis-4.0.9
[root@localhost redis-4.0.9]# pwd
/redis-4.0.9
[root@localhost redis-4.0.9]# make
配置開機啟動
[root@localhost redis-4.0.9]# mkdir /etc/redis
[root@localhost redis-4.0.9]# cp /redis-4.0.9/redis.conf /etc/redis/6379.conf
[root@localhost redis-4.0.9]# cp /redis-4.0.9/utils/redis_init_script /etc/init.d/redis
編輯啟動文件(此處盡量全文復制,后臺運作容易遺忘)
[root@localhost redis-4.0.9]# vim /etc/init.d/redis
[root@localhost redis-4.0.9]# cat /etc/init.d/redis
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
# chkconfig: 2345 10 90
# description: Start and Stop redisREDISPORT=6379
#EXEC=/usr/local/bin/redis-server
EXEC=/redis-4.0.9/src/redis-server
#CLIEXEC=/usr/local/bin/redis-cli
CLIEXEC=/redis-4.0.9/src/redis-cliPIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/${REDISPORT}.conf"case "$1" instart)if [ -f $PIDFILE ]thenecho "$PIDFILE exists, process is already running or crashed"elseecho "Starting Redis server..."$EXEC $CONF &fi;;stop)if [ ! -f $PIDFILE ]thenecho "$PIDFILE does not exist, process is not running"elsePID=$(cat $PIDFILE)echo "Stopping ..."$CLIEXEC -p $REDISPORT shutdownwhile [ -x /proc/${PID} ]doecho "Waiting for Redis to shutdown ..."sleep 1doneecho "Redis stopped"fi;;*)echo "Please use start or stop as first argument";;
esac
[root@localhost redis-4.0.9]# chmod +x /etc/init.d/redis
[root@localhost redis-4.0.9]# chkconfig --add redis# 這個命令是老版本centos添加開機啟動項用的,這里是按照官方文檔選用的這種方式[root@localhost redis-4.0.9]# chkconfig redis on# 設置redis開機啟動[root@localhost redis-4.0.9]# chkconfig --list注:該輸出結果只顯示 SysV 服務,并不包含
原生 systemd 服務。SysV 配置數據
可能被原生 systemd 配置覆蓋。 要列出 systemd 服務,請執行 'systemctl list-unit-files'。查看在具體 target 啟用的服務請執行'systemctl list-dependencies [target]'。netconsole 0:關 1:關 2:關 3:關 4:關 5:關 6:關
network 0:關 1:關 2:開 3:開 4:開 5:開 6:關
redis 0:關 1:關 2:開 3:開 4:開 5:開 6:關# 這里的0-6對應的是centos的0-6狀態,1是單用戶模式[root@localhost redis-4.0.9]# systemctl daemon-reload# 重新加載自啟動信息[root@localhost redis-4.0.9]# systemctl start redis
[root@localhost redis-4.0.9]# systemctl status redis
redis測試
[root@localhost redis-4.0.9]# /redis-4.0.9/src/redis-cli
127.0.0.1:6379> set name liumuquan
OK
127.0.0.1:6379> get name
"liumuquan"
127.0.0.1:6379>
3.3、redis持久化
3.3.1、持久化簡介
Redis 持久化是指將 Redis 內存中的數據持久化保存到硬盤上,以防止服務器重啟或宕機時數據丟失。在 Redis 中,有兩種主要的持久化方式:RDB(Redis DataBase)和 AOF(Append Only File)。
-
RDB 持久化:
- RDB 持久化通過定期將 Redis 內存中的數據快照寫入磁盤來實現。管理員可以配置 Redis 定期將內存中的數據以快照的形式保存到一個
.rdb
文件中。 - 這種方式類似于拍照,Redis 在指定的時間點將當前的數據狀態保存下來。這種方式適合用于備份,恢復較大數據集時速度較快,因為只需要讀取一個文件即可還原數據。
- RDB 持久化通過定期將 Redis 內存中的數據快照寫入磁盤來實現。管理員可以配置 Redis 定期將內存中的數據以快照的形式保存到一個
-
AOF 持久化:
- AOF 持久化則是通過記錄 Redis 服務器所執行的寫命令(例如 SET、INCR 等)來記錄數據變化。這些命令以追加的方式寫入一個文件中,稱為 AOF 文件。
- 這種方式類似于錄制操作日志,Redis 在執行寫命令時將其追加到文件末尾。當服務器需要恢復時,會重新執行 AOF 文件中的命令,從而重建數據狀態。
- AOF 文件通常比 RDB 文件更大,因為它記錄了每個寫操作,但它提供了更精細的數據恢復和更小的數據丟失風險。
大概可以這么理解:
-
RDB 類比:想象你在玩一個游戲,游戲允許你在每個關卡結束時保存進度。這樣,即使你在下一個關卡失敗,你可以重新加載上一個關卡的進度并繼續游戲。
-
AOF 類比:而 AOF 則像你在玩一個沒有保存功能的游戲,但它可以記錄下你每一步的操作。如果你因為失誤或游戲崩潰而需要重新開始,你可以根據你的操作日志重新執行每一步,從而恢復到你離開的地方,雖然過程有點麻煩,但是保證了你不會丟失任何進度。
兩種方法雖然有不同,但是由于實際使用中的特殊性,當不需要數據安全時兩個全關就行,需要時雙開,因RDB數據不實時,但同時使用兩者時服務器只會找AOF文件,所以RDB留作萬一的手段。
3.3.2、配置redis持久化
RDB默認開啟,查看配置
[root@localhost ~]# vim /redis-4.0.9/redis.confdbfilename dump.rdb
#使用RDB時,持久化存在本地的文件叫dump.rdbdir ./
#持久化數據存儲在本地的路徑save 900 1
save 300 10
save 60 10000
#觸發快照的時機,
#save 多少時間內 被改過多少次
#出發以上條件就會被拍攝快照stop-writes-on-bgsave-error yes
#當snapshot時出現錯誤無法繼續時,是否阻塞客戶端“變更操作”,“錯誤”可能因為磁盤已滿/磁盤故障/OS級別異常等,這里配置的是報錯拒絕繼續寫入rdbcompression yes
#是否啟用rdb文件壓縮,默認為“yes”,壓縮很占用cpu,同時同時可以節省存儲空間和減少網絡傳輸時間
客戶端使用命令進行持久化save存儲
[root@localhost ~]#./redis-cli -h ip -p port save
#前臺進行存儲
[root@localhost ~]#./redis-cli -h ip -p port bgsave
#后臺進行存儲#每次快照持久化都是將內存數據完整寫入到磁盤一次,并不是增量的只同步臟數據。如果數據量大的話,而且寫操作比較多,必然會引起大量的磁盤io操作,可能會嚴重影響性能。
AOF默認關閉,開啟方式
[root@localhost ~]# vim /redis-4.0.9/redis.conf##此選項為aof功能的開關,默認為“no”,可以通過“yes”來開啟aof功能
##只有在“yes”下,aof重寫/文件同步等特性才會生效
appendonly yes appendfilename appendonly.aof
#指定aof文件名稱appendfsync everysec
#指定aof操作中文件同步策略,有三個合法值:always everysec no,默認為everysec
#這行指令設置了 AOF 文件的同步方式。everysec 表示每秒鐘將 AOF 文件同步到磁盤一次,以確保即使系統崩潰,最多丟失一秒鐘的數據。no-appendfsync-on-rewrite no
#在aof-rewrite(重寫)期間,appendfsync是否暫緩文件同步,"no"表示“不暫緩”,“yes”表示“暫緩”,默認為“no”auto-aof-rewrite-min-size 64mb
#觸發aof rewrite的最小文件尺寸auto-aof-rewrite-percentage 100
#這行指令設置了觸發自動 AOF 重寫的增長百分比。100 表示當當前 AOF 文件大小比上一次重寫時的大小增長了 100%(即翻倍)時,觸發自動 AOF 重寫。重寫是為了使aof體積保持最小,而確保保存最完整的數據。
3.4、redis主從
3.4.1、redis主從簡介
-
用法
Redis支持類似于MySQL的主從結構,允許配置一主多從甚至多級從結構。主從結構旨在提供冗余備份和增強讀性能,例如將性能消耗較大的SORT操作分擔給從服務器。Redis的主從同步是異步進行的,不會影響主服務器的主要邏輯或性能。在主從架構中,可以考慮關閉主服務器的數據持久化,由從服務器承擔這一任務,以提高主服務器的處理性能。通常情況下,從服務器設置為只讀,以防止誤修改數據,但仍可接受CONFIG等命令。對于不安全的網絡環境,建議重命名重要命令以避免誤操作。
-
原理
從服務器通過發送SYNC指令向主服務器請求同步。主服務器收到SYNC指令后,會執行BGSAVE命令生成RDB文件進行數據持久化。在持久化期間,主服務器將所有寫操作緩存在內存中。BGSAVE完成后,主服務器將RDB文件發送給從服務器,從服務器將文件存儲到磁盤并加載到內存。然后,主服務器以Redis協議格式將緩存的寫操作發送給從服務器。即使多個從服務器同時發出SYNC指令,主服務器也只執行一次BGSAVE,并將生成的RDB文件發送給所有從服務器。在Redis 2.8版本之前,主從斷開連接后會進行全量數據同步,而2.8版本后支持高效的增量同步,顯著降低了連接斷開恢復成本。主服務器在內存中維護緩沖區,用于存儲將發送給從服務器的內容。如果從服務器與主服務器連接斷開,從服務器會嘗試重新連接,成功后發送“希望同步的主服務器ID”和“希望請求的復制偏移量”。主服務器驗證ID匹配后,檢查緩沖區中是否存在請求的偏移量,并根據需要向從服務器發送增量內容。增量同步功能需要服務器端支持全新的PSYNC指令,該指令從Redis 2.8版本開始提供。
3.4.2、?redis主從部署
3.4.2.1、基礎環境
IP | 角色 |
---|---|
192.168.188.128 | master |
192.168.188.129 | slave1 |
192.168.188.130 | slave2 |
在slave1和slave2上部署上redis
slave1操作如下
[root@localhost /]# tar xf redis-4.0.9.tar.gz
[root@localhost /]# cd /redis-4.0.9
[root@localhost redis-4.0.9]# make
[root@localhost redis-4.0.9]# mkdir /etc/redis
[root@localhost redis-4.0.9]# cp /redis-4.0.9/redis.conf /etc/redis/6379.conf
[root@localhost redis-4.0.9]# cp /redis-4.0.9/utils/redis_init_script /etc/init.d/redis
[root@localhost redis-4.0.9]# vim /etc/init.d/redis
[root@localhost redis-4.0.9]# vim /etc/init.d/redis
[root@localhost redis-4.0.9]# cat /etc/init.d/redis
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
# chkconfig: 2345 10 90
# description: Start and Stop redisREDISPORT=6379
#EXEC=/usr/local/bin/redis-server
EXEC=/redis-4.0.9/src/redis-server
#CLIEXEC=/usr/local/bin/redis-cli
CLIEXEC=/redis-4.0.9/src/redis-cliPIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/${REDISPORT}.conf"case "$1" instart)if [ -f $PIDFILE ]thenecho "$PIDFILE exists, process is already running or crashed"elseecho "Starting Redis server..."$EXEC $CONF &fi;;stop)if [ ! -f $PIDFILE ]thenecho "$PIDFILE does not exist, process is not running"elsePID=$(cat $PIDFILE)echo "Stopping ..."$CLIEXEC -p $REDISPORT shutdownwhile [ -x /proc/${PID} ]doecho "Waiting for Redis to shutdown ..."sleep 1doneecho "Redis stopped"fi;;*)echo "Please use start or stop as first argument";;
esac
[root@localhost redis-4.0.9]# scp /etc/init.d/redis 192.168.188.130:/etc/init.d/
[root@localhost redis-4.0.9]# chmod +x /etc/init.d/redis
[root@localhost redis-4.0.9]# chkconfig --add redis
[root@localhost redis-4.0.9]# chkconfig redis on
[root@localhost redis-4.0.9]# systemctl daemon-reload
[root@localhost redis-4.0.9]# systemctl start redis
slave2操作同slave1
3.4.2.2、master配置
[root@localhost ~]# vim /etc/redis/6379.conf#bind 127.0.0.1
#注釋掉
bind 0.0.0.0
#增加監聽地址為所有ip#protected-mode yes
protected-mode no
#關閉保護模式[root@localhost ~]# systemctl restart redis
3.4.2.3、salve1配置
[root@localhost redis-4.0.9]# vim /etc/redis/6379.confslaveof 192.168.188.128 6379
#bind 127.0.0.1
bind 0.0.0.0
#protected-mode yes
protected-mode no[root@localhost redis-4.0.9]# systemctl restart redis
3.4.2.3、salve2配置
同slave1
3.4.3、redis主從測試
在master上
[root@localhost ~]# /redis-4.0.9/src/redis-cli
127.0.0.1:6379> set your_id 1210
OK
127.0.0.1:6379> get your_id
"1210"
#查詢主從狀態
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.188.129,port=6379,state=online,offset=1557,lag=1
slave1:ip=192.168.188.130,port=6379,state=online,offset=1557,lag=0
master_replid:65eda2694558d007f08f5645d92fb67c4423c265
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1557
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1557
127.0.0.1:6379>
在slave1上
[root@localhost redis-4.0.9]# /redis-4.0.9/src/redis-cli
127.0.0.1:6379> get your_id
"1210"
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.188.128
master_port:6379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_repl_offset:1669
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:65eda2694558d007f08f5645d92fb67c4423c265
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1669
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:253
repl_backlog_histlen:1417
127.0.0.1:6379>
主從架構實現,可以保持數據同步,但此時集群無法實現災備冗余,主服務器宕機時,從服務器此時無法承擔主服務器角色,需要使用redis-sentine來實現。
3.5、redis-sentinel
3.5.1、redis-sentinel簡介
Redis Sentinel是Redis官方推薦的高可用性(HA)解決方案,允許你創建一個能夠自動處理各種故障的Redis部署,無需人工干預。
作用:
- 檢測Master狀態。
- 在Master異常時進行Master-Slave切換,將一個Slave提升為新的Master,原Master降級為Slave。
- 切換后,會自動更新配置文件:master_redis.conf會新增slaveof配置,sentinel.conf中的監控目標也會相應調整。
工作方式:
- 每個Sentinel每秒向已知的Master、Slave和其他Sentinel實例發送PING命令。
- 如果一個實例超過配置的down-after-milliseconds時間未響應PING命令,Sentinel會將其標記為主觀下線。
- Sentinel持續檢查主觀下線的Master狀態,確認是否達到客觀下線條件。
- 當足夠多的Sentinel在指定時間內確認主觀下線狀態時,Master會被標記為客觀下線。
3.5.2、redis-sentinel部署
繼續使用上面的環境
1)每臺機器上修改redis主配置文件設置:bind 0.0.0.0(略)
2)每臺機器上修改sentinel配置文件:
master如下
[root@localhost ~]# vim /redis-4.0.9/sentinel.conf
#sentinel monitor mymaster 127.0.0.1 6379 2
sentinel monitor mymaster 192.168.188.128 6379 2# 當集群中有2個(超過半數)sentinel認為master死了時,才能真正認為該master已經不可用了。#sentinel down-after-milliseconds mymaster 30000
sentinel down-after-milliseconds mymaster 3000# 3秒內沒收到有效回復后認定主服務器離線(默認30秒)#sentinel failover-timeout mymaster 180000
sentinel failover-timeout mymaster 10000# 故障發生后10秒內完成選舉,若sentinel在該配置值內未能完成failover(故障轉移)操作(即故障時master/slave自動切換),則認為本次failover失敗。# protected-mode no
protected-mode no# 關閉保護模式
slave1、slave2同上
3)啟動哨兵,三臺都要啟動
[root@localhost ~]# cd /redis-4.0.9
[root@localhost redis-4.0.9]# ./src/redis-sentinel sentinel.conf
3.5.3、redis-sentinel測試
關閉主服務器,觀察從服務器改變狀態
在master上使用ctrl+c停止當前進程
[root@localhost redis-4.0.9]# systemctl stop redis
觀察從服務器返回信息
?選舉slave2成為主服務器,slave2狀態如下
[root@localhost redis-4.0.9]# /redis-4.0.9/src/redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.188.129,port=6379,state=online,offset=63531,lag=0
slave1:ip=192.168.188.128,port=6379,state=online,offset=63531,lag=0
master_replid:b417e01353b4a576aaba97987acd33602ba5d9df
master_replid2:bd33fbabce342aeb3ec5c5aa85aaf1a2e5a02b23
master_repl_offset:63676
second_repl_offset:4257
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:63676
127.0.0.1:6379>
3.6、redis使用經驗
- Master的工作不應包括持久化任務,如RDB快照和AOF日志文件。
- 如果數據非常重要,可以讓某個Slave開啟AOF備份數據,設置為每秒同步一次。
- 為了提高主從復制的速度和連接穩定性,最好將Master和Slave部署在同一個局域網內。
- 在主庫壓力較大時,應盡量避免增加從庫,可以通過為現有從庫增加從庫來緩解壓力。
- 主從復制應采用單向鏈表結構而不是樹狀結構,例如:Master(寫) <- Slave1(讀) <- Slave2(讀) <- Slave3(讀)... 這種結構有助于提高穩定性和處理單點故障問題。如果Master宕機,可以立即將Slave1提升為新的Master,其他從庫保持不變。