☰
Manage 安装与配置实战:环境治理、依赖版本与故障排查
2026/10/2 19:20:01 网站建设 项目流程

“Manage 的安装与配置”这个题目看着朴素,没有任何花哨的定语,但真正动手做过的人都知道,它背后藏着的是一整套环境治理的活儿。我手上常年维护四套环境:本地开发机、联调测试、预发、生产,每一套都要跑 JDK、Node、Maven、MySQL、Redis、Nginx 这一长串东西。以前的做法是写一份文档,新人照着装,装到最后总有一两个版本对不上,排查半天。后来我把这套流程收敛到了一个自托管的 Manage 平台上,装一次、纳管一片,“安装与配置”这件事从大半天压缩到了四十分钟左右。

这篇不讲虚的,从选型、依赖安装、目录规划,到配置文件里每一行到底是干什么的,再到我实际踩过的坑,全部摊开写。适合两类人看:一类是第一次接手这套东西、需要一份能照着抄的清单的人;另一类是已经装上了、但配置总出问题、想搞清楚“为什么这么配”的人。哪怕你之前只装过 JDK 和 MySQL,跟着走也不会卡住。

1. Manage 是什么:先把定位说清楚

1.1 从“散装环境”说起

在没有统一平台之前,团队的开发环境基本处于“散装”状态。每个人机器上 JDK 的版本不一样,有人是 1.8,有人是 11,还有人图新装了 17;Node 更乱,nvm 里挂了三四个版本,node -v一敲出来五花八门;Maven 的本地仓库路径各写各的,settings.xml里的镜像地址全凭个人喜好。这种状态在小项目上还能忍,一旦进入多人协作,问题就会集中爆发。

我印象最深的一次事故是这样的:联调环境上跑得好好的构建脚本,挪到测试服务器上直接报UnsupportedClassVersionError。查了半天,原因是编译机用的是 JDK 11,测试服务器上是 JDK 8,class 文件的主版本号对不上。这类问题的可怕之处在于,它不会在你写代码的时候暴露,而是等到打包部署那一刻才炸,排查成本极高。第二类高发问题是路径写死,某个脚本里硬编码了/home/zhangsan/node/bin/npm,换个人执行立刻找不到命令。第三类就是权限混乱,服务用 root 跑,日志目录谁都能写,一次误操作把数据目录删了。

散装环境的本质问题,是没有单一事实来源。每台机器上的环境都是“历史遗留”,没人能准确说出当前线上到底跑的是哪个版本。Manage 要解决的就是这件事:把散落的运行时、服务、配置收敛到一个有统一视图的地方。

1.2 Manage 的四个核心模块

从部署结构上看,Manage 一般拆成四块,理解这四块的分工,后面安装配置才不会晕。

模块运行形态主要职责依赖
控制台 Web静态资源,由 Nginx 托管提供界面,发起所有操作浏览器即可
服务端 ServerJava 进程,监听 8080业务逻辑、调度、鉴权、APIJDK 17、MySQL、Redis
Agent轻量常驻进程,装在被纳管机器上采集状态、执行下发的指令仅需基础运行环境
存储层MySQL + Redis + 本地工作区元数据、缓存、构建产物磁盘空间

控制台只负责“看和点”,真正的脏活累活在 Server 和 Agent 里。这个分层设计很关键:Server 挂了,被纳管机器上的服务该跑还是跑,只是看不到实时状态;Agent 挂了,Server 上会显示离线,但不会影响已有业务。很多人第一次装的时候把 Agent 和 Server 装在同一台机器上,图省事,这在小规模场景下没问题,但要知道这俩是独立进程,日志也是分开的,排查的时候别混在一起看。

1.3 什么情况别折腾自建

说句实在话,不是所有团队都需要自建一套 Manage。以下三种情况我建议直接放弃自建:单人开发、没有多环境诉求,直接本地装好 JDK 和 Node 就行;团队规模小于三人且不做持续交付,用现成的托管方案更省心;纯前端小项目,一个 Node 加一个静态服务器就够了,引入 Manage 属于杀鸡用牛刀。

