Java开发选服务器8核16G真的适合你吗摘要做Java开发选服务器很多人的第一反应是8核16G。但从JVM内存模型和线程模型来看不少Java应用根本用不到这么多资源。本文从JVM实际内存消耗、不同业务场景的资源需求出发帮你根据实际情况选对配置。附带JVM参数模板和监控排查命令。关键词Java、服务器选型、JVM调优、Spring Boot、云服务器分类Java / 服务器运维 / 性能优化8核16G是怎么变成默认选项的不管什么业务大家选服务器都是8核16G。日活1000的小工具8核16G。日活50万的电商后台8核16G。一个内部管理系统还是8核16G。问为什么答不上来。要么是别人推荐的要么是云厂商默认就是这个。8核16G成了一种回避思考的安全选项——低了怕不够高了嫌贵8核16G卡在中间心理上觉得应该没问题。实际上很多Java应用4核8G绑绑有余有些8核16G反而不够用。关键是要算不是猜。先搞清楚Java应用怎么吃资源JVM内存不等于你设的那个数很多同学以为分配16G内存Java就能用16G。不对。JVM进程实际占用的物理内存RSS通常比你设的堆内存-Xmx大不少具体大多少取决于线程数、Metaspace使用情况、NIO直接内存等。常见的项目里RSS大约是-Xmx的1.5到2倍。JVM内存分布堆内存-Xmx ← 对象实例存放的地方占大头 ├── 新生代Eden Survivor └── 老年代 非堆内存 ← 容易被忽略 ├── Metaspace ← 类元数据 ├── 线程栈 ← 每个线程默认1MB ├── 直接内存 ← NIO用的DirectByteBuffer └── JIT编译缓存举个例子# JVM参数-Xmx2g-Xms2g-XX:MetaspaceSize256m堆设了2G但实际进程可能占3-4G# 查看Java进程实际内存ps-pPID-opid,rss,vsz,commPID RSS VSZ COMM 12345 3840000 12500000 javaRSS约3.7GB比-Xmx的2G多了一倍左右。所以选服务器内存的时候别只看堆设了多少。堆内存 × 2再留1-2G给操作系统大概就是你要的服务器内存。CPU和并发的关系Spring Boot默认用Tomcat线程池最大200个线程server:tomcat:threads:max:200200个线程不意味着需要200个CPU核心。大部分Java Web应用是IO密集型的——线程在等数据库、等下游接口的时候会让出CPU其他线程接着用。8核CPU通过时间片轮转能撑住远超8个的并发线程。实际看一下就知道了top-bn1|grepjavaPID %CPU %MEM COMMAND 12345 12.3 8.5 javaCPU才用了12%。8核远远用不满4核可能都够。不同业务场景的实际资源需求以下是根据实际项目整理的参考不是精确值但能给个方向。内部管理系统特征日活几十到几百CRUD为主 CPU使用率3-8% 实际RSS1-1.5GB堆512MB就够 推荐2核4G JVM-Xmx512m -Xms512m普通业务API特征日活几千到几万有数据库和Redis CPU使用率10-25% 实际RSS2-4GB堆1-2G 推荐4核8G JVM-Xmx2g -Xms2g中型Web应用特征日活十万级较高并发 CPU使用率20-50% 实际RSS4-8GB堆2-4G 推荐8核16G JVM-Xmx4g -Xms4g高并发API服务特征日活百万级高并发 推荐多实例4核8G 或 单台16核32G大部分中小型Java Web应用4核8G起步就够了。一个真实的选型经历之前帮一个做SaaS的朋友选服务器。Spring Boot应用日活大约2000主要是表单提交、数据查询、报表导出。他本来要买8核16G月费800左右。我让他先开一台2核4G跑一下看数据。用Prometheus监控了3天CPU使用率平均6%峰值18% 内存RSS约1.8GB堆峰值约600MB 网络IO峰值约2Mbps2核4G绑绑有余。最后选了4核8G留余量月费300多。一年省了将近6000块他拿这个钱多买了一台做冷备反而提升了可用性。怎么判断你的配置够不够压测上线前最靠谱的方法。用wrk或JMeter模拟真实流量# wrk简单压测4线程100并发持续60秒wrk-t4-c100-d60s-spost.lua http://localhost:8080/api/query# JMeter复杂场景多个接口混合压测jmeter-n-ttest_plan.jmx-lresult.jtl-e-o./report压测时关注□ CPU峰值是否超过70%超过考虑加核 □ RSS是否超过服务器内存的80%超过考虑加内存 □ Full GC频率高不高可能需要调JVM或加内存 □ 接口P99响应时间是否在可接受范围上线后监控压测模拟不了所有场景上线后要持续看数据。# JVM堆内存使用情况JDK 9用jcmd替代jmapjcmdPIDGC.heap_infogarbage-first heap total 3145728K, used 640000K [0x0000000700000000, 0x0000000800000000) region size 1024K, 120 young (122880K), 6 survivors (6144K)堆总共3G用了640MB使用率约20%。如果长期低于50%说明堆设大了可以减小。# GC统计JDK 9jcmdPIDGC.stat# 或者用jstatJDK 8常用JDK 9仍然可用但建议迁移到jcmdjstat-gcutilPID5000S0 S1 E O M CCS YGC YGCT FGC FGCT 0.00 32.15 45.67 28.91 95.32 92.1 128 1.234 2 0.456重点看这几个O列老年代使用率持续涨到80%以上可能有内存泄漏FGC列Full GC次数频繁Full GC说明内存不够或有泄漏YGCT/YGC年轻代GC耗时/次数单次耗时过长说明年轻代可能设太大了JVM参数和服务器配置怎么配合服务器选好了JVM参数也要配对。配错了硬件再好也白搭。JDK 8java\-Xmx3g-Xms3g\-XX:MetaspaceSize256m-XX:MaxMetaspaceSize256m\-XX:UseG1GC-XX:MaxGCPauseMillis200\-XX:HeapDumpOnOutOfMemoryError\-XX:HeapDumpPath/var/log/java/heapdump.hprof\-XX:PrintGCDetails-XX:PrintGCDateStamps\-Xloggc:/var/log/java/gc.log\-jarapp.jarJDK 11及以上JDK 9开始GC日志参数换了旧的-XX:PrintGCDetails和-Xloggc会报警告甚至报错。用-Xlog统一替代java\-Xmx3g-Xms3g\-XX:MetaspaceSize256m-XX:MaxMetaspaceSize256m\-XX:UseG1GC-XX:MaxGCPauseMillis200\-XX:HeapDumpOnOutOfMemoryError\-XX:HeapDumpPath/var/log/java/heapdump.hprof\-Xlog:gc*:file/var/log/java/gc.log:time,uptime:filecount5,filesize10m\-jarapp.jar不同配置对应的JVM参数2核4G -Xmx1g -Xms1g 4核8G -Xmx3g -Xms3g 8核16G -Xmx6g -Xms6g 16核32G-Xmx12g -Xms12g经验法则堆内存设为服务器内存的35%-40%。留够空间给Metaspace、线程栈、直接内存和操作系统。8G的机器堆设6G甚至7G系统内存会很紧张容易触发OOM Killer——操作系统看你内存不够直接把进程杀了。那种排查起来很迷惑Java日志里什么都没有进程就消失了。# 检查是不是被OOM Killer杀了dmesg|grep-ioom\|kill如果看到类似Out of memory: Kill process 12345 (java)就是操作系统杀的不是JVM的问题。多实例比单机高配更靠谱这是我想特别说的一点。方案A单台8核16G → 月费约600-800元 方案B两台4核8G → 月费约300×2 600元同样的钱方案B多了一台机器的冗余。A机挂了服务就断了B方案挂了一台另一台还撑着。而且双实例可以搭负载均衡做滚动更新发布不停机。# nginx负载均衡 upstream backend { server 10.0.1.10:8080; server 10.0.1.11:8080; } server { listen 80; location / { proxy_pass http://backend; } }更新的时候先摘一台、更新、验证没问题、挂回去再摘另一台。整个过程用户无感知。除非你的应用有特殊的单机需求比如本地缓存一致性否则优先选多实例。什么时候确实需要高配也不是所有场景都适合低配。以下情况确实需要往上加JVM堆需要8G以上。大量对象缓存在内存里或者做复杂的数据处理和报表生成堆要大。CPU密集型计算。图片处理、PDF生成、大量正则、复杂的规则引擎CPU是瓶颈。同一台机器跑多个服务。应用MySQLRedis挤在一台机器上资源被多个进程分摊。建议分开部署别混在一起。总结场景推荐配置月费参考内部管理系统2核4G100-200元普通业务API4核8G200-400元中型Web应用8核16G400-800元高并发服务多实例4核8G600-800元双实例大部分Java Web应用4核8G起步足够。省下来的钱不如多加一台做冗余。选配置的逻辑就一句话先压测再选配先小后大按需升级。不要拍脑袋选8核16G。根据实际数据做决定既不浪费也不委屈。之前帮好几个做Java开发的朋友选过服务器发现大家对配置完全没有概念要么高配浪费要么低配卡顿。写出来希望能帮到有同样困惑的同学。下一篇聊TCP拥塞控制对你的业务有什么影响从Reno到BBR—— 为什么带宽明明没跑满但传输速度就是上不去有问题评论区聊。
Java开发选服务器:8核16G真的适合你吗
Java开发选服务器8核16G真的适合你吗摘要做Java开发选服务器很多人的第一反应是8核16G。但从JVM内存模型和线程模型来看不少Java应用根本用不到这么多资源。本文从JVM实际内存消耗、不同业务场景的资源需求出发帮你根据实际情况选对配置。附带JVM参数模板和监控排查命令。关键词Java、服务器选型、JVM调优、Spring Boot、云服务器分类Java / 服务器运维 / 性能优化8核16G是怎么变成默认选项的不管什么业务大家选服务器都是8核16G。日活1000的小工具8核16G。日活50万的电商后台8核16G。一个内部管理系统还是8核16G。问为什么答不上来。要么是别人推荐的要么是云厂商默认就是这个。8核16G成了一种回避思考的安全选项——低了怕不够高了嫌贵8核16G卡在中间心理上觉得应该没问题。实际上很多Java应用4核8G绑绑有余有些8核16G反而不够用。关键是要算不是猜。先搞清楚Java应用怎么吃资源JVM内存不等于你设的那个数很多同学以为分配16G内存Java就能用16G。不对。JVM进程实际占用的物理内存RSS通常比你设的堆内存-Xmx大不少具体大多少取决于线程数、Metaspace使用情况、NIO直接内存等。常见的项目里RSS大约是-Xmx的1.5到2倍。JVM内存分布堆内存-Xmx ← 对象实例存放的地方占大头 ├── 新生代Eden Survivor └── 老年代 非堆内存 ← 容易被忽略 ├── Metaspace ← 类元数据 ├── 线程栈 ← 每个线程默认1MB ├── 直接内存 ← NIO用的DirectByteBuffer └── JIT编译缓存举个例子# JVM参数-Xmx2g-Xms2g-XX:MetaspaceSize256m堆设了2G但实际进程可能占3-4G# 查看Java进程实际内存ps-pPID-opid,rss,vsz,commPID RSS VSZ COMM 12345 3840000 12500000 javaRSS约3.7GB比-Xmx的2G多了一倍左右。所以选服务器内存的时候别只看堆设了多少。堆内存 × 2再留1-2G给操作系统大概就是你要的服务器内存。CPU和并发的关系Spring Boot默认用Tomcat线程池最大200个线程server:tomcat:threads:max:200200个线程不意味着需要200个CPU核心。大部分Java Web应用是IO密集型的——线程在等数据库、等下游接口的时候会让出CPU其他线程接着用。8核CPU通过时间片轮转能撑住远超8个的并发线程。实际看一下就知道了top-bn1|grepjavaPID %CPU %MEM COMMAND 12345 12.3 8.5 javaCPU才用了12%。8核远远用不满4核可能都够。不同业务场景的实际资源需求以下是根据实际项目整理的参考不是精确值但能给个方向。内部管理系统特征日活几十到几百CRUD为主 CPU使用率3-8% 实际RSS1-1.5GB堆512MB就够 推荐2核4G JVM-Xmx512m -Xms512m普通业务API特征日活几千到几万有数据库和Redis CPU使用率10-25% 实际RSS2-4GB堆1-2G 推荐4核8G JVM-Xmx2g -Xms2g中型Web应用特征日活十万级较高并发 CPU使用率20-50% 实际RSS4-8GB堆2-4G 推荐8核16G JVM-Xmx4g -Xms4g高并发API服务特征日活百万级高并发 推荐多实例4核8G 或 单台16核32G大部分中小型Java Web应用4核8G起步就够了。一个真实的选型经历之前帮一个做SaaS的朋友选服务器。Spring Boot应用日活大约2000主要是表单提交、数据查询、报表导出。他本来要买8核16G月费800左右。我让他先开一台2核4G跑一下看数据。用Prometheus监控了3天CPU使用率平均6%峰值18% 内存RSS约1.8GB堆峰值约600MB 网络IO峰值约2Mbps2核4G绑绑有余。最后选了4核8G留余量月费300多。一年省了将近6000块他拿这个钱多买了一台做冷备反而提升了可用性。怎么判断你的配置够不够压测上线前最靠谱的方法。用wrk或JMeter模拟真实流量# wrk简单压测4线程100并发持续60秒wrk-t4-c100-d60s-spost.lua http://localhost:8080/api/query# JMeter复杂场景多个接口混合压测jmeter-n-ttest_plan.jmx-lresult.jtl-e-o./report压测时关注□ CPU峰值是否超过70%超过考虑加核 □ RSS是否超过服务器内存的80%超过考虑加内存 □ Full GC频率高不高可能需要调JVM或加内存 □ 接口P99响应时间是否在可接受范围上线后监控压测模拟不了所有场景上线后要持续看数据。# JVM堆内存使用情况JDK 9用jcmd替代jmapjcmdPIDGC.heap_infogarbage-first heap total 3145728K, used 640000K [0x0000000700000000, 0x0000000800000000) region size 1024K, 120 young (122880K), 6 survivors (6144K)堆总共3G用了640MB使用率约20%。如果长期低于50%说明堆设大了可以减小。# GC统计JDK 9jcmdPIDGC.stat# 或者用jstatJDK 8常用JDK 9仍然可用但建议迁移到jcmdjstat-gcutilPID5000S0 S1 E O M CCS YGC YGCT FGC FGCT 0.00 32.15 45.67 28.91 95.32 92.1 128 1.234 2 0.456重点看这几个O列老年代使用率持续涨到80%以上可能有内存泄漏FGC列Full GC次数频繁Full GC说明内存不够或有泄漏YGCT/YGC年轻代GC耗时/次数单次耗时过长说明年轻代可能设太大了JVM参数和服务器配置怎么配合服务器选好了JVM参数也要配对。配错了硬件再好也白搭。JDK 8java\-Xmx3g-Xms3g\-XX:MetaspaceSize256m-XX:MaxMetaspaceSize256m\-XX:UseG1GC-XX:MaxGCPauseMillis200\-XX:HeapDumpOnOutOfMemoryError\-XX:HeapDumpPath/var/log/java/heapdump.hprof\-XX:PrintGCDetails-XX:PrintGCDateStamps\-Xloggc:/var/log/java/gc.log\-jarapp.jarJDK 11及以上JDK 9开始GC日志参数换了旧的-XX:PrintGCDetails和-Xloggc会报警告甚至报错。用-Xlog统一替代java\-Xmx3g-Xms3g\-XX:MetaspaceSize256m-XX:MaxMetaspaceSize256m\-XX:UseG1GC-XX:MaxGCPauseMillis200\-XX:HeapDumpOnOutOfMemoryError\-XX:HeapDumpPath/var/log/java/heapdump.hprof\-Xlog:gc*:file/var/log/java/gc.log:time,uptime:filecount5,filesize10m\-jarapp.jar不同配置对应的JVM参数2核4G -Xmx1g -Xms1g 4核8G -Xmx3g -Xms3g 8核16G -Xmx6g -Xms6g 16核32G-Xmx12g -Xms12g经验法则堆内存设为服务器内存的35%-40%。留够空间给Metaspace、线程栈、直接内存和操作系统。8G的机器堆设6G甚至7G系统内存会很紧张容易触发OOM Killer——操作系统看你内存不够直接把进程杀了。那种排查起来很迷惑Java日志里什么都没有进程就消失了。# 检查是不是被OOM Killer杀了dmesg|grep-ioom\|kill如果看到类似Out of memory: Kill process 12345 (java)就是操作系统杀的不是JVM的问题。多实例比单机高配更靠谱这是我想特别说的一点。方案A单台8核16G → 月费约600-800元 方案B两台4核8G → 月费约300×2 600元同样的钱方案B多了一台机器的冗余。A机挂了服务就断了B方案挂了一台另一台还撑着。而且双实例可以搭负载均衡做滚动更新发布不停机。# nginx负载均衡 upstream backend { server 10.0.1.10:8080; server 10.0.1.11:8080; } server { listen 80; location / { proxy_pass http://backend; } }更新的时候先摘一台、更新、验证没问题、挂回去再摘另一台。整个过程用户无感知。除非你的应用有特殊的单机需求比如本地缓存一致性否则优先选多实例。什么时候确实需要高配也不是所有场景都适合低配。以下情况确实需要往上加JVM堆需要8G以上。大量对象缓存在内存里或者做复杂的数据处理和报表生成堆要大。CPU密集型计算。图片处理、PDF生成、大量正则、复杂的规则引擎CPU是瓶颈。同一台机器跑多个服务。应用MySQLRedis挤在一台机器上资源被多个进程分摊。建议分开部署别混在一起。总结场景推荐配置月费参考内部管理系统2核4G100-200元普通业务API4核8G200-400元中型Web应用8核16G400-800元高并发服务多实例4核8G600-800元双实例大部分Java Web应用4核8G起步足够。省下来的钱不如多加一台做冗余。选配置的逻辑就一句话先压测再选配先小后大按需升级。不要拍脑袋选8核16G。根据实际数据做决定既不浪费也不委屈。之前帮好几个做Java开发的朋友选过服务器发现大家对配置完全没有概念要么高配浪费要么低配卡顿。写出来希望能帮到有同样困惑的同学。下一篇聊TCP拥塞控制对你的业务有什么影响从Reno到BBR—— 为什么带宽明明没跑满但传输速度就是上不去有问题评论区聊。