1. 程式人生 > >Tomcat多實例集群架構 安全優化和性能優化

Tomcat多實例集群架構 安全優化和性能優化

cti java.net null cape 增加 排查 基礎 添加 finished

Tomcat多實例

復制tomcat目錄

#將tar解壓出來的tomcat復制出兩個實例來
cp
-a /usr/local/apache-tomcat-8.0.46 /usr/local/tomcat1 cp -a /usr/local/apache-tomcat-8.0.46 /usr/local/tomcat2

修改多實例配置文件

#創建多實例的網頁根目錄
mkdir -p /data/www/www/ROOT
#修改多實例配置文件的以下三行
vim /usr/local/tomcat/conf/server.xml
 22  <Server port="8005" shutdown="SHUTDOWN">    #管理端口及停止命令
    
69 <Connector port="8080" protocol="HTTP/1.1" #對外提供服務的端口 123 <Host name="localhost" appBase="webapps" #網站域名及網頁根目錄路徑 第一個實例 <Server port="8011" shutdown="SHUTDOWN"> <Connector port="8081" protocol="HTTP/1.1" <Host name="localhost" appBase="/data/www/www" 第二個實例 <Server port="
8012" shutdown="SHUTDOWN"> <Connector port="8082" protocol="HTTP/1.1" <Host name="localhost" appBase="/data/www/www"

啟動多實例

/usr/local/tomcat1/bin/startup.sh 
/usr/local/tomcat2/bin/startup.sh 

Tomcat集群

使用nginx+Tomcat反向代理集群

Tomcat安全優化和性能優化

安全優化

  • 降權啟動
  • telnet管理端口保護
  • ajp連接端口保護
  • 禁用管理端

(1)降權啟動(同nginx優化部分的監牢模式)

降權的原則就是利用普通用戶來啟動Tomcat :

(1)將Tomcat程序目錄拷貝到普通用戶家目錄下

(2)修改家目錄下程序的配置文件(啟動端口,檢測端口等),並重新指定網頁根目錄路徑。

(3)遞歸授權拷貝後的Tomcat程序的屬主屬組為普通用戶。

(4)用su命令切換為普通用戶,啟動Tomcat進程

(5)此時Tomcat進程的權限為普通用戶權限

(6)如果利用/etc/rc.local文件配置普通用戶程序的開機啟動,那麽需要利用su -c臨時切換身份啟動。具體可參考linux基礎教案裏的用戶管理部分

passwd wk                #創建普通用戶wk
cp -a /usr/local/apache-tomcat-8.0.46/ /home/wk/tomcat    #復制tar解壓的tomcat到wk的家目錄
vim conf/server.xml                 #修改配置文件  改啟動端口 監聽端口 網頁家目錄位置
<Server port="8111" shutdown="SHUTDOWN">
<Connector port="8888" protocol="HTTP/1.1"
<Host name="localhost"  appBase="/home/wk/tomcat/webapps"
chown -R wk:wk tomcat            #修改權限
su wk            #進入普通影虎
./tomcat/bin/startup.sh    #啟動tomcat

(2)telnet管理端口保護

cat /usr/local/tomcat/conf/server.xml
<Server port="8005" shutdown="SHUTDOWN">    #表示通過8005端口來接受SHUTDOWN,用來停止Tomcat進程。默認的方式是非常危險的。需要進行修改
Tomcat默認通過8005端口來接收SHUTDOWN這個字符串來關閉Tomcat進程,但這是非常危險的,因此需要修改端口號來防護。否則,通過telnet命令即可強行關閉Tomcat進程

#利用Telnet來關閉Tomcat進程 telnet
127.0.0.1 8005 #通過telnet連接本地8005端口 [wk@wk ~]$ telnet 127.0.0.1 8005 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is ^]. SHUTDOWN          #輸入大寫shutdown關閉tomcat Connection closed by foreign host.

(3)ajp連接端口保護

vim tomcat/conf/server.xml
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />    #這是AJP協議打開的端口,我們並不需要開啟這個端口,因此註釋掉本行
 <!--Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /-->

(4)禁用管理端

Tomcat默認在安裝完成後的網頁目錄裏有很多多余的目錄,刪除所有不需要用到的目錄,並清空ROOT網頁默認根目錄下的所有東西,規避可能的代碼漏洞

cd tomcat/webapps/        
mkdir /tmp/webapps.b      
mv * /tmp/webapps.b    
mkdir ROOT    

性能優化

1 屏蔽DNS查詢 enableLookups="false"

DNS查詢非常消耗時間,如果開啟會影響Tomcat性能,因此關閉。

#默認沒有,需添加配置文件如下代碼段,在Connector標簽位置。表示禁止DNS查詢
    <Connector  port="8888" protocol="HTTP/1.1"
               connectionTimeout="6000" enableLookups="false" acceptCount="800"
               redirectPort="8443" />