自建真正划算的临界点,大概在“有三个以上环境 + 五个人以上 + 每周至少两次交付”这个量级。到了这个规模,环境不一致带来的返工成本,会远远超过一次部署投入的两三天时间。我自己这套平台上线之后,最直观的收益是新人入职上手时间从一天变成了一小时,以及“我这里能跑你那里跑不了”这句话彻底消失了。

2. 安装前的准备:选型、依赖与目录规划

2.1 操作系统与硬件门槛

操作系统方面,Ubuntu 22.04 LTS 和 CentOS 7.9 我都跑过,表现稳定。选 LTS 版本的理由很简单:软件源里的 JDK、Nginx 版本相对新且长期有安全更新,不用自己去编译。如果你的环境是 CentOS 7,要注意它的默认glibc版本偏老,装 Node 20 的时候建议用官方二进制包而不是源码编译,能省掉一堆兼容问题。

硬件配置上,我给一个实测过的基线:4 核 8G 内存、100G 系统盘。这个配置能支撑大约 20 台被纳管机器、日常几十个构建任务。内存主要吃在两块:JVM 堆和 MySQL 的缓冲池,8G 是舒服的起点,4G 会很紧张。磁盘之所以建议 100G,是因为工作区会存放构建产物和日志,增长速度快得超出预期,我见过一个中等规模团队三个月攒了 40G 的构建缓存。如果预算允许,把工作区单独挂一块盘,后期扩容和迁移都会轻松很多。

网络方面,Server 需要能主动访问被纳管机器的 Agent 端口,通常是内网的 9100。如果跨网段,提前把安全组和防火墙规则理清楚,否则会出现“Agent 显示在线但下发指令超时”这种很别扭的现象。这个坑我在第一次部署时踩过,当时以为是 Agent 有 bug,查了两个小时才发现是中间一层防火墙拦了回包。

2.2 依赖组件版本对照表

版本选择是安装配置里最容易被忽略、又最容易出问题的一环。下面这张表是我当前生产环境实际在用的版本组合,经过了半年多运行验证。

组件推荐版本最低可用版本选择理由
JDK17 LTS11服务端基于 Spring Boot 3.x,强制要求 17 起
Node.js20 LTS18前端用 Vite 5 构建,要求 18 以上
Maven3.9.63.6.33.9 起对 HTTPS 镜像源支持更完整
MySQL8.0.355.7.30需要窗口函数,且默认字符集必须是 utf8mb4
Redis7.26.26.2 起支持 ACL,能更细粒度控制权限
Nginx1.241.18稳定分支,try_files行为可预期
Git2.402.20Agent 拉取仓库需要较新的协议支持

这里要特别强调 JDK 版本。很多人的机器上预装了 1.8,装完 Manage 启动直接报类版本错误。判断方法很直接:java -version看一眼。如果显示1.8.0_xxx,别犹豫,装一个 17 并存,用JAVA_HOME切换,不要试图卸载系统自带的 1.8,有些系统组件会依赖它。

MySQL 的字符集也值得单独说。Manage 里存的是多语言混合内容,包括机器主机名、项目描述、构建日志片段,如果库的字符集是utf8(MySQL 里的utf8其实是三字节的残缺实现),存四字节字符时会直接报错或者截断。建库时必须显式指定utf8mb4,这个后面初始化环节我会给完整命令。

2.3 目录结构与运行账号设计

目录规划这件事,装机的时候花十分钟,后面能省下无数次找文件的痛苦。我用的结构是这样的:

路径用途建议属主
/opt/manage/server服务端程序与 jar 包manage
/opt/manage/web前端构建产物manage
/opt/manage/config所有配置文件集中存放manage
/opt/manage/data工作区、构建产物、临时文件manage
/opt/manage/logs应用日志manage
/opt/runtimeJDK、Node、Maven 等运行时root

把配置文件单独拎出来放在config目录,是我强烈建议的做法。原因是升级的时候你只需要替换server和web两个目录,配置完全不用动。很多人图省事把配置写在 jar 包同级的application.yml,升级时一覆盖,配置全没了,只能凭记忆重写一遍。

运行账号方面,绝对不要用 root 跑服务。创建一个专用系统账号:

sudo useradd -r -m -d /opt/manage -s /sbin/nologin manage sudo chown -R manage:manage /opt/manage

