在高并发场景下,作者提供了一个简单、稳定、可扩展的延迟信息列表框架,具有准确的定时任务和延迟列表处理功能。自开源半年多以来,已成功为十多家中小企业提供了准确的定期调度计划,经受住了生产环境的考验。为了使更多的童鞋受益,现在给出了开源框架地址:https://github.com/sunshinelyz/mykit-delay
小伙伴问题小伙伴:监控怎么办?
我:你指的是我:
小伙伴:性能指标。
我:以后会写这些文章。
使用JMX监控Tomcat
关于监控的文章先写什么?想想看,我们先写一篇使用文章JMX监控Tomcat实战文章。好入主题。
激活Tomcat的JMX远程配置
要通过JMX远程监控Tomcat,首先需要激活Tomcat的JMX远程配置。
① 修改脚本
先修改Tomcat启动脚本,windows下为bin/catalina.bat(linux下为catalina.sh),添加以下内容,8999是jmxremote第二个端口号false表示不需要鉴权:
setJMX_REMOTE_CONFIG=-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.port=8999-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.authenticate=falsesetCATALINA_OPTS=?TALINA_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
② 鉴权
上述配置不需要权利鉴定。如果需要权利鉴定,则添加以下内容:
setJMX_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.accesssetCATALINA_OPTS=?TALINA_OPTS%%JMX_REMOTE_CONFIG%③ 授权文件的复制和修改
$JAVA_HOME/jre/lib/management下有jmxremote.access和jmxremote.password将两个文件复制到模板文件中$CATALINA_BASE/conf目录下
- 修改$CATALINA_BASE/conf/jmxremote.access 添加内容
monitorRolereadonlycontrolRolereadwrite - 修改$CATALINA_BASE/conf/jmxremote.password 添加内容:
monitorRolebinghecontrolRolebinghe注:如果采取上述步骤,则会导致注意:Tomcat如果不能启动,很可能是密码文件的权限问题
需要修改jmxremote.password访问文件的权限只能运行Tomcat用户有访问权限 :
Windows的NTFS在文件系统下,选择文件,点击右键 -->“属性”-->“安全”--> 点“高级”--> 点“更改权限”--> 去掉“从父项继承....”--> 选择弹出窗口“删除”,所有访问权限都被删除了。再次选择“添加”--> “高级”--> “立即查找”,选择您的用户(或用户组,如果用户不能,则选择用户组),例如administrator,点“确定",“确定"。来到权限项目窗口,检查“完全控制”,点“确定”,OK了。
官方的提示
Thepasswordfileshouldberead-onlyandonlyaccessiblebytheoperatingsystemuserTomcatisrunningas.④验证配置
重新启动Tomcat,在Windows命令行输入“netstat -a”检查配置端口号是否已打开,如果打开,说明上述配置已成功。
⑤ 使用jconsole测试JMX
运行$JAVA_HOME/bin目录下的jconsole.exe,打开J2SE如果是本地的,监控和管理控制台,然后建立连接Tomcat然后直接选择并单击连接。如果是远程的,请输入远程选项卡,填写地址、端口号、用户名和密码。Mbean属性页中给出了相应的数据,Catalina中是tomcat的,java.lang是jvm是的。对于加粗的黑体属性值,需要双击才能看到内容。
代码获取监控指标
StringjmxURL="service:jmx:rmi:///jndi/rmi://192.168.10.93:8999/jmxrmi";JMXServiceURLserviceURL=newJMXServiceURL(jmxURL);Mapmap=newHashMap();//用户名密码,在jmxremote.password文件中查看String[]credentials=newString[]{"monitorRole","tomcat"};map.put("jmx.remote.credentials",credentials);JMXConnectorconnector=JMXConnectorFactory.connect(serviceURL,map);MBeanServerConnectionmbsc=connector.getMBeanServerConnection();////端口最好动态获取ObjectNamethreadObjName=newObjectName("Catalina:type=ThreadPool,name=http-8080");MBeanInfombInfo=mbsc.getMBeanInfo(threadObjName);//tomcat线程数对应的属性值StringattrName="currentThreadCount";MBeanAttributeInfo[]mbAttributes=mbInfo.getAttributes();System.out.println("currentThreadCount:" mbsc.getAttribute(threadObjName,attrName));importjava.lang.management.MemoryUsage;importjava.text.SimpleDateFormat;importjava.util.Date;importjava.util.Formatter;importjava.util.HashMap;importjava.util.Iterator;importjava.util.Map;importjava.util.Set;importjavax.management.MBeanAttributeInfo;importjavax.management.MBeanInfo;importjavax.management.MBeanServerConnection;importjavax.management.ObjectInstance;importjavax.management.ObjectName;importjavax.management.openmbean.CompositeDataSupport;importjavax.management.remote.JMXConnector;importjavax.management.remote.JMXConnectorFactory;importjavax.management.remote.JMXServiceURL;/***@authorbinghe*@descriptionJMX监控Tomcat代码实战*/publicclassJMXTest{publicstaticvoidmain(String[]args){try{StringjmxURL="service:jmx:rmi:///jndi/rmi://127.0.0.1:8999/jmxrmi";JMXServiceURLserviceURL=newJMXServiceURL(jmxURL);Mapmap=newHashMap();String[]credentials=newString[]{"monitorRole","tomcat"};map.put("jmx.remote.credentials",credentials);JMXConnectorconnector=JMXConnectorFactory.connect(serviceURL,map);MBeanServerConnectionmbsc=connector.getMBeanServerConnection();////端口最好动态获取ObjectNamethreadObjName=newObjectName("Catalina:type=ThreadPool,name=http-8080");MBeanInfombInfo=mbsc.getMBeanInfo(threadObjName);StringattrName="currentThreadCount";//tomcat线程数对应的属性值MBeanAttributeInfo[]mbAttributes=mbInfo.getAttributes();System.out.println("currentThreadCount:" mbsc.getAttribute(threadObjName,attrName));//heapfor(intj=0;j<mbsc.getDomains().length;j ){System.out.println("###########" mbsc.getDomains()[j]);}SetMBeanset=mbsc.queryMBeans(null,null);System.out.println("MBeanset.size():" MBeanset.size());IteratorMBeansetIterator=MBeanset.iterator();while(MBeansetIterator.hasNext()){ObjectInstanceobjectInstance=(ObjectInstance)MBeansetIterator.next();ObjectNameobjectName=objectInstance.getObjectName();StringcanonicalName=objectName.getCanonicalName();System.out.println("canonicalName:" canonicalName);if(canonicalName.equals("Catalina:host=localhost,type=Cluster")){//GetdetailsofclusterMBeansSystem.out.println("ClusterMBeansDetails:");System.out.println("=========================================");//getMBeansDetails(canonicalName);StringcanonicalKeyPropList=objectName.getCanonicalKeyPropertyListString();}}//ObjectNameruntimeObjName=newObjectName("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"));Datestarttime=newDate((Long)mbsc.getAttribute(runtimeObjName,"StartTime"));SimpleDateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");System.out.println("启动时间:" df.format(starttime));Longtimespan=(Long)mbsc.getAttribute(runtimeObjName,"Uptime");System.out.println("连续工作时间:" JMXTest.formatTimeSpan(timespan));/////堆利用率ObjectNameheapObjName=newObjectName("java.lang:type=Memory");MemoryUsageheapMemoryUsage=MemoryUsage.from((CompositeDataSupport)mbsc.getAttribute(heapObjName,"HeapMemoryUsage"));longmaxMemory=heapMemoryUsage.getMax();//堆最大longcommitMemory=heapMemoryUsage.getCommitted()longusedMemory=heapMemoryUsage.getUsed();System.out.println("heap:" (double)usedMemory*100/commitMemory "%");///堆利用率MemoryUsagenonheapMemoryUsage=MemoryUsage.from((CompositeDataSupport)mbsc.getAttribute(heapObjName,"NonHeapMemoryUsage"));longnoncommitMemory=nonheapMemoryUsage.getCommitted();longnonusedMemory=heapMemoryUsage.getUsed();System.out.println("nonheap:" (double)nonusedMemory*100/noncommitMemory "%");ObjectNamepermObjName=newObjectName("java.lang:type=MemoryPool,name=PermGen");MemoryUsagepermGenUsage=MemoryUsage.from((CompositeDataSupport)mbsc.getAttribute(permObjName,"Usage"));longcommitted=permGenUsage.getCommitted()longused=heapMemoryUsage.getUsed();//System.out.println("permgen:" (double)used*100/committed "%");//持久堆积利用率//ObjectNamemanagerObjName=newObjectName("Catalina:type=Manager,*");Set<ObjectName>s=mbsc.queryNames(managerObjName,null);for(ObjectNameobj:s){System.out.println("应用名:" obj.getKeyProperty("path"));ObjectNameobjname=newObjectName(obj.getCanonicalName());System.out.println("最大会话数:" mbsc.getAttribute(objname,"maxActiveSessions"));System.out.println("会话数:" mbsc.getAttribute(objname,"activeSessions"));System.out.println("活动会话数:" mbsc.getAttribute(objname,"sessionCounter"));}//ObjectNamethreadpoolObjName=newObjectName("Catalina:type=ThreadPool,*");Set<ObjectName>s2=mbsc.queryNames(threadpoolObjName,null);for(ObjectNameobj:s2){System.out.println("端口名:" obj.getKeyProperty("name"));ObjectNameobjname=newObjectName(obj.getCanonicalName());System.out.println("最大线程数:" mbsc.getAttribute(objname,"maxThreads"));System.out.println("当前线程数:" mbsc.getAttribute(objname,"currentThreadCount"));System.out.println("繁忙线程数:" mbsc.getAttribute(objname,"currentThreadsBusy"));}}catch(Exceptione){e.printStackTrace();}}publicstaticStringformatTimeSpan(longspan){longminseconds=span00;span=span/1000;longseconds=span`;span=span/60;longmins=span`;span=span/60;longhours=span$;span=span/24;longdays=span;return(newFormatter()).format("%1$d天%2$02d:%3$02d:%4$02d.%5$03d",days,hours,mins,seconds,minseconds).toString();}}Tomcat9 JVM参数调优
修改配置
#要添加在tomcat的bin下catalina.sh里添加JAVA_OPTS="-Xms1024m-Xmx2048m-Xss2048K-XX:PermSize=128m-XX:MaxPermSize=256m"参数说明
- -Xms 初始内存大小一般设置为和Xmx一致性,避免每次垃圾回收后重新分配内存
- -Xmx 最大可用内存
- -Xmn 年轻时的大小
- -Xss 设置每个线程栈的大小
- -XX:MetaspaceSize=512M 当初始元空间达到这个值时,会触发垃圾收集,同时卸载类型。GC调整值:如果释放大量空间,则适当降低值;如果释放少量空间,则不超过MaxMetaspaceSize适当提高值。
- -XX:MaxMetaspaceSize=512M
- -XX: UseConcMarkSweepGC 并发标记清除(CMS)收集器
- -XX: CMSClassUnloadingEnabled
- -XX: HeapDumpOnOutOfMemoryError 表示当JVM发生OOM自动生成时DUMP文件。
- -XX:HeapDumpPath={目录}/java_heapdump.hprof。未指定文件名的,默认为:java__heapDump.hprof。
Tomcat 相关参数优化
修改连接数、线程数、缓存server.xml
打开注释的默认连接池配置。
默认配置如下:
<!<Executorname="tomcatThreadPool"namePrefix="catalina-exec-"maxThreads="150"minSpareThreads="4"/>修改实例:
<Executorname="tomcatThreadPool"namePrefix="catalina-exec-"maxThreads="150"minSpareThreads="100"prestartminSpareThreads="true"maxQueueSize="100"/>参数说明:
- name:线程名称
- namePrefix:线程前缀
- maxThreads:默认情况下,最大并发连接数为200,一般建议设置500~ 800 ,根据其硬件设施条件和实际业务需要确定。
- minSpareThreads:Tomcat启动初始线程数,默认值25
- prestartminSpareThreads:在tomcat初始化是在初始化时开始的minSpareThreads 不设置值trueminSpareThreads 的值没有效果。
- maxQueueSize:最大等待队列数超过时拒绝要求
修改后的配置如下:
<Connectorport="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"/>参数说明:
- port:连接端口。
- protocol:连接器使用的传输方式。
- executor:连接器使用的线程池名称
- enableLookups:禁用DNS 查询
- maxIdleTime:空闲时间超过此时间后,空闲线程将被销毁,默认值为6000(1分钟),单位毫秒。
- acceptCount:指定当使用所有可用处理请求的线程数时,可以放置在处理队列中的请求数超过此数的请求不予处理,默认设置 100 。
- maxPostSize:限制 以FORM URL 参数模式POST默认情况下,小,单位字节,默认为 2097152(2兆)10485760 为 10M。禁止限制的,可设置为 -1。
- acceptorThreadCount:默认值为1,用于接收连接的线程数量。一般来说,这意味着服务器是多核的CPU,若为多核 CPU 一般配置为 2。
- disableUploadTimeOut:允许Servlet容器正在执行一个较长的连接超时值Servlet完成它的执行需要很长时间,默认值是false。
- keepAliveTimeout - 表示,在下次请求到来之前,tomcat保持连接需要多长时间。也就是说,如果客户端不断要求,且不超过期限,则应始终保持连接。
- maxKeepAliveRequests -表示连接最大支持的请求数。超过请求数的连接也将被关闭(此时将返回一个Connection: close头到客户端).(maxKeepAliveRequests="1"代表禁用长连接)(1表示禁用,-1默认情况下,100个数100个。一般设置在100~200之间)
本文转载自微信公众号「冰河技术」,请注意以下二维码。转载本文,请联系冰河技术微信官方账号。