努力
加油

在Linux服务器上部署Java应用需要哪些准备工作?

在 Linux 服务器上部署 Java 应用,看似简单,实则细节决定成败。很多新手直接 java -jar app.jar 就跑起来了,这在开发环境没问题,但在生产环境,这种裸奔的方式是绝对不可取的。

作为一名在云原生和运维领域摸爬滚打多年的“老兵”,我把部署前的准备工作拆解为基础设施层、运行环境层、应用配置层和安全与监控层四个维度来聊。这不仅是步骤,更是避坑指南。

一、 基础设施层:选对土壤

Java 应用对资源有一定要求,尤其是内存和 CPU。在阿里云、腾讯云或 AWS 等主流云厂商购买云服务器(ECS/CVM)时,不要只看价格。

  1. 操作系统选型

    • 推荐:CentOS Stream 7/8, Ubuntu 20.04/22.04 LTS, Debian 11。
    • 注意:CentOS 8 已停止维护,建议迁移到 CentOS Stream 或 Rocky Linux/AlmaLinux。Ubuntu Server 版本较新,内核支持较好,适合需要较新内核特性的场景。
    • 内核参数优化:这是很多人忽略的点。Linux 默认的文件描述符限制(ulimit)通常较低,Java 高并发场景下容易报错 Too many open files。
      • 修改 /etc/security/limits.conf,增加 nofile 限制(如 65535)。
      • 调整 /etc/sysctl.conf 中的 net.ipv4.tcp_tw_reuse, net.core.somaxconn 等网络参数,提升 TCP 连接处理能力。
  2. 磁盘 I/O 性能

    • Java 应用涉及大量日志写入和临时文件操作。如果是核心业务,建议使用云盘中的 ESSD 或 SSD 类型,避免使用低性能的 HDD,否则 GC(垃圾回收)停顿加上磁盘 IO 等待,会导致服务响应极慢。

二、 运行环境层:JDK 不是随便装的

别直接从官网下载二进制包解压了事,虽然可行,但不够专业。

  1. JDK 版本选择

    • LTS 原则:生产环境务必使用长期支持版本(LTS),如 JDK 8, 11, 17, 21。
    • 发行版差异:
      • OpenJDK:开源免费,主流选择。
      • Corretto (AWS) / Dragonwell (阿里) / TencentKona:国内大厂提供的 OpenJDK 发行版,针对 Linux 内核和硬件做了深度优化,GC 算法也有增强,强烈建议在国产云服务器上使用对应厂商的 JDK。
    • 版本一致性:确保测试环境和生产环境的 JDK 小版本号一致,避免因版本差异导致的类加载问题或 Bug。
  2. 安装方式

    • 推荐:使用包管理器(yum/apt)安装,或者使用 SDKMAN! 管理多版本。
    • 避免:手动解压 tar.gz 后不配置环境变量,导致后续升级麻烦。
    • 验证:安装后执行 java -version 和 javac -version(如果需要编译),确认路径正确。

三、 应用配置层:解耦与标准化

这是最容易出问题的地方。不要把配置硬编码在代码里。

  1. 配置文件分离

    • 使用 Spring Boot 的 application.yml 或 properties 文件。
    • 关键配置:
      • server.port: 指定非 8080 端口(防止冲突和安全考虑)。
      • spring.profiles.active: 区分 dev, test, prod 环境。
      • 数据库连接池:检查 HikariCP 或 Druid 的配置,特别是 maximumPoolSize,根据服务器 CPU 核心数和内存合理设置,不要盲目调大。
  2. JVM 参数调优(重中之重)

    • 不要依赖 JVM 默认参数!必须显式指定。
    • 基础参数:
      -Xms2g -Xmx2g  # 堆内存初始值和最大值设为相同,避免动态扩容带来的性能抖动
      -XX:+UseG1GC    # 现代 JVM 推荐使用 G1 垃圾收集器
      -XX:MaxGCPauseMillis=200 # 目标最大 GC 停顿时间
      -XX:+HeapDumpOnOutOfMemoryError # OOM 时自动 dump 堆栈
      -XX:HeapDumpPath=/data/logs/heapdump.hprof # dump 文件存放路径
    • 元空间:-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m,防止类加载过多导致 OOM。
    • 日志输出:将 GC 日志输出到文件,便于后期分析:-Xloggc:/data/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps。
  3. 启动脚本规范化

    • 不要直接用 nohup java -jar ... &。
    • 编写标准的 Shell 启动脚本,包含:
      • PID 文件管理(用于优雅停止)。
      • 日志重定向(stdout/stderr 分离)。
      • 健康检查钩子(可选)。
      • 示例结构:
        #!/bin/bash
        APP_NAME="my-app"
        JAVA_OPTS="-Xms2g -Xmx2g ..."
        nohup java $JAVA_OPTS -jar $APP_NAME.jar > /dev/null 2>&1 &
        echo $! > /var/run/$APP_NAME.pid

四、 安全与监控层:看不见的不存在

  1. 防火墙与安全组

    • 最小权限原则:只开放必要端口(如 80, 443, 以及内部通信端口)。
    • 云厂商安全组:在阿里云/腾讯云的控制台配置安全组规则,禁止所有 IP 访问 SSH(22 端口),仅允许特定管理 IP 段访问。
    • 本地防火墙:即使有云安全组,也建议在服务器内部启用 firewalld 或 iptables 作为第二道防线。
  2. 用户权限隔离

    • 严禁使用 root 运行 Java 应用!
    • 创建一个专用用户,如 appuser,拥有应用目录的读写权限,但没有系统级高危权限。
    • 修改应用目录所有权:chown -R appuser:appuser /opt/my-app。
  3. 日志与监控

    • 日志轮转:使用 logrotate 配置日志切割,防止日志文件撑爆磁盘。
    • 监控探针:
      • 基础监控:CPU、内存、磁盘 IO、网络流量(云厂商自带)。
      • 应用监控:集成 Micrometer + Prometheus + Grafana,暴露 /actuator/prometheus 端点。
      • APM 工具:如果预算允许,接入 SkyWalking 或 Pinpoint,追踪链路耗时。

五、 部署流程自动化(进阶)

如果你还在手动 scp 上传 jar 包,那效率太低且易出错。

  • CI/CD 流水线:使用 Jenkins、GitLab CI 或 GitHub Actions。
  • 容器化部署:强烈建议将 Java 应用打包成 Docker 镜像。
    • 优势:环境一致性、快速回滚、资源隔离。
    • 结合 Kubernetes (K8s) 或 Docker Swarm 进行编排。
    • 即使不用 K8s,单节点 Docker 部署也比裸机部署更可控。

总结清单(Checklist)

在按下“发布”按钮前,请核对:

  • [ ] 服务器 OS 已更新补丁,内核参数优化完成。
  • [ ] JDK 版本正确,环境变量配置无误。
  • [ ] 应用以非 root 用户身份运行。
  • [ ] JVM 堆内存、GC 参数、元空间大小已根据服务器资源配置。
  • [ ] 配置文件中的数据库密码、Redis 地址等敏感信息已加密或通过配置中心注入。
  • [ ] 防火墙仅开放必要端口。
  • [ ] 日志轮转策略已配置。
  • [ ] 备份了旧版本应用和数据,以便紧急回滚。

部署 Java 应用,“稳”比“快”重要。前期花时间在环境准备和参数调优上,能省去后期无数个深夜排查问题的痛苦。