1、总结tomcat优化方法
由于Tomcat的运行依赖于JVM,从虚拟机的角度把Tomcat的调整分为外部环境调优 JVM 和 Tomcat 自身调优两部分。
- 内存空间优化
Tomcat的JVM参数设置
JAVA_OPTS="-server -Xms4g -Xmx4g -XX:NewSize= -XX:MaxNewSize= "
-server:服务器模式
-Xms:堆内存初始化大小
-Xmx:堆内存空间上限(不指定时,大约使用总内存的1/4)
-XX:NewSize=:新生代空间初始化大小
-XX:MaxNewSize=:新生代空间最大值
生产案例:
[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服务器并发连接数不高,生产建议分配物理内存通常4G到8G较多,如果需要更多连接,一般会利用虚拟化技术实现多台tomcat
- 线程池调整
常用属性:
connectionTimeout :连接超时时长,单位ms
maxThreads:最大线程数,默认200
minSpareThreads:最小空闲线程数
maxSpareThreads:最大空闲线程数
acceptCount:当启动线程满了之后,等待队列的最大长度,默认100
URIEncoding:URI 地址编码格式,建议使用 UTF-8
enableLookups:是否启用客户端主机名的DNS反向解析,缺省禁用,建议禁用,就使用客户端IP就行
compression:是否启用传输压缩机制,建议 "on",CPU和流量的平衡- compressionMinSize:启用压缩传输的数据流最小值,单位是字节
- 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程序出现oom如何解决?什么场景下会出现oom?
当JVM因为没有足够内存来为对象分配空间,并且垃圾回收器也没有空间可回收时,系统会出现如下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)
通常出现OOM的原因是:
- 给应用分配的内存太少,一般是启动时的JVM参数指定太少
- 应用使用太多,并且用完没有释放,此时就会造成内存泄漏或内存溢出
- 可以通过JDK工具来分析原因,如jvisualvm配合Visual GC插件;或通过商业软件profiler定位出现问题的代码
解决思路:
- 限制java进程的max heap,并且降低java程序的worker数量,从而降低内存使用
- 给系统增加swap空间
- 设置内核参数,不允许内存申请过量,不推荐的做法;
- linux默认是允许内存申请过量的,系统寄希望于实际上用不到那么多内存,但如果出现内存过量时:
linux通过OOM killer机制,挑选一个进程kill来腾出部分内存,还不够那就继续kill,也可以通过vm.panic_on_oom,当发生OOM时就自动重启系统,重启和kill都可能造成业务中断,linux 2.6之后,允许通过vm.overcommit_memory内核参数来禁止memory overcommit
3、简述redis特点及其应用场景
redis特点:
- 速度快: 10W QPS,基于内存,C语言实现
- 单线程
- 持久化
- 支持多种数据结构
- 支持多种编程语言
- 功能丰富: 支持Lua脚本,发布订阅,事务,pipeline等功能
- 简单: 代码短小精悍(单机核心代码只有23000行左右),单线程开发容易,不依赖外部库,使用简单
- 主从复制
- 支持高可用和分布式
redis应用场景:
- Session 共享:常见于web集群中的Tomcat或者PHP中多web服务器session共享
- 缓存:数据查询、电商网站商品信息、新闻内容
- 计数器:访问排行榜、商品浏览数等和次数相关的数值统计场景
- 微博/微信社交场合:共同好友,粉丝数,关注,点赞评论等
- 消息队列:ELK的日志缓存、部分业务的订阅发布系统
- 地理位置: 基于GEO(地理信息定位),实现摇一摇,附近的人,外卖等功能
4、对比redis的RDB、AOF模式的优缺点
- RDB对内存执行快照,保存了某个时间点内存中的所有数据,当出现问题时可以恢复到不同时间点的版本;但RDB不能实时保存数据,会丢失故障时到上一个时间点之间未保存的数据;
- RDB是通过父进程fork的子进程来执行的保存工作;但如果子进程在存在期间,发生了大量的写操作,会导致子进程执行复制操作,就会出现很多的page-fault,这样需要消耗不少性能在复制上
- AOF的数据安全性相对较高,根据使用的fsync策略(何时同步内存数据到磁盘),默认是1s同步一次,就算发生故障,也只会丢失1s内的数据;但根据fsync的策略不同,aof可能速度慢于rdb
- AOF会产生重复记录,比如对一个数据执行了创建和修改,则创建和修改两个操作都会被记录;
- AOF在恢复大数据集时需要比RDB久的时间,因为RDB是直接加载到内存,而AOF则需要一条条执行操作;
5、实现redis哨兵,模拟master故障场景
环境:
初始master节点:192.168.184.101
初始slave1节点:192.168.184.102
初始slave2节点: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 "安装软件包失败,请检查网络配置" 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 用户创建成功"
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 服务启动成功,Redis信息如下:" || { action "Redis 启动失败" false ;exit; }
redis-cli -a $PASSWORD INFO Server 2> /dev/null
}
install
在所有主从节点配置
[root@centos7-01 ~]# vi /apps/redis/etc/redis.conf
bind 0.0.0.0
masterauth 123456
requirepass 123456
在所有从节点配置
[root@centos7-02 ~]# echo "replicaof 192.168.184.101 6379" >> /apps/redis/etc/redis.conf
[root@centos7-02 ~]# systemctl restart redis
测试主从复制
#查看master状态
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写数据
[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查看数据
[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节点使用相同的以下示例的配置文件
[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
将配置文件复制到slave节点
[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/
在所有节点生成新的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
所有节点配置目录权限,启动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状态
[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节点故障
[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已提升为主节点
#查看slave节点日志
[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节点状态
[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节点sentinel状态
[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
恢复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节点恢复后状态为slave