Author Archives: Node

在 Linux 多节点安装配置 Apache Zookeeper 分布式集群

规划:

三台物理服务器就形成了(法定人数)。对于高可用性集群,您可以使用高于3的任何奇数。例如,如果设置5台服务器,则集群可以处理两个故障节点等。

物理服务器需要开启的端口 2888 3888 和 2181 上有入站连接。如果启用了 IPtables 或 Firewall,请确保启用指定的端口,因为zookeeper 需要通过这些端口进行通信。

OS:Centos 7.4 x64
Zookeeper-3.4.10

在本教程中,我们将在以下3台服务器部署zookeeper分布式群集:

10.10.204.63
10.10.204.64
10.10.204.65

先决条件:

在安装 Zookeeper 之前,你应该在系统中安装并配置好 JDKOracle Java8,这将与Zookeeper配合使用。

Linux JAVA JDK JRE 环境变量安装与配置

步骤1: 在各个实例上安装Zookeeper。

 下载Zookeeper
 # cd /tmp
 # wget //apache.fayea.com/zookeeper/stable/zookeeper-3.4.10.tar.gz
 解压它
 # tar zxvf zookeeper-3.4.10.tar.gz
 移动 Zookeeper 到 /usr/local/
 # mv zookeeper-3.4.10 /usr/local/
 创建软连接
 # ln -s /usr/local/zookeeper-3.4.10 /usr/local/zookeeper
 拷贝配置文件
 # cp /usr/local/zookeeper/conf/zoo_sample.cfg /usr/local/zookeeper/conf/zoo.cfg
 创建数据及日志存放目录
 # mkdir -p /usr/local/zookeeper/data
 # mkdir -p /usr/local/zookeeper/logs
 新建用户
 # groupadd zookeeper
 # useradd -g zookeeper -s /sbin/nologin zookeeper
 赋予Zookeeper目录权限
 # chown -R zookeeper:zookeeper /usr/local/zookeeper-3.4.10 /usr/local/zookeeper
 # chmod +755 /usr/local/zookeeper-3.4.10

步骤2:修改配置文件。

 # vim /usr/local/zookeeper/conf/zoo.cfg

默认值:

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# //zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to “0” to disable auto purge feature
#autopurge.purgeInterval=1

修改为:

#服务器之间或客户端与服务器之间维持心跳的时间间隔,每隔tickTime时间就会发送一个心跳。
tickTime=2000
#这个配置项是用来配置Zookeeper接受客户端(这里所说的客户端不是用户连接Zookeeper 服务器的客户端,而是Zookeeper服务器集群中连接到Leader的Follower 服务器)初始化连接时最长 能忍受多少个心跳时间间隔数。当已经超过 10 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20 秒。
initLimit=10
#这个配置项标识Leader与Follower之间发送消息,请求和应答时间长度,最长不能超过多少个tickTime的时间长度,总的时间长度就是5*2000=10秒(适用于3.4以上版本)。
syncLimit=5
#这个参数和上面的参数搭配使用,这个参数指定了需要保留的文件数目。默认是保留3个。
autopurge.snapRetainCount=3
#这个参数指定了清理频率,单位是小时,需要填写一个1或更大的整数,默认是0,表示不开启自己清理功能(适用于3.4以上版本)。
autopurge.purgeInterval=1
maxClientCnxns=60
#修改数据目录(可以是任意目录)。
dataDir=/usr/local/zookeeper/data
#新增日志目录(可以是任意目录)。
dataLogDir=/usr/local/zookeeper/logs
#Zookeeper服务器监听的端口,以接受客户端的访问请求。
clientPort=2181
#新增以下内容。
server.1=10.10.204.63:2888:3888
server.2=10.10.204.64:2888:3888
server.3=10.10.204.65:2888:3888

步骤3:分别在各个Zookeeper实例中创建myid文件。

 # echo "1" >> /usr/local/zookeeper/data/myid
 # echo "2" >> /usr/local/zookeeper/data/myid
 # echo "3" >> /usr/local/zookeeper/data/myid

步骤4:添加系统变量。

编辑:/etc/profile  文件,添加以下内容:

 export ZOOKEEPER_HOME=/usr/local/zookeeper/
 export PATH=$ZOOKEEPER_HOME/bin:$PATH

执行以下命令使其系统变量永久生效:

 # source /etc/profile

步骤5:创建系统单元文件。

在 /usr/lib/systemd/system 目录下创建  zookeeper.service  ,并填写如下内容:

[Unit]
 Description=zookeeper.service
 After=network.target

[Service]
 Type=forking
 Environment=ZOO_LOG_DIR=/usr/local/zookeeper/
 ExecStart=/usr/local/zookeeper/bin/zkServer.sh start
 ExecStop=/usr/local/zookeeper/bin/zkServer.sh stop
 ExecReload=/usr/local/zookeeper/bin/zkServer.sh restart
 Restart=always
 User=zookeeper
 Group=zookeeper

[Install]
 WantedBy=multi-user.target

步骤6:启动Zookeeper。

重新加载配置信息:systemctl daemon-reload
启动zookeeper服务:systemctl start zookeeper.service
关闭zookeeper服务:systemctl stop zookeeper.service
查看进程状态及日志:systemctl status zookeeper.service
开机自启动:systemctl enable zookeeper.service
关闭自启动:systemctl disable zookeeper.service

步骤7:放行 2888、3888、2181 端口。

 # firewall-cmd --permanent --zone=public --add-port=2888/tcp
 # firewall-cmd --permanent --zone=public --add-port=3888/tcp
 # firewall-cmd --permanent --zone=public --add-port=2181/tcp

重载防火墙:

 # firewall-cmd --reload

步骤8:查看Zookeeper状态

分别检测3台服务器的运行状态是否正常。

查看 10.10.204.63 节点;

 [root@10-10-204-63 ~]# /usr/local/zookeeper/bin/zkServer.sh status
 ZooKeeper JMX enabled by default
 Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: leader

查看 10.10.204.64 节点;

 [root@10-10-204-64 ~]# /usr/local/zookeeper/bin/zkServer.sh status
 ZooKeeper JMX enabled by default
 Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: follower

查看 10.10.204.65 节点;

 [root@10-10-204-65 ~]# /usr/local/zookeeper/bin/zkServer.sh status
 ZooKeeper JMX enabled by default
 Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
 Mode: follower

服务器中ZooKeeper分别扮演者不同的角色,1台将处于 leader(领导)地位,另外2台将处于 follower (追随者)。如果您获得相同的结果,那么你已经正确地安装配置好了ZooKeeper集群服务器。

步骤9:在3台物理服务器中的任意一台使用客户端连接。