-r表示创建系统账号,-s /sbin/nologin表示禁止登录 shell。这样即使服务被攻破,攻击者拿到的也只是个无法登录的受限账号,横向移动难度大增。运行时目录/opt/runtime保持 root 属主、755 权限,普通用户只读,避免被篡改。

注意:创建完账号后,务必检查/opt/manage/data的属主。我遇到过因为工作区是 root 属主,导致服务启动时无法写入,报了一个非常隐晦的Permission denied,日志里只显示“初始化工作区失败”,完全没有提示是权限问题。

3. Manage 本体安装:从依赖到跑起来

3.1 基础依赖安装实操

先装 JDK。Ubuntu 系列最省事的方式是走包管理:

sudo apt update sudo apt install -y openjdk-17-jdk java -version

如果系统源里的版本不够新,或者你用的是 CentOS,建议用官方压缩包手动部署,路径可控性更好:

sudo mkdir -p /opt/runtime sudo tar -zxvf jdk-17.0.9_linux-x64_bin.tar.gz -C /opt/runtime/ sudo mv /opt/runtime/jdk-17.0.9 /opt/runtime/jdk17

环境变量不要直接写进/etc/profile,那个文件内容多、容易改坏。单独放一个 profile 片段更清爽:

sudo tee /etc/profile.d/manage-runtime.sh <<'EOF' export JAVA_HOME=/opt/runtime/jdk17 export MAVEN_HOME=/opt/runtime/maven export NODE_HOME=/opt/runtime/node20 export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$NODE_HOME/bin:$PATH EOF sudo chmod +x /etc/profile.d/manage-runtime.sh source /etc/profile.d/manage-runtime.sh

这种写法的好处是,后续新增运行时(比如再加个 Gradle)只需要往这个文件里追加一行,不用去动系统文件。Node 20 直接用二进制包解压即可,比装 nvm 更适合服务器场景,因为服务器上通常不需要频繁切版本:

sudo tar -xJf node-v20.11.0-linux-x64.tar.xz -C /opt/runtime/ sudo mv /opt/runtime/node-v20.11.0-linux-x64 /opt/runtime/node20 node -v && npm -v

Maven 装完一定要改settings.xml,否则构建时从默认中央仓库拉依赖会慢到让人怀疑人生。配置文件放在$MAVEN_HOME/conf/settings.xml,重点改两处:localRepository指向一个独立大盘路径,mirror换成内网或就近的镜像源。本地仓库单独放的理由是,它会长到几十 G,放在系统盘迟早把盘撑满。

3.2 数据库与缓存的初始化

MySQL 安装完成后,第一件事是建库建账号。这里给出我用了很久的标准语句:

CREATE DATABASE manage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'manage'@'127.0.0.1' IDENTIFIED BY 'StrongPass_2024'; GRANT ALL PRIVILEGES ON manage.* TO 'manage'@'127.0.0.1'; FLUSH PRIVILEGES;

注意主机名部分写的是127.0.0.1而不是%。服务端和数据库在同一台机器上时,限定来源能有效防止误连。如果数据库独立部署,就换成服务端的内网 IP。用%是很多人的习惯,但它的含义是“允许任意来源”,在安全上是明显减分的。

字符集和排序规则要写全,utf8mb4_general_ci在绝大多数场景下够用,如果对多语言排序有严格要求的场景,换成utf8mb4_0900_ai_ci。另外记得调整连接数上限,Manage 在并发构建时会开不少连接:

# /etc/mysql/mysql.conf.d/mysqld.cnf max_connections = 500 innodb_buffer_pool_size = 2G

innodb_buffer_pool_size设成物理内存的 25% 到 40% 是个经验值。8G 内存的机器给 2G 比较稳妥,给太多会和 JVM 抢内存,反而拖慢整体。

Redis 这边,安装后重点改三处配置:

sudo sed -i 's/^# requirepass .*/requirepass StrongRedisPass_2024/' /etc/redis/redis.conf sudo sed -i 's/^bind 127.0.0.1 ::1/bind 127.0.0.1/' /etc/redis/redis.conf