2 jvm調優

Tomcat最吃內存,只要內存足夠,這只貓就跑的很快。
如果系統資源有限,那就需要進行調優,提高資源使用率。

#優化catalina.sh初始化腳本。在catalina.sh初始化腳本中添加以下代碼:
#catalina.sh的路徑為:/usr/local/tomcat/bin/catalina.sh
#此行優化代碼需要加在腳本的最開始,聲明位置。不要放在後邊
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=512m -XX:MaxPermSize=512m"
#代碼說明:
server:一定要作為第一個參數,在多個CPU時性能佳
-Xms:初始堆內存Heap大小,使用的最小內存,cpu性能高時此值應設的大一些
-Xmx:初始堆內存heap最大值,使用的最大內存
上面兩個值是分配JVM的最小和最大內存,取決於硬件物理內存的大小,建議均設為物理內存的一半。
-XX:PermSize:設定內存的永久保存區域
-XX:MaxPermSize:設定最大內存的永久保存區域
-XX:MaxNewSize:
-Xss 15120 這使得JBoss每增加一個線程(thread)就會立即消耗15M內存,而最佳值應該是128K,默認值好像是512k.
+XX:AggressiveHeap 會使得 Xms沒有意義。這個參數讓jvm忽略Xmx參數,瘋狂地吃完一個G物理內存,再吃盡一個G的swap。
-Xss:每個線程的Stack大小
-verbose:gc 現實垃圾收集信息
-Xloggc:gc.log 指定垃圾收集日誌文件
-Xmn:young generation的heap大小,一般設置為Xmx的3、4分之一
-XX:+UseParNewGC :縮短minor收集的時間
-XX:+UseConcMarkSweepGC :縮短major收集的時間

JVM的調優比較復雜,如果想要更詳細的理解JVM如何調優,那麽請參考網友文章:http://www.cnblogs.com/xingzc/p/5756119.html

企業案例:Linux下java/http進程高解決案例

生產環境下某臺tomcat7服務器,在剛發布的時候一切都很正常,在運行一段時間後就出現CPU占用很高的問題,基本上是負載一天比一天高。諸如此類問題,請排查!

問題分析:

(1)程序屬於CPU密集型,和開發溝通過,排除此類情況
(2)程序代碼有問題,出現死循環,可能性極大

問題解決:

(1)開發那邊無法排查代碼某個模塊有問題,從日誌上也無法分析得出
(2)我們可以嘗試通過jstack命令來精確定位出現錯誤的代碼段,從而拿給開發排查

首先查找進程高的PID號(先找到是哪個PID號的進程導致的)

top -H

查看這個進程所有系統調用(再找到是哪個PID號的線程導致的)

strace -p 進程的PID

如果是Web應用,可以繼續打印該線程的堆棧信息(找出有問題的代碼塊)

printf "%x\n" 線程的PID --->#將有問題的線程的PID號轉換成16進制格式
jstack 進程的PID | grep 線程PID號的十六進制格式 -A 30 #過濾出有問題的線程的堆棧信息,找出問題代碼塊

實際操作演示:

 pgrep -l java
2031 java       #java進程及對應PID號
2295 java
2321 java
 strace -p 2031       #查看PID號為2031的java進程的所有線程調用情況
Process 2031 attached - interrupt to quit
futex(0x7f4cdd0e79d0, FUTEX_WAIT, 2032, NULL    #只有一個線程,線程的PID號為2032
^C <unfinished ...>
Process 2031 detached
printf "%x\n" 2032   #將線程的PID號2032轉換成十六進制格式
7f0
jstack 2031 | grep 7f0 -A 30 #追蹤進稱號為2031的進程的所有線程調用,從裏面過濾出16進制為7f0的線程的代碼調用情況
"main" #1 prio=5 os_prio=0 tid=0x00007f4cd4008800 nid=0x7f0 runnable [0x00007f4cdd0e5000]
   java.lang.Thread.State: RUNNABLE
    at java.net.PlainSocketImpl.socketAccept(Native Method)
    at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)    #圓括號裏顯示的是(代碼類名:具體調用的代碼行號)
    at java.net.ServerSocket.implAccept(ServerSocket.java:545)
    at java.net.ServerSocket.accept(ServerSocket.java:513)
    at org.apache.catalina.core.StandardServer.await(StandardServer.java:446)
    at org.apache.catalina.startup.Catalina.await(Catalina.java:713)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:659)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:351)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:485)
"VM Thread" os_prio=0 tid=0x00007f4cd406d000 nid=0x7f1 runnable 
"VM Periodic Task Thread" os_prio=0 tid=0x00007f4cd40b8800 nid=0x7f8 waiting on condition 
JNI global references: 244

Tomcat多實例集群架構 安全優化和性能優化