客户端连接信息如下所示:

 [root@10-10-204-63 ~]# /usr/local/zookeeper/bin/zkCli.sh -server 10.10.204.64:2181
 Connecting to 10.10.204.64:2181
 2017-08-13 20:30:11,816 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.10-39d3a4f269333c922ed3db283be479f9deacaa0f, built on 03/23/2017 10:13 GMT
 2017-08-13 20:30:11,863 [myid:] - INFO [main:Environment@100] - Client environment:host.name=103-28-204-63.10.10.204.63
 2017-08-13 20:30:11,863 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.8.0_144
 2017-08-13 20:30:11,875 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=Oracle Corporation
 2017-08-13 20:30:11,883 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/usr/java/jdk1.8.0_144/jre
 2017-08-13 20:30:11,883 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=/usr/local/zookeeper/bin/../build/classes:/usr/local/zookeeper/bin/../build/lib/*.jar:/usr/local/zookeeper/bin/../lib/slf4j-log4j12-1.6.1.jar:/usr/local/zookeeper/bin/../lib/slf4j-api-1.6.1.jar:/usr/local/zookeeper/bin/../lib/netty-3.10.5.Final.jar:/usr/local/zookeeper/bin/../lib/log4j-1.2.16.jar:/usr/local/zookeeper/bin/../lib/jline-0.9.94.jar:/usr/local/zookeeper/bin/../zookeeper-3.4.10.jar:/usr/local/zookeeper/bin/../src/java/lib/*.jar:/usr/local/zookeeper/bin/../conf:.:/usr/java/jdk1.8.0_144/jre/lib/rt.jar:/usr/java/jdk1.8.0_144/lib/dt.jar:/usr/java/jdk1.8.0_144/lib/tools.jar:/usr/java/jdk1.8.0_144/jre/lib
 2017-08-13 20:30:11,884 [myid:] - INFO [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
 2017-08-13 20:30:11,884 [myid:] - INFO [main:Environment@100] - Client environment:java.io.tmpdir=/tmp
 2017-08-13 20:30:11,884 [myid:] - INFO [main:Environment@100] - Client environment:java.compiler=
 2017-08-13 20:30:11,884 [myid:] - INFO [main:Environment@100] - Client environment:os.name=Linux
 2017-08-13 20:30:11,884 [myid:] - INFO [main:Environment@100] - Client environment:os.arch=amd64
 2017-08-13 20:30:11,885 [myid:] - INFO [main:Environment@100] - Client environment:os.version=3.10.0-514.21.2.el7.x86_64
 2017-08-13 20:30:11,885 [myid:] - INFO [main:Environment@100] - Client environment:user.name=root
 2017-08-13 20:30:11,885 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/root
 2017-08-13 20:30:11,885 [myid:] - INFO [main:Environment@100] - Client environment:user.dir=/root
 2017-08-13 20:30:11,893 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection, connectString=10.10.204.64:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@69d0a921
 Welcome to ZooKeeper!
 2017-08-13 20:30:12,103 [myid:] - INFO [main-SendThread(10.10.204.64:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server 10.10.204.64/10.10.204.64:2181. Will not attempt to authenticate using SASL (unknown error)
 JLine support is enabled
 2017-08-13 20:30:12,768 [myid:] - INFO [main-SendThread(10.10.204.64:2181):ClientCnxn$SendThread@876] - Socket connection established to 10.10.204.64/10.10.204.64:2181, initiating session
 2017-08-13 20:30:12,935 [myid:] - INFO [main-SendThread(10.10.204.64:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server 10.10.204.64/10.10.204.64:2181, sessionid = 0x15dda7deb6c0000, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
 [zk: 10.10.204.64:2181(CONNECTED) 2] create /renwoledb 'renwole' #创建数据节点
 Created /renwoledb
 [zk: 10.10.204.64:2181(CONNECTED) 3] get /renwoledb #调出节点数据
 renwole
 cZxid = 0x500000002
 ctime = Sun Aug 13 21:19:24 CST 2017
 mZxid = 0x500000002
 mtime = Sun Aug 13 21:19:24 CST 2017
 pZxid = 0x500000002
 cversion = 0
 dataVersion = 0
 aclVersion = 0
 ephemeralOwner = 0x0
 dataLength = 7
 numChildren = 0

整个zookeeper集群到此已经搭建并测试完成。如果 leader 节点出现故障,其他 follower (追随者)会投票选择新的 leader ,所以这就是我们想要的 Zookeeper 分布式集群。

转载请注明本文地址。

Redis Sentinel冗余配置为Redis实例提供自动故障切换

关于 Redis Sentinel

Redis主从复制能够生成一个或多个Redis服务器的副本,但是它不会在主服务器和从Redis服务器之间提供自动故障切换。因此Sentinel为Redis实例提供了一个简单而自动化的高可用性(HA)解决方案,如果当前的主服务器不按预期工作,则可以将从服务器升级为主服务器。假设您已经有一个Redis Replication集群,你将需要配置Sentinel(哨兵),从而完成故障自动切换。更多介绍请参阅官方Redis Sentinel 文档。

Redis源码包中已经包含了一个 sentinel.conf 作为Sentinel的配置文件,配置文件中自带了关于各个配置项的解释。先上架构图:

+———————–+                        +——————–+
| Redis Master:6379  |     _____       | Redis Svale:6379|
| Sentinel1:26379       |                         | Sentinel2:26379 |
+———————–+                        +——————–+

所有Redis节点都应以相同的方式配置和类似的服务器规格,如在故障转移情况下,任何从站都可能会由Sentinel升级为新的Master。

1.开始下面部署前,建议先预读以下文章:

Linux Centos7 Redis 4.0.1 源码编译安装配置
如何在 Centos 7上配置 Redis Replication 主从复制群集

2.现在开始部署(由于资源有限,暂用2台Server做为测试):

OS:CentOS 7.4
Redis sentinel 4.0.1
Redis Master+Sentinel 10.10.204.64
Redis Slave+Sentinel 10.10.204.65

3.分别修改主从的哨兵配置文件 sentinel.conf (除bind不一样外,其他均相同):

# vim /usr/local/redis/sentinel.conf

 bind 10.10.204.64 #网卡绑定的IP地址
 sentinel monitor mymaster 10.10.204.64 6379 2 #填写Master的IP地址以及端口,这个2代表;当集群中有2个sentinel认为master挂了时,才能真正认为该master已经不可用了
 sentinel down-after-milliseconds mymaster 5000 #如果5秒内检测不到mymaster节点存活,则认为主节点故障从而进行转移操作
 sentinel failover-timeout mymaster 180000 #故障转移的超时时间(单位毫秒)
 sentinel parallel-syncs mymaster 1 #设置故障转移后,允许多少从服务器连接主节点发起同步请求
 sentinel auth-pass mymaster RenwoleQxl5qpKHrh9khuTW #设置连接密码
 protected-mode no #为了redis client能内网连接操作redis-sentinel
 logfile /usr/local/redis/logs/sentinel.log #添加指定日志文件存储位置

4.分别在主从上创建Redis sentinel系统单元文件:

# vim /usr/lib/systemd/system/redis-sentinel.service

[Unit]
 Description=Redis persistent key-value database
 After=network.target

[Service]
 User=redis
 Group=redis
 ExecStart=/usr/local/bin/redis-sentinel /usr/local/redis/sentinel.conf --daemonize no
 ExecStop=/usr/local/bin/redis-cli -p 26379 shutdown
 Restart=always

[Install]
 WantedBy=multi-user.target

5.重载systemctl并启动sentinel(哨兵机制)服务:

 # systemctl daemon-reload
 # systemctl start redis-sentinel.service
 # systemctl enable redis-sentinel.service

6.将端口加入防火墙(要保证所有Redis实例相互通信):

 # firewall-cmd --zone=public --add-port=26379/tcp --permanent
 # firewall-cmd --reload

7.验证Redis故障切换:

查看Master 10.10.204.64角色,以及slave0的连接状态(正常):

 10.10.204.64:6379> info
 ...
 # Replication
 role:master
 connected_slaves:1
 slave0:ip=10.10.204.65,port=6379,state=online,offset=8681829,lag=1
 master_replid:0ed3591a6caf4ae4b59d3943dc8d7f4c0440b724
 master_replid2:0000000000000000000000000000000000000000
 master_repl_offset:8681829
 ...

查看Slave 10.10.204.65角色,以及master连接状态(正常):

 10.10.204.65:6379> info
 ...
 # Replication
 role:slave
 master_host:10.10.204.64
 master_port:6379
 master_link_status:up
 master_last_io_seconds_ago:1
 master_sync_in_progress:0
 slave_repl_offset:8692657
 ...

8.停止Redis Master服务器并查看sentinel日志记录:

 # systemctl stop redis
 # cat /usr/local/redis/logs/sentinel.log
 5403:X 11 Aug 11:05:47.633 * +slave slave 10.10.204.64:6379 10.10.204.64 6379 @ mymaster 10.10.204.65 6379
 5403:X 11 Aug 11:05:52.694 # +sdown slave 10.10.204.64:6379 10.10.204.64 6379 @ mymaster 10.10.204.65 6379

9.再查看打印的 Redis Slave sentinel日志记录:

 # cat /usr/local/redis/logs/sentinel.log
 2873:X 11 Aug 11:05:25.006 * +slave slave 10.10.204.64:6379 10.10.204.64 6379 @ mymaster 10.10.204.65 6379
 2873:X 11 Aug 11:05:30.061 # +sdown slave 10.10.204.64:6379 10.10.204.64 6379 @ mymaster 10.10.204.65 6379

日志中分别表示,已经将之前 Redis Slave 10.10.204.65 变成了主。

10.现在再模拟下之前的Redis Master 10.10.204.64上线后的状态:

 # systemctl start redis
 # cat /usr/local/redis/logs/sentinel.log
 5403:X 11 Aug 11:15:38.743 # -sdown slave 10.10.204.64:6379 10.10.204.64 6379 @ mymaster 10.10.204.65 6379
 5403:X 11 Aug 11:15:48.691 * +convert-to-slave slave 10.10.204.64:6379 10.10.204.64 6379 @ mymaster 10.10.204.65 6379

日志明确显示 Redis Master 10.10.204.64 被降级为 Redis Slave 10.10.204.65 的从,再不会变成Master,除非Slave出现故障。

扩展阅读:

查看Sentinel状态:

 # redis-cli -p 26379 -h 10.10.204.64 -a Qxl5qpKHrh9khuTW
 10.10.204.64: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=10.10.204.65:6379,slaves=1,sentinels=2

常用命令:

sentinel master mymaster #查看Master的状态信息
SENTINEL slaves mymaster #查看Salves的信息
SENTINEL sentinels mymaster #查看哨兵的状态
SENTINEL get-master-addr-by-name mymaster #获取当前master的地址

一旦一个Sentinel成功对一个Master进行了failover,它将会把关于Master的最新配置通过广播形式通知其它sentinel,其它的sentinel则更新对应master的配置。

注:如果不能正常故障切换,请检查您的机器之间的端口是否通信,大多数都是因为这个原因导致。

到目前为止Redis Sentinel已经配置完成,而且测试数据看起来一切都很好。

如何在CentOS 7上配置 Redis Replication 主从复制群集

关于 Redis Replication

Redis支持异步主从复制,允许一个或多个Redis服务器 隶属于Redis Master服务器的精确副本。Redis主从复制的配置是非常简单的,只需安装几个步骤即可。有关Redis更多信息,请参阅官方的Redis复制文档

对于生产环境,将数据复制到至少两个节点被认为是最佳的做法。这允许在环境故障的情况下恢复,这在您的应用程序用户基础增长以及体验尤为重要。它还允许您安全地与生产数据交互,而无需修改或影响性能。

1.规划(由于资源有限,暂用2台Server做为测试):

OS:CentOS 7.4
Redis 4.0.1
Redis Master 10.10.204.64
Redis Slave 10.10.204.65

2.配置Redis Replication之前首先需要安装Redis实例服务:

Linux Centos7 Redis 4.0.1 源码编译安装配置

3.主从互相添加Hosts:

主服务器:

 # echo “10.10.204.64 10-10-204-64” >> /etc/hosts
 # echo “10.10.204.65 10-10-204-65” >> /etc/hosts

从服务器:

 # echo “10.10.204.65 10-10-204-65” >> /etc/hosts
 # echo “10.10.204.64 10-10-204-64” >> /etc/hosts

4.Redis.conf 配置文件:

其实Slave的配置和Master基本一致,为什么这么说呢,当Master挂掉之后,那么Slave就担任了Master工作,所以一些参数就必须和Master相同,所以主从分别,只需要修改相应的pidfile,端口,日志文件名,并配上Master的地址和认证密码即可,生产环境亦是如此。

Master & Slave 通用配置:

 # vim /usr/local/redis/redis.conf
 port 6379 #端口信息
 daemonize yes #如果需要在后台运行,把该项改为yes
 pidfile /var/run/redis_6379.pid #主从PID路径
 logfile "/usr/local/redis/log/redis.log" #设置日志文件路径
 requirepass RenwoleQxl5qpKHrh9khuTW #设置设置256位连接密码
 masterauth RenwoleQxl5qpKHrh9khuTW #如果Master设置了密码,则Slave需要通过masterauth配置密码
 repl-diskless-sync yes #无硬盘复制功能通过以下配置
 repl-diskless-sync-delay 5
 maxmemory-policy volatile-lru #最大内存策略:如果达到内存限制了,Redis如何选择删除key.多选
 repl-ping-slave-period 10 #多少秒ping一次Master
 repl-timeout 60 #复制的超时时间,这个时间一定要大于ping的时间
 timeout 300 #客户端闲置多长时间后断开连接,默认为0关闭此功能
 min-slaves-to-write 3 #最小slave链接数默认为0
 min-slaves-max-lag 10 #最小的slave,最大延迟数默认为10
 dir /usr/local/redis-4.0.1 #自定义数据存储路径
 tcp-keepalive 60 #建议60,首先找到设置并将其设置为60秒
 appendonly yes 为了提高耐用性保证,可以启用仅追加文件的持久性,这助于最大程度减少系统故障时的数据丢失,同时IO的读写会付出相应的代价
 appendfilename "redis-staging-ao.aof"
 repl-backlog-ttl 3600 #在某些时候, master 不再连接 slaves,backlog 将被释放。如果设置为 0 意味着不释放 backlog
 maxclients 10000 #当连接数超过这个值时,redis 将不再接收其他连接请求,客户端尝试连接时将收到 error 信息

5.Master 配置:

bind 127.0.0.1 10.10.204.64

6.Slave 配置:

 bind 127.0.0.1 10.10.204.65
 slaveof 10.10.204.64 6379 #设置Master的IP与端口

注意:当从服务器执行了slaveof命令后,从服务器中原来的数据将清空,重新加载主服务器中的数据。

7.重新启动 Master & Slave 查看主从连接状态:

 # systemctl restart redis

8.查看 Master 角色以及Slave连接状态(注意:红色部分):

 # redis-cli
 10.10.204.64:6379> auth RenwoleQxl5qpKHrh9khuTW
 OK
 10.10.204.64:6379> info Replication

 # Replication
 role:master
 connected_slaves:1
 slave0:ip=10.10.204.65,port=6379,state=online,offset=101640,lag=1
 master_replid:cd78097afde482dd3ef18cf74ec66da7f2d7d140
 master_replid2:0000000000000000000000000000000000000000
 master_repl_offset:101640
 ...

9.查看Slave角色以及连接Master的状态(注意:红色部分):

 # redis-cli
 10.10.204.65:6379> auth RenwoleQxl5qpKHrh9khuTW
 OK
 10.10.204.65:6379> info Replication
 # Replication
 role:slave
 master_host:10.10.204.64
 master_port:6379
 master_link_status:up
 master_last_io_seconds_ago:7
 master_sync_in_progress:0
 slave_repl_offset:101906
 slave_priority:100
 slave_read_only:1
 connected_slaves:0
 ...

10.在Master节点上操作:

 10.10.204.64:6379> set key renwole.com
 OK
 10.10.204.64:6379> scan 0
 1) "0"
 2) 1) "name"
 2) "key"
 3) "name1"

11.检查Slave节点是否同步:

 10.10.204.65:6379> scan 0
 1) "0"
 2) 1) "key"
 2) "name1"
 3) "name"
 10.10.204.65:6379> get key
 "renwole.com"

Slave信息显示已经成功同步。

:Redis Replication 配置要求需要两台或多台redis实例之间保证端口相互通信,否则不能正常实现Redis复制。

12.Redis主从复制看起来完美无瑕,但由于Redis目前仅支持主从复制备份,而无法提供故障自动切换。所以这并不能满足我们的业务需求。

请参阅《Redis Sentinel冗余配置为Redis实例提供自动故障切换》高可用(HA)解决方案。

Redisson 缓存 Tomcat Redis Session Manager 变量

部署负载均衡时,使用一台Nginx作为前端服务器,多台Tomcat作为后端服务器。Nginx 会根据负载策略把请求分发给Tomcat服务器。默认Tomcat服务器的session(共享会话)是不可跨越服务器的,若是同一个用户的不同请求被分发到不同的Tomcat服务器,就会造成 session 变量丢失,需要用户重新登录。在讲解Redisson之前,我先来分析以下两种方案的Session会话共享。

方案一:Nginx原生 Upstream ip_hash

ip_hash 是根据请求的IP进行分发,对于同一个IP的请求会转发到同一台Tomcat服务器。

1.Nginx 配置如下:《Nginx 1.3 集群负载均衡器 反向代理安装配置优化

 upstream webservertomcat {
 ip_hash;
 server 10.10.204.63:8023 weight=1 max_fails=2 fail_timeout=2;
 server 10.10.204.64:8023 weight=1 max_fails=2 fail_timeout=2;
 #server 127.0.0.1:8080 backup;
 }
 server {
 listen 80;
 server_name www.myname.com myname.com;
 location / {
 proxy_pass //webservertomcat;
 proxy_redirect off;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 client_max_body_size 10m;
 client_body_buffer_size 128k;
 proxy_connect_timeout 90;
 proxy_send_timeout 90;
 proxy_read_timeout 90;
 proxy_buffer_size 4k;
 proxy_buffers 4 32k;
 proxy_busy_buffers_size 64k;
 proxy_temp_file_write_size 64k;
 add_header Access-Control-Allow-Origin *;
 }
 }

以上配置生产环境不建议使用,原因有二:

1.Nginx可能不是最前端的服务器,如Squid或CDN作为前端缓存,则Nginx实际是拿Squid或CDN服务器的IP地址,达不到根据客户端请求IP分流的效果。
2.有些机构是使用动态虚拟IP或有多个出口IP,用户访问会切换IP,则无法将某个用户的请求固定到同一个Tomcat服务器。

方案二:Nginx_Upstream_jvm_route

Nginx_upstream_jvm_route 是一个第三方 nginx 扩展模块,该模块通过 session cookie 实现 session 会话粘性,如果在cookie和url中并没有session,则这只是个简单的round-robin 负载均衡。

实现方法:用户初次请求分发到后端Server时;会把响应的Server标识添加到名称为JSESSIONID的cookie中,再次请求时;jvm_route看到session中有后端服务器的名称,它就把请求转到对应的服务器上。模块地址://code.google.com/archive/p/nginx-upstream-jvm-route/

1.Nginx配置如下:

 upstream tomcats_jvm_route {
 server 10.10.204.63:8023 srun_id=tomcat1;
 server 10.10.204.64:8023 srun_id=tomcat2;
 jvm_route $cookie_JSESSIONID|sessionid reverse;
 }

2.在多个Tomcat的server.xml添加配置如下:

 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">

3.配置后,请求的名称为JSESSIONID的cookie末尾会被添加服务器标识,如下:

 JSESSIONID=33775B80D8E0DB5AEAD61F86D6666C45.tomcat2;

4.生产环境不建议使用,原因:

4.1根据tomcat的特性,当server.xml配置文件中加了jvmRoute值后,会给sessionid加上jvmRoute值的后缀,根据这一特性 nginx_upstream_jvm_route对每次访问请求中的sessionId的值自动匹配对应的server。这样就会每次都访问都会到同一个Tomcat Server,这样就解决了访问不同tomcat节点session发生变化的问题。但是这种方式会出现一个问题,当一直被访问的Tomcat服务器宕机后,负载就会将用户分配到其他Server,这样就会造成session发生变化,从而就需要重新登录。

方案三:Tomcat Redis Session Manager

使用 Redis 共享 session,也就是本节中重点讲解的部分。以上两种方案均是将Session存储在Tomcat容器中,当请求从一个Tomcat转发到另一个Tomcat时,Session就会失效,因为Session在各个Tomcat中不能共享。如果使用Redis等缓存数据库系统存储Session,就可以在Tomcat实例之间实现Session共享。

Java框架redisson实现Tomcat会话管理器(Tomcat Session Manager),支持Apache Tomcat 6.x,7.x和8.x。配置方法如下:

1.编辑 TOMCAT_BASE/conf/context.xml 文件节点,添加以下内容:

<Manager className="org.redisson.tomcat.RedissonSessionManager"<Manager className="org.redisson.tomcat.RedissonSessionManager"  configPath="${catalina.base}/redisson-config.json" />

注:configPath – 是指的Redisson的JSON或YAML格式的配置文件路径。配置文件详见这里

2.拷贝相应的***两个***JAR包到指定的TOMCAT_BASE/lib目录下:

适用于 JDK 1.8+

redisson-all-3.5.0.jar

for Tomcat 6.x

redisson-tomcat-6-3.5.0.jar

for Tomcat 7.x

redisson-tomcat-7-3.5.0.jar

for Tomcat 8.x

redisson-tomcat-8-3.5.0.jar

3.按照 [Single instance mode]单实例模式的说明,创建编辑 Json 格式的 redisson-config.json 文件,添加以下内容,并将其上传到TOMCAT_BASE下,重载Tomcat服务即可。

{
 "singleServerConfig":{
 "idleConnectionTimeout":10000,
 "pingTimeout":1000,
 "connectTimeout":10000,
 "timeout":3000,
 "retryAttempts":3,
 "retryInterval":1500,
 "reconnectionTimeout":3000,
 "failedAttempts":3,
 "password":null,
 "subscriptionsPerConnection":5,
 "clientName":null,
 "address": "redis://127.0.0.1:6379",
 "subscriptionConnectionMinimumIdleSize":1,
 "subscriptionConnectionPoolSize":50,
 "connectionMinimumIdleSize":10,
 "connectionPoolSize":64,
 "database":0,
 "dnsMonitoring":false,
 "dnsMonitoringInterval":5000
 },
 "threads":0,
 "nettyThreads":0,
 "codec":null,
 "useLinuxNativeEpoll":false
 }

4.开始测试session。创建session.jsp并添加以下代码,上传到TOMCAT_BASE/webapps/ROOT/下。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>shared session</title>
</head>
<body>
<br>session id=<%=session.getId()%>
</body>
</html>

5.浏览器访问会出现以下会话信息

 session id=1D349A69E8F5A27E1C12DEEFC304F0DC

6.现在查看Redis中是否存储了该值,如果存在会话值,此时你重启Tomcat后,该会话值也不会发生变化。

 # redis-cli
 127.0.0.1:6379> keys *
 1) "redisson_tomcat_session:1D349A69E8F5A27E1C12DEEFC304F0DC"

已经存储成功。

如果是Redis集群或多实例模式,可参阅以下更多资料进行配置:

//github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks#144-tomcat-redis-session-manager
//github.com/redisson/redisson/wiki/2.-Configuration
//github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95 (中文文档)

最佳 Nginx 配置文件优化方案

以下是生产环境中适用的Nginx优化文件,你也可以根据自己的需求调优。

 user www www;
 #用户&组
 worker_processes auto;
 #通常是CPU核的数量存储数据的硬盘数量及负载模式,不确定时将其设置为可用的CPU内核数(设置为“auto”将尝试自动检测它)
 error_log /usr/local/nginx/logs/error.log crit;
 pid /usr/local/nginx/logs/nginx.pid;
 #指定pid文件的位置,默认值就可以

 worker_rlimit_nofile 65535;
 #更改worker进程的最大打开文件数限制
 events {
 use epoll;
 multi_accept on;
 #在Nginx接到一个新连接通知后,调用accept()来接受尽量多的连接
 worker_connections 65535;
 #最大访问客户数,修改此值时,不能超过 worker_rlimit_nofile 值
 }
 http {
 include mime.types;
 default_type application/octet-stream;
 #使用的默认的 MIME-type
 log_format '$remote_addr - $remote_user [$time_local] "$request" '
 '$status $body_bytes_sent "$http_referer" '
 '"$http_user_agent" "$http_x_forwarded_for"';
 #定义日志格式
 charset UTF-8;
 #设置头文件默认字符集
 server_tokens off;
 #Nginx打开网页报错时,关闭版本号显示
 access_log off;
 sendfile on;
 tcp_nopush on;
 #告诉nginx在一个数据包里发送所有头文件,而不一个接一个的发送
 tcp_nodelay on;
 #是否启用 nagle 缓存算法,告诉nginx不要缓存数据
 sendfile_max_chunk 512k;
 #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限
 keepalive_timeout 65;
 #HTTP连接持续时间,值越大无用的线程变的越多,0:关闭此功能,默认为75
 client_header_timeout 10;
 client_body_timeout 10;
 #以上两项是设置请求头和请求体各自的超时时间
 reset_timedout_connection on;
 #告诉nginx关闭不响应的客户端连接
 send_timeout 30;
 #客户端响应超时时间,若客户端停止读取数据,释放过期的客户端连接,默认60s
 limit_conn_zone $binary_remote_addr zone=addr:5m;
 #用于保存各种key,如:当前连接数的共享内存的参数,5m是5兆字节,这个值应该被设置的足够大,以存储(32K*5)32byte状态或者(16K*5)64byte状态
 limit_conn addr 100;
 #key最大连接数,这里key是addr,我设置的值是100,这样就允许每个IP地址最多同时打开100个连接数
 server_names_hash_bucket_size 128;
 #nginx启动出现could not build the server_names_hash, you should increase错误时,请提高这个参数的值一般设成64就够了
 client_body_buffer_size 10K;
 client_header_buffer_size 32k;
 #客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小进行设置
 large_client_header_buffers 4 32k;
 client_max_body_size 8m;
 #上传文件大小设置,一般是动态应用类型

 #线程池优化,使用--with-threads配置参数编译
 #aio threads;
 #thread_pool default threads=32 max_queue=65536;
 #aio threads=default;
 #关于更多线程请点击查看

 #fastcgi性能调优

 fastcgi_connect_timeout 300;
 #连接到后端 Fastcgi 的超时时间
 fastcgi_send_timeout 300;
 #与 Fastcgi 建立连接后多久不传送数据,就会被自动断开
 fastcgi_read_timeout 300;
 #接收 Fastcgi 应答超时时间
 fastcgi_buffers 4 64k;
 #可以设置为 FastCGI 返回的大部分应答大小,这样可以处理大部分请求,较大的请求将被缓冲到磁盘
 fastcgi_buffer_size 64k;
 #指定读取 Fastcgi 应答第一部分需要多大的缓冲区,可以设置gastcgi_buffers选项指定的缓冲区大小
 fastcgi_busy_buffers_size 128k;
 #繁忙时的buffer,可以是fastcgi_buffer的两倍
 fastcgi_temp_file_write_size 128k;
 #在写入fastcgi_temp_path时将用多大的数据块,默认值是fastcgi_buffers的两倍,该值越小越可能报 502 BadGateway
 fastcgi_intercept_errors on;
 #是否传递4**&5**错误信息到客户端,或允许nginx使用error_page处理错误信息.

 #fastcgi_cache配置优化(若是多站点虚拟主机,除fastcgi_cache_path(注意keys_zone=名称)全部加入php模块中)

 fastcgi_cache fastcgi_cache;
 #开启FastCGI缓存并指定一个名称,开启缓存可以降低CPU的负载,防止502错误出现
 fastcgi_cache_valid 200 302 301 1h;
 #定义哪些http头要缓存
 fastcgi_cache_min_uses 1;
 #URL经过多少次请求将被缓存
 fastcgi_cache_use_stale error timeout invalid_header http_500;
 #定义哪些情况下用过期缓存
 #fastcgi_temp_path /usr/local/nginx/fastcgi_temp;
 fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2 keys_zone=fastcgi_cache:15m inactive=1d max_size=1g;
 #keys_zone=缓存空间的名字,cache=用多少内存,inactive=默认失效时间,max_size=最多用多少硬盘空间。
 #缓存目录,可以设置目录层级,举例:1:2会生成16*256个字目录
 fastcgi_cache_key $scheme$request_method$host$request_uri;
 #定义fastcgi_cache的key
 #fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

 #响应头

 add_header X-Cache $upstream_cache_status;
 #缓存命中
 add_header X-Frame-Options SAMEORIGIN;
 #是为了减少点击劫持(Clickjacking)而引入的一个响应头
 add_header X-Content-Type-Options nosniff;

 #GZIP性能优化

 gzip on;
 gzip_min_length 1100;
 #对数据启用压缩的最少字节数,如:请求小于1K文件,不要压缩,压缩小数据会降低处理此请求的所有进程速度
 gzip_buffers 4 16k;
 gzip_proxied any;
 #允许或者禁止压缩基于请求和响应的响应流,若设置为any,将会压缩所有请求
 gzip_http_version 1.0;
 gzip_comp_level 9;
 #gzip压缩等级在0-9内,数值越大压缩率越高,CPU消耗也就越大
 gzip_types text/plain text/css application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/json image/jpeg image/gif image/png;
 #压缩类型
 gzip_vary on;
 #varyheader支持,让前端的缓存服务器识别压缩后的文件,代理
 include /usr/local/nginx/conf/vhosts/*.conf;
 #在当前文件中包含另一个文件内容的指令

 #静态文件的缓存性能调优

 open_file_cache max=65535 inactive=20s;
 #这个将为打开文件指定缓存,max 指定缓存数量.建议和打开文件数一致.inactive 是指经过多长时间文件没被请求后删除缓存
 open_file_cache_valid 30s;
 #这个是指多长时间检查一次缓存的有效信息,例如我一直访问这个文件,30秒后检查是否更新,反之更新
 open_file_cache_min_uses 2;
 #定义了open_file_cache中指令参数不活动时间期间里最小的文件数
 open_file_cache_errors on;
 #NGINX可以缓存在文件访问期间发生的错误,这需要设置该值才能有效,如果启用错误缓存.则在访问资源(不查找资源)时.NGINX会报告相同的错误

 #资源缓存优化
 server {

 #防盗链设置

 location ~* \.(jpg|gif|png|swf|flv|wma|asf|mp3|mmf|zip|rar)$ {
 #防盗类型
 valid_referers none blocked *.renwole.com renwole.com;
 #none blocked参数可选.允许使用资源文件的域名
 if ($invalid_referer) {
 return 403;
 #rewrite ^/ //renwole.com
 #若不符合条件域名,则返回403或404也可以是域名
 }
 }
 location ~ .*\.(js|css)$ {
 access_log off;
 expires 180d;
 #健康检查或图片.JS.CSS日志.不需要记录日志.在统计PV时是按照页面计算.而且写入频繁会消耗IO.
 }
 location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|swf|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
 access_log off;
 log_not_found off;
 expires 180d;
 #视图&元素很少改变.可将内容缓存到用户本地.再次访问网站时就无需下载.节省流量.加快访问速度.缓存180天
 }
 }
 server {
 listen 80 default_server;
 server_name .renwole.com;
 rewrite ^ //renwole.com$request_uri?;
 }
 server {
 listen 443 ssl http2 default_server;
 listen [::]:443 ssl http2;
 server_name .renwole.com;
 root /home/web/renwole;
 index index.html index.php;

 ssl_certificate /etc/letsencrypt/live/renwole.com/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/renwole.com/privkey.pem;

 ssl_dhparam /etc/nginx/ssl/dhparam.pem;
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
 ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';

 ssl_session_cache shared:SSL:50m;
 ssl_session_timeout 1d;
 ssl_session_tickets off;
 ssl_prefer_server_ciphers on;
 add_header Strict-Transport-Security max-age=15768000;
 ssl_stapling on;
 ssl_stapling_verify on;

 include /usr/local/nginx/conf/rewrite/wordpress.conf;
 access_log /usr/local/nginx/logs/renwole.log;

 location ~ \.php$ {
 root /home/web/renwole;
 #fastcgi_pass 127.0.0.1:9000;
 fastcgi_pass unix:/var/run/www/php-cgi.sock;
 fastcgi_index index.php;
 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 include fastcgi_params;
 }
 }
 }

以上就是本站所使用的环境优化情况,如你有更好的方案不妨分享出来。如有什么有不足之处,还请谅解。

更多模块了解,请参阅//nginx.org/en/docs/

Liunx Centos 双网卡&双IP配置 只有一个IP通信解决方案

症状:

由于Linux Centos 默认启用了反向路由检查,才会导致双网卡配置上双IP只有一个IP通信,还有可能会出现重启网卡的时候瞬间双IP都通,大概隔1-2秒左右,就只会通一个。

方案:

如果两个网卡在同一个Vlan里面,那么服务器可能从eth0 或 eth1发现网关,如果一个包从eth0进入了, 而网关是在eth1上, 那么从eth1是出不去的, 自然也就不通了。反向路由检查的要求是:包从哪里来回哪里去。

关闭反向路由检查(注意修改对应的网卡名称)

# echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter 
# echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter 
# echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter
以上重启后自动失效,如果需要开机自动关闭反向路由检查, 将以上加入  /etc/rc.local  最后一行即可。

更多解决方法:

待续中…

Apache Tomcat 8.5 安全配置与高并发优化

通常我们在生产环境中,Tomcat的默认配置显然不能满足我们的产品需求,所以很多时候都需要对Tomcat的配置进行调优,以下综合我自己的经验来配置 Tomcat 安全与优化情况,如果你有更好的方案,请留言,我会参考并加纳进去。

关于JAVA JDK JRE的安装配置,请阅读《Linux JAVA JDK JRE 环境变量安装与配置》篇。
关于Tomcat的安装,请阅读《Linux Apache Tomcat 8.5 安装与配置》篇。

1.编辑修改配置文件:

# vim /usr/program/tomcat8/conf/server.xml

2.禁用8005端口

telnet localhost 8005 然后输入 SHUTDOWN 就可以关闭 Tomcat,为了安全我们要禁用该功能

默认值:

<Server port="8005" shutdown="SHUTDOWN">

修改为:

<Server port="-1" shutdown="SHUTDOWN">

3.应用程序安全&关闭自动部署

默认值:

<Host name="localhost" appBase="webapps"
 unpackWARs="true" autoDeploy="true">

修改为:

<Host name="localhost" appBase="webapps"
 unpackWARs="false" autoDeploy="false" reloadable="false">

4.maxThreads 连接数限制修改配置

默认值:

<!--
 <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
 maxThreads="150" minSpareThreads="4"/>
 -->

修改为:

<Executor
 name="tomcatThreadPool"
 namePrefix="catalina-exec-"
 maxThreads="500"
 minSpareThreads="30"
 maxIdleTime="60000"
 prestartminSpareThreads = "true"
 maxQueueSize = "100"
/>

参数解释:

maxThreads:最大并发数,默认设置 200,一般建议在 500 ~ 800,根据硬件设施和业务来判断
minSpareThreads:Tomcat 初始化时创建的线程数,默认设置 25
maxIdleTime:如果当前线程大于初始化线程,那空闲线程存活的时间,单位毫秒,默认60000=60秒=1分钟。
prestartminSpareThreads:在 Tomcat 初始化的时候就初始化 minSpareThreads 的参数值,如果不等于 true,minSpareThreads 的值就没啥效果了
maxQueueSize:最大的等待队列数,超过则拒绝请求

5.Connector 参数优化配置

默认值:

<Connector 
 port="8080" 
 protocol="HTTP/1.1" 
 connectionTimeout="20000" 
 redirectPort="8443" 
 />

修改为:

 

<Connector
 executor="tomcatThreadPool"
 port="8080"
 protocol="org.apache.coyote.http11.Http11Nio2Protocol"
 connectionTimeout="60000"
 maxConnections="10000"
 redirectPort="8443"
 enableLookups="false"
 acceptCount="100"
 maxPostSize="10485760"
 maxHttpHeaderSize="8192"
 compression="on"
 disableUploadTimeout="true"
 compressionMinSize="2048"
 acceptorThreadCount="2"
 compressableMimeType="text/html,text/plain,text/css,application/javascript,application/json,application/x-font-ttf,application/x-font-otf,image/svg+xml,image/jpeg,image/png,image/gif,audio/mpeg,video/mp4"
 URIEncoding="utf-8"
 processorCache="20000"
 tcpNoDelay="true"
 connectionLinger="5"
 server="Server Version 11.0"
 />

参数解释:

protocol:Tomcat 8 设置 nio2 更好:org.apache.coyote.http11.Http11Nio2Protocol
protocol:Tomcat 6 设置 nio 更好:org.apache.coyote.http11.Http11NioProtocol
protocol:Tomcat 8 设置 APR 性能飞快:org.apache.coyote.http11.Http11AprProtocol 更多详情:《Tomcat 8.5 基于 Apache Portable Runtime(APR)库性能优化
connectionTimeout:Connector接受一个连接后等待的时间(milliseconds),默认值是60000。
maxConnections:这个值表示最多可以有多少个socket连接到tomcat上
enableLookups:禁用DNS查询
acceptCount:当tomcat起动的线程数达到最大时,接受排队的请求个数,默认值为100。
maxPostSize:设置由容器解析的URL参数的最大长度,-1(小于0)为禁用这个属性,默认为2097152(2M) 请注意, FailedRequestFilter 过滤器可以用来拒绝达到了极限值的请求。
maxHttpHeaderSize:http请求头信息的最大程度,超过此长度的部分不予处理。一般8K。
compression:是否启用GZIP压缩 on为启用(文本数据压缩) off为不启用, force 压缩所有数据
disableUploadTimeout:这个标志允许servlet容器使用一个不同的,通常长在数据上传连接超时。 如果不指定,这个属性被设置为true,表示禁用该时间超时。
compressionMinSize:当超过最小数据大小才进行压缩
acceptorThreadCount:用于接受连接的线程数量。增加这个值在多CPU的机器上,尽管你永远不会真正需要超过2。 也有很多非维持连接,您可能希望增加这个值。默认值是1。
compressableMimeType:配置想压缩的数据类型
URIEncoding:网站一般采用UTF-8作为默认编码。
processorCache:协议处理器缓存的处理器对象来提高性能。 该设置决定多少这些对象的缓存。-1意味着无限的,默认是200。 如果不使用Servlet 3.0异步处理,默认是使用一样的maxThreads设置。 如果使用Servlet 3.0异步处理,默认是使用大maxThreads和预期的并发请求的最大数量(同步和异步)。
tcpNoDelay:如果设置为true,TCP_NO_DELAY选项将被设置在服务器套接字,而在大多数情况下提高性能。这是默认设置为true。
connectionLinger:秒数在这个连接器将持续使用的套接字时关闭。默认值是 -1,禁用socket 延迟时间。
server:隐藏Tomcat版本信息,首先隐藏HTTP头中的版本信息

6.隐藏或修改 Tomcat 版本号

 # cd /usr/local/tomcat/lib/
 # unzip catalina.jar
 # cd org/apache/catalina/util
 # vim ServerInfo.properties
 server.info=Apache Tomcat/8.5.16
 server.number=8.5.16.0
 server.built=Jun 21 2017 17:01:09 UTC

将以上去掉或修改版本号即可。

7.删除禁用默认管理页面以及相关配置文件

 # rm -rf /usr/local/apache-tomcat-8.5.16/webapps/*
 # rm -rf /usr/local/apache-tomcat-8.5.16/conf/tomcat-users.xml

参考内容:
//tomcat.apache.org/tomcat-8.5-doc/config/
//github.com/judasn/Linux-Tutorial/blob/master/Tomcat-Install-And-Settings.md
//wiki.jikexueyuan.com/project/linux-in-eye-of-java/Tomcat-Install-And-Settings.html
//netkiller.github.io/journal/tomcat.html
//zjliu.me/2015/12/14/tomcat-config-connector/

Tomcat 8.5 基于 Apache Portable Runtime(APR)库性能优化

Tomcat可以使用Apache Portable Runtime来提供卓越的性能及可扩展性,更好地与本地服务器技术的集成。Apache Portable Runtime是一个高度可移植的库,位于Apache HTTP Server 2.x的核心。APR有许多用途,包括访问高级IO功能(如sendfile,epoll和OpenSSL),操作系统级功能(随机数生成,系统状态等)以及本地进程处理(共享内存,NT管道和Unix套接字)。

这些功能不仅仅是一个后端集中的技术,还可以让Tomcat成为通用的网络服务器,可以实现与本地的其他Web技术更好的集成,并使Java成为一个完整的网络服务器平台。

官方要求:

APR 1.2+ development headers (libapr1-dev package)
OpenSSL 1.0.2+ development headers (libssl-dev package)
JNI headers from Java compatible JDK 1.4+
GNU development environment (gcc, make)

生产环境:

CentOS Linux release 7.3.1611 (Core) x86 64
Server version: Apache Tomcat/8.5.16
java version “1.8.0_131”

Apache Tomcat/8.5.16 的安装请查看《Linux Apache Tomcat 8.5 安装与配置

1.安装相关依赖包

# yum -y install gcc gcc-c++ libtool* autoconf automake expat-devel perl perl-devel

2.下载安装包

# cd /tmp/
# wget //mirror.bit.edu.cn/apache/apr/apr-1.6.2.tar.gz
# wget //mirror.bit.edu.cn/apache/apr/apr-iconv-1.2.1.tar.gz
# wget //mirror.bit.edu.cn/apache/apr/apr-util-1.6.0.tar.gz
# wget //www.openssl.org/source/openssl-1.1.0f.tar.gz

3.安装APR

# tar zxvf apr-1.6.2.tar.gz
# cd apr-1.6.2
# vim configure

默认值:

RM='$RM'

修改为:

RM='$RM -f'
# ./configure --prefix=/usr/local/apr
# make && make install

4.安装apr-iconv

# tar zxvf apr-iconv-1.2.1.tar.gz
# cd apr-iconv-1.2.1
# ./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr
# make && make install

5.安装apr-util

# tar zxvf apr-util-1.6.0.tar.gz
# cd apr-util-1.6.0
# ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-apr-iconv=/usr/local/apr-iconv/bin/apriconv
# make && make install

6.安装OpenSSL

# tar zxvf openssl-1.1.0f.tar.gz
# cd openssl-1.1.0f
# ./config --prefix=/usr/local/openssl
# make -j 4 && make install

7.安装tomcat-native

# cd /usr/local/tomcat/bin/
# tar zxvf tomcat-native.tar.gz
# cd tomcat-native-1.2.12-src/native
# ./configure --with-ssl=/usr/local/openssl --with-apr=/usr/bin/apr-1-config --with-java-home=/usr/java/jdk1.8.0_131
# make && make install

注意:如果以上 configure 失败,可以执行 make distclean 清除

8.添加变量内容

# vim /etc/profile.d/jdk.sh
export LD_LIBRARY_PATH=/usr/local/apr/lib:$LD_LIBRARY_PATH
# source /etc/profile.d/jdk.sh

至此APR安装成功。

9.接下来需要修改tomcat配置文件中的APR运行模式,并测试是否安装成功。

# vim /usr/local/tomcat/conf/server.xml

默认值:

<Connector port="8080" protocol="HTTP/1.1"
 connectionTimeout="20000"
 redirectPort="8443" />

修改为:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
 connectionTimeout="20000"
 redirectPort="8443" />

默认值:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

修改为:

<Connector port="8009" protocol="org.apache.coyote.ajp.AjpAprProtocol" redirectPort="8443" />

10.现在重启tomcat服务,并查看启动日志

# systemctl restart tomcat
# cat /usr/local/tomcat/logs/catalina.out
...
INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib]
INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]
INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
...

注意:可以看到红色部分,提示找不到基于APR的Apache Tomcat Native库,因此无法使用APR模式启动。

解决方案:

# cp -R /usr/local/apr/lib/* /usr/lib64
# cp -R /usr/local/apr/lib/* /usr/lib

再次重启tomcat,并查看启动日志

# cat /usr/local/tomcat/logs/catalina.out
...
INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-apr-8080"]
INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-apr-8009"]
...

可以看到已经以apr协议模式启动成功,经基于APR的技术web压力测试,Tomcat的性能飙升。

Linux Apache Tomcat 8.5 安装与配置

生产环境:

Server version: Apache Tomcat/8.5.16
CentOS Linux release 7.3.1611 (Core) x86-64

1.Apache Tomcat/8.5.16依赖jre7及以上版本,不过jdk高版本已经包含jre,关于jdk&jre的安装请查看《Linux JAVA JDK JRE 环境变量安装与配置

2.创建tomcat专有用户

# groupadd tomcat
# useradd -g tomcat -s /bin/false tomcat
或
# useradd -g tomcat -s /sbin/nologin tomcat

注意

-g tomcat用户隶属于tomcat组
-s /bin/false 禁用shell访问

3.Apache Tomcat 8.5下载安装与配置&设置用户组权限并创建软连接

# cd /tmp
# wget //apache.fayea.com/tomcat/tomcat-8/v8.5.16/bin/apache-tomcat-8.5.16.tar.gz
# tar zxvf apache-tomcat-8.5.16.tar.gz
# mv apache-tomcat-8.5.16 /usr/local/
# cd /usr/local/
# chown -hR tomcat:tomcat apache-tomcat-8.5.16
# ln -s apache-tomcat-8.5.16 tomcat

4.添加tomcat自启动systemd服务单元文件

# vim /lib/systemd/system/tomcat.service

[Unit]
Description=Apache Tomcat 8
After=syslog.target network.target

[Service]
Type=forking
User=tomcat
Group=tomcat

Environment=JAVA_HOME=/usr/local/jdk/jre
Environment=CATALINA_PID=/usr/local/tomcat/temp/tomcat.pid
Environment=CATALINA_HOME=/usr/local/tomcat
Environment=CATALINA_BASE=/usr/local/tomcat
Environment='CATALINA_OPTS=-Xms512M -Xmx4096M -server -XX:+UseParallelGC'
Environment='CATALINA_OPTS=-Dfile.encoding=UTF-8 -server -Xms2048m -Xmx2048m -Xmn1024m -XX:SurvivorRatio=10 -XX:MaxTenuringThreshold=15 -XX:NewRatio=2 -XX:+DisableExplicitGC'
Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'

ExecStart=/usr/local/tomcat/bin/startup.sh
ExecStop=/bin/kill -15 $MAINPID
Restart=on-failure

[Install]
WantedBy=multi-user.target

5.重载systemd服务单元,给予软连接目录权限,启动Apache Tomcat服务并设置Tomcat为开机自启动

# systemctl daemon-reload
# cd /usr/local/
# chown -hR tomcat:tomcat tomcat
# systemctl start tomcat
# systemctl enable tomcat

6.配置Apache Tomcat用户实现远程登录

在tomcat-users.xml文件<tomcat-users></tomcat-users>中间添加;

# vim /usr/local/tomcat/conf/tomcat-users.xml
<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>

tomcat8.5之后的版本,已经增强远程登录安全过滤规则,默认不支持远程登录,需要修改配置文件。

修改文件:

/host-manager/META-INF/context.xml
/manager/META-INF/context.xml

默认值:

<Valve className="org.apache.catalina.valves.RemoteAddrValve"
 allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />

修改为:

<Valve className="org.apache.catalina.valves.RemoteAddrValve"
 addConnectorPort="true"
 allow="127\.\d+\.\d+\.\d+;\d*|::1;\d*|0:0:0:0:0:0:0:1;\d*|.*;8080"/>

详情可查看 Valve 文档

7.配置Firewalld防火墙

如果不放行8080端口,就无法在外部使用8080进行访问,现在将端口放行并重载firewall服务

# firewall-cmd --zone=public --add-port=8080/tcp --permanent
# firewall-cmd --reload
# firewall-cmd --list-ports
# firewall-cmd --list-services

目前为止Apache Tomcat 8.5.16已经成功安装。现在您可以使用IP:port进行测试访问。

Linux JAVA JDK JRE 环境变量安装与配置

一般安装JDK JAVA环境有2种方式,下面我逐个说明。

生产环境:

$ hostnamectl
 Static hostname: localhost.localdomain
 Icon name: computer-vm
 Chassis: vm
 Machine ID: 769ef9902d8743958a40cb81db696433
 Boot ID: ce70591a91b64e73926682db72441f7b
 Virtualization: microsoft
 Operating System: CentOS Linux 7 (Core)
 CPE OS Name: cpe:/o:centos:centos:7
 Kernel: Linux 3.10.0-514.2.2.el7.x86_64
 Architecture: x86-64

一、rpm Tool安装方式(相对简单)

1.下载对应的JAVA JDK RPM包 64位:

//www.oracle.com/technetwork/java/javase/downloads/index.html

2.开始安装:

# cd /tmp
# rpm -ivh jdk-8u144-linux-x64.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:jdk1.8.0_144-2000:1.8.0_144-fcs  ################################# [100%]
Unpacking JAR files...
        tools.jar...
        plugin.jar...
        javaws.jar...
        deploy.jar...
        rt.jar...
        jsse.jar...
        charsets.jar...
        localedata.jar...

3.RPM包安装完成,验证是否安装成功,如果有输出JDK相关版本说明已经安装成功。

# java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

4.添加JAVA JDK环境变量:

# vim /etc/profile.d/java.sh

JAVA_HOME=/usr/java/jdk1.8.0_144
JRE_HOME=/usr/java/jdk1.8.0_144/jre
CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export JAVA_HOME JRE_HOME PATH CLASSPATH

5.永久使环境变量生效:

# source /etc/profile.d/java.sh

RPM安装方式已经完成。

二、JAVA JDK源码Tarball包安装方式(推荐)

1.先卸载之前通过rpm或yum安装的包,如果输出无,说明没安装,反之已安装。

# rpm -qa | grep -E '^open[jre|jdk]|j[re|dk]'
libbasicobjects-0.1.1-27.el7.x86_64
openjpeg-libs-1.5.1-16.el7_3.x86_64
gobject-introspection-1.42.0-1.el7.x86_64
openjpeg-1.5.1-16.el7_3.x86_64
jdk1.8.0_131-1.8.0_131-fcs.x86_64
pygobject3-base-3.14.0-3.el7.x86_64
openjpeg-devel-1.5.1-16.el7_3.x86_64

2.卸载已安装的JDK:

# yum -y remove jdk1.8.0_131-1.8.0_131-fcs.x86_64

3.下载对应的JDK版本Tarball包 64位并解压:

//www.oracle.com/technetwork/java/javase/downloads/index.html

# cd /mnt
# tar zxvf jdk-8u144-linux-x64.tar.gz
# mv jdk-8u144-linux-x64 /usr/local/
# cd /usr/local/
# ln -s jdk-8u144-linux-x64 jdk

4.添加JAVA JDK环境变量:

# vim /etc/profile.d/jdk.sh

JAVA_HOME=/usr/local/jdk
JRE_HOME=/usr/local/jdk/jre
CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export JAVA_HOME JRE_HOME PATH CLASSPATH

5.永久使JAVA JDK环境变量生效:

# source /etc/profile.d/jdk.sh

6.查看JAVA JDK版本输出:

# java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

7.至此java jdk环境安装配置已经完成。

JAVA JDK JRE环境安装有多种方式,每一种方式都可以使用,找到适合自己的,如果要我推荐,我建议选择Tarball构建。