第一处设密码,第二处限制只监听本机。第三处是持久化策略,默认的 RDB 可能丢数据,改成 AOF 更稳妥,代价是磁盘写入增加。Manage 里 Redis 主要存会话和任务队列,丢失会导致用户被踢下线、任务重跑,不算致命,但能避免就避免。

3.3 服务端的打包与启动

进入server目录,用 Maven 打包。第一次打包建议跳过测试,速度快很多:

cd /opt/manage/server mvn clean package -DskipTests -T 1C

-T 1C表示按 CPU 核数并行构建,四核机器上能把打包时间压掉大约一半,这是我实测有效的参数。打包完成后产物在target/下,把它挪到固定位置:

cp target/manage-server.jar /opt/manage/server/manage-server.jar

启动方式有两种。手动调试阶段直接命令行起,方便看日志:

sudo -u manage /opt/runtime/jdk17/bin/java \ -jar /opt/manage/server/manage-server.jar \ --spring.config.location=/opt/manage/config/application.yml

生产环境必须用 systemd 托管,否则进程一崩就没人拉起来。配置文件写到/etc/systemd/system/manage.service:

[Unit] Description=Manage Server After=network.target mysql.service redis-server.service [Service] User=manage Group=manage WorkingDirectory=/opt/manage/server Environment="MANAGE_DB_PASSWORD=StrongPass_2024" Environment="MANAGE_REDIS_PASSWORD=StrongRedisPass_2024" ExecStart=/opt/runtime/jdk17/bin/java -Xms1g -Xmx2g -XX:+UseG1GC -jar /opt/manage/server/manage-server.jar --spring.config.location=/opt/manage/config/application.yml Restart=always RestartSec=10 LimitNOFILE=65535 [Install] WantedBy=multi-user.target

这段配置里有几个细节值得解释。密码通过Environment注入而不是写进配置文件,是为了让配置文件可以进版本库而不泄露敏感信息,配合配置里的${MANAGE_DB_PASSWORD}占位符生效。LimitNOFILE=65535是必须的,Manage 会维持大量长连接,默认的 1024 文件句柄很快就不够用,表现是间歇性的连接失败。-Xms和-Xmx设成一样,避免堆在运行期间反复伸缩带来的抖动。

启用并启动:

sudo systemctl daemon-reload sudo systemctl enable manage sudo systemctl start manage sudo systemctl status manage

3.4 前端构建与反向代理

前端用 Node 构建,依赖安装一定要用npm ci而不是npm install。前者的行为由 lock 文件严格决定,能保证每次构建产物完全一致,后者会去更新依赖,埋下隐患。

