小伙伴問我性能指標(biāo)監(jiān)控怎么做,這次我安排上了?。?/h1>
作者個人研發(fā)的在高并發(fā)場景下,提供的簡單、穩(wěn)定、可擴(kuò)展的延遲消息隊(duì)列框架,具有精準(zhǔn)的定時任務(wù)和延遲隊(duì)列處理功能。自開源半年多以來,已成功為十幾家中小型企業(yè)提供了精準(zhǔn)定時調(diào)度方案,經(jīng)受住了生產(chǎn)環(huán)境的考驗(yàn)。為使更多童鞋受益,現(xiàn)給出開源框架地址:https://github.com/sunshinelyz/mykit-delay
小伙伴的疑問小伙伴:監(jiān)控怎么做?
我:你指的是?
小伙伴:性能指標(biāo)。
我:后面會專門寫這些文章。
使用JMX監(jiān)控Tomcat
關(guān)于監(jiān)控的文章,先寫些什么呢?想來想去,我們先來寫一篇使用JMX監(jiān)控Tomcat的實(shí)戰(zhàn)文章吧。好了,我們直接進(jìn)入主題。
激活Tomcat的JMX遠(yuǎn)程配置
要通過JMX遠(yuǎn)程監(jiān)控Tomcat,首先需要激活Tomcat的JMX遠(yuǎn)程配置。
① 修改腳本
先修改Tomcat的啟動腳本,windows下為bin/catalina.bat(linux下為catalina.sh),添加以下內(nèi)容,8999是jmxremote使用的端口號,第二個false表示不需要鑒權(quán):
- set JMX_REMOTE_CONFIG=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
- set CATALINA_OPTS=%CATALINA_OPTS% %JMX_REMOTE_CONFIG%
要注意以上語句的位置不能太后面,可以加在【if "%OS%" == "Windows_NT" setlocal】一句后的大段的注釋后面。
參考官方說明:
- http://tomcat.apache.org/tomcat-6.0-doc/monitoring.html#Enabling_JMX_Remote
- http://tomcat.apache.org/tomcat-7.0-doc/monitoring.html#Enabling_JMX_Remote
- http://tomcat.apache.org/tomcat-8.0-doc/monitoring.html#Enabling_JMX_Remote
- http://tomcat.apache.org/tomcat-9.0-doc/monitoring.html#Enabling_JMX_Remote
② 鑒權(quán)
上面的配置是不需要鑒權(quán)的,如果需要鑒權(quán)則添加的內(nèi)容為:
- set JMX_REMOTE_CONFIG=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access
- set CATALINA_OPTS=%CATALINA_OPTS% %JMX_REMOTE_CONFIG%
③ 復(fù)制并修改授權(quán)文件
$JAVA_HOME/jre/lib/management下有jmxremote.access和jmxremote.password的模板文件,將兩個文件復(fù)制到$CATALINA_BASE/conf目錄下
- 修改$CATALINA_BASE/conf/jmxremote.access 添加內(nèi)容
- monitorRole readonly
- controlRole readwrite
- 修改$CATALINA_BASE/conf/jmxremote.password 添加內(nèi)容:
- monitorRole binghe
- controlRole binghe
注意:如果進(jìn)行了以上步驟導(dǎo)致Tomcat啟動不了,那么很可能是密碼文件的權(quán)限問題
需要修改jmxremote.password文件的訪問權(quán)限,只有運(yùn)行Tomcat的用戶才能擁有訪問權(quán)限 :
Windows的NTFS文件系統(tǒng)下,選中文件,點(diǎn)右鍵 -->“屬性”-->“安全”--> 點(diǎn)“高級”--> 點(diǎn)“更改權(quán)限”--> 去掉“從父項(xiàng)繼承....”--> 彈出窗口中選“刪除”,這樣就刪除了所有訪問權(quán)限。再選“添加”--> “高級”--> “立即查找”,選中你的用戶(或用戶組,如果選用戶不行那就選用戶組),例administrator,點(diǎn)“確定",“確定"。來到權(quán)限項(xiàng)目窗口,勾選“完全控制”,點(diǎn)“確定”,OK了。
官方的提示
- The password file should be read-only and only accessible by the operating system user Tomcat is running as.
④驗(yàn)證配置
重新啟動Tomcat,在Windows命令行輸入“netstat -a”查看配置的端口號是否已打開,如果打開,說明上面的配置成功了。
⑤ 使用jconsole測試JMX
運(yùn)行$JAVA_HOME/bin目錄下的jconsole.exe,打開J2SE監(jiān)視和管理控制臺,然后建立連接,如果是本地的Tomcat則直接選擇然后點(diǎn)擊連接,如果是遠(yuǎn)程的,則進(jìn)入遠(yuǎn)程選項(xiàng)卡,填寫地址、端口號、用戶名、口令即可連接。。Mbean屬性頁中給出了相應(yīng)的數(shù)據(jù),Catalina中是tomcat的,java.lang是jvm的。對于加粗的黑體屬性值,需雙擊一下才可看內(nèi)容。
代碼獲取監(jiān)控指標(biāo)
- 關(guān)鍵代碼
- String jmxURL = "service:jmx:rmi:///jndi/rmi://192.168.10.93:8999/jmxrmi";
- JMXServiceURL serviceURL = new JMXServiceURL(jmxURL);
- Map map = new HashMap();
- // 用戶名密碼,在jmxremote.password文件中查看
- String[] credentials = new String[] { "monitorRole", "tomcat" };
- map.put("jmx.remote.credentials", credentials);
- JMXConnector connector = JMXConnectorFactory.connect(serviceURL, map);
- MBeanServerConnection mbsc = connector.getMBeanServerConnection();
- // 端口最好是動態(tài)取得
- ObjectName threadObjName = new ObjectName("Catalina:type=ThreadPool,name=http-8080");
- MBeanInfo mbInfo = mbsc.getMBeanInfo(threadObjName);
- // tomcat的線程數(shù)對應(yīng)的屬性值
- String attrName = "currentThreadCount";
- MBeanAttributeInfo[] mbAttributes = mbInfo.getAttributes();
- System.out.println("currentThreadCount:" + mbsc.getAttribute(threadObjName, attrName));
- 完整代碼
- import java.lang.management.MemoryUsage;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.Formatter;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import javax.management.MBeanAttributeInfo;
- import javax.management.MBeanInfo;
- import javax.management.MBeanServerConnection;
- import javax.management.ObjectInstance;
- import javax.management.ObjectName;
- import javax.management.openmbean.CompositeDataSupport;
- import javax.management.remote.JMXConnector;
- import javax.management.remote.JMXConnectorFactory;
- import javax.management.remote.JMXServiceURL;
- /**
- * @author binghe
- * @description JMX監(jiān)控Tomcat代碼實(shí)戰(zhàn)
- */
- public class JMXTest {
- public static void main(String[] args) {
- try {
- String jmxURL = "service:jmx:rmi:///jndi/rmi://127.0.0.1:8999/jmxrmi";
- JMXServiceURL serviceURL = new JMXServiceURL(jmxURL);
- Map map = new HashMap();
- String[] credentials = new String[] { "monitorRole", "tomcat" };
- map.put("jmx.remote.credentials", credentials);
- JMXConnector connector = JMXConnectorFactory.connect(serviceURL,map);
- MBeanServerConnection mbsc = connector.getMBeanServerConnection();
- // 端口最好是動態(tài)取得
- ObjectName threadObjName = new ObjectName("Catalina:type=ThreadPool,name=http-8080");
- MBeanInfo mbInfo = mbsc.getMBeanInfo(threadObjName);
- String attrName = "currentThreadCount";// tomcat的線程數(shù)對應(yīng)的屬性值
- MBeanAttributeInfo[] mbAttributes = mbInfo.getAttributes();
- System.out.println("currentThreadCount:" + mbsc.getAttribute(threadObjName, attrName));
- // heap
- for (int j = 0; j < mbsc.getDomains().length; j++) {
- System.out.println("###########" + mbsc.getDomains()[j]);
- }
- Set MBeanset = mbsc.queryMBeans(null, null);
- System.out.println("MBeanset.size() : " + MBeanset.size());
- Iterator MBeansetIterator = MBeanset.iterator();
- while (MBeansetIterator.hasNext()) {
- ObjectInstance objectInstance = (ObjectInstance) MBeansetIterator.next();
- ObjectName objectName = objectInstance.getObjectName();
- String canonicalName = objectName.getCanonicalName();
- System.out.println("canonicalName : " + canonicalName);
- if (canonicalName.equals("Catalina:host=localhost,type=Cluster")) {
- // Get details of cluster MBeans
- System.out.println("Cluster MBeans Details:");
- System.out.println("=========================================");
- // getMBeansDetails(canonicalName);
- String canonicalKeyPropList = objectName.getCanonicalKeyPropertyListString();
- }
- }
- // ------------------------- system ----------------------
- ObjectName runtimeObjName = new ObjectName("java.lang:type=Runtime");
- System.out.println("廠商:"+ (String) mbsc.getAttribute(runtimeObjName, "VmVendor"));
- System.out.println("程序:"+ (String) mbsc.getAttribute(runtimeObjName, "VmName"));
- System.out.println("版本:"+ (String) mbsc.getAttribute(runtimeObjName, "VmVersion"));
- Date starttime = new Date((Long) mbsc.getAttribute(runtimeObjName,"StartTime"));
- SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- System.out.println("啟動時間:" + df.format(starttime));
- Long timespan = (Long) mbsc.getAttribute(runtimeObjName, "Uptime");
- System.out.println("連續(xù)工作時間:" + JMXTest.formatTimeSpan(timespan));
- // ------------------------ JVM -------------------------
- // 堆使用率
- ObjectName heapObjName = new ObjectName("java.lang:type=Memory");
- MemoryUsage heapMemoryUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(heapObjName,"HeapMemoryUsage"));
- long maxMemory = heapMemoryUsage.getMax();// 堆最大
- long commitMemory = heapMemoryUsage.getCommitted();// 堆當(dāng)前分配
- long usedMemory = heapMemoryUsage.getUsed();
- System.out.println("heap:" + (double) usedMemory * 100 / commitMemory + "%");// 堆使用率
- MemoryUsage nonheapMemoryUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(heapObjName,"NonHeapMemoryUsage"));
- long noncommitMemory = nonheapMemoryUsage.getCommitted();
- long nonusedMemory = heapMemoryUsage.getUsed();
- System.out.println("nonheap:" + (double) nonusedMemory * 100 / noncommitMemory + "%");
- ObjectName permObjName = new ObjectName("java.lang:type=MemoryPool,name=Perm Gen");
- MemoryUsage permGenUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(permObjName, "Usage"));
- long committed = permGenUsage.getCommitted();// 持久堆大小
- long used = heapMemoryUsage.getUsed();//
- System.out.println("perm gen:" + (double) used * 100 / committed + "%");// 持久堆使用率
- // -------------------- Session ---------------
- ObjectName managerObjName = new ObjectName("Catalina:type=Manager,*");
- Set<ObjectName> s = mbsc.queryNames(managerObjName, null);
- for (ObjectName obj : s) {
- System.out.println("應(yīng)用名:" + obj.getKeyProperty("path"));
- ObjectName objname = new ObjectName(obj.getCanonicalName());
- System.out.println("最大會話數(shù):" + mbsc.getAttribute(objname, "maxActiveSessions"));
- System.out.println("會話數(shù):" + mbsc.getAttribute(objname, "activeSessions"));
- System.out.println("活動會話數(shù):" + mbsc.getAttribute(objname, "sessionCounter"));
- }
- // ----------------- Thread Pool ----------------
- ObjectName threadpoolObjName = new ObjectName("Catalina:type=ThreadPool,*");
- Set<ObjectName> s2 = mbsc.queryNames(threadpoolObjName, null);
- for (ObjectName obj : s2) {
- System.out.println("端口名:" + obj.getKeyProperty("name"));
- ObjectName objname = new ObjectName(obj.getCanonicalName());
- System.out.println("最大線程數(shù):" + mbsc.getAttribute(objname, "maxThreads"));
- System.out.println("當(dāng)前線程數(shù):" + mbsc.getAttribute(objname, "currentThreadCount"));
- System.out.println("繁忙線程數(shù):" + mbsc.getAttribute(objname, "currentThreadsBusy"));
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public static String formatTimeSpan(long span) {
- long minseconds = span % 1000;
- span = span / 1000;
- long seconds = span % 60;
- span = span / 60;
- long mins = span % 60;
- span = span / 60;
- long hours = span % 24;
- span = span / 24;
- long days = span;
- return (new Formatter()).format("%1$d天 %2$02d:%3$02d:%4$02d.%5$03d", days, hours, mins, seconds, minseconds).toString();
- }
- }
Tomcat9 JVM參數(shù)調(diào)優(yōu)
修改配置
- #要添加在tomcat 的bin 下catalina.sh 里添加
- JAVA_OPTS="-Xms1024m -Xmx2048m -Xss2048K -XX:PermSize=128m -XX:MaxPermSize=256m"
參數(shù)說明
- -Xms 初始化內(nèi)存大小,一般設(shè)置為和Xmx一致,避免每次垃圾回收后重新分配內(nèi)存
- -Xmx 最大可用內(nèi)存
- -Xmn 年輕代大小
- -Xss 設(shè)置每個線程棧的大小
- -XX:MetaspaceSize=512M 初始元空間大小,達(dá)到該值就會觸發(fā)垃圾收集進(jìn)行類型卸載,同時GC會對該值進(jìn)行調(diào)整:如果釋放了大量的空間,就適當(dāng)降低該值;如果釋放了很少的空間,那么在不超過MaxMetaspaceSize時,適當(dāng)提高該值。
- -XX:MaxMetaspaceSize=512M
- -XX:+UseConcMarkSweepGC 并發(fā)標(biāo)記清除(CMS)收集器
- -XX:+CMSClassUnloadingEnabled
- -XX:+HeapDumpOnOutOfMemoryError 表示當(dāng)JVM發(fā)生OOM時,自動生成DUMP文件。
- -XX:HeapDumpPath={目錄}/java_heapdump.hprof。如果不指定文件名,默認(rèn)為:java__heapDump.hprof。
Tomcat 相關(guān)參數(shù)優(yōu)化
連接數(shù),線程數(shù),緩存,修改server.xml
打開被注釋的默認(rèn)連接池配置。
默認(rèn)配置如下所示:
- <!--
- <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
- maxThreads="150" minSpareThreads="4"/>
- -->
修改實(shí)例:
- <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
- maxThreads="150"
- minSpareThreads="100"
- prestartminSpareThreads="true"
- maxQueueSize="100"/>
參數(shù)說明:
- name:線程名稱
- namePrefix:線程前綴
- maxThreads:最大并發(fā)連接數(shù),不配置時默認(rèn)200,一般建議設(shè)置500~ 800 ,要根據(jù)自己的硬件設(shè)施條件和實(shí)際業(yè)務(wù)需求而定。
- minSpareThreads:Tomcat啟動初始化的線程數(shù),默認(rèn)值25
- prestartminSpareThreads:在tomcat初始化的時候就初始化minSpareThreads的值, 不設(shè)置trueminSpareThreads 的值就沒啥效果了 。
- maxQueueSize:最大的等待隊(duì)列數(shù),超過則拒絕請求
修改后的配置如下所示:
- <Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- redirectPort="8443"
- executor="tomcatThreadPool"
- enableLookups="false"
- maxIdleTime="60000"
- acceptCount="100"
- maxPostSize="10485760"
- acceptorThreadCount="2"
- disableUploadTimeout="true"
- URIEncoding="utf-8"
- keepAliveTimeout ="6000"
- maxKeppAliveRequests="500"
- />
參數(shù)說明:
- port:連接端口。
- protocol:連接器使用的傳輸方式。
- executor:連接器使用的線程池名稱
- enableLookups:禁用DNS 查詢
- maxIdleTime:線程空閑時間,超過該時間后,空閑線程會被銷毀,默認(rèn)值為6000(1分鐘),單位毫秒。
- acceptCount:指定當(dāng)所有可以使用的處理請求的線程數(shù)都被使用時,可以放到處理隊(duì)列中的請求數(shù),超過這個數(shù)的請求將不予處理,默認(rèn)設(shè)置 100 。
- maxPostSize:限制 以FORM URL 參數(shù)方式的POST請求的內(nèi)容大小,單位字節(jié),默認(rèn)是 2097152(2兆),10485760 為 10M。如果要禁用限制,則可以設(shè)置為 -1。
- acceptorThreadCount:用于接收連接的線程的數(shù)量,默認(rèn)值是1。一般這個指需要改動的時候是因?yàn)樵摲?wù)器是一個多核CPU,如果是多核 CPU 一般配置為 2。
- disableUploadTimeOut:允許Servlet容器,正在執(zhí)行使用一個較長的連接超時值,以使Servlet有較長的時間來完成它的執(zhí)行,默認(rèn)值為false。
- keepAliveTimeout - 表示在下次請求過來之前,tomcat保持該連接多久。這就是說假如客戶端不斷有請求過來,且未超過過期時間,則該連接將一直保持。
- maxKeepAliveRequests -表示該連接最大支持的請求數(shù)。超過該請求數(shù)的連接也將被關(guān)閉(此時就會返回一個Connection: close頭給客戶端).(maxKeepAliveRequests="1"代表禁用長連接)(1表示禁用,-1表示不限制個數(shù),默認(rèn)100個。一般設(shè)置在100~200之間)
本文轉(zhuǎn)載自微信公眾號「冰河技術(shù)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系冰河技術(shù)公眾號。