• [Java] JVM的生命周期
    JVM的生命周期jvm的生命周期主要包含三个部分,虚拟机的启动,虚拟机的运行,还有虚拟机的退出。虚拟机的启动       java虚拟机的启动是通过引导类加载器(boostrap class loader)创建一个初始类来完成,这个类是由虚拟机的具体实现指定的。虚拟机的运行       执行一个java程序的时候,其实执行的是一个java虚拟机进程虚拟机的退出有如下几种情况程序正常执行退出程序在执行中遇到异常或者错误而异常终止由于操作系统出现错误导致Java虚拟机进程终止某线程调用Runtime类或者System类的exit方法,或者Runtime类的halt方法,并且Java安全管理器也允许这次exit或者halt操作除此之外,JNI规范描述用JNI Invocation API来加载或者卸载Java虚拟机时,Java虚拟机的退出情况
  • [技术干货] 2020-09-24:jvm监控系统是通过jmx做的么?
    2020-09-24:jvm监控系统是通过jmx做的么?#福大大架构师每日一题#
  • [Java] jvm的主要组成部分
    类加载器运行时数据区执行引擎本地库接口
  • [Java] jvm的垃圾回收器
    标记-清除算法标记-整理算法复制算法分代算法
  • [Java] jvm的运行时数据区
    程序计数器虚拟机栈本地方法栈
  • [Java] jvm的垃圾算法
    标记-清除算法;标记-整理算法;复制算法;分代算法。
  • [技术干货] JVM监控java.lang.management简介
        java.lang.management是JDK自带的一套工具库。通过工厂类ManagementFactory对外提供一套管理接口,提供JVM和JVM所运行操作系统的各种信息,例如:内存使用情况、GC情况和操作系统版本等。基于以上信息,可以辅助我们对定位问题或者性能调优提供数据支撑。Management同时允许从本地和远程(JMX)对正在运行的JVM进行监视和管理。MXBean简介      根据ManagementFactory的javadoc,可以看出它提供了大量的工厂方法,使得我们可以通过调用这些方法来获取JVM各组件相关的JavaBean,通过这些JavaBean就可以获取到对应组件的运行状态数据。而这些JavaBean是各个服务启动时自动注册好的,运行数据也是提前计算好的,所以我们并不会因为获取相关数据,而导致额外消耗资源进行计算。       这些JavaBean被称之为MBean或者MXBean。MBean和MXBean两者的区别在于:MXBean是一个特殊的MBean,它的数据类型被限制为开放类型,基本上是原始类型、字符串及其组合。由于这些限制,MXBean可以在不加载类的情况下使用,这使得它们甚至可以与非Java客户机进行互操作。这个特性对于我们进行通用封装是十分重要的。使用案例1:      JVM频繁的FullGC或者Java服务发生了OOM,但是JVM进程并没有自动退出。这种场景下,仅仅在操作系统层面对JVM进程进行监控是不能及时发现相关问题的。可以使用MemoryMXBean和GarbageCollectorMXBean来获取相关信息;并结合其他监控或者定时执行机制,实现告警等功能。实现代码:public class MemoryMXBeanTest {    private static volatile MemoryMXBean memoryMBean;    private static volatile List<GarbageCollectorMXBean> garbageCollectorMXBeanList;     /**     *  获取memoryMBean     */    private static void initMemoryMXBean() {        synchronized (MemoryMXBeanTest.class) {            if (memoryMBean == null) {                try {                    memoryMBean = AccessController.doPrivileged(                            new PrivilegedExceptionAction<MemoryMXBean>() {                                @Override                                public MemoryMXBean run() throws DrsException {                                    return ManagementFactory.getMemoryMXBean();                                }                            });                } catch (Exception exp) {                    log.error("", exp);                }            }        }    }     /**     * 获取GarbageCollectorMXBean     */    private static void initGarbageCollectorMXBean() {        synchronized (MemoryMXBeanTest.class) {            if (garbageCollectorMXBeanList == null) {                try {                    garbageCollectorMXBeanList = AccessController.doPrivileged(                            new PrivilegedExceptionAction<List<GarbageCollectorMXBean>>() {                                @Override                                public List<GarbageCollectorMXBean> run() throws DrsException {                                    return ManagementFactory.getGarbageCollectorMXBeans();                                }                            });                } catch (Exception exp) {                    log.error("", exp);                }            }        }    }     public static MemoryMXBean getMemoryMBean() {        if (memoryMBean == null) {            initMemoryMXBean();        }        return memoryMBean;    }     public static List<GarbageCollectorMXBean> getGCMXBeanList() {        if (garbageCollectorMXBeanList == null) {            initGarbageCollectorMXBean();        }        return garbageCollectorMXBeanList;    }     private Map<String, Object> getMemStatus() {        Map<String, Object> memStatus = new HashMap<String, Object>();        // 堆内存        memStatus.put("Heap mem Committed", getMemoryMBean().getHeapMemoryUsage().getCommitted());        memStatus.put("Heap mem Init", getMemoryMBean().getHeapMemoryUsage().getInit());        memStatus.put("Heap mem Max", getMemoryMBean().getHeapMemoryUsage().getMax());        memStatus.put("Heap mem Used", getMemoryMBean().getHeapMemoryUsage().getUsed());        // 堆内存使用率        memStatus.put("Heap mem Used Rato",                (getMemoryMBean().getHeapMemoryUsage().getUsed() * 100 / getMemoryMBean().getHeapMemoryUsage().getMax()) + "%");         // 堆外内存        memStatus.put("Non-Heap mem Committed", getMemoryMBean().getNonHeapMemoryUsage().getCommitted());        memStatus.put("Non-Heap mem Init", getMemoryMBean().getNonHeapMemoryUsage().getInit());        memStatus.put("Non-Heap mem Used", getMemoryMBean().getNonHeapMemoryUsage().getUsed());        return memStatus;    }     private Map<String, Object> getGcStatus() {        Map<String, Object> gcStatus = new HashMap<String, Object>();        if (!CollectionUtils.isEmpty(getGCMXBeanList())) {            // 不同的垃圾回收器            for (GarbageCollectorMXBean gcMXBean : getGCMXBeanList()) {                gcStatus.put(gcMXBean.getName() + "-" + Arrays.toString(gcMXBean.getMemoryPoolNames()) + "-count", gcMXBean.getCollectionCount());                gcStatus.put(gcMXBean.getName() + "-" + Arrays.toString(gcMXBean.getMemoryPoolNames()) + "-time", gcMXBean.getCollectionTime());            }        }        return gcStatus;    }     public void print() {        log.info("jvm mem status: {}", GsonUtils.toJson(getMemStatus()));         log.info("jvm gc status: {}", GsonUtils.toJson(getGcStatus()));    } }运行结果:2020-03-09 08:24:30,001 jvm mem status: {"Non-Heap mem Used":201168408,"Heap mem Used":710231248,"Heap mem Used Rato":"48%","Heap mem Committed":1467482112,"Non-Heap mem Init":2555904,"Non-Heap mem Committed":207945728,"Heap mem Init":1474297856,"Heap mem Max":1467482112}2020-03-09 08:24:30,001 jvm gc status: {"PS Scavenge-[PS Eden Space, PS Survivor Space]-count":210,"PS MarkSweep-[PS Eden Space, PS Survivor Space, PS Old Gen]-time":842,"PS MarkSweep-[PS Eden Space, PS Survivor Space, PS Old Gen]-count":4,"PS Scavenge-[PS Eden Space, PS Survivor Space]-time":2213}使用案例2      有业务功能大量并发,同时占用了大量数据库连接;从而导致连接池中可用连接长时间无空闲的话,就会导致业务持久化操作异常。下面就以使用Druid数据库连接池为例,通过Druid自带的MXbean获取连接池相关信息。PS:      1、多数Java连接池都会注册MXbean并记录重要监控数据,具体实现和数据线略有差别;      2、druid自带monitor;需要配置额外的数据库进行存储,可参见:https://github.com/alibaba/druid/wiki/druid-monitor%E8%AE%BE%E8%AE%A1      通过JMX连接JVM,可以看到DruidDataSource下有两个数据源,他们的ObjectName为:com.alibaba.druid:type=DruidDataSource,id=XXX,每个数据源的MXBean中各有一组Attribute记录相关监控项。实现代码:public class DruidMXBeanTest {     private static volatile MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();     private static void initMBeanServer() {        synchronized (DruidMXBeanTest.class) {            if (mBeanServer == null) {                try {                    mBeanServer = AccessController.doPrivileged(                            new PrivilegedExceptionAction<MBeanServer>() {                                @Override                                public MBeanServer run() throws DrsException {                                    return ManagementFactory.getPlatformMBeanServer();                                }                            });                } catch (Exception exp) {                    log.error("", exp);                }            }        }    }     private static MBeanServer getMBeanServer() {        if (mBeanServer == null) {            initMBeanServer();        }        return mBeanServer;    }     public static Set<ObjectInstance> queryMBeans(String objectName) {        try {            if (getMBeanServer() != null) {                return getMBeanServer().queryMBeans(new ObjectName(objectName), null);            }        } catch (Exception e) {            log.error("", e);        }        return null;    }     public static Map<String, Object> getAttributes(String objectName, List<String> attrNameList) {        try {            return getAttributes(new ObjectName(objectName), attrNameList);        } catch (Exception e) {            log.error("", e);        }        return null;    }     public static Map<String, Object> getAttributes(ObjectName objectName, List<String> attrNameList) {        Map<String, Object> result = new HashMap<String, Object>();        if (CollectionUtils.isEmpty(attrNameList) || getMBeanServer() == null) {            return result;        }        try {            AttributeList attributeList = getMBeanServer().getAttributes(objectName, attrNameList.toArray(new String[] {}));            for (int i = 0; i < attrNameList.size(); i++) {                result.put(attrNameList.get(i), i < attributeList.size() ? ((Attribute) attributeList.get(i)).getValue() : "");            }            return result;        } catch (Exception e) {            log.error("", e);        }        return result;    }     private Map<String, Map<String, Object>> getDruidDataSourceStatus() {        Map<String, Map<String, Object>> druidDataSourceMap = new HashMap<String, Map<String, Object>>();        try {            // 结果数量不固定并且ID每次随机,使用带通配符的ObjectName进行批量查询            Set<ObjectInstance> druidDataSourceSet = queryMBeans("com.alibaba.druid:type=DruidDataSource,id=*");            if (druidDataSourceSet != null) {                 // 一个数据源一组attribute                druidDataSourceSet.stream().forEach(objectInstance -> {                    Map<String, Object> druidDataSource = new HashMap<String, Object>();                     /**                     * 需要获取到的监控项                     *                      * druid更多相关监控项可以在com.alibaba.druid.pool.DruidDataSource中查看(注意使用时需要大写驼峰格式)                     */                    List<String> attrList = new ArrayList<String>() {                        {                            // 数据源用户名                            add("Username");                            // 最大连接池数量                            add("MaxActive");                            // 最小连接池数量                            add("MinIdle");                            // 连接池中空闲连接数                            add("PoolingCount");                            // 连接池中正在使用的连接数                            add("ActiveCount");                        }                    };                    druidDataSource = getAttributes(objectInstance.getObjectName(), attrList);                    druidDataSourceMap.put(String.valueOf(druidDataSource.get("Username")), druidDataSource);                });            }         } catch (Exception e) {            log.error("", e);        }        return druidDataSourceMap;    }     public void print() {        log.info("druid dataSource status: {}", GsonUtils.toJson(getDruidDataSourceStatus()));    }} 运行结果:2020-03-09 08:24:30,002 druid dataSource status: {"db1":{"Username":"db1","MaxActive":20,"MinIdle":5,"ActiveCount":0,"PoolingCount":5},"db2":{"Username":"db2","MaxActive":20,"MinIdle":10,"ActiveCount":1,"PoolingCount":9}}  总结很多开源中间件都会使用Management方式进行自定义扩展,记录相关运行状况数据;例如Kafka、logback等,都可以使用类似方式获取数据。参考资料:https://www.jianshu.com/p/5d854245051dhttps://baike.baidu.com/item/java.lang.management/5179868?fr=aladdinhttp://www.voidcn.com/article/p-cwctaeex-bsq.htmlhttps://zimt8.com/questions/16275207/https://docs.oracle.com/javase/tutorial/jmx/mbeans/mxbeans.htmlhttps://docs.oracle.com/javase/8/docs/api/java/lang/management/package-summary.html
  • [其他] HBase调优(转载)
    1.提升Bulkload效率操作场景批量加载功能采用了MapReduce jobs直接生成符合HBase内部数据格式的文件,然后把生成的StoreFiles文件加载到正在运行的集群。使用批量加载相比直接使用HBase的API会节约更多的CPU和网络资源。ImportTSV是一个HBase的表数据加载工具。前提条件在执行批量加载时需要通过“Dimporttsv.bulk.output”参数指定文件的输出路径操作步骤参数入口:执行批量加载任务时,在BulkLoad命令行中加入如下参数。参数功能默认值/建议值hbase39现有值hbasea现有值-Dimporttsv.mapper.class用户自定义mapper通过把键值对的构造从mapper移动到reducer以帮助提高性能。mapper只需要把每一行的原始文本发送给reducer,reducer解析每一行的每一条记录并创建键值对。说明:当该值配置为“org.apache.hadoop.hbase.mapreduce.TsvImporterByteMapper”时,只在执行没有HBASE_CELL_VISIBILITY OR HBASE_CELL_TTL选项的批量加载命令时使用。使用“org.apache.hadoop.hbase.mapreduce.TsvImporterByteMapper”时可以得到更好的性能org.apache.hadoop.hbase.mapreduce.TsvImporterByteMapper和org.apache.hadoop.hbase.mapreduce.TsvImporterTextMappe不需要调整✅不需要调整✅2.提升连续put场景(修改为建议值)操作场景:对大批量、连续put的场景,配置下面的两个参数为“false”时能大量提升性能。“hbase.regionserver.wal.durable.sync”“hbase.regionserver.hfile.durable.sync”当提升性能时,缺点是对于DataNode(默认是3个)同时故障时,存在小概率数据丢失的现象。对数据可靠性要求高的场景请慎重配置参数功能默认值/建议值hbase39现有值hbasea现有值hbase.regionserver.wal.durable.sync每一条wal是否持久化到硬盘默认true,建议改为false无,即默认true无,即默认true hbase.regionserver.hfile.durable.sync hfile写是否立即持久化到硬盘。默认true,建议改为false  无,即默认true  无,即默认true 3.Put和Scan性能综合调优与JVM GC参数有关的参数RegionServer GC_OPTS参数设置建议:-Xms与-Xmx设置相同的值,需要根据实际情况设置,增大内存可以提高读写性能,可以参考参数“hfile.block.cache.size”(见表12-4)和参数“hbase.regionserver.global.memstore.size”(见表12-3)的介绍进行设置。-XX:NewSize与-XX:MaxNewSize设置相同值,建议低负载场景下设置为“512M”,高负载场景下设置为“2048M”。-XX:CMSInitiatingOccupancyFraction建议设置为“100 * (hfile.block.cache.size + hbase.regionserver.global.memstore.size + 0.05)”,最大值不超过90。-XX:MaxDirectMemorySize表示JVM使用的堆外内存,建议低负载情况下设置为“512M”,高负载情况下设置为“2048M”。参数功能默认值/建议值hbase39现有值hbasea现有值hfile.block.cache.size(提升实时读数据效率)-Xms与-Xmx设置相同的值,需要根据实际情况设置,增大内存可以提高读写性能数据缓存所占的RegionServer GC -Xmx百分比,在读高负载情况下可以适当调大以增大缓存命中率以提高性能默认值0.250.40.4hbase.regionserver.global.memstore.size建议设置为“hbase.hregion.memstore.flush.size * 写活跃region数 / RegionServer GC -Xmx”。默认值为“0.4”,表示使用RegionServer GC -Xmx的40%。默认值0.40.40.4-XX:NewSize与-XX:MaxNewSize设置相同值建议低负载场景下设置为“512M”,高负载场景下设置为“2048M”。低负载:512M  高负载:2048M无无-XX:CMSInitiatingOccupancyFraction建议设置为“100 * (hfile.block.cache.size + hbase.regionserver.global.memstore.size + 0.05)”,最大值不超过90计算值:70无无-XX:MaxDirectMemorySize表示JVM使用的堆外内存,建议低负载情况下设置为“512M”,高负载情况下设置为“2048M”。低负载:512M  高负载:2048M无无Put相关参数RegionServer处理put请求的数据,会将数据写入memstore和hlog,当memstore大小达到设置的“hbase.hregion.memstore.flush.size”参数值大小时,memstore就会刷新到HDFS生成HFile。当当前region的列簇的HFile数量达到“hbase.hstore.compaction.min”参数值时会触发compaction。当当前region的列簇HFile数达到“hbase.hstore.blockingStoreFiles”参数值时会阻塞memstore刷新生成HFile的操作,导致put请求阻塞。 参数功能默认值/建议值hbase39现有值hbasea现有值hbase.hregion.memstore.flush.size当memstore大小达到设置的“hbase.hregion.memstore.flush.size”参数值大小时,memstore就会刷新到HDFS生成HFile。建议设置为HDFS块大小的整数倍,在内存足够put负载大情况下可以调整增大。单位:字节默认值:134217728字节=128mb256mb128mbhbase.hstore.compaction.min当一个Store中文件超过该值时,会进行compact,适当增大该值,可以减少文件被重复执行compaction。但是如果过大,会导致Store中文件数过多而影响读取的性能。默认值 :6无无hbase.hstore.compaction.max控制一次compaction操作时的文件数量的最大值。与“hbase.hstore.compaction.max.size”的作用基本相同,主要是控制一次compaction操作的时间不要太长10空值10hbase.hstore.blockingStoreFiles当列簇的HFile数达到该阈值,阻塞该region的所有操作,直到compcation完成,在put高负载场景下可以适当调大。默认值:151010hbase.hstore.flusher.countmemstore的flush线程数,在put高负载场景下可以适当调大2无无hbase.regionserver.thread.compaction.smallHFile compaction线程数,在put高负载情况下可以适当调大10无无 Scan相关参数 参数功能默认值/建议值hbase39现有值hbasea现有值hbase.client.scanner.timeout.period客户端和RegionServer端参数,表示scan租约的时间,建议设置为60000ms的整数倍,在读高负载情况下可以适当调大。单位:毫秒。60000ms60s无  Handler相关参数 参数功能默认值/建议值hbase39现有值hbasea现有值hbase.regionserver.handler.count(提升实时读数据效率)RegionServer上的RPC服务器实例数,建议设置为200 ~ 400之间。2003030hbase.regionserver.metahandler.countRegionServer中处理优先请求的程序实例的数量,建议设置为200 ~ 400之间。10010无  4.提升实时写数据效率写数据服务端调优参数功能默认值/建议值hbase39现有值hbasea现有值hbase.regionserver.thread.compaction.throttle控制一次Minor Compaction时,进行compaction的文件总大小的阈值。Compaction时的文件总大小会影响这一次compaction的执行时间,如果太大,可能会阻塞其它的compaction或flush操作。1610612736(单位:字节)无无hbase.hregion.majorcompaction设置Major Compaction的执行周期。默认值为604800000毫秒。由于执行Major Compaction会占用较多的系统资源,如果正在处于系统繁忙时期,会影响系统的性能。如果业务没有较多的更新、删除、回收过期数据空间时,可以把该值设置为0,以禁止Major Compaction。如果必须要执行Major Compaction,以回收更多的空间,可以适当增加该值,同时配置参数“hbase.offpeak.end.hour”和“hbase.offpeak.start.hour”以控制Major Compaction发生在业务空闲的时期604800000(单位:毫秒)0.7day07dayhbase.regionserver.maxlogshbase.regionserver.hlog.blocksize表示一个RegionServer上未进行Flush的Hlog的文件数量的阈值,如果大于该值,RegionServer会强制进行flush操作。表示每个HLog文件的最大大小。如果HLog文件大小大于该值,就会滚动出一个新的HLog文件,旧的将被禁用并归档。这两个参数共同决定了RegionServer中可以存在的未进行Flush的hlog数量。当这个数据量小于MemStore的总大小的时候,会出现由于HLog文件过多而触发的强制flush操作。这个时候可以适当调整这两个参数的大小,以避免出现这种强制flush的情况。32134217728(单位:字节)—128mb32无 无无  5.读/写数据表设计调优配置参数描述默认值COMPRESSION配置数据的压缩算法,这里的压缩是HFile中block级别的压缩。对于可以压缩的数据,配置压缩算法可以有效减少磁盘的IO,从而达到提高性能的目的。说明:并非所有数据都可以进行有效压缩。例如一张图片的数据,因为图片一般已经是压缩后的数据,所以压缩效果有限。 常用的压缩算法是SNAPPY,因为它有较好的Encoding/Decoding速度和可以接受的压缩率。NONEBLOCKSIZE配置HFile中block块的大小,不同的block块大小,可以影响HBase读写数据的效率。越大的block块,配合压缩算法,压缩的效率就越好;但是由于HBase的读取数据是以block块为单位的,所以越大的block块,对于随机读的情况,性能可能会比较差。如果要提升写入的性能,一般扩大到128KB或者256KB,可以提升写数据的效率,也不会影响太大的随机读性能。65536(单位:字节)IN_MEMORY配置这个表的数据优先缓存在内存中,这样可以有效提升读取的性能。对于一些小表,而且需要频繁进行读取操作的,可以设置此配置项。false 6.JVM参数优化当集群数据量达到一定规模后,JVM的默认配置将无法满足集群的业务需求,轻则集群变慢,重则集群服务不可用。所以需要根据实际的业务情况进行合理的JVM参数配置,提高集群性能变量名变量影响的角色hbase39现有值hbasea现有值HBASE_OPTS该变量中设置的参数,将影响HBase的所有角色-Xms8g -Xmx8g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseConcMarkSweepGC -XX:-CMSConcurrentMTEnabled -XX:+CMSIncrementalMode -Djava.net.preferIPv4Stack=true $HBASE_OPTS HBASE_OPTS="$HBASE_OPTS -XX:+UseConcMarkSweepGC -XX:ErrorFile=/app/log/hbase/hs_err_pid%p.log -Djava.io.tmpdir=/tmp"SERVER_GC_OPTS该变量中设置的参数,将影响HBase Server端的所有角色,例如:Master、RegionServer等。SERVER_GC_OPTS="-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/app/log/hbase/gc.log-`date +'%Y%m%d%H%M'`"CLIENT_GC_OPTS该变量中设置的参数,将影响HBase的Client进程HBASE_MASTER_OPTS该变量中设置的参数,将影响HBase的MasterHBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -Xmx30720m $JDK_DEPENDED_OPTS”HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS  -XX:MaxDirectMemorySize=4096m " HBASE_REGIONSERVER_OPTS该变量中设置的参数,将影响HBase的RegionServerHBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xmn4096m -XX:CMSInitiatingOccupancyFraction=70  -Xms20480m -Xmx20480m $JDK_DEPENDED_OPTS”HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS  -XX:MaxDirectMemorySize=4096m " HBASE_THRIFT_OPTS该变量中设置的参数,将影响HBase的Thrift转载自:https://blog.csdn.net/mnasd/article/details/81304888
总条数:85 到第
上滑加载中