操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    能目標:

    · 了解Tomcat

    · 熟悉Tomcat多虛擬主機環境

    · 會使用jmeter工具

    · 會優化Tomcat

    · 能處理常見錯誤

    11.1 案例分析

    11.1.1 案例概述

    自2017年11月編程語言排行榜Java占比13%,高居榜首,Tomcat也一度成為Java開發人員的首選。其開源、占用系統資源少、跨平臺等特性被深受喜愛。本章主要學習如何部署Tomcat服務,根據生產環境實現多個虛擬主機的配置,最后的重點是進行壓測,根據壓測結果如何優化Tomcat服務及常見的內存溢出如何處理。

    11.1.2 案例前置知識點

    1. Tomcat介紹

    自從JSP發布之后,推出了各式各樣的JSP引擎。Apache Group在完成GNUJSP1.0的開發以后,開始考慮在SUN的JSWDK基礎上開發一個可以直接提供Web服務的JSP服務器,當然同時也支持Servlet, 這樣Tomcat就誕生了。

    Tomcat是Apache 軟件基金會(Apache Software Foundation)的Jakarta 項目中的一個核心項目,由Apache、Sun 和其他一些公司及個人共同開發而成。其被JavaWorld雜志的編輯選為2001年度最具創新的Java產品,同時它又是sun公司官方推薦的Servlet和JSP容器,因此其越來越多的受到軟件公司和開發人員的喜愛。由于有了Sun 的參與和支持,最新的Servlet 和JSP 規范總是能在Tomcat 中得到體現,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 規范。因為Tomcat 技術先進、性能穩定,而且免費,因而深受Java 愛好者的喜愛并得到了部分軟件開發商的認可,成為目前比較流行的Web 應用服務器。

    Tomcat 服務器是一個免費的開放源代碼的Web 應用服務器,屬于輕量級應用服務器,在中小型系統和并發訪問用戶不是很多的場合下被普遍使用,是開發和調試JSP 程序的首選。對于一個初學者來說,可以這樣認為,當在一臺機器上配置好Apache 服務器,可利用它響應HTML(標準通用標記語言下的一個應用)頁面的訪問請求。實際上,Tomcat是Apache 服務器的擴展,但運行時它是獨立運行的,所以當運行Tomcat 時,它實際上作為一個與Apache 獨立的進程單獨運行的。

    當配置正確時,Apache 為HTML頁面服務,而Tomcat 實際上運行JSP 頁面和Servlet。另外,Tomcat和IIS等Web服務器一樣,具有處理HTML頁面的功能,另外它還是一個Servlet和JSP容器,獨立的Servlet容器是Tomcat的默認模式。不過,Tomcat處理靜態HTML的能力不如Apache服務器。

    2. Tomcat核心組件

    通常意義上的Web服務器接受請求后,只是單純地響應靜態資源,如HTML文件,圖片文件等,不能在后端進行一定的處理操作。 Tomcat是Apache下的一個子項目,它具備Web服務器的所有功能,不僅可以監聽接受請求并響應靜態資源,而且可以在后端運行特定規范的Java代碼Servlet,同時將執行的結果以HTML代碼的形式寫回客戶端。 Tomcat由一系列的組件構成,其中核心的組件有三個: 1)Web容器:完成Web服務器的功能。 2)Servlet容器:名字為catalina,用于處理Servlet代碼。 3)JSP容器:用于將JSP動態網頁翻譯成Servlet代碼。

    3. Tomcat處理請求過程

    1) 請求被發送到本機端口8080,被在那里偵聽的Coyote HTTP/11.1 Connector獲得。 2) Connector把該請求交給它所在的Service的Engine來處理,并等待來自Engine的回應。

    3) Engine獲得請求localhost/yy/index.JSP,匹配它所擁有的所有虛擬主機Host。 4) Engine匹配到名為localhost的Host。即使匹配不到也把請求交給該Host處理,因為該Host被定義為該Engine的默認主機。 5) localhost Host獲得請求/yy/index.JSP,匹配它所擁有的所有Context。 6) Host匹配到路徑為/yy的Context。如果匹配不到,就把該請求交給路徑名為""的Context去處理。 7) path="/yy"的Context獲得請求/index.JSP,在它的mapping table中尋找對應的Servlet。 8) Context匹配到URL PATTERN為*.JSP的Servlet,對應于JSPServlet類。

    9) 構造HttpServletRequest對象和HttpServletResponse對象,作為參數調用JSPServlet的doGet()或doPost()方法。

    10)Context把執行完了之后的HttpServletResponse對象返回給Host。 11)Host把HttpServletResponse對象返回給Engine。 12)Engine把HttpServletResponse對象返回給Connector 。13)Connector把HttpServletResponse對象返回給客戶browser。

    11.1.3 案例環境

    1. 本案例實驗環境

    表11-1 案例的實驗環境

    2. 案例需求

    1)部署Tomcat服務。

    2)配置虛擬主機。

    3)Tomcat優化。

    4)常見錯誤分析及處理。

    3. 案例實現思路

    1)安裝Tomcat需要的環境。

    2)安裝Tomcat服務。

    3)配置虛擬主機。

    4)客戶端安裝壓測軟件進行壓測并調優。

    5)常見錯誤說明。

    11.2 案例實施

    11.2.1 下載并安裝JDK

    1. 在部署Tomcat之前必須安裝好jdk,因為jdk是Tomcat運行的必要環境。而jdk的安裝也相對比較簡單,版本有很多,這里我們選擇rpm版本即可!打開oracle官網http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html,該網頁中會有172的大版本。根據所使用的計算機硬件配置,選擇其中一個安裝包,如圖11.1所示。本章,選擇基于linux64位rpm版本,必須選中Accept License Agreement再進行下載。

    圖11.1

    2. 下載完安裝包后,將其上傳到服務器/root目錄下,執行安裝命令:

    [root@localhost ~]# rpm -ivh jdk-8u171-linux-x64.rpm

    準備中... ################################# [100%]

    正在升級/安裝...

    1:jdk1.8-2000:1.8.0_171-fcs ################################# [100%]

    Unpacking JAR files...

    tools.jar...

    plugin.jar...

    javaws.jar...

    deploy.jar...

    rt.jar...

    jsse.jar...

    charsets.jar...

    localedata.jar...

    3. 上面顯示安裝完成,jdk安裝目錄在/usr/java/jdk1.8.0_171-amd64,設置jdk的環境變量,編輯/etc/profile文件,增加如下內容:

    [root@localhost ~]# vim /etc/profile

    export JAVA_HOME=/usr/java/jdk1.8.0_171-amd64

    export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar

    export PATH=$JAVA_HOME/bin:$PATH

    4. 使環境變量生效:

    [root@localhost ~]# source /etc/profile

    5. 查看jdk版本號,已經顯示是我們安裝的軟件版本:

    [root@localhost ~]# java -version

    java version "1.8.0_171"

    Java(TM) SE Runtime Environment (build 1.8.0_171-b11)

    Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)

    11.2.2 安裝啟動Tomcat

    1. 執行下面的命令,從Tomcat官網下載apache-tomcat-9.0.8.tar.gz穩定版本:

    [root@localhost ~]# wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.8/bin/apache-tomcat-9.0.8.tar.gz

    2. 將安裝包移動Tomcat目錄到/usr/local下面:

    [root@localhost ~]# tar zxf apache-tomcat-9.0.8.tar.gz

    [root@localhost ~]# mv apache-tomcat-9.0.8 /usr/local/tomcat

    3. 啟動Tomcat:

    [root@localhost ~]# /usr/local/tomcat/bin/startup.sh

    Using CATALINA_BASE: /usr/local/tomcat

    Using CATALINA_HOME: /usr/local/tomcat

    Using CATALINA_TMPDIR: /usr/local/tomcat/temp

    Using JRE_HOME: /usr/java/jdk1.8.0_171-amd64

    Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar

    Tomcat started.

    瀏覽器打開http://192.168.9.236:8080進行訪問會出現Tomcat主頁,如圖11.2所示。

    圖11.2

    4. 相信大家第一次啟動查看日志會發現Tomcat啟動很慢,默認情況下都需要幾十秒,可以修改jdk參數進行改善,打開/usr/java/jdk1.8.0_171-amd64/jre/lib/security/java.security文件,找到如下內容:securerandom.source=file:/dev/random修改成securerandom.source=file:/dev/urandom。

    [root@localhost conf]# vim /usr/java/jdk1.8.0_171-amd64/jre/lib/security/java.security

    securerandom.source=file:/dev/urandom

    [root@localhost conf]# /usr/local/tomcat/bin/shutdown.sh//關閉Tomcat

    Using CATALINA_BASE: /usr/local/tomcat

    Using CATALINA_HOME: /usr/local/tomcat

    Using CATALINA_TMPDIR: /usr/local/tomcat/temp

    Using JRE_HOME: /usr/java/jdk1.8.0_171-amd64

    Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar

    [root@localhost conf]# /usr/local/tomcat/bin/startup.sh //啟動Tomcat

    Using CATALINA_BASE: /usr/local/tomcat

    Using CATALINA_HOME: /usr/local/tomcat

    Using CATALINA_TMPDIR: /usr/local/tomcat/temp

    Using JRE_HOME: /usr/java/jdk1.8.0_171-amd64

    Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar

    Tomcat started.

    然后,重啟Tomcat就會發現啟動時間變短了很多。

    5. 查看Tomcat安裝后目錄結構,如下圖11.3所示:

    圖11.3

    下面,對每個目錄進行說明。

    1)bin

    存放啟動和關閉Tomcat的腳本文件,比較常用的是catalina.sh、startup.sh、shutdown.sh三個文件。

    2)conf

    存放Tomcat服務器的各種配置文件,比較常用的是server.xml、context..xml、tomcat-users.xml、web.xml四個文件。

    3)lib

    存放Tomcat服務器的jar包,一般不作任何改動,除非連接第三方服務,比如redis,那就需要添加相對應的jar包。

    4)logs

    存放Tomcat日志。

    5)temp

    存放Tomcat運行時產生的文件。

    6)webapps

    存放項目資源的目錄。

    7)work

    Tomcat工作目錄,一般清除Tomcat緩存的時候會使用到。

    11.2.3 虛擬主機配置

    可能有時候公司會有多個項目需要運行,那么肯定不可能是一臺服務器上運行多個Tomcat服務,這樣會消耗太多的系統資源。此時,就需要使用到Tomcat虛擬主機。例如現在新增兩個域名www.test.com和bbs.test.com,希望通過這兩個域名訪問到不同的項目內容。

    1. 創建www和bbs項目目錄和文件

    執行下面的命令,可以創建www和bbs項目目錄和文件。

    [root@localhost ~]# mkdir /usr/local/tomcat/webapps/www

    [root@localhost ~]# echo "This is www page\!" > /usr/local/tomcat/webapps/www/index.jsp

    [root@localhost ~]# mkdir /usr/local/tomcat/webapps/bbs

    [root@localhost ~]# echo "This is bbs page\!" > /usr/local/tomcat/webapps/bbs/index.jsp

    2. 修改Tomcat主配置文件

    修改Tomcat主配置文件/usr/local/tomcat/conf/server.xml,在</Host>下面增加如下內容:

    //關于www.test.com的虛擬主機配置

    <Host name="www.test.com" appBase="/usr/local/tomcat/webapps"

    unpackWARs="true" autoDeploy="true" xmlValidation="false"

    xmlNamespaceAware="false">

    <Context docBase="/usr/local/tomcat/webapps/www"

    path="" reloadable="true" />

    </Host>

    //關于bbs.test.com的虛擬主機配置

    <Host name="bbs.test.com" appBase="/usr/local/tomcat/webapps"

    unpackWARs="true" autoDeploy="true" xmlValidation="false"

    xmlNamespaceAware="false">

    <Context docBase="/usr/local/tomcat/webapps/bbs"

    path="" reloadable="true" />

    </Host>

    [root@localhost ~]# /usr/local/tomcat/bin/shutdown.sh

    [root@localhost ~]# /usr/local/tomcat/bin/startup.sh

    3. 測試

    客戶端綁定兩個域名需要寫入本機hosts,Tomcat默認端口是8080。

    192.168.9.236 www.test.com

    192.168.9.236 bbs.test.com

    使用瀏覽器訪問http://www.test.com:8080,頁面效果如圖11.4所示。

    圖11.4

    使用瀏覽器訪問http://bbs.test.com:8080,頁面效果如圖11.5所示。

    圖11.5

    11.2.4 Tomcat優化

    Tomcat 的缺省配置并不適合生產環境,它會頻繁出現假死現象需要重啟,只有通過不斷壓測優化才能讓它最高效率穩定的運行。優化主要有三方面,分為操作系統優化(內核參數優化),Tomcat 配置文件參數優化,Java 虛擬機(JVM)調優。其中最難理解的就是jvm調優。系統優化本章不介紹,本章將配合jmeter壓測工具進行調優前和調優后的數據進行比較。

    1. Tomcat配置文件參數優化

    關于Tomcat主配置文件server.xml里面很多默認的配置項,但并不能滿足業務需求,常用的優化相關參數如下。

    1)maxThreads:Tomcat 使用線程來處理接收的每個請求,這個值表示Tomcat可創建的最大的線程數,默認值是200。

    2)minSpareThreads:最小空閑線程數,Tomcat 啟動時的初始化的線程數,表示即使沒有人使用也開這么多空線程等待,默認值是 10。

    3)maxSpareThreads:最大備用線程數,一旦創建的線程超過這個值,Tomcat 就會關閉不再需要的 socket 線程。默認值是-1(無限制)。一般不需要指定。

    4)URIEncoding:指定 Tomcat 容器的 URL 編碼格式,語言編碼格式這塊倒不如其它 Web 服務器軟件配置方便,需要分別指定。

    5)connnectionTimeout:網絡連接超時,單位:毫秒,設置為0表示永不超時,這樣設置有隱患的。通常默認20000毫秒就可以。

    6) enableLookups:是否反查域名,以返回遠程主機的主機名,取值為:true 或 false,如果設置為false,則直接返回IP地址,為了提高處理能力,應設置為 false。

    disableUploadTimeout:上傳時是否使用超時機制。應設置為true。

    8) connectionUploadTimeout:上傳超時時間,畢竟文件上傳可能需要消耗更多的時間,這個根據你自己的業務需要自己調,以使Servlet有較長的時間來完成它的執行,需要與上一個參數一起配合使用才會生效。

    9)acceptCount:指定當所有可以使用的處理請求的線程數都被使用時,可傳入連接請求的最大隊列長度,超過這個數的請求將不予處理,默認為100個。

    10)compression:是否對響應的數據進行 GZIP 壓縮,off:表示禁止壓縮;on:表示允許壓縮(文本將被壓縮)、force:表示所有情況下都進行壓縮,默認值為off,壓縮數據后可以有效的減少頁面的大小,一般可以減小1/3左右,節省帶寬。

    11)compressionMinSize:表示壓縮響應的最小值,只有當響應報文大小大于這個值的時候才會對報文進行壓縮,如果開啟了壓縮功能,默認值就是2048。

    compressableMimeType:壓縮類型,指定對哪些類型的文件進行數據壓縮。

    13)noCompressionUserAgents="gozilla, traviata":對于以下的瀏覽器,不啟用壓縮。

    如果已經對代碼進行了動靜分離,靜態頁面和圖片等數據就不需要Tomcat 處理了,那么也就不需要在Tomcat 中配置壓縮了。因為這里只有一臺Tomcat服務器,而且壓測的是Tomcat首頁,會有圖片和靜態資源文件,所以這里啟用壓縮。

    以上是一些常用的配置參數,還有好多其它的參數設置,還可以繼續深入的優化,HTTP Connector 與 AJP Connector 的參數屬性值,可以參考官方文檔的詳細說明進行學習。鏈接地址http://tomcat.apache.org/tomcat-9.0-doc/config/http.html,下面開始對Tomcat配置文件優化進行前后的對比。

    要壓測,首先學習關于jmeter壓測工具基本的使用方法。執行步驟如下:

    1)客戶端安裝jdk,可以從Oracle官方下載,安裝過程直接下一步即可!

    2)運行jmeter軟件,如題11.6所示。

    圖11.6

    3)打開壓測腳本進行壓測,點擊左上角文件->打開->選擇壓測腳本,如圖11.7所示。

    圖11.7

    4.點擊打開按鈕,點擊第一排綠色三角按鈕(鼠標指上去后會顯示啟動)開始進行壓測,如圖11.8所示。

    圖11.8

    壓測腳本里設置的是20秒啟動4000個線程數,并發為2000,超時時間是50000毫秒。也可以適當的根據自己的需求進行修改。為了不那么復雜,從壓測結果看只關注聚合報告,聚合報告只關注Average、90% Line、Error%這三列,因為壓測Tomcat首頁壓力不會太大,所以Error都是為0屬于正常。先看一組優化前(默認的配置)壓測截圖,如圖11.9所示。

    圖11.9

    5. 打開Tomcat主配置文件server.xml,找到默認配置:

    <Connector port="8080" protocol="HTTP/11.1"

    connectionTimeout="20000"

    redirectPort="8443" />

    將默認配置做修改:

    <Connector port="8080" protocol="HTTP/11.1"

    connectionTimeout="20000"

    redirectPort="8443" minSpareThreads="50"

    enableLookups="false" disableUploadTimeout="true"

    acceptCount="300" maxThreads="500" processorCache="500"

    URIEncoding="UTF-8"

    compression="on"

    compressionMinSize="2048"

    compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,image/gif,image/jpg,image/png"/>

    6. 重新啟動Tomcat服務器,jmeter還是繼續保持同樣的參數進行壓測,優化后壓測截圖,如11.10所示。

    圖11.10

    從結果看優化后的平均值和90%響應時間比優化前的快。

    2. JVM優化

    Tomcat 啟動命令行中的優化參數,就是 JVM 的優化 。Tomcat 首先跑在 JVM 之上的,因為它的啟動其實也只是一個Java命令行,首先我們需要對這個Java的啟動命令行進行調優。不管是YGC還是Full GC、GC都會導致程序運行中斷,正確的選擇不同的GC策略,調整JVM、GC的參數,可以極大的減少由于GC工作而導致的程序運行中斷方面的問題,進而適當的提高 Java程序的工作效率。但是調整GC是以個極為復雜的過程,由于各個程序具備不同的特點,如Web和GUI程序就有很大區別(Web可以適當的停頓,但GUI停頓是客戶無法接受的),而且由于跑在各個機器上的配置不同(主要 CPU個數,內存不同),所以使用的 GC 種類也會不同。下面對JVM 參數做比較詳細的說明。

    Tomcat 的啟動參數位于安裝目錄 ${JAVA_HOME}/bin目錄下,Linux操作系統就是 catalina.sh 文件。Java_OPTS就是用來設置JVM 相關運行參數的變量,下面具體看JVM常用參數詳解。

    -server:一定要作為第一個參數,只要Tomcat是運行在生產環境中,這個參數必須給加上,不然后面的參數不會生效 。

    -Xms:表示Java初始化堆的大小,-Xms與-Xmx設成一樣的值,避免JVM反復重新申請內存,導致性能大起大落,默認值為物理內存的1/64,默認(MinHeapFreeRatio參數可以調整)空余堆內存小于40%時,JVM就會增大堆直到 -Xmx 的最大限制。

    -Xmx:表示最大Java堆大小,當應用程序需要的內存超出堆的最大值時虛擬機就會提示內存溢出,并且導致應用服務崩潰,因此一般建議堆的最大值設置為物理內存的最大值的50%。

    -XX:NewSize:設置新生代內存大小。

    -XX:MaxNewSize:設置最大新生代新生代內存大小。

    -XX:PermSize:設置持久代內存大小。

    -XX:MaxPermSize:設置最大值持久代內存大小,永久代不屬于堆內存,堆內存只包含新生代和老年代。

    XX:+AggressiveOpts:作用如其名(aggressive),啟用這個參數,則每當JDK版本升級時,你的JVM都會使用最新加入的優化技術(如果有的話)。

    -XX:+UseBiasedLocking:啟用一個優化了的線程鎖,我們知道在我們的appserver,每個http請求就是一個線程,有的請求短有的請求長,就會有請求排隊的現象,甚至還會出現線程阻塞,這個優化了的線程鎖使得你的appserver內對線程處理自動進行最優調配。

    -XX:+DisableExplicitGC:在 程序代碼中不允許有顯示的調用"System.gc()"。每次在到操作結束時手動調用 System.gc() 一下,付出的代價就是系統響應時間嚴重降低,就和關于 Xms,Xmx 里的解釋的原理一樣,這樣去調用GC導致系統的JVM大起大落。

    -XX:+UseParNewGC:對新生代采用多線程并行回收,這樣收得快,注意最新的JVM 版本,當使用 -XX:+UseConcMarkSweepGC 時,-XX:UseParNewGC 會自動開啟。因此,如果年輕代的并行GC不想開啟,可以通過設置 -XX:-UseParNewGC 來關掉。

    -XX:MaxTenuringThreshold:設置垃圾最大年齡。如果設置為0的話,則新生代對象不經過 Survivor 區,直接進入老年代。對于老年代比較多的應用(需要大量常駐內存的應用),可以提高效率。如果將此值設置為一 個較大值,則新生代對象會在 Survivor 區進行多次復制,這樣可以增加對象在新生代的存活時間,增加在新生代即被回收的概率,減少Full GC的頻率,這樣做可以在某種程度上提高服務穩定性。該參數只有在串行 GC 時才有效,這個值的設置是根據本地的 jprofiler 監控后得到的一個理想的值,不能一概而論原搬照抄。

    -XX:+CMSParallelRemarkEnabled:在使用 UseParNewGC 的情況下,盡量減少 mark 的時間。

    -XX:+UseCMSCompactAtFullCollection:在使用concurrent gc的情況下,防止 memoryfragmention,對live object進行整理,使memory碎片減少。

    -XX:LargePageSizeInBytes:指定 Java heap 的分頁頁面大小,內存頁的大小不可設置過大, 會影響Perm的大小。

    -XX:+UseFastAccessorMethods:使用get,set方法轉成本地代碼,原始類型的快速優化。

    -XX:+UseCMSInitiatingOccupancyOnly:只有在oldgeneration在使用了初始化的比例后 concurrent collector 啟動收集。

    -Duser.timezone=Asia/Shanghai:設置用戶所在時區。

    -Djava.awt.headless=true:這個參數一般我們都是放在最后使用。有時我們會在我們的J2EE工程中使用一些圖表工具,如:jfreechart,用于在Web 網頁輸出GIF/JPG等流,在Windows環境下,一般我們的app server在輸出圖形時不會碰到什么問題,但是在Linux/Unix 環境下經常會碰到一個 exception 導致你在 Windows開發環境下圖片正常顯示,可是在Linux/Unix下卻顯示不出來,因此加上這個參數以免避這樣的情況出現。

    -Xmn:新生代的內存空間大小,注意:此處的大小是(eden+ 2 survivor space)。與 jmap -heap 中顯示的 New gen 是不同的。整個堆大小=新生代大小 + 老生代大小 + 永久代大小。在保證堆大小不變的情況下,增大新生代后,將會減小老生代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的 3/8。

    -XX:CMSInitiatingOccupancyFraction:當堆滿之后,并行收集器便開始進行垃圾收集。例如,當沒有足夠的空間來容納新分配或提升的對象。對于CMS收集器,長時間等待是不可取的,因為在并發垃圾收集期間應用持續在運行(并且分配對象)。因此,為了在應用程序使用完內存之前完成垃圾收集周期,CMS收集器要比并行收集器更先啟動。因為不同的應用會有不同對象分配模式,JVM會收集實際的對象分配(和釋放)的運行時數據,并且分析這些數據,來決定什么時候啟動一次CMS垃圾收集周期。這個參數設置有很大技巧,基本上滿足(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100 >=Xmn就不會出現 promotion failed。例如在應用中Xmx是6000,Xmn是512,那么 Xmx-Xmn是5488M,也就是老年代有 5488M,CMSInitiatingOccupancyFraction=90 說明老年代到 90% 滿的時候開始執行對老年代的并發垃圾回收(CMS),這時還 剩10%的空間是 5488*10%=548M,所以即使 Xmn(也就是新生代共512M)里所有對象都搬到老年代里,548M 的空間也足夠了,所以只要滿足上面的公式,就不會出現垃圾回收時的promotion failed,因此這個參數的設置必須與Xmn關聯在一起。

    -XX:+CMSIncrementalMode:該標志將開啟 CMS 收集器的增量模式。增量模式經常暫停 CMS 過程,以便對應用程序線程作出完全的讓步。因此,收集器將花更長的時間完成整個收集周期。因此,只有通過測試后發現正常 CMS 周期對應用程序線程干擾太大時,才應該使用增量模式。由于現代服務器有足夠的處理器來適應并發的垃圾收集,所以這種情況發生得很少,用于但 CPU情況。

    -XX:NewRatio:年輕代(包括 Eden 和兩個 Survivor 區)與年老代的比值(除去持久代),-XX:NewRatio=4 表示年輕代與年老代所占比值為 1:4,年輕代占整個堆棧的 1/5,Xms=Xmx 并且設置了Xmn的情況下,該參數不需要進行設置。

    -XX:SurvivorRatio:Eden 區與 Survivor 區的大小比值,設置為 8,表示 2 個 Survivor 區(JVM 堆內存年輕代中默認有 2 個大小相等的 Survivor 區)與 1 個 Eden 區的比值為 2:8,即 1 個 Survivor 區占整個年輕代大小的 1/10。

    -XX:+UseSerialGC:設置串行收集器。

    -XX:+UseParallelGC:設置為并行收集器。此配置僅對年輕代有效。即年輕代使用并行收集,而年老代仍使用串行收集。

    -XX:+UseParallelOldGC:配置年老代垃圾收集方式為并行收集,JDK6.0 開始支持對年老代并行收集。

    -XX:ConcGCThreads:早期 JVM 版本也叫-XX:ParallelCMSThreads,定義并發 CMS 過程運行時的線程數。比如 value=4 意味著 CMS 周期的所有階段都以 4 個線程來執行。盡管更多的線程會加快并發 CMS 過程,但其也會帶來額外的同步開銷。因此,對于特定的應用程序,應該通過測試來判斷增加 CMS 線程數是否真的能夠帶來性能的提升。如果還標志未設置,JVM 會根據并行收集器中的 -XX:ParallelGCThreads 參數的值來計算出默認的并行 CMS 線程數。

    -XX:ParallelGCThreads:配置并行收集器的線程數,即:同時有多少個線程一起進行垃圾回收,此值建議配置與CPU數目相等。

    -XX:OldSize:設置JVM啟動分配的老年代內存大小,類似于新生代內存的初始大小 -XX:NewSize。

    以上就是一些常用的配置參數,但是有些參數是可以被替代的,配置思路需要考慮的是 Java 提供的垃圾回收機制。虛擬機的堆大小決定了虛擬機花費在收集垃圾上的時間和頻度。收集垃圾能夠接受的速度和應用有關,應該通過分析實際的垃圾收集的時間和頻率來調整。假如堆的大小很大,那么完全垃圾收集就會很慢,但是頻度會降低。假如您把堆的大小和內存的需要一致,完全收集就很快,但是會更加頻繁。調整堆大小的目的是最小化垃圾收集的時間,以在特定的時間內最大化處理客戶的請求。在基準測試的時候,為確保最好的性能,要把堆的大小設大,確保垃圾收集不在整個基準測試的過程中出現。

    測試前,先還原Tomcat到默認的配置文件,重啟后壓測一組優化前壓測截圖,如圖11.11所示。

    圖11.11

    上述關于jvm優化參數太多,很多參數需要對GC回收有很深刻的認識。如果優化的不合適,往往會起到事倍功半的效果。下面是常見的優化參數,修改/usr/local/tomcat/bin/catalina.sh,增加紅色字體。

    # OS specific support. $var _must_ be set to either true or false.

    JAVA_OPTS="-server -Xms4096m -Xmx4096m -XX:PermSize=2048m -XX:MaxPermSize=2048m"

    cygwin=false

    darwin=false

    重啟Tomcat服務再次進行一輪壓測,如圖11.12所示。

    圖11.12

    從結果看優化后的平均值和90%響應時間比優化前的快。

    結論:在每次優化完后壓測數據都可能會存在差異,甚至環境一樣壓測結果都會不一樣,一般都是取多組數據平均值。本案例中的簡單的優化配置也不一定適合你的環境,但是至少優化的方向是正確的。如果想對jmeter進行深入學習,請查閱相關文檔。

    11.2.5 常見錯誤說明

    1.java.lang.OutOfMemoryError: Java heap space——JVM Heap(堆)溢出

    JVM 在啟動的時候會自動設置JVM Heap的值,其初始空間(即-Xms)是物理內存的1/64,最大空間(-Xmx)不可超過物理內存。可以利用JVM提供的 -Xmn -Xms -Xmx等選項可進行設置。Heap的大小是Young Generation和Tenured Generaion之和。在 JVM中如果98%的時間是用于GC,且可用的Heap size不足2%的時候將拋出此異常信息。

    解決方法:手動設置 JVM Heap(堆)的大小。

    2. java.lang.OutOfMemoryError: PermGen space——PermGen space溢出

    PermGen space的全稱是 Permanent Generation space,是指內存的永久保存區域。為什么會內存溢出,這是由于這塊內存主要是被JVM存放Class和Meta信息的,Class在被Load的時候被放入PermGen space區域,它和存放Instance的Heap區域不同,sun 的GC不會在主程序運行期對PermGen space進行清理。所以,如果你的APP會載入很多 CLASS的話,就很可能出現PermGen space溢出。

    解決方法:手動設置 MaxPermSize 大小。

    3. java.lang.StackOverflowError——棧溢出

    JVM依然是采用棧式的虛擬機,這個和C與Pascal都是一樣的。函數的調用過程都體現在堆棧和退棧上了。調用構造函數的"層"太多了,以致于把棧區溢出了。通常來講,一般棧區遠遠小于堆區的,因為函數調用過程往往不會多于上千層,而即便每個函數調用需要 1K 的空間(這個大約相當于在一個C函數內聲明了256個int類型的變量),那么棧區也不過是需要1MB 的空間。通常棧的大小是1-2MB的。通常遞歸也不要遞歸的層次過多,很容易溢出。

    解決方法:修改程序。

    背景

    Linux CentOS7 操作系統下,開機啟動項的添加有兩種方式:一種是傳統的編輯腳本文件放置 /etc/init.d 目錄下,使用 chkconfig 命令添加;另一種是編寫服務文件,由 systemd 調用啟動。

    前面介紹的 MySQL 安裝后的開機啟動服務文件為 mysql.service,屬于 systemd 方式添加的。

    我們的 Java web 應用通常是依賴于 MySQL 數據庫服務的,必須保證 MySQL 服務啟動后再啟動 Tomcat 容器。因此,使用 chkconfig 方式就可能出現 Tomcat 比 MySQL 服務先啟動、導致 Tomcat 應用數據庫連接異常的問題。

    systemd 服務管理命令可以指定服務間的依賴關系,基于此,我們可以自定義tomcat.service 文件來實現 Tomcat開機啟動。

    第一步,編寫啟動腳本

    準備 Tomcat 的開機啟動 Shell 腳本,接收啟動參數如 start、stop;它可以直接調用 tomcat 的 startup.sh完成的,也可以添加額外的流程,如 Web 環境初始化邏輯等,然后再調用 startup.sh。

    這是一個比較常見的 Tomcat 開機啟動服務腳本

    #!/bin/bash 
    JAVA_HOME=/usr/java/jdk1.8.0_151
    CATALINA_HOME=/usr/lib/tomcat
    export JAVA_HOME
    export CATALINA_HOME
    
    start_tomcat=$CATALINA_HOME/bin/startup.sh
    stop_tomcat=$CATALINA_HOME/bin/shutdown.sh
    
    start() {                                                              
             echo -n "Starting tomcat: "
             ${start_tomcat}
             echo "Tomcat start ok."
    }
    
    stop() {
             echo -n "Shutting down tomcat: "
             ${stop_tomcat}
             echo "Tomcat stop ok."
     }
    
                                                   
     case "$1" in
       start)
             start
             ;;
       stop)
             stop
             ;;
       restart)
             stop
             sleep 10
             start
             ;;
       *)
      echo "Usage: $0 {start|stop|restart}"
     esac
    
     exit 0

    touch /home/tomcat,vi 編輯并輸入上述腳本內容,即完成了開機腳本的編寫。本質就是一個 shell 腳本,轉而調用真正的 Tomcat 的腳本。

    第二步,編寫服務文件

    開機時,systemd 會讀取 /etc/systemd/system 目錄下以 .service 后綴的文件。
    編寫服務文件。

    cd /etc/systemd/system 
    touch tomcat.service

    編寫 tomcat.service 文件,內容如下

    [Unit]
    Description=MyTomcat
    After=mysql.service
    
    [Service]
    Type=forking
    
    # Disable service start and stop timeout logic of systemd for mysqld service.
    TimeoutSec=0
    
    ExecStart=/home/tomcat start
    ExecStop=/home/tomcat stop
    PrivateTmp=true
    
    [Install]
    WantedBy=multi-user.target

    注意事項:

    1. Unit 里面的 After 設置為 mysql.service ,是可以保證 MySQL 服務啟動之后,才開始執行該服務腳本。
    2. TimeoutSec=0 標識讓開機啟動不處理 Tomcat 啟動超時異常,保證 Tomcat 耗時過長時不會被系統 terminating
    3. 可以指定 PID File為 /run 目錄的下某個文件,如 /run/mytomcat.pid 但是不應該用tomcat.pid,這里配置的是 Tomcat 開機啟動服務的 PID 文件,真正的 Tomcat 進程也會有一個 tomcat.pid 的進程編號文件,必須避免沖突
    4. ExecStart 和 ExecStop 是指定服務的啟動腳本,如果沒有第一步編寫的 tomcat 腳本的話,可以直接用為 tomcat/bin/startup.sh 的。

    第三步,啟動服務

    tomcat.service 文件準備好之后,使用 systemctl enable tomcat.service 命令添加服務。

    systemctl start/stop/status tomcat.service 啟動、停止、狀態查看。

    此外 service 文件修改后,需要調用 systemctl daemon-reload命令重新加載。

    啟示錄

    首先,以這種方式添加 Tomcat 之后,使用 jps 命令查看 Java 進程時,是找不到 tomcat進程的,只能用 ps -ef|grep java 方式才能查到,這點與 chkconfig 方式不同。

    其次,這種方式真正的 Tomcat 腳本啟動后會在根目錄下生成一個 tomcat.pid 的進程文件,而 chkconfig 方式卻不會。

    第三,chkconfig 方式添加開機啟動時,如果啟動腳本中想等待其他服務完成、而執行了sleep 命令的話,會出現超時中斷啟動問題。

    Dec 6 19:17:21 localhost systemd: tomcat.service start operation timed out. Terminating.
    Dec 6 19:17:21 localhost systemd: Failed to start SYSV: Starts and Stops the Tomcat daemon…
    Dec 6 19:17:21 localhost systemd: Unit tomcat.service entered failed state.
    Dec 6 19:17:21 localhost systemd: tomcat.service failed.

    第四,Linux 的系統日志文件 /var/log/messages 里面記錄系統開機啟動的所有日志信息,一般服務啟動操作都是有成對日志信息的,我們可以在這里檢查服務啟動的流程是否正確。

    這是 MySQL 的日志信息:

    Starting MySQL Server…
    Started MySQL Server.
    Starging MyTomcat…
    Started MyTomcat

    配置 MyTomcat 啟動 Aftemysql.service 后,日志就是上述這樣的順序了。

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有