cd /opt/manage/web-src npm ci npm run build sudo cp -r dist/* /opt/manage/web/ sudo chown -R manage:manage /opt/manage/web

构建完之后,用 Nginx 做静态托管和 API 反向代理。这个配置是整个安装里最关键也最容易配错的一环:

server { listen 80; server_name manage.internal.example.com; root /opt/manage/web; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_read_timeout 300s; } location /ws/ { proxy_pass http://127.0.0.1:8080/ws/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } }

try_files那一行是前端单页应用的标准写法,作用是访问任何前端路由都返回index.html,由前端自己决定渲染哪个页面。少了这一行,页面刷新就会 404。proxy_read_timeout 300s是针对构建任务调大超时,默认 60 秒会把长时间运行的构建请求直接掐断。WebSocket 那段是给实时日志推送用的,Connection "upgrade"必须写成带引号的形式,不加引号 Nginx 会报语法错误,这是个很隐蔽的坑。

3.5 冒烟测试与首次登录

服务起来之后,别急着打开浏览器,先用命令行做三轮验证。第一轮验证服务端活着:

curl -s http://127.0.0.1:8080/actuator/health # 期望输出:{"status":"UP"}

第二轮验证数据库连通,看日志里有没有连接池初始化失败的报错:

tail -n 100 /opt/manage/logs/manage-server.log | grep -i "hikari\|datasource"

第三轮验证 Nginx 转发通:

curl -s -o /dev/null -w "%{http_code}\n" http://manage.internal.example.com/api/actuator/health # 期望输出:200

三轮都过了再打开浏览器。首次登录通常使用默认管理员账号,登录后第一件事就是改密码,别拖。我见过有人装完忘了改,两个月后才发现有人从外网扫到了这个端口,虽然最后没造成损失,但那种后背发凉的感觉不值得体验第二次。

4. 配置详解:每一个参数到底在干什么

4.1 服务端核心配置逐段拆解

配置文件是整个系统的大脑,这里给出一份完整示例,然后逐段解释。

server: port: 8080 shutdown: graceful tomcat: threads: max: 200 min-spare: 20 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/manage?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true username: manage password: ${MANAGE_DB_PASSWORD} hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 max-lifetime: 1200000 redis: host: 127.0.0.1 port: 6379 password: ${MANAGE_REDIS_PASSWORD} database: 0 timeout: 3000 manage: workspace: /opt/manage/data agent: port: 9100 token: ${MANAGE_AGENT_TOKEN} heartbeat-interval: 30 offline-threshold: 90 build: max-concurrent: 4 timeout: 1800

shutdown: graceful这一行很容易被忽略,但价值很高。它的作用是收到停止信号时,先把手上的请求处理完再退出,而不是一刀切断。在升级场景下,这一行能避免正在构建的任务被强行中断。tomcat.threads.max: 200是给 Web 请求准备的线程数,4 核机器上设 200 已经比较宽裕,设太大反而增加上下文切换开销。

JDBC 连接串里有三个参数值得单说。serverTimezone=Asia/Shanghai不加会导致时间字段存进去差 8 小时,这是 Java 连 MySQL 8 的经典问题。allowPublicKeyRetrieval=true是 MySQL 8 默认使用caching_sha2_password认证插件时的必需项,不加会报认证失败。rewriteBatchedStatements=true能让批量插入性能提升好几倍,Manage 在批量写入机器状态时会用到。

Hikari 连接池的max-lifetime: 1200000表示连接最长存活 20 分钟。这个值必须小于 MySQL 的wait_timeout,否则会出现连接被数据库单方面关闭、应用还在用的情况,报错是Communications link failure。MySQL 默认wait_timeout是 28800 秒,所以 20 分钟是安全的。

4.2 Agent 配置与纳管接入

Agent 的配置比服务端简单,但 token 和心跳两个参数必须理解清楚。token是 Agent 向 Server 证明身份的凭证,两边必须完全一致。生成方式建议用随机字符串:

openssl rand -hex 32

把这个值同时填进服务端的MANAGE_AGENT_TOKEN和每台被纳管机器的 Agent 配置里,通过环境变量注入,不要明文写在文件里。heartbeat-interval: 30表示 Agent 每 30 秒上报一次状态,offline-threshold: 90表示连续 90 秒没上报就标记为离线。这两个值的关系是:阈值至少要是间隔的 2.5 倍,否则网络稍有抖动就会误报离线,运维群里天天响告警。

Agent 侧还有一个容易忽略的配置项:采集范围。默认会采集 CPU、内存、磁盘、进程数,如果你的机器上跑着敏感进程,可以通过白名单限制只上报指定进程。这个配置在合规要求高的环境里是必选项。

4.3 数据源、缓存与存储配置

工作区workspace的路径规划有个细节:一定要和备份策略对齐。因为这个目录里存着构建产物、临时文件和日志,是磁盘增长的主要来源。我建议按workspace/builds、workspace/tmp、workspace/artifacts三个子目录分开,方便针对性地做清理策略。构建产物可以设保留最近 30 天的清理规则,临时文件每次任务结束就删,产物目录按业务重要性单独决定。

Redis 的database: 0表示用 0 号库。如果同一台 Redis 上还跑着别的应用,一定要分库,否则会互相干扰。判断方法是在配置里搜一下有没有别的地方也用database: 0。这个坑我踩过:Manage 的会话数据被另一个应用清库操作一起冲掉了,用户集体掉线,查了半天才定位到是共用了同一个库。

4.4 安全配置:别把控制台裸在外面

安全这块我列四条底线,按重要性排序:

  • 首次登录立刻改密码,并且开启强密码策略,长度至少 12 位,含大小写、数字、符号。
  • 关闭注册入口。自建平台的用户应该由管理员创建,公开注册等于给陌生人开门。
  • 不要直接把 8080 暴露到公网。所有流量走 Nginx,服务端只监听127.0.0.1,在application.yml里把server.address设成127.0.0.1。
  • 开启操作审计。谁在什么时候对哪台机器下发了什么命令,必须有完整记录。出了事这是唯一能追溯的依据。

如果平台需要跨公网访问,务必套一层 HTTPS。内网自建可以用内部 CA 签发证书,不必强求公有证书。配置上就是在 Nginx 的 server 块里加 443 监听和证书路径,同时把 80 端口的请求 301 跳转过去。

5. 常见故障与排查实录

5.1 启动阶段五类高发故障

这五类问题基本覆盖了我遇到过的所有“起不来”场景,按发生频率排序。

第一类是端口占用。现象是启动日志里出现Address already in use。定位命令很直接:

sudo ss -lntp | grep -E '8080|9100|3306|6379'

找到占用进程后,先判断它是不是旧版本的 Manage 没退干净,是的话kill掉重启即可。

第二类是数据库连不上。表现形式多样,日志里可能是Access denied,也可能是Unknown database,还可能是长时间卡住后超时。按顺序排查:账号密码对不对、库存不存在、bind-address有没有限制来源、防火墙规则通不通。我常用的排查命令是直接用命令行客户端连一遍,把应用层的问题剥掉:

mysql -h 127.0.0.1 -P 3306 -u manage -p manage -e "SELECT 1;"

第三类是 JDK 版本不符。报错是UnsupportedClassVersionError,错误信息里会带上具体的版本号,比如class file version 61.0。61 对应 JDK 17,如果你的 java 是 1.8 就会报这个。解决方法是用绝对路径启动,别依赖 PATH。

第四类是工作区权限。前面提过,症状是日志只写一句含糊的初始化失败。排查方法:

sudo -u manage touch /opt/manage/data/.test && rm /opt/manage/data/.test

用服务账号亲自试一下写权限,比看日志快得多。

第五类是 Redis 认证失败。日志里的关键词是NOAUTH Authentication required或者WRONGPASS。前者说明配置里没填密码,后者说明密码填错了。改完配置记得systemctl restart manage,改了配置不重启是我见过最高频的低级失误。

5.2 排查速查表

把上面这些经验整理成一张表,遇到问题直接对照:

现象可能原因定位命令处理方式
启动即退出,无异常堆栈配置文件路径不对journalctl -u manage -n 50检查--spring.config.location
健康检查返回 DOWN数据库或 Redis 不通curl 127.0.0.1:8080/actuator/health看 health 详情里的组件状态
页面能开但接口 502Nginx 转发地址错tail -f /var/log/nginx/error.log核对proxy_pass端口
刷新页面 404缺try_files直接看 Nginx 配置补上try_files $uri $uri/ /index.html
Agent 显示在线但超时回包被防火墙拦telnet 被纳管IP 9100放通双向 9100
构建任务卡住不动并发数设太低看max-concurrent配置调到 CPU 核数
时间显示差 8 小时缺时区参数看 JDBC URL加serverTimezone=Asia/Shanghai
日志文件涨到几十 G没配轮转du -sh /opt/manage/logs配logrotate

这张表里的每一条都是我实际撞过的,尤其是时间差 8 小时那条,第一次遇到的时候我盯着数据库里的时间戳看了很久,怀疑是服务器时区没设对,结果问题出在 JDBC 连接串上。

5.3 上线后的稳定性调优

服务跑起来只是第一步,让它稳得住需要做一些调优。我把实际生效的几项列出来。

JVM 方面,G1 垃圾回收器配上-XX:MaxGCPauseMillis=200是比较通用的组合。如果堆内存超过 4G,可以考虑上 ZGC,停顿时间能压到毫秒级,代价是内存占用略高。生产环境的堆大小建议不超过物理内存的一半,剩下的留给操作系统页缓存和 MySQL。

Nginx 方面,worker_processes设成 CPU 核数,worker_connections设 10240,同时打开sendfile和tcp_nopush。这几项能让静态资源的分发效率明显提升,尤其是前端资源包有几兆的时候,差别肉眼可见。

日志方面,必须配轮转,否则迟早撑爆磁盘。一个简单的logrotate配置:

/opt/manage/logs/*.log { daily rotate 14 compress delaycompress missingok notifempty copytruncate }

copytruncate这个选项很关键。因为 Java 进程会一直持有日志文件句柄,用默认的移动方式会导致进程继续往已删除的文件里写,磁盘空间不会释放。加上这个选项,日志被截断而不是移动,空间能正常回收。

注意:调完/etc/security/limits.conf里的文件句柄数之后,光重启 Manage 是没用的,必须重启对应的 systemd 服务,因为 systemd 有自己的LimitNOFILE设置,会覆盖系统的 limits。这个点卡了我很久,最后是在 systemd 单元里显式写LimitNOFILE=65535才解决。

6. 备份、升级与迁移的实操建议

6.1 备份策略:三件套缺一不可

Manage 的备份要覆盖三样东西:数据库、配置文件、工作区。缺任何一样,恢复的时候都会缺胳膊少腿。

数据库用逻辑备份最稳妥,配合定时任务:

mysqldump -u manage -p'StrongPass_2024' \ --single-transaction --routines --triggers \ manage | gzip > /backup/manage_$(date +%F).sql.gz

--single-transaction保证备份期间不锁表,业务照常跑。这一点很重要,不加的话备份会锁全表,赶上业务高峰期直接把平台卡死。配置文件直接打包config目录即可,体积小,建议每次都全量备份。工作区体积大,全量备份不现实,只备份artifacts目录下的关键产物就好,tmp和builds里的内容可以重建,不备份。

保留策略上,数据库备份留 30 天,配置文件留 90 天,产物按业务需要决定。备份文件一定要定期做恢复演练,我见过备份脚本跑了一年从没报错,真出事的时候才发现备份出来的是空文件,因为密码改了但脚本里的密码没同步更新。

6.2 平滑升级的标准流程

升级这件事,顺序错了就会造成业务中断。我总结的流程是:先停 Agent,再备数据,然后换包,最后起服务。

# 1. 在被纳管机器上暂停 Agent(避免升级期间下发指令) sudo systemctl stop manage-agent # 2. 备份 sudo systemctl stop manage mysqldump ... > /backup/pre_upgrade.sql tar -czf /backup/config_$(date +%F).tar.gz /opt/manage/config # 3. 替换程序与前端产物 sudo cp manage-server-new.jar /opt/manage/server/manage-server.jar sudo cp -r dist-new/* /opt/manage/web/ # 4. 执行数据库变更脚本(如果有) mysql -u manage -p manage < upgrade_v2.3_to_v2.4.sql # 5. 启动并验证 sudo systemctl start manage curl -s http://127.0.0.1:8080/actuator/health # 6. 恢复 Agent sudo systemctl start manage-agent

先停 Agent 这个顺序,很多人会搞反。如果不停 Agent,升级过程中 Server 可能会给老版本 Agent 下发新格式的指令,Agent 解析不了就会报错,日志里一堆异常,虽然不影响最终结果,但排查起来很干扰。

6.3 迁移到新机器的注意事项

迁移时最容易翻车的不是数据本身,而是那些“配置之外的隐性依赖”。我踩过的有:忘记把 Agent 的 token 带过去,导致所有机器显示离线;忘记调整workspace路径,新机器上目录不存在;忘了把 JVM 参数一起迁移,性能莫名其妙下降一截。

建议的做法是把所有非默认配置整理成一份清单,迁移时逐项核对。清单至少包括:数据库连接串、Redis 地址与密码、Agent token、工作区路径、并发数、JVM 参数、Nginx 配置。整理一次之后,后续每次迁移都能复用,不会再漏。

另外一个建议是,迁移完成后先在一台非关键机器上做全流程验证,确认纳管、构建、日志查看都正常,再逐步放开其余机器。一上来全量切换,出问题时影响面太大,恢复也慢。

最后分享一个我一直在用的习惯:每次环境有变动,无论是改了配置、升了版本还是调了参数,都在config目录下开一个CHANGELOG.md,写清楚时间、改了什么、为什么改。这东西看起来是额外负担,但等到三个月后出了问题回头查,“当时为什么把这个参数调成 4”这种问题,翻记录十秒钟就能有答案,比自己回忆靠谱得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询