本文目录一览:
怎么给JVM加启动参数?
不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM、GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率。但是调整GC是以个极为复杂的过程,由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要cup个数,内存不同),所以使用的GC种类也会不同(如何选择见GC种类及如何选择)。本文将注重介绍JVM、GC的一些重要参数的设置来提高系统的性能。
GC性能方面的考虑
对于GC的性能主要有2个方面的指标:吞吐量throughput(工作时间不算gc的时间占总的时间比)和暂停pause(gc发生时app对外显示的无法响应)。
1. Total Heap
默认情况下,vm会增加/减少heap大小以维持free space在整个vm中占的比例,这个比例由MinHeapFreeRatio和MaxHeapFreeRatio指定。
一般而言,server端的app会有以下规则:
对vm分配尽可能多的memory;
将Xms和Xmx设为一样的值。如果虚拟机启动时设置使用的内存比较小,这个时候又需要初始化很多对象,虚拟机就必须重复地增加内存。
处理器核数增加,内存也跟着增大。
2. The Young Generation
另外一个对于app流畅性运行影响的因素是young generation的大小。young generation越大,minor collection越少;但是在固定heap size情况下,更大的young generation就意味着小的tenured generation,就意味着更多的major collection(major collection会引发minor collection)。
NewRatio反映的是young和tenured generation的大小比例。NewSize和MaxNewSize反映的是young generation大小的下限和上限,将这两个值设为一样就固定了young generation的大小(同Xms和Xmx设为一样)。
如果希望,SurvivorRatio也可以优化survivor的大小,不过这对于性能的影响不是很大。SurvivorRatio是eden和survior大小比例。
一般而言,server端的app会有以下规则:
首先决定能分配给vm的最大的heap size,然后设定最佳的young generation的大小;
如果heap size固定后,增加young generation的大小意味着减小tenured generation大小。让tenured generation在任何时候够大,能够容纳所有live的data(留10%-20%的空余)。
经验规则
年轻代大小选择
响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择).在此种情况下,年轻代收集发生的频率也是最小的.同时,减少到达年老代的对象.
吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度.因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用.
避免设置过小.当新生代设置过小时会导致:1.YGC次数更加频繁 2.可能导致YGC对象直接进入旧生代,如果此时旧生代满了,会触发FGC.
年老代大小选择
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得:
并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象.
较小堆引起的碎片问题
因为年老代的并发收集器使用标记,清除算法,所以不会对堆进行压缩.当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象.但是,当堆空间较小时,运行一段时间以后,就会出现"碎片",如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记,清除方式进行回收.如果出现"碎片",可能需要进行如下配置:
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩.
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
用64位操作系统,Linux下64位的jdk比32位jdk要慢一些,但是吃得内存更多,吞吐量更大
XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力
使用CMS的好处是用尽量少的新生代,经验值是128M-256M, 然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存, 大约20-80ms的应用程序停顿时间
系统停顿的时候可能是GC的问题也可能是程序的问题,多用jmap和jstack查看,或者killall -3 java,然后查看java控制台日志,能看出很多问题。(相关工具的使用方法将在后面的blog中介绍)
仔细了解自己的应用,如果用了缓存,那么年老代应该大一些,缓存的HashMap不应该无限制长,建议采用LRU算法的Map做缓存,LRUMap的最大长度也要根据实际情况设定。
采用并发回收时,年轻代小一点,年老代要大,因为年老大用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿
JVM参数的设置(特别是 –Xmx –Xms –Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold等参数的设置没有一个固定的公式,需要根据PV old区实际数据 YGC次数等多方面来衡量。为了避免promotion faild可能会导致xmn设置偏小,也意味着YGC的次数会增多,处理并发访问的能力下降等问题。每个参数的调整都需要经过详细的性能测试,才能找到特定应用的最佳配置。
promotion failed:
垃圾回收时promotion failed是个很头痛的问题,一般可能是两种原因产生,第一个原因是救助空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向Full GC,网站停顿时间较长。
解决方方案一:
第一个原因我的最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,第二个原因我的解决办法是设置CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行CMS,年老代有足够的空间接纳来自年轻代的对象。
解决方案一的改进方案:
又有改进了,上面方法不太好,因为没有用到救助空间,所以年老代容易满,CMS执行会比较频繁。我改善了一下,还是用救助空间,但是把救助空间加大,这样也不会有promotion failed。具体操作上,32位Linux和64位Linux好像不一样,64位系统似乎只要配置MaxTenuringThreshold参数,CMS还是有暂停。为了解决暂停问题和promotion failed问题,最后我设置-XX:SurvivorRatio=1 ,并把MaxTenuringThreshold去掉,这样即没有暂停又不会有promotoin failed,而且更重要的是,年老代和永久代上升非常慢(因为好多对象到不了年老代就被回收了),所以CMS执行频率非常低,好几个小时才执行一次,这样,服务器都不用重启了。
-Xmx4000M -Xms4000M -Xmn600M -XX:PermSize=500M -XX:MaxPermSize=500M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log
CMSInitiatingOccupancyFraction值与Xmn的关系公式
上面介绍了promontion faild产生的原因是EDEN空间不足的情况下将EDEN与From survivor中的存活对象存入To survivor区时,To survivor区的空间不足,再次晋升到old gen区,而old gen区内存也不够的情况下产生了promontion faild从而导致full gc.那可以推断出:eden+from survivor old gen区剩余内存时,不会出现promontion faild的情况,即:
(Xmx-Xmn)*(1-CMSInitiatingOccupancyFraction/100)=(Xmn-Xmn/(SurvivorRatior+2)) 进而推断出:
CMSInitiatingOccupancyFraction =((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100
例如:
当xmx=128 xmn=36 SurvivorRatior=1时 CMSInitiatingOccupancyFraction=((128.0-36)-(36-36/(1+2)))/(128-36)*100 =73.913
当xmx=128 xmn=24 SurvivorRatior=1时 CMSInitiatingOccupancyFraction=((128.0-24)-(24-24/(1+2)))/(128-24)*100=84.615…
当xmx=3000 xmn=600 SurvivorRatior=1时 CMSInitiatingOccupancyFraction=((3000.0-600)-(600-600/(1+2)))/(3000-600)*100=83.33
CMSInitiatingOccupancyFraction低于70% 需要调整xmn或SurvivorRatior值。
OushuDB 快速入手
快速入手
本节将通过RPM安装物理机版本的一个Centos/Redhat 7.x单节点集群。假设我们安装的服务器hostname为oushu(可以通过命令:hostname 直接获取,请将文中所有出现的oushu替换为实际的hostname)。此次部署大约需要您30分钟时间。
安装准备
首先使用root登录。 查看有无avx指令:
cat /proc/cpuinfo | grep avx
安装oushu yum源:
#Redhat/CentOS 7.0, 7.1, 7.2系统并且包含avx指令请配置以下YUM源:
wget -P /etc/yum.repos.d/ $获取的repo url
#Redhat/CentOS 7.0, 7.1, 7.2系统但不包含avx指令请配置以下YUM源:
wget -P /etc/yum.repos.d/ $获取的repo url
#Redhat/CentOS 7.3系统并且包含avx指令请配置以下YUM源:
wget -P /etc/yum.repos.d/ $获取的repo url
#Redhat/CentOS 7.3系统但不包含avx指令请配置以下YUM源:
wget -P /etc/yum.repos.d/ $获取的repo url
#Redhat/CentOS 7.4系统并且包含avx指令请配置以下YUM源:
wget -P /etc/yum.repos.d/ $获取的repo url
#Redhat/CentOS 7.4系统但不包含avx指令请配置以下YUM源:
wget -P /etc/yum.repos.d/ $获取的repo url
禁用selinux:
sed -i "s/^SELINUX\=enforcing/SELINUX\=disabled/g" /etc/selinux/configsetenforce 0
关闭防火墙:
systemctl stop iptablessystemctl disable iptablessystemctl stop firewalldsystemctl disable firewalld
安装Java:
yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-develmkdir -p /usr/java//注意查看本机的java版本ln -s /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.141-2.b16.el7_4.x86_64 /usr/java/default
安装HDFS
安装HDFS并且创建其使用的目录,这里我们假设我们的机器上有两个数据盘,分别mount在/data1和/data2目录,如果您有多块盘,下面的目录创建以及配置文件需要做相应的更改。尤其对HDFS的数据目录以及OushuDB的临时文件目录位置。
#由于hadoop依赖于特定版本的snappy,请先卸载snappy确保安装的顺利进行yum -y remove snappy#安装HDFS RPM,RPM安装会自动创建hdfs用户yum install -y hadoop hadoop-hdfs#在/data1上创建NameNode目录mkdir -p /data1/hdfs/namenode#在每块盘上创建DataNode数据目录,并更改权限mkdir -p /data1/hdfs/datanodechmod -R 755 /data1/hdfschown -R hdfs:hadoop /data1/hdfsmkdir -p /data2/hdfs/datanodechmod -R 755 /data2/hdfschown -R hdfs:hadoop /data2/hdfs
复制下列文件到/etc/hadoop/conf/中(遇到覆盖提示,请输入y,表示确认覆盖)
.
.
.
编辑/etc/hadoop/conf/core-site.xml文件中的fs.defaultFS属性,其他系统通过这个url来访问HDFS,注:在做format之前,请确认已经将core-site.xml中fs.defaultFS的值由oushu替换成hostname。:
propertynamefs.defaultFS/namevaluehdfs://oushu:9000/value/property
编辑 /etc/hadoop/conf/hadoop-env.sh,加入下面参数。这些参数配置了Java Home,Hadoop配置文件,日志文件目录,以及JVM选项。根据存储的HDFS数据量大小,需要适当修改NameNode的-Xmx值。HDFS数据量越大,-Xmx值应该设的越大。
export JAVA_HOME="/usr/java/default"
export HADOOP_CONF_DIR="/etc/hadoop/conf"
export HADOOP_NAMENODE_OPTS="-Xmx6144m -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70"
export HADOOP_DATANODE_OPTS="-Xmx2048m -Xss256k"
export HADOOP_LOG_DIR=/var/log/hadoop/$USER
因为/etc/hadoop/conf/hdfs-site.xml中默认使用/data1和/data2两块盘,如果你有多块盘,你需要更改dfs.data.dir属性,使得HDFS用到所有盘:
propertynamedfs.data.dir/namevalue/data1/hdfs/datanode,/data2/hdfs/datanode/valuefinaltrue/final/property
格式化NameNode,并启动NameNode和DataNode。
注:在format过程中如果询问是否要format,请输入y,表示确认。
sudo -u -E hdfs hdfs namenode -formatsudo -u -E hdfs /usr/hdp/current/hadoop-client/sbin/hadoop-daemon.sh start namenodesudo -u -E hdfs /usr/hdp/current/hadoop-client/sbin/hadoop-daemon.sh start datanode
HDFS日志在/var/log/hadoop/hdfs/中。如果因为配置出错,可以查看错误日志,并依据改正。
检查hdfs是否成功运行:
su - hdfshdfs dfsadmin -reporthdfs dfs -mkdir /testnodehdfs dfs -put /usr/hdp/current/hadoop-client/sbin/hadoop-daemon.sh /testnode/hdfs dfs -ls -R /
你也可以查看HDFS web界面:
安装OushuDB
安装OushuDB RPM,OushuDB RPM安装会自动创建gpadmin用户。
yum install -y hawq
在配置文件/etc/sysctl.conf添加内容
kernel.shmmax = 1000000000kernel.shmmni = 4096kernel.shmall = 4000000000kernel.sem = 250 512000 100 2048kernel.sysrq = 1kernel.core_uses_pid = 1kernel.msgmnb = 65536kernel.msgmax = 65536kernel.msgmni = 2048net.ipv4.tcp_syncookies = 0net.ipv4.conf.default.accept_source_route = 0net.ipv4.tcp_tw_recycle = 1net.ipv4.tcp_max_syn_backlog = 200000net.ipv4.conf.all.arp_filter = 1net.ipv4.ip_local_port_range = 10000 65535net.core.netdev_max_backlog = 200000fs.nr_open = 3000000kernel.threads-max = 798720kernel.pid_max = 798720# increase networknet.core.rmem_max=2097152net.core.wmem_max=2097152net.core.somaxconn=4096
使系统配置生效:
sysctl -p
创建OushuDB本地元数据目录和临时文件目录:
#创建OushuDB本地元数据目录,下面两个目录分别为master和segment使用mkdir -p /data1/hawq/masterddmkdir -p /data1/hawq/segmentdd#创建OushuDB临时文件目录,每块盘需要创建一个临时文件目录,这样可以让OushuDB使用到所有盘。mkdir -p /data1/hawq/tmpchmod -R 755 /data1/hawqchown -R gpadmin:gpadmin /data1/hawqmkdir -p /data2/hawq/tmpchmod -R 755 /data2/hawqchown -R gpadmin:gpadmin /data2/hawq
在HDFS上创建OushuDB数据目录:
sudo -u hdfs hdfs dfs -mkdir -p /hawq_defaultsudo -u hdfs hdfs dfs -chown -R gpadmin /hawq_default
编辑/usr/local/hawq/etc/slaves,去掉文件中的localhost,并加入oushu。slaves文件中存放所有slave节点的地址,每行一个节点。修改后文件为:
oushu
编辑/usr/local/hawq/etc/hawq-site.xml, 因为/usr/local/hawq/etc/hawq-site.xml中默认使用/data1和/data2两块盘,如果你有多块盘,你需要更改hawq_master_temp_directory和hawq_segment_temp_directory值,用到所有盘:
propertynamehawq_master_address_host/namevalueoushu/valuedescriptionThe host name of hawq master./description/propertypropertynamehawq_dfs_url/namevalueoushu:9000/hawq_default/valuedescriptionURL for accessing HDFS./description/propertypropertynamemagma_nodes_url/namevaluelocalhost:6666/valuedescriptionurls for accessing magma./description/propertypropertynamehawq_master_directory/namevalue/data1/hawq/masterdd/valuedescriptionThe directory of hawq master./description/propertypropertynamehawq_segment_directory/namevalue/data1/hawq/segmentdd/valuedescriptionThe directory of hawq segment./description/propertypropertynamehawq_master_temp_directory/namevalue/data1/hawq/tmp,/data2/hawq/tmp/valuedescriptionThe temporary directory reserved for hawq master. Note: please DONOT add " " between directries./description/propertypropertynamehawq_segment_temp_directory/namevalue/data1/hawq/tmp,/data2/hawq/tmp/valuedescriptionThe temporary directory reserved for hawq segment. Note: please DONOT add " " between directories./description/property
OushuDB4.0版本新增Magma的单独配置和启停功能,使用magam服务时,首先创建magma node数据目录:
# 创建mamga node数据目录mkdir -p /data1/hawq/magma_segmentddmkdir -p /data2/hawq/magma_segmentddchown -R gpadmin:gpadmin /data1/hawqchown -R gpadmin:gpadmin /data2/hawq
然后编辑配置/usr/local/hawq/etc/magma-site.xml:
propertynamenodes_file/namevalueslaves/valuedescriptionThe magma nodes file name at GPHOME/etc/description/propertypropertynamenode_data_directory/namevalue;/valuedescriptionThe data directory for magma node/description/propertypropertynamenode_log_directory/namevalue~/hawq-data-directory/segmentdd/pg_log/valuedescriptionThe log directory for magma node/description/propertypropertynamenode_address_port/namevalue6666/valuedescriptionThe port magma node listening/description/propertypropertynamemagma_range_number/namevalue2/value/propertypropertynamemagma_replica_number/namevalue3/value/propertypropertynamemagma_datadir_capacity/namevalue3/value/propertypropertynamecompact_trigger_ap_ratio_limit/namevalue0.2/valuedescriptionThe threshold of triggering compact in MAGMAAP format./description/propertypropertynamecompact_trigger_tp_ratio_limit/namevalue0.5/valuedescriptionThe threshold of triggering compact in MAGMAAP catalog/description/property
以gpadmin用户登录:
su - gpadmin
设置免密码ssh:
source /usr/local/hawq/greenplum_path.shhawq ssh-exkeys -h oushu
初始化OushuDB,在询问是否初始化时,请输入y,表示确认初始化。
hawq init cluster //OushuDB4.0 默认不启动magma服务
hawq init cluster --with_magma //OushuDB4.0新增,3.X版本不支持该选项
// OushuDB4.0版本新增--with_magma选项,但只有hawq init|start|stop cluster命令可以带--with_magma选项。
OushuDB管理工具日志在/home/gpadmin/hawqAdminLogs/中,OushuDB master日志和segment日志分别在/data1/hawq/masterdd/pg_log/ 和/data1/hawq/segmentdd/pg_log/中。如果因为配置出错,可以查看错误日志,并依据改正。
检查OushuDB是否运行正常:
su - gpadminsource /usr/local/hawq/greenplum_path.shpsql -d postgresselect * from gp_segment_configuration; //确定所有节点是up状态create table t(i int);insert into t select generate_series(1,1000);select count(*) from t;
体验新执行器
本章节通过TPCH lineitem 表来展示新执行器的使用。
建立e_lineitem外部表用来生成TPCH lineitem 数据,
CREATE EXTERNAL WEB TABLE E_LINEITEM ( L_ORDERKEY INT8 ,L_PARTKEY INTEGER ,L_SUPPKEY INTEGER ,L_LINENUMBER INTEGER ,L_QUANTITY FLOAT ,L_EXTENDEDPRICE FLOAT ,L_DISCOUNT FLOAT ,L_TAX FLOAT ,L_RETURNFLAG VARCHAR(1) ,L_LINESTATUS VARCHAR(1) ,L_SHIPDATE TEXT ,L_COMMITDATE TEXT ,L_RECEIPTDATE TEXT ,L_SHIPINSTRUCT CHAR(25) ,L_SHIPMODE VARCHAR(10) ,L_COMMENT VARCHAR(44) )EXECUTE 'bash -c "$GPHOME/bin/dbgen -b $GPHOME/bin/dists.dss -T L -s 1 -N 6 -n $((GP_SEGMENT_ID + 1))"'on 6 format 'text' (delimiter '|');
创建ORC 表
CREATE TABLE lineitem( L_ORDERKEY INT8,L_PARTKEY INTEGER,L_SUPPKEY INTEGER,L_LINENUMBER INTEGER,L_QUANTITY FLOAT,L_EXTENDEDPRICE FLOAT,L_DISCOUNT FLOAT,L_TAX FLOAT,L_RETURNFLAG TEXT,L_LINESTATUS TEXT,L_SHIPDATE TEXT,L_COMMITDATE TEXT,L_RECEIPTDATE TEXT,L_SHIPINSTRUCT TEXT,L_SHIPMODE TEXT,L_COMMENT TEXT)WITH (APPENDONLY = true, OIDS = FALSE, ORIENTATION = orc);
插入数据
INSERT INTO lineitem SELECT * FROM e_lineitem;
从下面的例子可以看到新执行器对于性能的大幅改进。
-----获取表行数------postgres=# set new_executor = on;SETpostgres=# SELECT COUNT(*) FROM lineitem;count---------6001215(1 row)Time: 17.006 mspostgres=# set new_executor = off;SETpostgres=# SELECT COUNT(*) FROM lineitem;count---------6001215(1 row)Time: 213.248 ms-----TPCH 查询 1 ------postgres=# set new_executor = on;SETpostgres=# SELECTl_returnflag,l_linestatus,sum(l_quantity)::bigint as sum_qty,sum(l_extendedprice)::bigint as sum_base_price,sum(l_extendedprice * (1 - l_discount))::bigint as sum_disc_price,sum(l_extendedprice * (1 - l_discount) * (1 + l_tax))::bigint as sum_charge,avg(l_quantity)::bigint as avg_qty,avg(l_extendedprice)::bigint as avg_price,avg(l_discount)::bigint as avg_disc,count(*) as count_orderFROMlineitemWHEREl_shipdate = '1998-08-20'GROUP BYl_returnflag,l_linestatus;l_returnflag | l_linestatus | sum_qty | sum_base_price | sum_disc_price | sum_charge | avg_qty | avg_price | avg_disc | count_order--------------+--------------+----------+----------------+----------------+--------------+---------+-----------+----------+-------------R | F | 37719753 | 56568041381 | 53741292685 | 55889619120 | 26 | 38251 | 0 | 1478870N | F | 991417 | 1487504710 | 1413082168 | 1469649223 | 26 | 38284 | 0 | 38854A | F | 37734107 | 56586554401 | 53758257135 | 55909065223 | 26 | 38273 | 0 | 1478493N | O | 73808911 | 110700990251 | 105167436999 | 109377979031 | 26 | 38248 | 0 | 2894278(4 rows)Time: 234.376 mspostgres=# set new_executor = off;SETpostgres=# SELECTl_returnflag,l_linestatus,sum(l_quantity)::bigint as sum_qty,sum(l_extendedprice)::bigint as sum_base_price,sum(l_extendedprice * (1 - l_discount))::bigint as sum_disc_price,sum(l_extendedprice * (1 - l_discount) * (1 + l_tax))::bigint as sum_charge,avg(l_quantity)::bigint as avg_qty,avg(l_extendedprice)::bigint as avg_price,avg(l_discount)::bigint as avg_disc,count(*) as count_orderFROMlineitemWHEREl_shipdate = '1998-08-20'GROUP BYl_returnflag,l_linestatus;l_returnflag | l_linestatus | sum_qty | sum_base_price | sum_disc_price | sum_charge | avg_qty | avg_price | avg_disc | count_order--------------+--------------+----------+----------------+----------------+--------------+---------+-----------+----------+-------------R | F | 37719753 | 56568041381 | 53741292685 | 55889619120 | 26 | 38251 | 0 | 1478870N | F | 991417 | 1487504710 | 1413082168 | 1469649223 | 26 | 38284 | 0 | 38854A | F | 37734107 | 56586554401 | 53758257135 | 55909065223 | 26 | 38273 | 0 | 1478493N | O | 73808911 | 110700990251 | 105167436999 | 109377979031 | 26 | 38248 | 0 | 2894278(4 rows)Time: 2341.147 ms
什么时候才用的到jvm调优,为什么要调优,有人能指教一下吗
JVM是最好的软件工程之一,它为Java提供了坚实的基础,许多流行语言如Kotlin、Scala、Clojure、Groovy都使用JVM作为运行基础。一个专业的Java工程师必须要了解并掌握JVM,接下来就给大家分享Java基础知识中JVM调优相关知识点。
杭州Java基础知识学习之JVM调优讲解
JVM常见的调优参数包括:
-Xmx:指定java程序的最大堆内存, 使用java -Xmx5000M -version判断当前系统能分配的最大堆内存;
-Xms:指定最小堆内存, 通常设置成跟最大堆内存一样,减少GC;
-Xmn:设置年轻代大小。整个堆大小=年轻代大小+年老代大小。所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8;
-Xss:指定线程的最大栈空间, 此参数决定了java函数调用的深度, 值越大调用深度越深, 若值太小则容易出栈溢出错误(StackOverflowError);
-XX:PermSize:指定方法区(永久区)的初始值,默认是物理内存的1/64,在Java8永久区移除, 代之的是元数据区,由-XX:MetaspaceSize指定;
-XX:MaxPermSize:指定方法区的最大值, 默认是物理内存的1/4,在java8中由-XX:MaxMetaspaceSize指定元数据区的大小;
-XX:NewRatio=n:年老代与年轻代的比值,-XX:NewRatio=2, 表示年老代与年轻代的比值为2:1;
-XX:SurvivorRatio=n:Eden区与Survivor区的大小比值,-XX:SurvivorRatio=8表示Eden区与Survivor区的大小比值是8:1:1,因为Survivor区有两个(from, to)。
JVM实质上分为三大块,年轻代(YoungGen),年老代(Old Memory),及持久代(Perm,在Java8中被取消)。
年轻代大小选择
响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
年老代大小选择
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。
减少年轻代和年老代花费的时间,一般会提高应用的效率。
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
较小堆引起的碎片问题
因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩。
一文彻底搞懂 CMS GC 参数配置
近期整理多个 HBase 集群的 JVM 参数,发现都是默认的 CMS GC 配置,如何调优 JVM 参数就成了一个绕不过的话题。因此,为了寻求一个 CMS GC 的 JVM 合理参数配置,笔者参考多篇社区文章及相关博客,总结了一些 CMS 相关的知识点,以及一套基于 CMS 的 JVM 参数配置。
CMS(Concurrent Mark Sweep,并发-标记-清除)是目前最常用的 JVM 垃圾回收器,这里不解释 CMS 的工作过程,只记录一些基础要点以帮助理解后面的内容:
经过理解各个参数的含义及取值影响,总结了以下的 JVM 参数配置,可以几乎不用调整使用:
如果是 64G 及以上的大堆,-Xmn 可以调整到2g,其他参数不变或微调。下面对一些重要的 JVM 参数介绍说明。
以下参数解析都建立在使用 CMS GC 策略基础上,这里使用 CMS GC 表示老年代垃圾回收,Young GC 表示新生代垃圾回收。
① -Xmx, -Xms, -Xmn
-Xmx、-Xms 分别表示 JVM 堆的最大值,初始化大小。-Xmx 等价于-XX:MaxHeapSize,-Xms 等价于-XX:InitialHeapSize。
-Xmn表示新生代大小,等价于-XX:MaxNewSize、-XX:NewSize,这个参数的设置对 GC 性能影响较大,设置小了会影响 CMS GC 性能,设置大了会影响 Young GC 性能,建议取值范围在1~3g,比如32g堆大小时可以设为1g,64g堆大小时可以设为2g,通常性能会比较高。
② -Xss
表示线程栈的大小,等价于-XX:ThreadStackSize,默认1M,一般使用不了这么多,建议值256k。
③ -XX:SurvivorRatio
新生代中 Eden 区与 Survivor 区的比值,默认8,这个参数设置过大会导致 CMS GC 耗时过长,建议调小,使得短寿对象在Young区可以被充分回收,减少晋升到Old区的对象数量,以此提升 CMS GC 性能。
④ -XX:+UseParNewGC, -XX:+UseConcMarkSweepGC
分别表示使用并行收集器 ParNew 对新生代进行垃圾回收,使用并发标记清除收集器 CMS 对老年代进行垃圾回收。
⑤ -XX:ParallelGCThreads, -XX:ParallelCMSThreads
分别表示 Young GC 与 CMS GC 工作时的并行线程数,建议根据处理器数量进行合理设置。
⑥ -XX:MaxTenuringThreshold
对象从新生代晋升到老年代的年龄阈值(每次 Young GC 留下来的对象年龄加一),默认值15,表示对象要经过15次 GC 才能从新生代晋升到老年代。设置太小会严重影响 CMS GC 性能,建议默认值即可。
⑦ -XX:+UseCMSCompactAtFullCollection
由于 CMS GC 会产生内存碎片,且只在 Full GC 时才会进行内存碎片压缩(因此 使用 CMS 垃圾回收器避免不了 Full GC)。这个参数表示开启 Full GC 时的压缩功能,减少内存碎片。
⑧ -XX:+UseCMSInitiatingOccupancyOnly , -XX:CMSInitiatingOccupancyFraction
-XX:CMSInitiatingOccupancyFraction 表示触发 CMS GC 的老年代使用阈值,一般设置为 70~80(百分比),设置太小会增加 CMS GC 发现的频率,设置太大可能会导致并发模式失败或晋升失败。默认为 -1,表示 CMS GC 会由 JVM 自动触发。
-XX:+UseCMSInitiatingOccupancyOnly 表示 CMS GC 只基于 CMSInitiatingOccupancyFraction 触发,如果未设置该参数则 JVM 只会根据 CMSInitiatingOccupancyFraction 触发第一次 CMS GC ,后续还是会自动触发。建议同时设置这两个参数。
⑨ -XX:+CMSClassUnloadingEnabled
表示开启 CMS 对永久代的垃圾回收(或元空间),避免由于永久代空间耗尽带来 Full GC。
在线工具
GC在线参数检查与优化:
GC在线日志分析:
参考文档
目前我们主要使用 CMS,其实比较大的heap建议使用 G1 垃圾回收器,关于 G1 后文我们会进行介绍总结。欢迎留下你的见解。
往期文章精选
◆ Apache Hudi 0.5.1版本重磅发布
◆ 贝壳找房基于 Flink 的实时平台建设
◆ 网易基于 HBase 的最佳实践
◆ 小米流式平台架构演进与实践
如果您喜欢这篇文章,点【在看】与转发都是一种鼓励,期待得到您的认可 ❥(^_-)