1、總結(jié)tomcat優(yōu)化方法
由于Tomcat的運(yùn)行依賴于JVM嘶卧,從虛擬機(jī)的角度把Tomcat的調(diào)整分為外部環(huán)境調(diào)優(yōu) JVM 和 Tomcat 自身調(diào)優(yōu)兩部分疮胖。
- 內(nèi)存空間優(yōu)化
Tomcat的JVM參數(shù)設(shè)置
JAVA_OPTS="-server -Xms4g -Xmx4g -XX:NewSize= -XX:MaxNewSize= "
-server:服務(wù)器模式
-Xms:堆內(nèi)存初始化大小
-Xmx:堆內(nèi)存空間上限(不指定時(shí),大約使用總內(nèi)存的1/4)
-XX:NewSize=:新生代空間初始化大小
-XX:MaxNewSize=:新生代空間最大值
生產(chǎn)案例:
[root@centos8 ~]#vim /usr/local/tomcat/bin/catalina.sh
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"
#一臺tomcat服務(wù)器并發(fā)連接數(shù)不高,生產(chǎn)建議分配物理內(nèi)存通常4G到8G較多,如果需要更多連接,一般會利用虛擬化技術(shù)實(shí)現(xiàn)多臺tomcat
- 線程池調(diào)整
常用屬性:
connectionTimeout :連接超時(shí)時(shí)長,單位ms
maxThreads:最大線程數(shù)设易,默認(rèn)200
minSpareThreads:最小空閑線程數(shù)
maxSpareThreads:最大空閑線程數(shù)
acceptCount:當(dāng)啟動線程滿了之后逗柴,等待隊(duì)列的最大長度,默認(rèn)100
URIEncoding:URI 地址編碼格式顿肺,建議使用 UTF-8
enableLookups:是否啟用客戶端主機(jī)名的DNS反向解析戏溺,缺省禁用,建議禁用屠尊,就使用客戶端IP就行
compression:是否啟用傳輸壓縮機(jī)制于购,建議 "on",CPU和流量的平衡- compressionMinSize:啟用壓縮傳輸?shù)臄?shù)據(jù)流最小值知染,單位是字節(jié)
- compressableMimeType:定義啟用壓縮功能的MIME類型text/html, text/xml, text/css,text/javascript
示例:
[root@centos8 ~]#vim /usr/local/tomcat/conf/server.xml
......
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
......
2肋僧、java程序出現(xiàn)oom如何解決?什么場景下會出現(xiàn)oom控淡?
當(dāng)JVM因?yàn)闆]有足夠內(nèi)存來為對象分配空間嫌吠,并且垃圾回收器也沒有空間可回收時(shí),系統(tǒng)會出現(xiàn)如下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)存太少掺炭,一般是啟動時(shí)的JVM參數(shù)指定太少
- 應(yīng)用使用太多辫诅,并且用完沒有釋放,此時(shí)就會造成內(nèi)存泄漏或內(nèi)存溢出
- 可以通過JDK工具來分析原因涧狮,如jvisualvm配合Visual GC插件炕矮;或通過商業(yè)軟件profiler定位出現(xiàn)問題的代碼
解決思路:
- 限制java進(jìn)程的max heap,并且降低java程序的worker數(shù)量者冤,從而降低內(nèi)存使用
- 給系統(tǒng)增加swap空間
- 設(shè)置內(nèi)核參數(shù)肤视,不允許內(nèi)存申請過量,不推薦的做法涉枫;
- linux默認(rèn)是允許內(nèi)存申請過量的邢滑,系統(tǒng)寄希望于實(shí)際上用不到那么多內(nèi)存,但如果出現(xiàn)內(nèi)存過量時(shí):
linux通過OOM killer機(jī)制愿汰,挑選一個進(jìn)程kill來騰出部分內(nèi)存困后,還不夠那就繼續(xù)kill,也可以通過vm.panic_on_oom衬廷,當(dāng)發(fā)生OOM時(shí)就自動重啟系統(tǒng)摇予,重啟和kill都可能造成業(yè)務(wù)中斷,linux 2.6之后吗跋,允許通過vm.overcommit_memory內(nèi)核參數(shù)來禁止memory overcommit
3侧戴、簡述redis特點(diǎn)及其應(yīng)用場景
redis特點(diǎn):
- 速度快: 10W QPS,基于內(nèi)存,C語言實(shí)現(xiàn)
- 單線程
- 持久化
- 支持多種數(shù)據(jù)結(jié)構(gòu)
- 支持多種編程語言
- 功能豐富: 支持Lua腳本,發(fā)布訂閱,事務(wù),pipeline等功能
- 簡單: 代碼短小精悍(單機(jī)核心代碼只有23000行左右),單線程開發(fā)容易,不依賴外部庫,使用簡單
- 主從復(fù)制
- 支持高可用和分布式
redis應(yīng)用場景:
- Session 共享:常見于web集群中的Tomcat或者PHP中多web服務(wù)器session共享
- 緩存:數(shù)據(jù)查詢、電商網(wǎng)站商品信息、新聞內(nèi)容
- 計(jì)數(shù)器:訪問排行榜救鲤、商品瀏覽數(shù)等和次數(shù)相關(guān)的數(shù)值統(tǒng)計(jì)場景
- 微博/微信社交場合:共同好友,粉絲數(shù),關(guān)注,點(diǎn)贊評論等
- 消息隊(duì)列:ELK的日志緩存久窟、部分業(yè)務(wù)的訂閱發(fā)布系統(tǒng)
- 地理位置: 基于GEO(地理信息定位),實(shí)現(xiàn)搖一搖,附近的人,外賣等功能
4、對比redis的RDB本缠、AOF模式的優(yōu)缺點(diǎn)
- RDB對內(nèi)存執(zhí)行快照斥扛,保存了某個時(shí)間點(diǎn)內(nèi)存中的所有數(shù)據(jù),當(dāng)出現(xiàn)問題時(shí)可以恢復(fù)到不同時(shí)間點(diǎn)的版本丹锹;但RDB不能實(shí)時(shí)保存數(shù)據(jù)稀颁,會丟失故障時(shí)到上一個時(shí)間點(diǎn)之間未保存的數(shù)據(jù);
- RDB是通過父進(jìn)程fork的子進(jìn)程來執(zhí)行的保存工作楣黍;但如果子進(jìn)程在存在期間匾灶,發(fā)生了大量的寫操作,會導(dǎo)致子進(jìn)程執(zhí)行復(fù)制操作租漂,就會出現(xiàn)很多的page-fault阶女,這樣需要消耗不少性能在復(fù)制上
- AOF的數(shù)據(jù)安全性相對較高,根據(jù)使用的fsync策略(何時(shí)同步內(nèi)存數(shù)據(jù)到磁盤)哩治,默認(rèn)是1s同步一次秃踩,就算發(fā)生故障,也只會丟失1s內(nèi)的數(shù)據(jù)业筏;但根據(jù)fsync的策略不同憔杨,aof可能速度慢于rdb
- AOF會產(chǎn)生重復(fù)記錄,比如對一個數(shù)據(jù)執(zhí)行了創(chuàng)建和修改蒜胖,則創(chuàng)建和修改兩個操作都會被記錄消别;
- AOF在恢復(fù)大數(shù)據(jù)集時(shí)需要比RDB久的時(shí)間,因?yàn)镽DB是直接加載到內(nèi)存台谢,而AOF則需要一條條執(zhí)行操作寻狂;
5、實(shí)現(xiàn)redis哨兵对碌,模擬master故障場景
環(huán)境:
初始master節(jié)點(diǎn):192.168.184.101
初始slave1節(jié)點(diǎn):192.168.184.102
初始slave2節(jié)點(diǎn):192.168.184.103
使用腳本安裝所有redis
[root@centos7-01 ~]# cat install_redis.sh
#!/bin/bash
. /etc/init.d/functions
VERSION=redis-6.2.4
PASSWORD=123456
INSTALL_DIR=/apps/redis
install() {
yum -y install gcc jemalloc-devel || { action "安裝軟件包失敗荆虱,請檢查網(wǎng)絡(luò)配置" false ; exit; }
wget http://download.redis.io/releases/${VERSION}.tar.gz || { action "Redis 源碼下載失敗" false ; exit; }
tar xf ${VERSION}.tar.gz
cd ${VERSION}
make -j 4 PREFIX=${INSTALL_DIR} install && action "Redis 編譯安裝完成" || { action "Redis 編譯安裝失敗" false ;exit ; }
ln -s ${INSTALL_DIR}/bin/redis-* /usr/bin/
mkdir -p ${INSTALL_DIR}/{etc,log,data,run}
cp redis.conf ${INSTALL_DIR}/etc/
sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e "/# requirepass/a requirepass $PASSWORD" -e "/^dir .*/c dir ${INSTALL_DIR}/data/" -e "/logfile .*/c logfile ${INSTALL_DIR}/log/redis-6379.log" -e "/^pidfile .*/c pidfile ${INSTALL_DIR}/run/redis_6379.pid" ${INSTALL_DIR}/etc/redis.conf
if id redis &> /dev/null ;then
action "Redis 用戶已存在" false
else
useradd -r -s /sbin/nologin redis
action "Redis 用戶創(chuàng)建成功"
fi
chown -R redis.redis ${INSTALL_DIR}
cat >> /etc/sysctl.conf <<EOF
net.core.somaxconn = 1024
vm.overcommit_memory = 1
EOF
sysctl -p
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
/etc/rc.d/rc.local
cat > /usr/lib/systemd/system/redis.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
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 &> /dev/null && action "Redis 服務(wù)啟動成功,Redis信息如下:" || { action "Redis 啟動失敗" false ;exit; }
redis-cli -a $PASSWORD INFO Server 2> /dev/null
}
install
在所有主從節(jié)點(diǎn)配置
[root@centos7-01 ~]# vi /apps/redis/etc/redis.conf
bind 0.0.0.0
masterauth 123456
requirepass 123456
在所有從節(jié)點(diǎn)配置
[root@centos7-02 ~]# echo "replicaof 192.168.184.101 6379" >> /apps/redis/etc/redis.conf
[root@centos7-02 ~]# systemctl restart redis
測試主從復(fù)制
#查看master狀態(tài)
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.184.102,port=6379,state=online,offset=351,lag=1
slave1:ip=192.168.184.103,port=6379,state=online,offset=351,lag=1
master_failover_state:no-failover
master_replid:6a5cf39edbeb45dd6b91eaa3cedcaf55bff50674
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:351
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:351
#在master寫數(shù)據(jù)
[root@centos7-01 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> set name test1
OK
#在slave查看數(shù)據(jù)
[root@centos7-02 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> get name
"test1"
配置哨兵
所有redis節(jié)點(diǎn)使用相同的以下示例的配置文件
[root@centos7-01 ~]# grep -vE '^#|^$' /apps/redis/etc/redis-sentinel.conf
bind 0.0.0.0
port 26379
daemonize yes
pidfile /apps/redis/run/redis-sentinel.pid
logfile "/apps/redis/log/sentinel_26379.log"
dir /tmp
sentinel monitor mymaster 192.168.184.101 6379 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 3000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
將配置文件復(fù)制到slave節(jié)點(diǎn)
[root@centos7-01 ~]# scp /apps/redis/etc/redis-sentinel.conf 192.168.184.102:/apps/redis/etc/
[root@centos7-01 ~]# scp /apps/redis/etc/redis-sentinel.conf 192.168.184.103:/apps/redis/etc/
在所有節(jié)點(diǎn)生成新的service文件
[root@centos7-01 ~]# cat /lib/systemd/system/redis-sentinel.service
[Unit]
Description=Redis Sentinel
After=network.target
[Service]
ExecStart=/apps/redis/bin/redis-sentinel /apps/redis/etc/redis-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
所有節(jié)點(diǎn)配置目錄權(quán)限,啟動sentinel
[root@centos7-01 ~]# chown -R redis.redis /apps/redis/
[root@centos7-01 ~]# systemctl daemon-reload
[root@centos7-01 ~]# systemctl enable --now redis-sentinel
查看sentinel狀態(tài)
[root@centos7-01 ~]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.184.101:6379,slaves=2,sentinels=3
模擬101master節(jié)點(diǎn)故障
[root@centos7-01 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> shutdown
not connected>
102slave已提升為主節(jié)點(diǎn)
#查看slave節(jié)點(diǎn)日志
[root@centos7-01 ~]# tail -f /apps/redis/log/sentinel_26379.log
31252:X 18 May 2022 08:07:13.148 # +sdown master mymaster 192.168.184.101 6379
31252:X 18 May 2022 08:07:13.177 # +new-epoch 1
31252:X 18 May 2022 08:07:13.178 # +vote-for-leader d8410373cb35a36984fb25a19c236f16c3d6e74d 1
31252:X 18 May 2022 08:07:13.240 # +odown master mymaster 192.168.184.101 6379 #quorum 3/2
31252:X 18 May 2022 08:07:13.240 # Next failover delay: I will not start a failover before Wed May 18 08:13:13 2022
31252:X 18 May 2022 08:07:14.289 # +config-update-from sentinel d8410373cb35a36984fb25a19c236f16c3d6e74d 192.168.184.103 26379 @ mymaster 192.168.184.101 6379
31252:X 18 May 2022 08:07:14.289 # +switch-master mymaster 192.168.184.101 6379 192.168.184.102 6379
31252:X 18 May 2022 08:07:14.290 * +slave slave 192.168.184.103:6379 192.168.184.103 6379 @ mymaster 192.168.184.102 6379
31252:X 18 May 2022 08:07:14.290 * +slave slave 192.168.184.101:6379 192.168.184.101 6379 @ mymaster 192.168.184.102 6379
31252:X 18 May 2022 08:07:17.291 # +sdown slave 192.168.184.101:6379 192.168.184.101 6379 @ mymaster 192.168.184.102 6379
# 查看102slave節(jié)點(diǎn)狀態(tài)
[root@centos7-02 ~]# redis-cli -a 123456 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.184.103,port=6379,state=online,offset=130524,lag=1
master_failover_state:no-failover
master_replid:7103af6186691a2d95490d649ce39ac48203caf6
master_replid2:6a5cf39edbeb45dd6b91eaa3cedcaf55bff50674
master_repl_offset:130669
second_repl_offset:92695
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:130669
#查看102slave節(jié)點(diǎn)sentinel狀態(tài)
[root@centos7-02 ~]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.184.102:6379,slaves=2,sentinels=3
恢復(fù)101redis
[root@centos7-01 ~]# systemctl start redis
[root@centos7-01 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.184.102
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:195382
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:7103af6186691a2d95490d649ce39ac48203caf6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:195382
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:191417
repl_backlog_histlen:3966
#原master節(jié)點(diǎn)恢復(fù)后狀態(tài)為slave