Tomcat多實例集群架構 安全優化和性能優化
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多實例集群架構 安全優化和性能優化