ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零搭建BYL我的世界开服器:Java版服务端配置与性能调优实战

从零搭建BYL我的世界开服器:Java版服务端配置与性能调优实战 1. 从零搭建BYL我的世界开服器为什么我要自己动手很多人第一次接触《我的世界》Java版联机第一反应是去租一个现成的服务器面板点点鼠标就完事。但真到了要装模组、调参数、开多个版本共存的时候那些面板要么限制太多要么收费不低要么干脆不给你完整的文件访问权限。我自己就吃过这个亏——想给几个朋友开一个1.8.9的生存服结果面板里连server.properties都不让改全最后只能自己动手。BYL我的世界开服器本质上就是一套帮你把Java版服务端跑起来的工具集合。它不是什么黑科技核心逻辑非常朴素下载对应版本的服务端核心jar文件配好Java运行环境写好启动脚本把端口和内存参数调对然后让服务端进程稳定跑着。听起来简单但每一步都有坑。这篇文章就是把我从零折腾到稳定的全过程拆开讲包括版本选择、核心文件获取、启动参数计算、常见报错排查以及怎么让服务在低配机器上也能跑得动。适合谁看如果你手里有一台闲置的电脑或者云主机想给几个朋友开个长期生存服又不想被各种面板绑死那这篇内容就是给你写的。如果你完全没碰过命令行也没关系我会把每个命令和每个参数都解释清楚。Java版服务端确实依赖JVM虚拟机运行会有垃圾回收带来的卡顿但通过合理的参数调优这个问题可以压到几乎无感。2. 开服前的硬性准备Java环境与核心文件获取2.1 Java版本选型别再用Java 8硬扛新版本了Java版服务端跑在JVM上Java版本选错轻则启动报错重则跑几分钟就崩。我见过太多人拿着Java 8去开1.18以上的服务端结果直接提示“Unsupported class file major version”。这不是服务端的问题是Java太老了。选型逻辑很简单跟着服务端版本走服务端版本推荐Java版本说明1.8 ~ 1.16.5Java 8老版本兼容性最好模组生态也认Java 81.17 ~ 1.18.2Java 171.17开始强制要求Java 16以上1.19 ~ 1.20.xJava 17 或 Java 21Java 21的GC表现更好但部分老模组可能不兼容1.21Java 21新版本对Java 21优化明显我自己的做法是机器上同时装Java 8和Java 21用哪个版本就在启动脚本里显式指定路径不依赖系统默认。这样开1.8.9生存服和开1.20模组服可以共存互不干扰。安装Java的时候有个细节Windows下尽量用免安装的zip包解压到固定目录比如C:\java\jdk-21然后把bin目录加到环境变量。用安装版也不是不行但有时候它会偷偷改你的默认Java版本导致你之前配好的服务端突然起不来。2.2 服务端核心从哪来官方、Paper、Purpur怎么选服务端核心也就是那个jar文件决定了你的服务器性能上限和功能范围。常见的有几类官方原版服务端Mojang官方发布最干净但性能一般插件支持几乎没有。适合纯原版生存人少的情况。Paper目前最主流的优化端性能比原版好很多支持Bukkit/Spigot插件生态。绝大多数生存服和插件服都用它。Purpur基于Paper的进一步扩展多了很多可配置项比如可调整的刷怪机制、更细的实体控制。适合想深度调优的服主。Fabric/Forge服务端模组服专用Fabric轻量Forge生态老牌。开模组服必须用这两个。我开1.8.9生存服的时候选的是Paper的1.8.9分支。为什么不用官方原版因为1.8.9原版服务端在多人同时在线时实体运算和区块加载的瓶颈很明显Paper在这方面做了大量异步优化同样的机器能多撑好几个人。获取核心文件的渠道我一般直接去Paper的官方构建站下载对应版本的jar。注意要选对构建号不是越新越好——有些最新构建可能引入了新bug建议选一个发布超过一周、下载量大的稳定构建。2.3 目录结构规划别把所有东西堆在一个文件夹里很多人开服就是把jar往桌面一扔双击就跑。跑起来之后发现配置文件、世界存档、日志、插件全混在一起想备份都不知道该备份啥。我建议从一开始就按下面的结构来byl-server/ ├── core/ # 服务端核心jar │ └── paper-1.8.9.jar ├── config/ # 配置文件 │ ├── server.properties │ ├── bukkit.yml │ └── spigot.yml ├── world/ # 主世界存档 ├── world_nether/ # 下界存档 ├── world_the_end/ # 末地存档 ├── plugins/ # 插件目录 ├── logs/ # 日志目录 └── start.sh / start.bat # 启动脚本这样规划的好处是备份的时候直接打包world开头的文件夹和config文件夹就行核心jar和插件可以单独管理。日志单独放出问题的时候直接看logs/latest.log不用在一堆文件里翻。3. 启动脚本的写法内存参数不是拍脑袋填的3.1 内存分配的计算逻辑启动脚本里最重要的就是-Xmx和-Xms这两个参数。-Xmx是JVM能用的最大堆内存-Xms是初始堆内存。很多人直接写-Xmx4G但机器总共就4G内存结果系统本身还要占1G多服务端跑起来就开始疯狂交换内存卡到没法玩。我的经验公式是最大堆内存 机器总内存 × 0.6 ~ 0.7。比如你的机器有8G内存那-Xmx最多给5G到5.5G留出空间给操作系统、JVM自身开销和堆外内存。如果是云主机只有2G内存那-Xmx给1G到1.2G就差不多了再多反而会触发系统级的OOM Killer。-Xms我一般设成和-Xmx一样大。为什么因为如果初始堆很小JVM会频繁扩容和收缩堆每次调整都是一次Full GC反而更卡。固定住初始堆和最大堆GC的行为更可预测。3.2 垃圾回收器的选择G1还是ZGCJava版服务端卡顿的一大来源就是垃圾回收。JVM在回收内存的时候会暂停应用线程表现出来就是玩家感觉“突然卡了一下”。不同GC的暂停时间差别很大Parallel GCJava 8的默认GC吞吐量高但暂停时间长适合单人大世界或者对延迟不敏感的场景。G1 GCJava 9以后的默认GC暂停时间比Parallel短适合大多数服务端场景。1.8.9服务端如果跑在Java 8上可以手动开启G1。ZGCJava 15引入的低延迟GC暂停时间极短但会占用更多CPU和内存。适合Java 21 高配机器。我开1.8.9生存服的时候因为用的是Java 8所以手动加了G1参数。实测下来同样10个人在线Parallel GC偶尔会有0.5秒左右的卡顿换成G1之后基本感觉不到。3.3 一份可直接抄的启动脚本下面是我在Linux上用的启动脚本Windows的话把路径分隔符和变量写法改一下就行#!/bin/bash # BYL我的世界开服器启动脚本 JAVA_PATH/usr/lib/jvm/java-21-openjdk/bin/java SERVER_JARcore/paper-1.8.9.jar MIN_MEM2G MAX_MEM4G # G1 GC参数 GC_PARAMS-XX:UseG1GC \ -XX:ParallelRefProcEnabled \ -XX:MaxGCPauseMillis200 \ -XX:UnlockExperimentalVMOptions \ -XX:DisableExplicitGC \ -XX:AlwaysPreTouch \ -XX:G1NewSizePercent30 \ -XX:G1MaxNewSizePercent40 \ -XX:G1HeapRegionSize8M \ -XX:G1ReservePercent20 \ -XX:G1HeapWastePercent5 \ -XX:G1MixedGCCountTarget4 \ -XX:InitiatingHeapOccupancyPercent15 \ -XX:G1MixedGCLiveThresholdPercent90 \ -XX:G1RSetUpdatingPauseTimePercent5 \ -XX:SurvivorRatio32 \ -XX:PerfDisableSharedMem \ -XX:MaxTenuringThreshold1 $JAVA_PATH -Xms$MIN_MEM -Xmx$MAX_MEM $GC_PARAMS -jar $SERVER_JAR nogui这里有几个参数值得单独说-XX:AlwaysPreTouch启动时就把内存全部预分配好避免运行中才去申请内存导致的卡顿。代价是启动慢几秒但值得。-XX:MaxTenuringThreshold1对象在新生代只存活一次就晋升到老年代减少新生代GC的频率。对于服务端这种大量短命对象的场景很有效。-XX:PerfDisableSharedMem关掉性能统计的内存映射文件避免某些系统上因为磁盘IO导致的卡顿。nogui不加这个参数会弹出一个图形界面在服务器上完全没必要还占资源。注意这些GC参数是针对Java 8到Java 17的G1 GC调优的。如果你用的是Java 21 ZGC参数写法完全不同不要直接套用。4. server.properties里那些真正影响体验的配置4.1 视距与模拟距离性能和体验的平衡点view-distance和simulation-distance这两个参数是服务端性能的最大杀手。view-distance决定玩家能看到多远的区块simulation-distance决定服务端实际运算多远的区块。默认的view-distance10意味着服务端要加载和发送玩家周围10个区块半径内的所有内容。10个人在线每人周围10个区块这个运算量非常恐怖。我一般会把它降到6到8配合客户端的视距设置玩家几乎感觉不到区别但服务端的TPS每秒刻数会稳定很多。simulation-distance更关键。它控制的是实际进行实体运算、红石运算、作物生长的范围。如果你开的是生存服玩家喜欢挂机刷怪塔那这个值不能太低否则刷怪塔效率会下降。我一般设成4到6既保证基本的生产活动又不至于让服务端被远处的红石机器拖垮。4.2 网络压缩与实体同步network-compression-threshold这个参数控制数据包压缩的阈值。默认是256意思是超过256字节的数据包会被压缩。对于带宽有限的服务器可以降到128甚至64让更多数据包被压缩节省带宽。但压缩本身也消耗CPU所以如果你的CPU比较弱反而不要调太低。entity-broadcast-range-percentage控制实体信息广播的范围百分比。默认100意味着实体在视距范围内都会被同步给玩家。如果你发现玩家多的时候实体同步很卡可以降到75甚至50远处的实体就不会频繁更新位置信息能省不少带宽和CPU。4.3 正版验证与白名单online-modetrue是正版验证。如果你开的是公开服强烈建议保持true否则各种乱七八糟的ID都能进来。如果是给朋友开的小服可以用false但一定要配合白名单。白名单的配置在whitelist.json里格式很简单[ { uuid: 玩家的UUID, name: 玩家ID } ]UUID可以通过在线工具查询或者让玩家进服一次之后从日志里抓。开了白名单之后记得在server.properties里把white-list设成true然后执行/whitelist reload让配置生效。5. 实测中遇到的坑与排查链路5.1 启动即崩从日志倒推问题服务端起不来第一件事永远是看日志。日志文件在logs/latest.log里面会记录启动过程中的每一步。常见的启动失败原因有这几类Java版本不匹配。日志里会出现Unsupported class file major version 61之类的字样61对应Java 1752对应Java 8。看到这个就去检查你的Java路径是不是指向了正确的版本。端口被占用。日志里会写Address already in use。这时候用netstat -tlnp | grep 25565查一下谁占着端口。如果是上次没关干净的服务端进程直接kill掉如果是其他程序就改server.properties里的server-port。内存不足。日志里会出现OutOfMemoryError或者Could not reserve enough space for object heap。前者是堆内存不够后者是物理内存不够。前者调大-Xmx后者只能加内存或者调小-Xmx。EULA未同意。第一次启动会生成eula.txt里面默认是eulafalse。改成eulatrue再启动。这个不是坑但新手经常忘。5.2 跑着跑着就卡TPS掉落的排查顺序服务端跑起来之后玩家反馈“卡”但日志里没有明显报错。这时候要按顺序排查第一步看TPS。在控制台输入/tps如果显示低于19说明服务端确实在掉刻。TPS低于15就明显能感觉到卡了。第二步看是什么在吃CPU。用/timings on开启性能分析跑几分钟后/timings paste生成报告。报告里会列出最耗时的插件、实体类型、区块加载等。我遇到过最常见的是某个插件在疯狂遍历实体或者某个玩家建了超大范围的红石时钟。第三步看内存和GC。如果TPS是间歇性掉落很可能是GC导致的。在启动参数里加上-Xlog:gc*Java 9或者-XX:PrintGCDetailsJava 8观察GC日志。如果Full GC频繁出现说明堆内存不够或者有内存泄漏。第四步看实体数量。用/kill e[typeitem]清理掉落物用/kill e[type!player]清理所有非玩家实体慎用。很多时候卡顿就是某个刷怪塔积累了上万个掉落物。5.3 1.8.9版本的专属坑区块加载与实体同步1.8.9这个版本比较老它的区块加载机制和现代版本差别很大。最明显的问题是当玩家快速移动时服务端加载新区块的速度跟不上玩家会看到“虚空”或者掉进未加载的区块里。我的解决办法是在spigot.yml里把chunk-loading相关的参数调一下chunk-loading: min-load-radius: 2 max-concurrent-loads: 8 max-load-rate: 100max-concurrent-loads控制同时加载的区块数量调太高会瞬间吃满CPU调太低又跟不上玩家移动。8是一个比较平衡的值。max-load-rate控制每秒最多加载多少区块100对于1.8.9来说已经比较激进了如果CPU弱可以降到50。还有一个1.8.9特有的问题实体同步范围。1.8.9的实体同步机制比较粗糙远处的实体也会频繁更新。在spigot.yml里把entity-tracking-range调小entity-tracking-range: players: 48 animals: 48 monsters: 48 misc: 32 other: 64这样只有玩家48格范围内的实体会被同步超出范围的实体就不更新位置了能省不少带宽。6. 让服务端长期稳定运行的经验6.1 自动重启与崩溃恢复服务端不可能永远不崩。与其手动去拉起来不如写一个守护脚本崩了自动重启。Linux下可以用systemdWindows下可以用一个简单的bat循环。systemd的配置大概长这样[Unit] DescriptionBYL Minecraft Server Afternetwork.target [Service] Typesimple Userminecraft WorkingDirectory/home/minecraft/byl-server ExecStart/home/minecraft/byl-server/start.sh Restarton-failure RestartSec10 [Install] WantedBymulti-user.target关键是Restarton-failure和RestartSec10意思是崩溃后等10秒自动重启。这样即使半夜崩了也能自己恢复。6.2 定时备份别等存档丢了才后悔存档丢失是服主最大的噩梦。我见过有人开了半年的服硬盘一坏全没了。备份不需要多复杂一个cron任务加一个tar命令就够0 */6 * * * cd /home/minecraft/byl-server tar -czf /backup/world-$(date \%Y\%m\%d-\%H\%M).tar.gz world world_nether world_the_end每6小时备份一次三个世界的存档文件名带时间戳。备份目录最好放在另一块硬盘或者远程存储上别和存档放同一个盘。注意备份的时候最好先执行/save-all让服务端把内存里的数据写盘再执行/save-off暂停自动保存备份完再/save-on。否则备份出来的存档可能不一致。6.3 玩家管理白名单、权限与行为记录小服靠信任大服靠制度。即使只有十几个人的服也建议装一个轻量的权限插件把OP权限拆开。比如给一个玩家essentials.tp权限让他能传送但不给essentials.gamemode权限防止他乱改模式。行为记录也很重要。装一个日志插件记录玩家的方块放置、破坏、容器打开等操作。万一出现纠纷能查是谁干的。1.8.9可用的日志插件有CoreProtect配置简单查询命令也直观。6.4 性能监控TPS、内存、在线人数的实时观察长期运行的服最好有一个简单的监控面板。不需要多复杂一个每5分钟记录一次TPS和内存占用的脚本就够#!/bin/bash while true; do TPS$(echo tps | nc localhost 25575 2/dev/null | grep -oP [\d.](?,)) MEM$(ps -o rss -p $(pgrep -f paper-1.8.9.jar) | awk {print $1/1024}) echo $(date %Y-%m-%d\ %H:%M:%S) TPS$TPS MEM${MEM}MB /var/log/mc-monitor.log sleep 300 done这个脚本通过RCON查询TPS通过ps查内存占用每5分钟记一条。跑一段时间之后你就能看出服务端在什么时间段压力最大提前做调整。7. 关于BYL开服器的一些个人体会折腾了这么久我最大的感受是开服这件事工具只是辅助真正决定体验的是你对参数的理解和对问题的排查能力。BYL我的世界开服器这个名字听起来像是一个成品软件但实际上它更像是一套方法论——知道去哪里拿核心、怎么配Java、怎么调参数、怎么排错。1.8.9这个版本虽然老但它的生存体验确实经典很多老玩家就认这个版本。代价是性能受限JVM的GC卡顿、区块加载慢、实体同步粗糙这些问题都需要手动去调。但调好之后10个人在线稳定跑个20 TPS是完全可以做到的。如果你刚开始开服我的建议是先用Paper的1.8.9核心跑起来把view-distance和simulation-distance降下来加上G1 GC参数装一个CoreProtect做日志然后观察一周的TPS曲线。等稳定了再考虑加插件、加模组、扩人数。别一上来就追求大而全稳定比功能多重要得多。最后分享一个小技巧服务端启动的时候加上-Dcom.mojang.eula.agreetrue这个JVM参数可以跳过EULA的交互确认适合写在自动化脚本里。但前提是你确实已经阅读并同意了EULA这个参数只是省去手动改文件的步骤不是绕过同意。
返回列表