1、總結(jié)tomcat優(yōu)化方法
外部環(huán)境JVM優(yōu)化
heap內(nèi)存分配
主要是對(duì)JVM組成中的Runtime Data Areas(運(yùn)行時(shí)數(shù)據(jù)區(qū))進(jìn)行優(yōu)化,在運(yùn)行時(shí)數(shù)據(jù)區(qū)中,heap(堆)存放的是創(chuàng)建的所有對(duì)象信息,是優(yōu)化的重點(diǎn)目標(biāo),調(diào)整或限制內(nèi)存的使用可以防止影響其他程序。
- 內(nèi)存分配可以配置最大值和初始值,建議將兩個(gè)值設(shè)置為一樣
- -Xms:設(shè)置年輕代+老年代的初始heap內(nèi)存大??;-Xmx:設(shè)置最大堆內(nèi)存;可以通過(guò)-Xmn同時(shí)設(shè)置兩則的值;
- -XX:NewSize:設(shè)置初始新生代大小;-XX:MaxNewSize:設(shè)置最大新生代內(nèi)存空間;
- -XX:NewRatio:以比例方式設(shè)置新生代和老年代;-XX:SurvivorRatio:以比例方式設(shè)置eden和survivor
垃圾回收器
heap是依靠GC垃圾回收器進(jìn)行管理的,垃圾回收器的功能主要是保證正常釋放不再使用的內(nèi)存空間,同時(shí)還需要盡可能的確保內(nèi)存空間的連續(xù)性。
通過(guò)將堆內(nèi)存進(jìn)行分代,分為年輕代、老年代、永久代,對(duì)不同代內(nèi)的對(duì)象執(zhí)行不同的垃圾回收策略。
- 年輕代可以分為eden區(qū)、幸存區(qū),幸存區(qū)是兩個(gè)大小相等、地位相同、可互換的區(qū),一個(gè)from區(qū),一個(gè)to區(qū)。
- 年輕代的垃圾回收策略采用的是標(biāo)記-清除+復(fù)制方式,新對(duì)象在eden區(qū)被創(chuàng)建,當(dāng)eden區(qū)滿(mǎn)后標(biāo)記存活對(duì)象,將存活對(duì)象復(fù)制到幸存區(qū);此后每當(dāng)eden區(qū)滿(mǎn),都會(huì)對(duì)eden區(qū)和幸存區(qū)的對(duì)象執(zhí)行標(biāo)記-清除,并將存活對(duì)象復(fù)制到另外一個(gè)幸存區(qū)(幸存區(qū)有兩個(gè),每次復(fù)制算法會(huì)使用其中一個(gè));
- 老年代:用于存放長(zhǎng)時(shí)間存活的對(duì)象
- 當(dāng)一個(gè)對(duì)象在年輕代被執(zhí)行了默認(rèn)15次復(fù)制(CMS垃圾回收器默認(rèn)6次,通過(guò)-XX:MaxTenuringThreshold=N來(lái)修改);或者當(dāng)一個(gè)幸存區(qū)與eden區(qū)都滿(mǎn)了時(shí),存活的對(duì)象將被復(fù)制到老年代;
- 老年代如果滿(mǎn)了,就會(huì)對(duì)所有heap區(qū)執(zhí)行清理,所有區(qū)域都觸發(fā)垃圾回收,老年代執(zhí)行的是標(biāo)記-壓縮算法,將幸存對(duì)象標(biāo)記,清理不帶標(biāo)記的對(duì)象后,將幸存對(duì)象向內(nèi)存的一端移動(dòng),整理后存活對(duì)象連續(xù)的集中在內(nèi)存的一端。
- 永久代:此空間不存在垃圾回收,關(guān)閉JVM會(huì)釋放區(qū)域內(nèi)存。此空間必須制定大小限制。
常用垃圾收集器:
- 新生代:serial、ParNew、Parallel Scavenge
- serial是獨(dú)占、串行的,只有一個(gè)線(xiàn)程執(zhí)行垃圾回收;
- -XX:+UseSerialGC:在新生代使用serial垃圾收集器,在老年代使用SerialOld垃圾回收器
- 獨(dú)占,指的是垃圾回收器工作期間工作線(xiàn)程需要等待回收完畢后才能繼續(xù)執(zhí)行;獨(dú)占和并發(fā)指的是垃圾回收進(jìn)程和工作進(jìn)程之間是否能同時(shí)工作。
- 串行,指的是單個(gè)垃圾回收器線(xiàn)程來(lái)完成回收工作;并行和串行是指的回收線(xiàn)程是多個(gè)并行還是單個(gè)串行。
- ParNew是并行、獨(dú)占的,與serial除了多線(xiàn)程外沒(méi)有區(qū)別,老年代經(jīng)常和CMS配合使用,關(guān)注的重點(diǎn)是盡量縮短垃圾收集時(shí)用戶(hù)線(xiàn)程的停頓時(shí)間,比較適合與用戶(hù)交互的程序,能夠提高響應(yīng)速度,提升用戶(hù)體驗(yàn)
- -XX:+UseParNewGC,手動(dòng)指定使用ParNew收集器執(zhí)行內(nèi)存回收;
- -XX:ParallelGCThreads,限制線(xiàn)程數(shù)量,默認(rèn)開(kāi)啟和CPU相同數(shù)量的線(xiàn)程數(shù)。
- Parallel Scavenge:并行、獨(dú)占,可動(dòng)態(tài)調(diào)節(jié)達(dá)到一個(gè)可控制的吞吐量
- -XX:+UseParallelGC,在新生代啟用Parallel Scavenge垃圾收集器
- 通過(guò)兩個(gè)參數(shù)來(lái)精確控制吞吐量。
- 一個(gè)是控制最大垃圾收集停頓時(shí)間的-XX:MaxGCPauseMillis;讓收集器盡可能保證內(nèi)存花費(fèi)時(shí)間不超過(guò)這個(gè)參數(shù)設(shè)置的毫秒數(shù),但并不是加快收集速度,而是會(huì)動(dòng)態(tài)調(diào)整收集頻率,因?yàn)橄到y(tǒng)會(huì)將新生代內(nèi)存空間調(diào)小來(lái)加快速度。
- 以及直接設(shè)置吞吐量大小的-XX:GCTimeRatio,垃圾收集時(shí)間占總時(shí)間的比率。
- -XX:+UseAdaptiveSizePolicy,打開(kāi)后不需要手動(dòng)指定內(nèi)存分配,JVM會(huì)根據(jù)系統(tǒng)運(yùn)行情況收集新能監(jiān)控信息,動(dòng)態(tài)調(diào)整參數(shù)以提供最合適的停頓時(shí)間或者最大的吞吐量,這個(gè)就叫做GC自適應(yīng)調(diào)節(jié)策略。這是ParNew和Parallel Scavenge的最大區(qū)別。
- Parallel Scavenge不能和老年代垃圾收集器CMS組合。
- serial是獨(dú)占、串行的,只有一個(gè)線(xiàn)程執(zhí)行垃圾回收;
- 老年代:Serial Old、Parallel Old、CMS(Concurrent Mark Sweep)
- Serial Old,是serial的老年代版本,串行、獨(dú)占
- Parallel Old:老年代的Parallel Scavenge,并行、獨(dú)占,也是關(guān)注吞吐量
- -XX:+UseParallelOldGC,老年代使用Parallel Old垃圾回收器
- -XX:ParallelGCThreads=N,在關(guān)注吞吐量的場(chǎng)景使用此選項(xiàng)增加并行線(xiàn)程數(shù)
- CMS:并發(fā)標(biāo)記清除算法,特點(diǎn)是在某些階段,比如并發(fā)標(biāo)記時(shí),盡量和工作線(xiàn)程一起運(yùn)行來(lái)減少STW的時(shí)長(zhǎng)(200ms以?xún)?nèi),STW是垃圾收集時(shí)工作線(xiàn)程會(huì)停止工作,所以叫StopTheWorld),提升響應(yīng)速度。
- CMS在初始標(biāo)記(只標(biāo)記GC Roots能直接關(guān)聯(lián)到的對(duì)象,速度很快)、重新標(biāo)記(修正并發(fā)標(biāo)記期間,用戶(hù)線(xiàn)程產(chǎn)生的垃圾)是串行的,會(huì)產(chǎn)生STW,其他并發(fā)標(biāo)記、并發(fā)清理都是并行的,并且這些階段的耗時(shí)更長(zhǎng),所以總體是并發(fā)的。
- -XX:+UseConcMarkSweepGC,開(kāi)啟老年代CMS垃圾回收器,啟動(dòng)后默認(rèn)自動(dòng)開(kāi)啟新生代ParNew
Tomcat自身優(yōu)化
對(duì)JVM的內(nèi)存空間優(yōu)化選項(xiàng)
JAVA_OPTS="-server -Xms4g -Xmx4g -XX:NewSize= -XX:MaxNewSize= "
-server:服務(wù)器模式
-Xms:堆內(nèi)存初始化大小
-Xmx:堆內(nèi)存空間上限
-XX:NewSize=:新生代空間初始化大小
-XX:MaxNewSize=:新生代空間最大值
#生產(chǎn)優(yōu)化案例
JAVA_OPTS="-server -Xms4g -Xmx4g -Xss512k -Xmn1g -XX:CMSInitiatingOccupancyFraction=65 -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=10 -XX:NewRatio=2 -XX:PermSize=128m -XX:MaxPermSize=512m -XX:CMSFullGCsBeforeCompaction=5 -XX:+ExplicitGCInvokesConcurrent -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods"
線(xiàn)程池的調(diào)整,調(diào)整Connector的參數(shù)
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
-
connectionTimeout:連接超時(shí)時(shí)長(zhǎng),單位ms -
maxThreads:最大線(xiàn)程數(shù),默認(rèn)200 -
minSpareThreads:最小空閑線(xiàn)程數(shù) -
maxSpareThreads:最大空閑線(xiàn)程數(shù) -
acceptCount:當(dāng)啟動(dòng)線(xiàn)程滿(mǎn)了之后,等待隊(duì)列的最大長(zhǎng)度,默認(rèn)100 -
URIEncoding:URI 地址編碼格式,建議使用 UTF-8 -
enableLookups:是否啟用客戶(hù)端主機(jī)名的DNS反向解析,缺省禁用,建議禁用,就使用客戶(hù)端IP就行 -
compression:是否啟用傳輸壓縮機(jī)制,建議 "on",CPU和流量的平衡-
compressionMinSize:?jiǎn)⒂脡嚎s傳輸?shù)臄?shù)據(jù)流最小值,單位是字節(jié) -
compressableMimeType:定義啟用壓縮功能的MIME類(lèi)型text/html, text/xml, text/css, text/javascript
-
2、java程序出現(xiàn)oom如何解決?什么場(chǎng)景下會(huì)出現(xiàn)oom?
當(dāng)JVM因?yàn)闆](méi)有足夠內(nèi)存來(lái)為對(duì)象分配空間,并且垃圾回收器也沒(méi)有空間可回收時(shí),系統(tǒng)會(huì)出現(xiàn)如下OOM日志:
Jul 10 10:20:30 kernel: Out of memory: Kill process 9527 (java) score 88 or sacrifice child
java的OOM日志:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:674)
at java.lang.StringBuilder.append(StringBuilder.java:208)
at HeapOom2.main(HeapOom2.java:6)
通常出現(xiàn)OOM的原因是:
- 給應(yīng)用分配的內(nèi)存太少,一般是啟動(dòng)時(shí)的JVM參數(shù)指定太少
- 應(yīng)用使用太多,并且用完沒(méi)有釋放,此時(shí)就會(huì)造成內(nèi)存泄漏或內(nèi)存溢出
- 可以通過(guò)JDK工具來(lái)分析原因,如jvisualvm配合Visual GC插件;或通過(guò)商業(yè)軟件profiler定位出現(xiàn)問(wèn)題的代碼
解決思路:
- 限制java進(jìn)程的max heap,并且降低java程序的worker數(shù)量,從而降低內(nèi)存使用
- 給系統(tǒng)增加swap空間
- 設(shè)置內(nèi)核參數(shù),不允許內(nèi)存申請(qǐng)過(guò)量,不推薦的做法;
- linux默認(rèn)是允許內(nèi)存申請(qǐng)過(guò)量的,系統(tǒng)寄希望于實(shí)際上用不到那么多內(nèi)存,但如果出現(xiàn)內(nèi)存過(guò)量時(shí):
- linux通過(guò)OOM killer機(jī)制,挑選一個(gè)進(jìn)程kill來(lái)騰出部分內(nèi)存,還不夠那就繼續(xù)kill
- 也可以通過(guò)vm.panic_on_oom,當(dāng)發(fā)生OOM時(shí)就自動(dòng)重啟系統(tǒng)
- 重啟和kill都可能造成業(yè)務(wù)中斷,linux 2.6之后,允許通過(guò)vm.overcommit_memory內(nèi)核參數(shù)來(lái)禁止memory overcommit
- linux默認(rèn)是允許內(nèi)存申請(qǐng)過(guò)量的,系統(tǒng)寄希望于實(shí)際上用不到那么多內(nèi)存,但如果出現(xiàn)內(nèi)存過(guò)量時(shí):
3、簡(jiǎn)述redis特點(diǎn)及其應(yīng)用場(chǎng)景
redis特點(diǎn):
- 開(kāi)源、遵循BSD協(xié)議、基于內(nèi)存的鍵值數(shù)據(jù)庫(kù)
- 提供將內(nèi)存通過(guò)網(wǎng)絡(luò)遠(yuǎn)程共享的一種服務(wù),類(lèi)似的還有memcached
- redis可以支持10W qps,c語(yǔ)言實(shí)現(xiàn)
- redis是單線(xiàn)程的(基于數(shù)據(jù)庫(kù)的操作是單線(xiàn)程),一個(gè)線(xiàn)程處理所有的網(wǎng)絡(luò)請(qǐng)求,因?yàn)閞edis是純內(nèi)存操作,再加上帶有I/O多路復(fù)用功能
- 支持?jǐn)?shù)據(jù)的持久化,可以將數(shù)據(jù)保存在磁盤(pán)中
- 支持更多的數(shù)據(jù)類(lèi)型:字符串、哈希、list、sets、sorted sets
- 支持?jǐn)?shù)據(jù)備份,可以實(shí)現(xiàn)Master-slave模式的數(shù)據(jù)備份,另外也支持使用快照(內(nèi)存數(shù)據(jù)的快照存儲(chǔ)到rdb文件中)+AOF(類(lèi)似mysql的binlog,將對(duì)數(shù)據(jù)的操作記錄下來(lái))
- 支持更大value的數(shù)據(jù),相比memcached僅支持1MB數(shù)據(jù),redis支持512MB(生產(chǎn)還是不建議超過(guò)2M)
- 支持集群橫向擴(kuò)展,memcached不支持集群功能,是通過(guò)客戶(hù)端根據(jù)hash來(lái)寫(xiě)入不同主機(jī)實(shí)現(xiàn)集群,redis則可以配置多主集群,也能支持集群的橫向擴(kuò)展,集群內(nèi)node本身也支持主備,因此可以同時(shí)提供高可用和性能擴(kuò)展
redis的應(yīng)用場(chǎng)景
- Session共享:常見(jiàn)Web集群中的Tomcat或PHP中的多Web服務(wù)器Session共享
- 緩存:提供數(shù)據(jù)查詢(xún)功能,如商品信息、新聞內(nèi)容等;可以配合mysql,從redis中讀取數(shù)據(jù),寫(xiě)入mysql同時(shí)同步給redis;
- 計(jì)數(shù)器:商品排行榜、商品瀏覽數(shù)和次數(shù)等相關(guān)數(shù)值統(tǒng)計(jì)
- 微博/微信等社交場(chǎng)合:多種數(shù)據(jù)類(lèi)型可以提供共同好友、粉絲數(shù)、關(guān)注、點(diǎn)贊評(píng)論等
- 消息隊(duì)列:ELK的日志緩存、部分業(yè)務(wù)的訂閱發(fā)布系統(tǒng)等
- 地理位置:同樣是基于多種數(shù)據(jù)類(lèi)型,提供定位服務(wù),實(shí)現(xiàn)搖一搖、附近的人、外賣(mài)等功能
4、對(duì)比redis的RDB、AOF模式的優(yōu)缺點(diǎn)
- RDB對(duì)內(nèi)存執(zhí)行快照,保存了某個(gè)時(shí)間點(diǎn)內(nèi)存中的所有數(shù)據(jù),當(dāng)出現(xiàn)問(wèn)題時(shí)可以恢復(fù)到不同時(shí)間點(diǎn)的版本;但RDB不能實(shí)時(shí)保存數(shù)據(jù),會(huì)丟失故障時(shí)到上一個(gè)時(shí)間點(diǎn)之間未保存的數(shù)據(jù);
- RDB是通過(guò)父進(jìn)程fork的子進(jìn)程來(lái)執(zhí)行的保存工作;但如果子進(jìn)程在存在期間,發(fā)生了大量的寫(xiě)操作,會(huì)導(dǎo)致子進(jìn)程執(zhí)行復(fù)制操作,就會(huì)出現(xiàn)很多的page-fault,這樣需要消耗不少性能在復(fù)制上
- AOF的數(shù)據(jù)安全性相對(duì)較高,根據(jù)使用的fsync策略(何時(shí)同步內(nèi)存數(shù)據(jù)到磁盤(pán)),默認(rèn)是1s同步一次,就算發(fā)生故障,也只會(huì)丟失1s內(nèi)的數(shù)據(jù);但根據(jù)fsync的策略不同,aof可能速度慢于rdb
- AOF會(huì)產(chǎn)生重復(fù)記錄,比如對(duì)一個(gè)數(shù)據(jù)執(zhí)行了創(chuàng)建和修改,則創(chuàng)建和修改兩個(gè)操作都會(huì)被記錄;
- AOF在恢復(fù)大數(shù)據(jù)集時(shí)需要比RDB久的時(shí)間,因?yàn)镽DB是直接加載到內(nèi)存,而AOF則需要一條條執(zhí)行操作;
5、實(shí)現(xiàn)redis哨兵,模擬master故障場(chǎng)景
#!/bin/bash
#****************************************************************************************#
#Author: Yabao11
#QQ: what QQ,no QQ
#Date: 2022-01-04
#FileName: nginx.sh
#URL: https://github.com/yabao11
#Description: Test Script
#Copyright (C): 2022 All rights reserved
#*******************************定義顏色*************************************************#
RED="\e[1;31m"
GREEN="\e[1;32m"
SKYBLUE="\e[1;36m"
YELLOW="\e[1;43m"
BLUE="\e[1;44m"
END="\e[0m"
RandomColor="\e[1;32m"
#****************************************************************************************#
function Ostype {
if grep -i -q "release 6" /etc/centos-release;then
echo Centos6
elif grep -i -q Centos-8 /etc/os-release;then
echo Centos
elif grep -i -q Centos-7 /etc/os-release;then
echo Centos7
elif grep -i -q Ubuntu /etc/os-release;then
echo Ubuntu
elif grep -i -q "RedHat" /etc/os-release;then
echo Redhat
fi
}
function color {
RES_COL=60
MOVE_TO_COL="echo -en \E[${RES_COL}G"
SETCOLOR_SUCCESS="echo -en \E[1;32m"
SETCOLOR_FAILURE="echo -en \E[1;31m"
SETCOLOR_WARNING="echo -en \E[1;33m"
SETCOLOR_NORMAL="echo -en \E[0m"
echo -n "$1" && $MOVE_TO_COL
echo -n "["
if [[ $2 = "success" || $2 = "0" ]]; then
${SETCOLOR_SUCCESS}
echo -n " OK "
elif [[ $2 = "failure" || $2 = "1" ]]; then
${SETCOLOR_FAILURE}
echo -n "FAILED"
else
${SETCOLOR_WARNING}
echo -n "WARNING"
fi
${SETCOLOR_NORMAL}
echo -n "]"
echo
}
function redis_install {
yum -y install gcc jemalloc-devel systemd-devel wget || { color "編譯軟件安裝失??!" 1;exit; }
[ -e /root/${redis_version}.tar.gz ] || wget http://download.redis.io/releases/${redis_version}.tar.gz -P /root/
tar xvf ${redis_version}.tar.gz || { color "文件解壓失敗" 1;exit; }
cd ${redis_version}
make USE_SYSTEMD=yes PREFIX=${redis_path} install > /dev.null && color "安裝成功" 0 || color "安裝失敗,檢查配置參數(shù)" 1
echo 'PATH=/data/redis/bin:$PATH' > /etc/profile.d/redis.sh
. /etc/profile.d/redis.sh
id redis || ( useradd -r -s /sbin/nologin redis && color "新增用戶(hù)redis" 0 || color "用戶(hù)redis新建失敗" 1 )
mkdir /data/redis/{etc,log,data,run}
{ cp redis.conf ${redis_path}/etc/;cp sentinel.conf ${redis_path}/etc/; } && color "配置文件復(fù)制完成" 0
chown -R redis.redis ${redis_path} && color "文件權(quán)限修改完畢" 0 || color "文件權(quán)限修改失敗" 1
cat >> /etc/sysctl.conf <<EOF
net.core.somaxconn = 1024
vm.overcommit_memory = 1
EOF
sysctl -p && color "全連接隊(duì)列和內(nèi)存超額分配內(nèi)核參數(shù)修改完成" 0 || color "內(nèi)核參數(shù)修改失敗" 1
echo never > /sys/kernel/mm/transparent_hugepage/enabled && color "關(guān)閉THP(透明大頁(yè))" 0 || "關(guān)閉THP失敗" 1
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
[ -e /lib/systemd/system/redis@.service ] && rm -rf /lib/systemd/system/redis@.service
cat > /lib/systemd/system/redis@.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=${redis_path}/bin/redis-server ${redis_path}/etc/%i.conf --supervised systemd
#ExecStop=/usr/libexec/redis-shutdown
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now redis@redis
}
function redis_config {
sed -i.bak -r -e 's/(^bind\s).*/\10.0.0.0/' \
-e 's/daemonize no/daemonize yes/' \
-e 's|^pidfile.*|pidfile '${redis_path}'/run/redis.pid|' \
-e 's|^logfile.*|logfile '${redis_path}'/log/redis.log|' \
-e 's|^dir.*|dir '${redis_path}'/data|' \
${redis_path}/etc/redis.conf && color "redis.conf配置文件修改完畢!" 0
systemctl restart redis@redis
}
function redis_slave {
while true;do
read -p "是否需要將當(dāng)前節(jié)點(diǎn)配置為slave節(jié)點(diǎn)?" askuser1
askuser1=`echo $askuser1 | tr 'A-Z' 'a-z'`
case $askuser1 in
y|yes)
read -p "輸入主節(jié)點(diǎn)IP地址:" slaveip
if [ -z ${slaveip} ];then
while [ -z ${slaveip} ];do
read -p "請(qǐng)輸入主節(jié)點(diǎn)IP地址:" slaveip
done
fi
echo "replicaof ${slaveip} 6379" >> /data/redis/etc/redis.conf && color "redis.conf配置文件修改完畢!" 0
systemctl restart redis@redis && color "服務(wù)重啟完成!" 0
break
;;
n|no)
break
;;
*)
inputerror
continue
;;
esac
done
}
function sentinel_config {
read -p "輸入主節(jié)點(diǎn)IP地址:" masterip
if [ -z ${masterip} ];then
while [ -z ${masterip} ];do
read -p "請(qǐng)輸入主節(jié)點(diǎn)IP地址:" masterip
done
fi
sed -i.bak -r -e '/#\s+bind\s+127.0.0.1/ibind 0.0.0.0' \
-e 's|^daemonize.*|daemonize yes|' \
-e 's|^logfile.*|logfile '${redis_path}'/log/redis-sentinel.log|' \
-e 's|^sentinel\smonitor\smymaster.*|sentinel monitor mymaster '${masterip}' 6379 2|' \
-e 's|^sentinel\sdown-after-milliseconds.*|sentinel down-after-milliseconds mymaster 3000|' \
${redis_path}/etc/sentinel.conf && color "sentinel配置文件修改成功!" 0
cat > /lib/systemd/system/redis-sentinel.service <<EOF
[Unit]
Description=Redis Sentinel
After=network.target
[Service]
ExecStart=${redis_path}/bin/redis-sentinel ${redis_path}/etc/sentinel.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
User=redis
Group=redis
Type=notify
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl restart redis-sentinel.service
}
read -p "請(qǐng)輸入希望安裝的redis版本,回車(chē)使用默認(rèn)版本:redis-6.2.6" redis
read -p "請(qǐng)輸入希望安裝的redis路徑,回車(chē)使用默認(rèn)路徑:/data/redis" predis
redis_version=${redis:-redis-6.2.6}
redis_path=${predis:-/data/redis}
#exec
PS3="請(qǐng)選擇您要執(zhí)行的操作?。?
MENU="
安裝redis
配置redis
配置為從節(jié)點(diǎn)
配置sentinel
退出
"
select M in $MENU ;do
case $REPLY in
1)
redis_install
;;
2)
redis_config
;;
3)
redis_slave
;;
4)
sentinel_config
;;
*)
exit
;;
esac
done
模擬master故障
正常狀態(tài)下可以看到117是master,下掛兩臺(tái)slave
[root@centos8mini ~]# redis-cli info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.32.121,port=6379,state=online,offset=40797,lag=1
slave1:ip=192.168.32.123,port=6379,state=online,offset=40797,lag=1
master_failover_state:no-failover
master_replid:eac897012d5f8c9e0b884b697fa3ac6b02707613
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:40940
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:40940
模擬master故障,stop redis服務(wù)
[root@centos8mini ~]# cat /data/redis/log/redis-sentinel.log
14655:X 08 Feb 2022 17:47:24.541 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
14655:X 08 Feb 2022 17:47:24.541 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=14655, just started
14655:X 08 Feb 2022 17:47:24.541 # Configuration loaded
14655:X 08 Feb 2022 17:47:24.542 * Increased maximum number of open files to 10032 (it was originally set to 1024).
14655:X 08 Feb 2022 17:47:24.542 * monotonic clock: POSIX clock_gettime
14655:X 08 Feb 2022 17:47:24.543 * Running mode=sentinel, port=26379.
14655:X 08 Feb 2022 17:47:24.544 # Sentinel ID is 2dd2794641405dfb5b747853fc9b4f1610caa887
14655:X 08 Feb 2022 17:47:24.544 # +monitor master mymaster 192.168.32.117 6379 quorum 2
14655:X 08 Feb 2022 17:47:24.546 * +slave slave 192.168.32.121:6379 192.168.32.121 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:47:24.550 * +slave slave 192.168.32.123:6379 192.168.32.123 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:47:25.773 * +sentinel sentinel b4b649e2058e2f3323294833d065ba1c70438e28 192.168.32.123 26379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:47:25.794 * +sentinel sentinel b6b4ffd63334c256f82c638c5487f17c47f31729 192.168.32.121 26379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:22.917 # +sdown master mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:22.971 # +odown master mymaster 192.168.32.117 6379 #quorum 3/2
14655:X 08 Feb 2022 17:50:22.971 # +new-epoch 1
14655:X 08 Feb 2022 17:50:22.971 # +try-failover master mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:22.975 # +vote-for-leader 2dd2794641405dfb5b747853fc9b4f1610caa887 1
14655:X 08 Feb 2022 17:50:22.982 # b4b649e2058e2f3323294833d065ba1c70438e28 voted for 2dd2794641405dfb5b747853fc9b4f1610caa887 1
14655:X 08 Feb 2022 17:50:22.983 # b6b4ffd63334c256f82c638c5487f17c47f31729 voted for 2dd2794641405dfb5b747853fc9b4f1610caa887 1
#sentinel選舉117作為leader
14655:X 08 Feb 2022 17:50:23.059 # +elected-leader master mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:23.059 # +failover-state-select-slave master mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:23.153 # +selected-slave slave 192.168.32.123:6379 192.168.32.123 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:23.153 * +failover-state-send-slaveof-noone slave 192.168.32.123:6379 192.168.32.123 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:23.242 * +failover-state-wait-promotion slave 192.168.32.123:6379 192.168.32.123 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:24.036 # +promoted-slave slave 192.168.32.123:6379 192.168.32.123 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:24.036 # +failover-state-reconf-slaves master mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:24.097 * +slave-reconf-sent slave 192.168.32.121:6379 192.168.32.121 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:25.043 * +slave-reconf-inprog slave 192.168.32.121:6379 192.168.32.121 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:25.043 * +slave-reconf-done slave 192.168.32.121:6379 192.168.32.121 6379 @ mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:25.094 # -odown master mymaster 192.168.32.117 6379
14655:X 08 Feb 2022 17:50:25.094 # +failover-end master mymaster 192.168.32.117 6379
#master發(fā)生了切換,從32.117切換到了32.123
14655:X 08 Feb 2022 17:50:25.094 # +switch-master mymaster 192.168.32.117 6379 192.168.32.123 6379
14655:X 08 Feb 2022 17:50:25.095 * +slave slave 192.168.32.121:6379 192.168.32.121 6379 @ mymaster 192.168.32.123 6379
14655:X 08 Feb 2022 17:50:25.095 * +slave slave 192.168.32.117:6379 192.168.32.117 6379 @ mymaster 192.168.32.123 6379
14655:X 08 Feb 2022 17:50:28.143 # +sdown slave 192.168.32.117:6379 192.168.32.117 6379 @ mymaster 192.168.32.123 6379
在123上查看,已經(jīng)成為了master
[root@centos8mini log]# redis-cli info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.32.121,port=6379,state=online,offset=150486,lag=1
master_failover_state:no-failover
master_replid:ba3c099830aeb8dc6348f663f74cb6cdd73806da
master_replid2:eac897012d5f8c9e0b884b697fa3ac6b02707613
master_repl_offset:150486
second_repl_offset:65405
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:3095
repl_backlog_histlen:147392
121依然是slave,但是指向123
[root@centos8mini bin]# redis-cli info replication
# Replication
role:slave
master_host:192.168.32.123
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:156534
slave_repl_offset:156534
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:ba3c099830aeb8dc6348f663f74cb6cdd73806da
master_replid2:eac897012d5f8c9e0b884b697fa3ac6b02707613
master_repl_offset:156534
second_repl_offset:65405
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:156534