ARTICLE DETAIL

资讯详情

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

Linux服务器Java开发环境配置指南:从JDK到Maven全流程

Linux服务器Java开发环境配置指南:从JDK到Maven全流程 1. 项目概述1.1 核心需求解析服务器Java开发环境配置这个标题看起来简单但实际做起来远比装个JDK复杂得多。我这些年帮团队搭建过不少服务器环境也接手过别人留下的烂摊子深知这里面水很深。很多人以为在服务器上配好Java环境就是把JDK解压、配个环境变量就完事了等真正部署项目时才发现各种问题版本冲突、内存分配不合理、日志撑爆磁盘、时区导致时间差八小时……每一样都让人头大。这篇文章面向的人群很明确刚接触服务器部署的Java开发新人、需要从零初始化服务器环境的全栈工程师、以及想规范团队开发环境的TL。核心目标只有一个——让你看完之后能一步步在Linux服务器上搭出一个干净、稳定、可维护的Java运行环境。先说清楚这篇文章解决什么问题不光是装好能跑这么简单而是要让你理解每一步操作背后的逻辑比如为什么选这个JDK版本、为什么JVM参数要那样配、为什么环境变量要写进profile.d而不是直接改/etc/profile。只有把这些为什么搞清楚了你才能举一反三遇到别的环境问题也能自己排查。我见过太多反面教材有人在生产服务器上直接apt install default-jdk装了个不知道什么版本的OpenJDK结果项目跑起来各种诡异报错有人把JDK装到一半发现磁盘空间不够只能尴尬地清缓存还有人环境变量配在~/.bashrc里加了个定时任务用cron执行Java程序结果环境变量压根没加载程序直接起不来。这些坑这篇文章都会帮你避开。下面我按一套完整的实操流程来写从方案选型到每一步配置命令再到常见问题排查全部基于我实际踩过的坑和经验总结你照着做基本不会翻车。1.2 适用场景与整体方案选型服务器上配Java开发环境最常见的有这么几种场景单人开发测试的云服务器、团队共用的开发机、以及即将上线项目的生产环境。不同场景对稳定性和性能的要求完全不一样所以我建议你先想清楚自己属于哪种情况再决定怎么做。很多人纠结一个问题到底用Oracle JDK还是OpenJDK我的建议是新项目一律用OpenJDK版本选LTS长期支持版目前主流是Java 8或Java 17。理由很简单免费、社区支持好、和Spring Boot等主流框架兼容性没问题。至于Oracle JDK除非你们公司有商业授权需求或者遗留项目强制要求否则没必要给自己找麻烦。服务器系统方面我强烈推荐CentOS 7/8或者Ubuntu 20.04/22.04 LTS。CentOS 7虽然已经停止维护了但国内很多云服务器厂商的镜像还是以它为主存量市场很大Ubuntu LTS则胜在社区活跃、软件源新。你选哪个都行关键是操作习惯要统一别这台机器用yum那台用apt维护起来会疯掉的。再说远程连接方式建议直接用密钥登录而不是密码登录安全性和便利性都好得多。配置好SSH之后后续所有操作都通过SSH终端完成Windows用户可以用Xshell或者直接用Windows Terminal里的SSH命令Mac和Linux用户就更是原生支持了。整体配置流程我梳理成了下面这张表后面每个环节都会详细展开步骤操作内容核心目的预计耗时1服务器基础环境检查与优化确认系统、资源、网络正常10分钟2JDK安装与环境变量配置提供Java运行基础15分钟3Maven/Gradle构建工具配置项目构建与依赖管理10分钟4Git与代码同步配置代码版本管理与拉取10分钟5环境验证与多版本切换确认一切就绪10分钟这个流程不是我拍脑袋定的而是多年实操总结出的最优顺序。先搞定基础系统层再装JDK然后是构建工具和版本管理工具最后做整体验证。每一步都建立在上一步的基础上层层递进出了问题也容易定位是哪一环节的锅。2. 配置前的准备工作与基础环境检查2.1 系统版本与硬件资源摸底拿到一台新服务器先别急着装东西花几分钟把底摸清楚。这一步能帮你避免后面很多麻烦尤其是那些装到一半才发现问题的尴尬局面。先看系统版本cat /etc/os-release这个命令在CentOS、Ubuntu上都适用会输出系统的名称和版本号。知道系统版本很关键因为不同版本的包管理器、软件源地址都不一样网上搜到的教程经常因为系统版本对不上而失效。接下来看硬件资源free -h # 查看内存 df -h # 查看磁盘空间 nproc # 查看CPU核数这三个命令必须跑一遍。内存大小直接决定你JVM堆内存怎么配磁盘剩余空间决定你能不能装得下JDK、Maven仓库和各种中间件CPU核数则影响G1垃圾回收器的配置策略。我见过有人2G内存的服务器非要给JVM分配1.5G堆内存结果系统本身加数据库直接OOM整个服务都崩了。这里有个很重要的判断逻辑只要你是在云服务器上装Java环境我默认你用的是Linux系统Windows Server不在本文讨论范围内。虽然Windows Server也能跑Java但生产环境99%都是Linux这篇文章所有命令和配置也都是基于Linux的你别在Windows上硬套。还有网络连通性新手最容易忽略。服务器如果要访问外网下载依赖包你需要确认网络正常ping -c 4 baidu.com curl -I https://repo.maven.apache.org/maven2/如果公司服务器在内网可能还需要配置代理或者内网镜像源。这一步提前确认好能避免后面Maven下载依赖时一堆超时错误。2.2 系统时区与基础软件包安装时区这个问题我放到前面说因为太重要了。默认情况下很多云服务器的系统时区是UTC比北京时间慢8个小时。日志里的时间戳全是错的定时任务也乱套排查问题的时候时间对不上简直让人抓狂。timedatectl set-timezone Asia/Shanghai timedatectl status # 确认时区已切换执行完这两条命令系统时间就和北京时间同步了。这里顺便说一下如果你后面装数据库、Redis这类中间件它们也会读取系统时区所以这一步做对了能省后面一堆事。接着装一些基础软件包都是后面用得上的工具CentOS/RHEL系列yum install -y vim net-tools wget curl lrzsz unzip zipUbuntu/Debian系列apt update apt install -y vim net-tools wget curl unzip zip这些工具各自的作用vim编辑配置文件必备虽然你也可以用nano但vim在Linux运维中是通用技能net-tools提供ifconfig、netstat等命令排查网络问题好用wget/curl下载文件、测试接口连通性lrzsz提供rz/sz命令方便从本地直接传文件到服务器unzip/zip解压和压缩后面处理JDK打包文件、项目发布包都要用这里面有个小经验lrzsz在远程终端里用特别方便但如果你用的终端工具本身支持拖拽上传比如某些IDE的Remote Development插件那这个包就可装可不装。不过为了保险起见我还是建议装上毕竟轻量又实用。2.3 SSH安全加固与登录配置远程登录服务器最怕什么密码被暴力破解。默认的22端口每天会有无数扫描机器人在尝试爆破所以我建议从第一天起就做好SSH安全配置。第一步生成密钥对。如果你还没有密钥在本地电脑执行ssh-keygen -t rsa -b 4096 -C your_emailexample.com生成后把公钥传到服务器ssh-copy-id root服务器IP或者手动把~/.ssh/id_rsa.pub的内容追加到服务器的~/.ssh/authorized_keys文件里。配好之后从本地登录服务器就不需要密码了。第二步修改SSH配置禁用密码登录vim /etc/ssh/sshd_config找到下面几项修改成PermitRootLogin prohibit-password PasswordAuthentication no PubkeyAuthentication yes然后重启SSH服务systemctl restart sshd注意改这个配置之前一定确认密钥登录已经生效否则一旦断开连接你就进不去了。我有个同事就干过这事改完配置重启SSH发现自己密钥没传上去服务器直接失联最后只能通过云厂商的控制台VNC去救援折腾了一个多小时。做完SSH加固还有几个安全层面的细节可以顺手做了防火墙只放行必要的端口22、80、443以及你Java应用要用的业务端口云安全组也同步限制来源IP。这些不做硬性要求但生产环境必须注意。3. JDK安装与环境变量配置详解3.1 OpenJDK版本选择与下载技巧这节是全文的核心JDK装得好不好直接决定你后面所有Java程序能不能稳定运行。版本怎么选我前面说了优先LTS版本但具体选Java 8还是Java 17要看你的项目技术栈如果项目用Spring Boot 2.x那Java 8是标配稳得很如果项目用Spring Boot 3.x那必须Java 17及以上因为Spring Boot 3直接抛弃了Java 8如果纯粹是学习或者新起的小项目直接上Java 17新特性用起来真香确认好版本之后下载方式有两种。一种是直接用包管理器装CentOS用yum、Ubuntu用apt# CentOS安装Java 8 yum install -y java-1.8.0-openjdk-devel # Ubuntu安装Java 17 apt install -y openjdk-17-jdk这种方式最省事但有一个问题你没法完全控制安装路径和版本细节而且某些精简版系统的源里包名可能不一样。对于需要精确控制环境的场景我建议用第二种方式。第二种是从官网下载tar.gz手动安装。以JDK 17为例# 先建目录 mkdir -p /usr/local/java cd /usr/local/java # 下载注意替换为实际可用的下载链接 wget https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-x64_bin.tar.gz # 解压 tar -zxvf openjdk-17.0.2_linux-x64_bin.tar.gz手动安装的好处是路径可控、多个版本可以共存后续切换JDK版本也方便。坏处就是每次升级要手动下载解压稍微麻烦一点。我个人习惯开发测试机用包管理器装生产环境手动安装指定版本用哪个心里有数。下载的时候有个细节OpenJDK官方下载页面的链接经常带一长串哈希路径直接用wget复制链接时容易出错。所以我的建议是先在本地浏览器把链接复制好确认url完整再粘贴到终端避免少了一段导致404。3.2 环境变量配置的正确姿势JDK解压完之后接下来就是配置环境变量。这一步看起来简单但很多人在这踩坑踩得最多的就是不知道把配置写在哪个文件里。网上很多教程让你直接改/etc/profile然后全部环境变量都往里面塞。这个做法我极其不推荐因为/etc/profile是系统级全局配置所有用户、所有shell都会加载一旦写错了影响面非常大。而且如果你后面装Maven、Tomcat、Node等一堆东西全塞进/etc/profile那个文件会乱成一锅粥。更优的做法是利用/etc/profile.d目录。系统在加载/etc/profile时会自动加载这个目录下所有的.sh文件所以你只需要新建一个专门的文件来放Java的环境变量彼此隔离、互不影响vim /etc/profile.d/java.sh写入以下内容# JDK 17 环境变量配置 export JAVA_HOME/usr/local/java/jdk-17.0.2 export PATH$JAVA_HOME/bin:$PATH export CLASSPATH.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib保存后让它立即生效source /etc/profile.d/java.sh为什么CLASSPATH要设置成那样因为Java在编译和运行时会用CLASSPATH来查找类文件点号代表当前目录。虽然JDK 9之后类库机制改了CLASSPATH不再是必须的但保留下来兼容老项目没坏处。然后验证安装是否成功java -version javac -version如果输出类似这样就说明JDK装好了java version 17.0.2 2022-01-18 LTS Java(TM) SE Runtime Environment (build 17.0.28-86) Java HotSpot(TM) 64-Bit Server VM (build 17.0.28-86, mixed mode, sharing)3.3 多JDK版本共存与快速切换有时候一台服务器上要跑多个项目老项目要Java 8新项目要Java 17这就涉及多版本共存的问题。解决方法很简单把不同版本的JDK放在不同目录然后用alternatives命令或者手动切换PATH。以alternatives方式为例# 注册不同JDK版本 alternatives --install /usr/bin/java java /usr/local/java/jdk-8u402/bin/java 1 alternatives --install /usr/bin/java java /usr/local/java/jdk-17.0.2/bin/java 2 # 切换版本 alternatives --config java执行后会显示一个列表输入对应的数字就切过去了。如果你用的是自定义的profile.d配置切换版本就得改JAVA_HOME指向。我有个项目实践觉得挺好用在profile.d里建一个软链方案让JAVA_HOME指向一个软链接以后只需要改软链接指向就能切换# 在 /usr/local/java 下创建软链接 ln -s jdk-17.0.2 current # JAVA_HOME 指向 export JAVA_HOME/usr/local/java/current以后要切到Java 8只需删除软链接重新指一下rm -f /usr/local/java/current ln -s jdk-8u402 /usr/local/java/current这个方案的优点是其他配置都不用动Maven、IDEA这些工具读到JAVA_HOME就自动跟着切过去了非常方便。4. Maven与项目构建工具配置4.1 Maven安装和仓库镜像加速Java项目肯定离不开构建工具目前Maven还是绝对的主流Gradle在Android和部分新项目里也用得很多。建议两个都了解一下但日常用Maven就足够了。Maven的安装方式和JDK很像可以用包管理器装也可以手动装。这里我讲手动装因为版本控制更灵活# 下载Maven以3.9.6为例 cd /usr/local wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz tar -zxvf apache-maven-3.9.6-bin.tar.gz mv apache-maven-3.9.6 maven然后配置环境变量还是在profile.d下新建文件vim /etc/profile.d/maven.shexport MAVEN_HOME/usr/local/maven export PATH$MAVEN_HOME/bin:$PATHsource /etc/profile.d/maven.sh mvn -v看到Maven版本信息就算成功了。这里有个细节Maven运行依赖JAVA_HOME环境变量所以必须先装好JDK并且JAVA_HOME配置正确否则mvn命令会报错找不到Java环境。装好Maven之后最重要的一步是配置国内镜像源。Maven默认的中央仓库在国外下载依赖速度慢到怀疑人生尤其在公司网络环境下经常超时。修改配置文件vim /usr/local/maven/conf/settings.xml找到 节点在里面加入mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror镜像源不是随便配个就行你需要注意mirrorOf的配置。central表示只镜像中央仓库如果你项目中还用到其他仓库比如JitPack可以改成*号全部镜像但一般建议保持central避免影响特殊仓库的获取逻辑。这是一个典型的知其所以然的点镜像的原理其实是在你本地和中央仓库之间加了一个代理你下载依赖的请求先发到阿里云阿里云那边缓存了海量依赖直接返回给你速度自然快很多。4.2 Maven本地仓库管理与多项目配置Maven的本地仓库默认在~/.m2/repository第一次构建项目时会下载大量依赖到这个目录。这里有几个管理建议都是经验之谈第一确认本地仓库路径。如果你是用root用户操作的默认就是/root/.m2/repository如果用普通用户部署就是/home/用户名/.m2/repository。要注意严格区分用户因为Maven会把依赖缓存在当前用户目录下不同用户之间不共享。第二如果有条件给Maven仓库目录所在的磁盘多留点空间。一个中型项目所有依赖加起来轻轻松松超过1G大型项目3-5G都很正常。用df -h确认一下你的/目录或者home目录空间够不够别到时候构建到一半磁盘写满。第三如果你的服务器要部署多个Java项目且共用一套Maven环境建议在settings.xml里统一配置本地仓库路径方便管理和清理settings localRepository/data/maven-repository/localRepository /settings这样所有项目、所有用户共享同一个依赖缓存构建速度更快磁盘占用也更集中。还有一个小技巧Maven的settings.xml可以配置profile来区分不同环境开发、测试、生产每个profile可以指定不同的仓库地址和参数。虽然这部分不是环境配置的必选项但提前了解对后面项目上线很有帮助。4.3 Gradle配置要点备选方案如果你的项目用的是Gradle那配置思路也差不多。Gradle安装同样有包管理器方式和手动方式但要注意Gradle和JDK版本有对应关系Gradle 7.x支持JDK 8到17Gradle 8.x要求JDK 8到21。装之前先查一下版本的兼容性表。Gradle的仓库加速配置在项目的build.gradle或者init.gradle文件中通常用阿里云镜像allprojects { repositories { maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/central } mavenCentral() } }Gradle默认的依赖缓存目录是~/.gradle和Maven互不干扰。如果你同时用Maven和Gradle管理不同项目要记住它们是两套独立的缓存体系别搞混了。5. Git、项目同步与代码拉取配置5.1 Git安装与全局配置装完JDK和构建工具接着搞定代码版本管理工具Git。这一步对服务器部署至关重要因为大多数项目都是通过Git拉取代码到服务器上部署的。安装很简单# CentOS yum install -y git # Ubuntu apt install -y git装完之后做全局配置git config --global user.name 你的名字 git config --global user.email 你的邮箱这个全局配置在服务器上主要是为了规范提交信息虽然你大概率不会在服务器上手动提交代码但某些自动化脚本可能会用到。然后是SSH密钥配置。服务器拉取私有仓库代码时推荐用SSH方式而不是HTTPS方式因为HTTPS每次都要输密码或者配tokenSSH则一劳永逸ssh-keygen -t rsa -b 4096 -C deployserver cat ~/.ssh/id_rsa.pub把输出的公钥内容添加到Git仓库GitHub、Gitee、GitLab都行的Deploy Key里。之后在服务器上执行git clone测试一下git clone gitgithub.com:yourname/yourproject.git /data/projects/yourproject如果克隆成功就说明Git环境全部就绪了。这里有个实战建议在服务器上部署项目时不要把代码直接放在root用户的home目录下建议单独建一个目录比如/data/projects然后用专门的应用账号比如app用户来管理代码和启动服务。这样即使应用被入侵攻击者也拿不到root权限安全等级完全不一样。5.2 代码同步策略与项目目录规划代码同步上我吃过不少亏总结出来一套还算靠谱的目录规范和流程。目录规划建议/data/ ├── projects/ # 所有项目代码放这里 │ ├── demo-api/ # 后端服务 │ ├── demo-admin/ # 管理后台 │ └── demo-web/ # 前端项目 ├── backups/ # 备份目录 ├── logs/ # 统一日志目录 └── app/ # 应用部署目录为什么代码目录和部署目录分开因为编译后的产物jar包、war包、静态文件和源码不应该混在一起。源码通过Git拉取更新部署目录则从构建结果复制或软链这样每次发布都干干净净。同步代码有两种常见策略第一种直接在生产服务器上git pull更新代码然后重新构建、重启应用。这种方式简单直观适合中小团队但需要服务器上有完整的构建工具链。第二种在CI/CD平台Jenkins、GitLab CI等上构建好产物通过scp/rsync等方式同步到服务器。这种方式生产环境更干净服务器只需要运行时的Java环境即可不需要装Maven/Gradle。如果你的服务器是纯生产环境我强烈建议用这种方式能大幅度降低环境出问题的概率。rsync同步命令示例rsync -avz --progress jenkins构建机IP:/data/build/demo-api.jar /data/app/demo-api/5.3 环境变量与配置文件的脱敏管理这个点很多人会忽视但非常关键项目里的数据库密码、Redis密码、第三方API密钥等敏感信息千万不要硬编码在代码里然后通过Git库分发。我在服务器上见过太多因为配置文件泄露导致的安全事故。推荐的方案有两种一种是用环境变量的方式注入配置。Spring Boot项目可以直接在application.yml里用${DB_PASSWORD}这种占位符然后在启动脚本或者systemd服务配置里设置环境变量spring: datasource: password: ${DB_PASSWORD}启动时export DB_PASSWORDyour_strong_password java -jar demo-api.jar另一种是用配置文件外部化。把application-prod.yml放在jar包外面通过--spring.config.location参数指定位置这样配置文件不进Git库每次部署只需要把配置文件放到约定位置即可。我个人的习惯是两者结合敏感信息用环境变量非敏感配置用外部化配置文件。既照顾了安全性又方便不同环境切换配置。6. 环境验证与常见问题排查6.1 全链路验证从Java到项目启动所有环境配好之后别急着部署项目先做一轮完整的验证流程。这一步能把90%的配置问题提前暴露出来省得你在项目启动时报一堆莫名其妙的错再来反查环境。验证清单如下# 1. 检查JDK版本 java -version javac -version # 2. 检查JAVA_HOME路径 echo $JAVA_HOME # 3. 检查Maven版本 mvn -v # 4. 检查Git版本 git --version # 5. 确认时区正确 date # 6. 确认端口可用以一个业务端口8080为例 ss -lntp | grep 8080每个检查项背后都有目的java和javac的版本必须一致否则编译和运行用的是两套环境可能出现编译时用的JDK 17特性但运行时只有JDK 8导致的NoSuchMethodErrorJAVA_HOME路径确认环境变量指向正确Maven版本确认构建工具可用时区确认避免日志时间错乱端口确认避免应用启动时端口被占用。做完这些基础验证再拉一个最简单的Spring Boot项目试跑一下# 新建一个临时项目目录 cd /tmp mvn archetype:generate -DgroupIdcom.demo -DartifactIdhello -DarchetypeArtifactIdmaven-archetype-quickstart # 构建 cd hello mvn clean package # 用Java直接跑一个最简单的类验证 java -cp target/hello-1.0-SNAPSHOT.jar com.demo.App能正常输出输出hello world就说明整条链路JDK - Maven - 编译 - 运行全部通了。这一步做完你再部署正式项目就会顺畅很多。6.2 高频问题排查实录JAVA_HOME与版本不一致这里我整理几个我实际运维中遇到的高频问题每个都是血泪教训换来的经验。问题一java -version有输出但mvn -v报错找不到Java环境。这个问题的根因通常是JAVA_HOME配置不对。Maven本身不用Java环境启动但它启动后要解析JAVA_HOME去找JDK。排查步骤echo $JAVA_HOME ls -l $JAVA_HOME/bin/java如果JAVA_HOME是空的或者路径不对重新按照前面说的profile.d方案配置一遍。注意配置完一定要source或者重新登录终端当前终端会话不会自动加载新的环境变量。问题二编译时报错java: command not found。这个更基础通常是PATH环境变量没包含JDK的bin目录。检查echo $PATH | grep java如果输出为空说明PATH配置有问题重新检查profile.d/java.sh里的export PATH行。问题三项目能编译但启动时报UnsupportedClassVersionError。这个报错的意思是编译用的JDK版本比运行用的JDK版本新。比如你用JDK 17编译的class文件拿到JDK 8上运行就会报这个错。解决办法是统一两端版本要么降编译版本要么升运行版本。我建议统一用JDK 17老项目保持JDK 8但同一套环境内不要混用。问题四Maven下载依赖特别慢或者一直卡住。优先检查settings.xml里的镜像源是否生效。用mvn -X或mvn help:effective-settings查看实际生效的镜像配置。我遇到过一种情况settings.xml写对了但项目pom.xml里自定义了repository而且优先级更高导致镜像没生效依赖还是从国外仓库下载。6.3 性能调优与JVM参数初始化环境配置的最后一块拼图是JVM参数。很多项目跑着跑着就内存溢出、频繁Full GC很大程度是因为JVM参数没配好。虽然这不是环境配置的必修课但对服务器Java环境来说极其重要。一个相对通用的启动参数模板2核4G服务器为例java -server -Xms512m -Xmx1024m -XX:MetaspaceSize128m -XX:MaxMetaspaceSize256m \ -XX:UseG1GC -XX:MaxGCPauseMillis200 -XX:HeapDumpOnOutOfMemoryError \ -XX:HeapDumpPath/data/logs/heapdump.hprof \ -jar demo-api.jar参数解释-Xms和-Xmx堆内存初始值和最大值。设成一样可以避免JVM动态伸缩带来的性能损耗但小内存机器建议留出余量-XX:MetaspaceSize元空间初始大小很多框架加载大量类时需要这个配置-XX:UseG1GC使用G1垃圾回收器JDK 9之后的默认选择对大堆和低延迟场景友好-XX:HeapDumpOnOutOfMemoryErrorOOM时自动导出堆转储文件排查内存问题必备-XX:HeapDumpPath堆转储文件的保存路径内存分配的比例参考服务器总内存4G时JVM堆最大1G左右留出内存给操作系统、Java进程自身、可能的数据库或缓存中间件。别贪心把所有内存都分给JVM不然系统本身的内存都不够了。日志和GC日志也要提前规划好-Xloggc:/data/logs/gc.log -XX:PrintGCDetails -XX:PrintGCDateStampsGC日志能帮你分析性能瓶颈排查线上问题少了它寸步难行。我见过太多服务的日志目录乱放磁盘满了也不知道所以强烈建议统一规划日志路径并定期清理。6.4 快速排查命令速查表最后送大家一个排查命令速查表都是我日常用得最多的建议收藏一下排查场景命令说明查看Java进程ps -ef | grep java确认应用是否在运行查看端口占用ss -lntp | grep 8080确认端口是否被占查看内存使用free -h确认系统内存余量查看磁盘空间df -hT确认磁盘是否写满查看应用日志tail -f /data/logs/app.log实时跟踪日志输出查看GC日志grep Full GC /data/logs/gc.log快速定位Full GC频率查看JVM堆内存jmap -heap 进程PID查看堆内存使用情况线程转储jstack 进程PID排查死锁和线程卡顿这些命令有什么作用一般什么时候用我简单标注一下进程查看和端口检查是部署后第一件事确认服务真的起来了内存和磁盘是日常巡检必看项很多问题在资源耗尽前会有预警日志跟踪是定位问题的第一入口jmap和jstack则是更深层次的工具OOM和线程卡死时基本必备。7. 项目部署与日常维护建议7.1 系统服务方式管理Java应用项目部署方式有很多种最简单的就是nohup后台运行但这种方式对运维很不友好进程管理靠ps和kill开机自启要手动处理日志没轮转。我强烈建议用systemd来管理Java应用这是现代Linux系统推荐的进程管理方式。新建一个systemd服务文件vim /etc/systemd/system/demo-api.service内容模板[Unit] DescriptionDemo API Service Afternetwork.target [Service] Typesimple Userapp Groupapp WorkingDirectory/data/app/demo-api EnvironmentJAVA_HOME/usr/local/java/current EnvironmentSPRING_PROFILES_ACTIVEprod ExecStart$JAVA_HOME/bin/java -server -Xms512m -Xmx1024m -jar /data/app/demo-api/demo-api.jar Restarton-failure RestartSec10s [Install] WantedBymulti-user.target然后启用并启动systemctl daemon-reload systemctl enable demo-api systemctl start demo-api systemctl status demo-api这种方式的好处太多了开机自启、自动重启、统一日志管理、用journalctl查看日志、systemctl控制启停。你从手动部署升级到服务化部署体验是质的飞跃。有个细节要提醒上面我用了Userapp和Groupapp意味着服务以专门的app用户运行。这是生产环境的安全基线要求应用进程不要用root跑否则一旦应用有漏洞整个服务器都沦陷了。创建app用户的命令useradd -m -s /bin/bash app7.2 日志轮转与磁盘空间管理Java应用的日志如果不做管理一个月就能把磁盘写满。我之前遇到过一台服务器日志文件涨到30G直接把盘占满数据库都连不上了。从那以后我要求所有Java应用必须配日志轮转。你可以用logrotate来做vim /etc/logrotate.d/demo-api/data/logs/demo-api/*.log { daily rotate 7 compress delaycompress missingok notifempty copytruncate }这个配置的含义每天轮转一次保留7份历史日志压缩旧日志如果文件缺失或为空不操作。copytruncate这个参数特别重要它通过复制截断的方式轮转日志应用不需要重启就能继续写新的日志。配置好之后用logrotate -d /etc/logrotate.d/demo-api试跑一下确认没有配置错误。另外应用自身的日志框架也要配置好滚动策略。Logback的配置里加上TimeBasedRollingPolicy按天切分日志保留30天这样即使logrotate漏了应用自己也有兜底。7.3 安全基线检查与环境审计环境配置完之后别急着撒手不管我建议做一次安全基线检查。这里列一个简单的检查清单是否禁用了root远程密码登录前面SSH配置那步已做服务器防火墙是否只放行必要端口Java应用是否以非root用户运行敏感配置是否通过环境变量注入而不是写死在代码里日志目录的权限是否为应用用户可写、其他用户不可读系统是否定期更新补丁这些检查项看着多其实每一项都对应着一类安全事故。比如日志权限设置不当可能导致普通用户也能看到数据库连接信息系统补丁不更新可能被已知漏洞攻击。运维工作就是这样可能90%的精力都花在预防那10%的小概率事件上。我自己一般每隔一周会登录服务器跑一遍上面这些检查命令顺手把日志清理一下看看磁盘和内存使用。这个习惯坚持了很多年帮我躲过了好几次灾难性的服务器故障。8. 我踩过的那些坑环境配置经验谈写到这里整套服务器Java开发环境配置的流程就完整了。最后分享几个我真实踩过的坑都极具代表性希望你不用再走我走过的弯路。第一个坑是JDK版本混淆。有一次我在测试服务器上装了两个JDK版本用alternatives切换了默认版本但Maven的surefire插件在编译时却还是用旧的JDK路径。排查了半天才发现是IDEA远程开发时IDEA自身读的是~/.mavenrc文件里的配置而不是系统的JAVA_HOME。这类工具链配置覆盖系统配置的情况很常见遇到版本不一致的问题优先排查有没有其他配置文件在捣乱。第二个坑是滥用/etc/profile。早年间我习惯把所有环境变量都写在/etc/profile里后来装了JDK、Maven、Redis、Tomcat、Node等一堆东西那个文件膨胀到了上百行。某次升级Redis时不小心删错了一行结果整个系统的环境变量全乱了所有服务起不来。那是我第一次深刻体会profile.d目录存在的意义用一个文件管一个软件的环境变量删错了也只是某一个软件挂掉不会全军覆没。第三个坑是生产服务器装JDK时图省事直接apt install。当时看着省了5分钟后来项目用了一些JDK内部类和方法生产环境没有这些类导致线上直接崩溃。从那天起我给自己定了条规矩生产环境必须手动安装并锁定JDK版本绝对不依赖包管理器自动拉起。还有一个小技巧我觉得特别实用每台服务器配置完后把安装版本、路径、部署信息记录在一个MD文件里放到服务器的/data/docs目录下。半年后你再看就会明白这个记录有多值钱。否则你完全想不起来这台服务器装的是什么版本的JDK、为什么某些路径要这样规划。根据我的经验只要把前面几步踏踏实实走完你的服务器Java环境就算配置到位了。接下来要做的就是在真实项目中不断积累经验了。环境的坑是有限的踩一个少一个但项目的坑是无限的。祝你少踩坑多用这些时间把精力花在业务代码上。
返回列表