Jetty 作為輕量級、高效能的 Java Servlet 容器,廣泛用於微服務與嵌入式場景。本文提供在 CentOS 7 上部署 Jetty 9 的標準化流程,涵蓋解壓、目錄結構、啟動腳本優化、JVM 參數調優、WebApp 部署描述符、請求日誌配置等生產環境關鍵要素。
# 解壓至標準路徑
cd /opt/app/
tar -xzf jetty-distribution-9.4.x.tar.gz
mv jetty-distribution-9.4.x jetty9
# 建立臨時目錄(供 Jetty 編譯 JSP、儲存上傳檔案等)
mkdir -p /opt/app/jetty9/tmp
建議遵循 JETTY_HOME(安裝目錄,唯讀)與 JETTY_BASE(執行實例目錄,可寫)分離原則,便於多實例共享安裝、獨立配置。本範例為簡化採用同目錄。
編輯 /opt/app/jetty9/bin/jetty.sh,在啟動區塊前注入以下環境變數:
export JETTY_ARGS="jetty.port=8080"
export JAVA="/usr/java/jdk1.8.0_xxx/bin/java"
export JETTY_HOME="/opt/app/jetty9"
export JETTY_BASE="$JETTY_HOME"
export JETTY_RUN="$JETTY_BASE"
export TMPDIR="$JETTY_HOME/tmp"
# 生產級 JVM 參數(根據實際記憶體調整)
export JAVA_OPTIONS="-server \
-Xms2g -Xmx2g -Xmn1g -Xss256k \
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m \
-XX:+UseParNewGC -XX:MaxTenuringThreshold=2 -XX:SurvivorRatio=8 \
-XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled \
-XX:+ParallelRefProcEnabled -XX:CMSFullGCsBeforeCompaction=5 \
-XX:+UseCMSCompactAtFullCollection -XX:+CMSClassUnloadingEnabled \
-XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly \
-XX:+AlwaysPreTouch \
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps \
-XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime \
-XX:-OmitStackTraceInFastThrow \
-Dcom.sun.management.jmxremote=true \
-Djava.rmi.server.hostname=YOUR_SERVER_IP \
-Dcom.sun.management.jmxremote.port=18787 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/jvmlogs \
-Xloggc:/var/jvmlogs/gc-%t.log"
-Xms=Xmx 避免動態擴縮容震盪,-Xmn 設定新生代大小(通常 1/2~1/3 堆)。ParNew + CMS 適合低延遲場景,-XX:+AlwaysPreTouch 預先觸發分頁故障減少首次 GC 停頓。HeapDumpOnOutOfMemoryError 產生堆快照,HeapDumpPath 指定目錄需預先建立且可寫。在 $JETTY_BASE/webapps/app.xml 定義 WebAppContext,實現零侵入式部署:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/app</Set>
<Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/app.war</Set>
<Set name="tempDirectory"><SystemProperty name="jetty.home" default="."/>/tmp</Set>
<Set name="persistTempDirectory">true</Set>
<Set name="handler">
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
<Set name="requestLog">
<New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
<Set name="filename"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Set>
<Set name="filenameDateFormat">yyyy_MM_dd</Set>
<Set name="LogTimeZone">Asia/Shanghai</Set>
<Set name="retainDays">60</Set>
<Set name="append">true</Set>
</New>
</Set>
</New>
</Set>
</Configure>
/app,避免根路徑衝突。SystemProperty 相對引用,支援 JETTY_BASE 切換。persistTempDirectory=true 避免重啟後 JSP 重新編譯。# 1. 放入 WAR 包
cp your-app.war /opt/app/jetty9/webapps/app.war
# 2. 建立日誌與 Dump 目錄
mkdir -p /opt/app/jetty9/logs /var/jvmlogs
chown -R jetty:jetty /opt/app/jetty9 /var/jvmlogs
# 3. 啟動/重啟
/opt/app/jetty9/bin/jetty.sh start
# 或重啟
/opt/app/jetty9/bin/jetty.sh restart
# 4. 驗證
curl -I https://localhost:8080/app/health
tail -f /opt/app/jetty9/logs/yyyy_mm_dd.request.log
| 項目 | 建議值/動作 |
|---|---|
| JDK 版本 | JDK 8u202+ / JDK 11 LTS / JDK 17 LTS |
| 檔案描述符限制 | ulimit -n 65535(/etc/security/limits.conf) |
| 系統參數優化 | net.core.somaxconn=65535, net.ipv4.tcp_tw_reuse=1 |
| 服務化管理 | 建立 systemd unit 檔,設定 Restart=on-failure, LimitNOFILE=65535 |
| 健康檢查端點 | 應用暴露 /health 或 /actuator/health,配合 Nginx upstream check |
| 日誌收集 | Filebeat/Fluentd 尾端收集 request.log 与 gc-*.log |
| 備份策略 | 定期備份 JETTY_BASE/webapps、logs、/var/jvmlogs |
netstat -tlnp | grep 8080,修改 JETTY_ARGS 或停用衝突程序。18787、java.rmi.server.hostname 是否為真實可達 IP。/var/jvmlogs 目錄存在且 Jetty 進程使用者有寫權限。logs/jetty-*.log 與 webapps/app.war 解壓後的 WEB-INF/logs。遵循本指南部署的 Jetty 9 實例,具備完善的記憶體管理、GC 可觀測性、標準化請求日誌、熱部署支援與故障自愈能力,可直接承擔生產級流量。後續可引入 Nginx 反向代理、SSL 終結、多實例叢集、Docker 容器化等進階架構演進。