openEuler 24.03 LTS部署实践:CentOS迁移至Java/MySQL/Redis/Nginx
2026/9/20 19:17:43 网站建设 项目流程

1. 迁移背景与选型理由:CentOS停服之后,为什么我选了openEuler 24.03 LTS

如果你手上还跑着一堆CentOS 7的机器,2024年6月30日之后应该已经感受到了压力——官方停止维护,CVE漏洞没人补,yum源纷纷失效,装个新软件包都费劲。之前CentOS 8提前终止维护更让很多人措手不及。我手上有十几台跑业务的服务期间,负责的项目大多是基于Java的Spring Boot服务,配合MySQL、Redis和Nginx,这套组合在CentOS上跑了五六年,稳定得让人懒得动它。但停服这件事不是“懒得动”就能绕过去的,等出了问题再迁移,成本更高。

当时摆在面前的选择其实有几个:切到Ubuntu/Debian系,继续用CentOS Stream,或者上Rocky/Alma这类RHEL兼容发行版,再就是openEuler。我逐一评估过。Ubuntu的apt体系和现有运维脚本不兼容,团队里好几个同事对apt不熟。CentOS Stream是滚动更新,生产环境求稳的心态下我接受不了。Rocky/Alma确实平滑,但本质上是RHEL的下游重建,对我这种想减少对美国上游依赖的团队来说,心理上总觉得不踏实。

最后定下来用openEuler 24.03 LTS,核心是这几点:

  • LTS版本周期长,社区明确承诺维护多年,这点对生产环境太重要了,我不可能每两年折腾一次大迁移。
  • 兼容性做得好,openEuler在RPM生态上兼容性很强,我的install脚本、systemd服务文件、yum/dnf使用习惯几乎不需要改。
  • 国内社区活跃,出问题找资料快,文档和Issue响应速度都不错。
  • 实际装完测下来,JDK、MySQL、Redis、Nginx这几样主流软件的安装方式和CentOS 7时期的习惯非常接近,迁移成本比预想低很多。

当然,openEuler不是没有缺点,比如默认软件源里的版本偏保守,某些第三方repo可能需要手动适配,但整体上在24.03 LTS这个版本上,日常部署体验已经很成熟。

这篇文章就是把我从零开始在一台干净服务器上部署这套全栈环境的过程完整记录下来。不求讲得多高深,但保证每一步都是我自己敲过、验证过的,能让你照着走一遍就少踩几个坑。

2. 系统安装与初始化:最小化安装后的第一轮配置

2.1 安装镜像选择与分区规划

openEuler 24.03 LTS的ISO从官网下载,分DVD和Everything等版本,服务器场景直接选DVD版就够了,不需要Everything里那些额外包。安装时语言建议选English,避免编码问题,后面需要中文再装语言包也来得及。

分区这里多说一句,很多人习惯“一键自动分区”,服务器上我不推荐这么做。我的做法是:

  • /boot:1GB,启动分区,给内核和grub用
  • /:50GB,系统根目录
  • /data:剩余全部空间,作为数据盘挂载点,MySQL的数据目录、应用的日志目录都放在这里
  • swap:如果内存小于16GB,建议留和内存等量的swap;内存够大可以设4GB或干脆关掉

这样规划的好处是系统盘和数据盘分离,将来如果系统挂了、要重装,数据盘的内容不受影响,直接重新挂载即可。我踩过一次根目录写满导致服务全部异常的坑,从那以后所有生产机器都是这个分区方式。

2.2 首次登录后的基础优化

安装完成后先做几个基础配置,别看步骤简单,省掉任何一个后面都会浪费更多时间。

第一件事,配置静态IP。24.03默认用NetworkManager,修改IP最稳妥的方式是用nmcli,直接编辑配置文件在某些版本上可能不生效。

# 查看当前网卡名称和连接名 nmcli device status nmcli connection show # 假设连接名为 ens33,修改为静态IP 192.168.1.100 nmcli connection modify ens33 ipv4.method manual \ ipv4.addresses 192.168.1.100/24 \ ipv4.gateway 192.168.1.1 \ ipv4.dns 223.5.5.5,114.114.114.114 nmcli connection up ens33 ip addr show ens33

这块值得专门提醒一个坑:如果你有多个网卡,nmcli connection modify的时候一定要确认连接名对应的是哪块网卡,改错了会把远程连接搞断。生产环境改网络配置前,最好先准备好带外管理或者现场操作手段。

第二件事,更换软件源。默认源在国内访问速度还行,但如果你的服务器在海外或者某些网络环境,建议换成镜像站。

# 备份原始源 cp -a /etc/yum.repos.d/openEuler.repo /etc/yum.repos.d/openEuler.repo.bak # 编辑仓库文件,将 url 中的 repo.openeuler.org 替换为镜像站地址 sed -i 's|repo.openeuler.org|mirrors.tuna.tsinghua.edu.cn/openeuler|g' /etc/yum.repos.d/openEuler.repo dnf clean all && dnf makecache

第三件事,系统更新和基础工具。

dnf update -y dnf install -y vim net-tools lrzsz wget curl tar unzip telnet lsof

net-tools装上是为了保留ifconfig/netstat的肌肉记忆,虽然新系统推荐ip命令,但排查问题时netstat -lntp的熟悉程度还是高一些。

第四件事,关防火墙和SELinux。这里不是无脑劝你关,内网环境可以先关掉降低排障成本,等全部服务调通后再按需开启并配置放行规则。公网环境我建议不关,而是放行精确端口,但排查问题时临时关闭,排查完再打开,这套思路在下面各个组件的联调阶段很管用。

systemctl stop firewalld && systemctl disable firewalld sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

SELinux这里多说两句。如果你不想彻底禁用,至少先设置为permissive模式跑一段时间。我之前在SELinux enforcing模式下部署Nginx反向代理,莫名奇妙502,排查到最后发现是httpd_can_network_connect这个布尔值没开。这类问题在新系统上特别容易浪费几个小时,所以要么关掉,要么熟悉SELinux的排错方法。

3. Java环境部署:OpenJDK的安装、配置与验证

3.1 选JDK版本的关键考量

openEuler 24.03 LTS默认源里的OpenJDK版本有8、11、17、21。选哪个取决于你现有项目的字节码编译版本。以最常见的Spring Boot项目来说,如果你的项目是用Java 8写的,且依赖了一些只在JDK 8下表现正常的旧库,就继续用JDK 8,不要为了追新而升级——生产环境追求的是稳定复制。如果你是新项目,可以直接选JDK 17,它是最普及的LTS版本,Spring Boot 3.x对它的支持已经非常成熟。

我这次演示选的是OpenJDK 17,原因是我要部署的Spring Boot 3应用最低要求就是17。另外注意openEuler的OpenJDK包名带java-[version]-openjdk,完整安装版是java-17-openjdk,而不是java-17-openjdk-headless。很多人习惯装headless版,但跑Spring Boot时有时需要用到字体、图形类库,headless不包含这些,会遇到莫名其妙的异常。

3.2 安装与配置

# 通过 dnf 安装OpenJDK 17完整版 dnf install -y java-17-openjdk java-17-openjdk-devel # 查看安装位置 which java ls -l /etc/alternatives/java

openEuler默认会配置好JAVA_HOME了吗?答案是部分配置。/etc/profile.d/java.sh这个脚本会设置JAVA_HOME,但很多情况下需要重新登录或者手动source它才生效。为了保险起见,我习惯在/etc/profile里显式追加一份,同时把自己的应用统一用同一个JDK版本,避免多版本切换带来的混乱。

cat >> /etc/profile <<'EOF' export JAVA_HOME=/usr/lib/jvm/java-17-openjdk export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar EOF source /etc/profile java -version

这里有个小细节:/usr/lib/jvm/java-17-openjdk最后的实际路径可能是xxxx架构后缀,像java-17-openjdk-17.0.x.x.x.arch这样的版本号目录。验证的时候用ls /usr/lib/jvm/看清楚再写。

3.3 验证Java环境是否可用

不要只执行java -version就完事,我见过不少人在这一步跳过去,后面项目起不来才回头怀疑JDK装坏了。建议写一个最小的Jar包或者直接用已有的Spring Boot Fat Jar验证一下:

java -jar myapp.jar --server.port=8080 --spring.profiles.active=test curl http://localhost:8080/actuator/health

看到{"status":"UP"}说明Java环境和端口监听都正常,再继续往下装其他组件。Java这块坑最少,但很多人恰恰是栽在最简单的地方——压根没装-devel包,导致后面编译某些依赖时找不到javac

4. MySQL 8.0部署:从repo配置到远程访问的完整链路

4.1 软件源策略:用官方repo还是openEuler源

openEuler 24.03 LTS源里自带MySQL?严格说自带的是MariaDB,或者是MySQL 8.0社区版,不同小版本源里情况不一样。为了可控性,我推荐用MySQL官方提供的yum repo,但要注意:openEuler 24.03基于内核5.10、glibc版本较高,MySQL官方repo的el8或el9包通常都能装上,具体要看你下载的release包版本。

我采用的方式是直接使用MySQL官方Yum仓库:

# 安装MySQL官方repo rpm -ivh https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm # 或者下载到本地再装,避免网络中断 wget https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm dnf install -y mysql80-community-release-el9-1.noarch.rpm # 安装MySQL社区版 dnf install -y mysql-community-server

如果官方repo在你网络环境下特别慢,也可以把mysql-community-server相关的几个rpm包下载到本地,再用dnf install ./xxx.rpm离线安装。小版本不一致问题不大,MySQL 8.0的内核版本是同一个大版本就行。

4.2 数据目录规划与初始化

我习惯把MySQL的数据目录放到独立数据盘上,也就是前面分区时说的/data。这个习惯来源于一次根目录被慢查询日志和binlog写满导致MySQL直接宕机的事故,从那以后MySQL相关的数据文件一律走独立挂载点。

mkdir -p /data/mysql # 先启动一次让系统自动初始化默认目录,再停掉做目录迁移 systemctl start mysqld systemctl stop mysqld # 默认数据目录在 /var/lib/mysql mv /var/lib/mysql /data/mysql # 如果系统默认目录里有mysql用户,需要调整属主 chown -R mysql:mysql /data/mysql # 修改配置文件 cat > /etc/my.cnf <<'EOF' [mysqld] datadir=/data/mysql socket=/var/lib/mysql/mysql.sock port=3306 character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci lower_case_table_names=1 max_connections=1000 innodb_buffer_pool_size=2G # 时区与本地对齐 default-time-zone='+08:00' skip-name-resolve EOF systemctl start mysqld

lower_case_table_names=1这个参数建议在初始化之前就定好,因为MySQL 8.0中这个参数在初始化后修改会直接导致表名大小写不一致问题,甚至服务起不来。如果你之前的项目里有大小写混合的表名,和1冲突,那就维持0,但应用层代码要保证表名大小写统一,否则在Linux上会报找不到表。

skip-name-resolve是性能优化项,MySQL不会对客户端IP做反向DNS解析。代价是grant授权时不能用主机名,只能写IP。对应用服务器固定IP的场景,这个取舍完全值得。

4.3 初始化密码与安全策略

第一次启动MySQL后,临时密码会写入错误日志。这个步骤很经典,但每次都会有人问“密码在哪里”。

grep 'temporary password' /var/log/mysqld.log # 输出示例:A temporary password is generated for root@localhost: xxxxxx # 登录并修改密码 mysql -uroot -p ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPass@2025'; FLUSH PRIVILEGES;

MySQL 8.0默认密码策略是validate_password,强度要求较高,必须有大小写字母、数字和特殊字符,长度至少8位。如果是在内网测试环境,可以用下面的方式降低强度,但生产环境千万别这么做:

SET GLOBAL validate_password.policy = LOW; SET GLOBAL validate_password.length = 6;

4.4 创建业务账号与远程访问配置

root账号只允许localhost登录,应用服务器如果和MySQL分离,要单独创建远程访问账号。这里有一个安全细节:不要用root去连,也不要用%通配符给所有IP放行,除非你确认网络安全组已经隔离了访问来源。

-- 创建专用账号,假设应用服务器IP为192.168.1.150 CREATE USER 'app_user'@'192.168.1.150' IDENTIFIED BY 'AppPass@2025'; GRANT ALL PRIVILEGES ON mydb.* TO 'app_user'@'192.168.1.150'; FLUSH PRIVILEGES; -- 验证 mysql -uapp_user -p -h192.168.1.100 mydb

远程访问确认没有问题后,记得检查一下3306端口是否监听:

netstat -lntp | grep 3306

如果MySQL装在本机,本机应用连接时用socket方式最快,JDBC URL里写成jdbc:mysql://localhost:3306/mydb会自动走socket;如果写成127.0.0.1则是TCP连接,会多一层网络开销。同一台机上部署,可以优先用localhost。

4.5 连接数打满、时区报错的排障

两个高频问题单独说一下。

连不上/连接数打满。默认max_connections是151,生产环境显然不够。我遇到过促销活动期间数据库直接报Too many connections,应用雪崩。除了把max_connections调大到500-1000,还要在应用层连接池上做限制。比如HikariCP的maximumPoolSize不要超过MySQLmax_connections的70%,留出30%给运维连接和其他工具。否则应用一扩容,数据库先挂。

时区报错。Spring Boot连接MySQL 8.0时,经常报The server time zone value 'CST' is unrecognized,这是因为驱动版本和服务器时区设置不匹配。在my.cnf中明确配上default-time-zone='+08:00'后,这个问题从根上消失,不用在JDBC URL里追加serverTimezone=Asia/Shanghai也能正常连接。

5. Redis部署与运行调优:缓存服务的配置要点

5.1 安装方式选择

Redis的安装有几种方式:dnf直接装、源码编译、用Docker跑。考虑到前面提到的生产环境团队习惯,以及Redis本身编译很快、参数定制性好,我选择了dnf装,但如果你的openEuler源里Redis版本较老,也可以从源码编译安装最新稳定版。

# 查看源里的版本 dnf info redis # 安装 dnf install -y redis redis-server --version

openEuler 24.03 LTS源里的Redis版本如果是7.x,那直接用dnf装完全够用。Redis 7.x相比6.x有不少性能优化,特别是多线程IO和更高效的内存管理,生产环境建议优先使用。

5.2 核心配置项修改

Redis默认配置/etc/redis/redis.conf(或/etc/redis.conf,取决于你的安装方式),需要改的核心项有几处。

守护进程与绑定地址:

# 如果你用systemd管理,Redis可以不以daemonize方式运行,让systemd直接管理前台进程 # 192.168.1.100 是本机IP,只允许内网访问 bind 127.0.0.1 192.168.1.100 protected-mode yes port 6379

这里有个习惯问题。如果daemonize yes,systemd管理起来反而别扭,推荐保持daemonize no,因为systemd本身可以管理前台进程、跟踪PID,崩溃了还能根据配置自动拉起。

持久化策略:

Redis的数据持久化有RDB快照和AOF日志两种方式。缓存场景下可以只开RDB,但如果Redis里存了部分重要的业务数据(比如分布式锁、排行榜),建议同时开启AOF,并且用appendfsync everysec来平衡性能与安全性。

appendonly yes appendfsync everysec save 900 1 save 300 10 save 60 10000

内存淘汰策略:

这是生产环境必配项。不配置的话,Redis内存写满后会直接拒绝写入,导致业务异常。常见选择是allkeys-lru(对所有key使用LRU算法淘汰),如果缓存数据中部分key绝对不能丢(比如验证码),就用volatile-lru,只淘汰设置了过期时间的key。

maxmemory 4gb maxmemory-policy allkeys-lru

maxmemory的值建议不超过物理内存的70%,要给操作系统和Java应用留足空间。

密码认证:

requirepass YourRedisPassword

如果只是内网使用、又做了网络安全隔离,不设密码也说得过去。但一旦Redis所在网络有公网暴露风险,不设密码等于裸奔。我见过一台没设密码、默认端口6379的Redis,上线第二天就被挖矿程序植入了定时任务。这不是危言耸听,安全组的配置一定要核查。

5.3 systemd管理Redis服务

用dnf安装的Redis会自动注册systemd服务。手工修改配置文件后,需要重启才能生效。

systemctl enable --now redis systemctl restart redis systemctl status redis redis-cli -a YourRedisPassword ping # 返回 PONG 说明服务正常

redis-cli带密码的时候会有一个warning提示密码暴露在命令行历史中,所以生产环境推荐用环境变量的方式验证:

REDISCLI_AUTH=YourRedisPassword redis-cli ping

5.4 Redis CLI的常用排查命令

部署完后建议把下面这几条命令跑一遍,确认运行状态:

redis-cli -a YourRedisPassword info memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio" redis-cli -a YourRedisPassword info clients | grep connected_clients redis-cli -a YourRedisPassword info stats | grep -E "total_commands_processed|expired_keys"

重点关注mem_fragmentation_ratio内存碎片率。如果这个值长期大于1.5,说明碎片太多,可能需要重启Redis或者调整jemalloc相关参数。如果小于1,则可能是开启了swap或者发生了内存溢出,这种状态比碎片高更危险。

6. Nginx部署与反向代理配置

6.1 安装与基础目录

Nginx在openEuler源里是稳定版,直接用dnf安装。

dnf install -y nginx nginx -v systemctl enable --now nginx

装完立刻确认一下服务是否正常:

systemctl status nginx curl http://localhost

看到Welcome to nginx或者openEuler的默认欢迎页,就说明起步没毛病。很多人到这一步就跳过配置检查,结果后面改了一堆配置重启后才发现语法错误,浪费时间。

6.2 配置核心思路:反向代理

Nginx在这里承担的是反向代理的角色,外部流量先到Nginx,再由Nginx把请求转发给后端Java应用。好处很多:可以统一做SSL终结、负载均衡、静态资源分离、限流、日志记录。

配置文件的习惯是不要动主配置/etc/nginx/nginx.conf,而是在/etc/nginx/conf.d/下新建一个专用配置。主配置里通常有include /etc/nginx/conf.d/*.conf;,天然支持这种方式。

cat > /etc/nginx/conf.d/myapp.conf <<'EOF' upstream myapp_backend { server 127.0.0.1:8080 weight=5 max_fails=3 fail_timeout=30s; # 如果有多个应用实例,继续加server行 # server 192.168.1.151:8080 weight=5; keepalive 32; } server { listen 80; server_name api.example.com; access_log /var/log/nginx/myapp-access.log main; error_log /var/log/nginx/myapp-error.log warn; # 静态资源直接由Nginx处理,不转给后端 location /static/ { alias /data/myapp/static/; expires 7d; add_header Cache-Control "public, max-age=604800"; } # 后端API请求转发 location /api/ { proxy_pass http://myapp_backend; 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_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 5s; proxy_read_timeout 60s; } location / { proxy_pass http://myapp_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } EOF # 测试配置语法 nginx -t # 优雅重载,服务不中断 nginx -s reload

6.3 静态资源与动静分离

Java应用里的Spring Boot默认使用内嵌Tomcat处理静态资源,性能远不如Nginx直接返回。对于图片、CSS、JS这类资源,让Nginx直接读磁盘能减轻Tomcat的压力,也提升用户访问速度。

部署时把Spring Boot的静态文件路径配置到/data/myapp/static/,Nginx直接alias到这个目录。注意aliasroot的区别:root /data/myapp/static/会拼上URI路径,alias则直接映射到指定目录,配置静态资源推荐用alias,避免多了一层目录。

6.4 配置HTTPS

如果域名已经备案、有正规证书,强烈推荐上HTTPS。openEuler 24.03上Nginx开启SSL很简单,用Let's Encrypt的证书或公司内部证书都行。

server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /etc/nginx/certs/api.example.com.crt; ssl_certificate_key /etc/nginx/certs/api.example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 非HTTPS请求自动跳转 if ($scheme != "https") { return 301 https://$host$request_uri; } }

证书获取这块不展开,Let's Encrypt的certbot工具在openEuler上可以正常使用。企业内网环境可以搭建私有CA,把CA证书下发到各服务器和终端,也能实现HTTPS加密。

6.5 systemd、日志切割与文件句柄

Nginx的systemd服务文件里,默认LimitNOFILE可能不够高。高并发场景下Nginx会报too many open files,哪怕worker_rlimit_nofile设置了也白搭,因为systemd层面的限制优先级更高。

mkdir -p /etc/systemd/system/nginx.service.d cat > /etc/systemd/system/nginx.service.d/override.conf <<'EOF' [Service] LimitNOFILE=65535 EOF systemctl daemon-reload systemctl restart nginx

日志切割用Nginx自带的手段是做信号量重开日志文件,配合logrotate。openEuler上安装Nginx后,/etc/logrotate.d/nginx这个配置通常会自带,确认一下里面的log路径对不对就行。对/var/log/nginx/*.log做按天切割、保留7天,基本够用。

7. 组件联调与高频踩坑排查

7.1 一个完整的部署顺序建议

这四个组件不是装完就完事,联调时的顺序很关键。我的建议是:

  1. 先装Java,本地把Java应用跑起来,确认端口通
  2. 再装MySQL,建库建账号,让Java应用连上MySQL,验证CRUD
  3. 装Redis,让Java应用写入Redis缓存,验证读缓存和过期策略
  4. 最后装Nginx,把80端口代理到Java应用的端口,验证从浏览器到Nginx到Java的完整链路

这个顺序能保证每一步都只排查一个变量。如果全装完再一把梭联调,出了问题你根本不知道是该查DB还是查Redis还是查Nginx。

7.2 Java应用崩溃最常见的几个原因

堆内存不足。Spring Boot默认堆内存是物理内存的1/4,如果机器内存小、机器上还跑着MySQL和Redis,Java很容易OOM。启动时显式指定:

java -Xms512m -Xmx1024m -jar myapp.jar

JDBC驱动版本不兼容。openEuler上如果MySQL版本是8.0.x,应用的mysql-connector-java驱动建议用8.0.x配套的版本,不要用5.x驱动,不然会报Communications link failure或者Public Key Retrieval is not allowed。后者可以在JDBC URL后面加allowPublicKeyRetrieval=true来规避,但治本的方法是用配套驱动版本。

Redis连接池耗尽。如果应用里用Lettuce客户端,默认池大小有限,高并发下会出现Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException。调大配置是一方面,更重要的是检查代码里有没有忘记释放连接的地方。Spring Boot的RedisTemplate如果使用不当,比如在循环里创建连接而不归还,就是用多大的池都不够。

7.3 MySQL时区、字符集与大小写敏感

这三个问题我在这套环境上每次重装都会遇到一次,列一下自查清单:

  • 时区报错:参考前面配置default-time-zone='+08:00',同时检查JDBC URL中是否还有serverTimezone=Asia/Shanghai,两个都配上并不冲突。
  • 中文乱码:MySQL侧确认character-set-server=utf8mb4,同时建库时显式DEFAULT CHARACTER SET utf8mb4,不要指望默认值。Java侧在Spring Boot的连接URL上加上characterEncoding=UTF-8
  • 表名大小写lower_case_table_names=1后,Hibernate/JPA生成的表名是全小写,如果代码中使用了@Table(name = "UserInfo")这样的混合命名,Hibernate会自动转成userinfo,Linux文件系统敏感,SQL里写UserInfo会找不到表。统一用lower_case_table_names=1,并在代码里全部用小写表名和字段名,能省去99%的烦恼。

7.4 Nginx 502/504的排查链路

Nginx一切正常但页面报502/504的时候,不要先去怀疑Nginx配置问题。我自己的排查路径是固定的:

  1. 看Nginx错误日志tail -f /var/log/nginx/myapp-error.log,能看到“connect() failed (111: Connection refused)”还是“upstream timed out”。
  2. 确认Java应用还活着curl http://127.0.0.1:8080/actuator/health,不通就去看Java日志,通常是应用挂了或GC卡死。
  3. 如果是Connection refused:Java应用挂了或者端口没监听。
  4. 如果是Connection reset by peer:Java应用可能正在重启或线程池已满,检查Tomcat的server.tomcat.max-threads配置。
  5. 如果是upstream timed out:大多数请求在Java侧处理超过Nginx的proxy_read_timeout(默认60s),适当调大到120s,同时排查后端是否有慢SQL或外部接口调用阻塞。

注意,Nginx的proxy_connect_timeout默认是60s,内网环境下一般1-5s就够了。如果设置太长,后端不可用时,用户会一直转圈等待。调短后用户体验会好很多,也更方便及时发现问题。

7.5 SELinux和网络不通的特殊情况

如果你没有关掉SELinux,就要注意Nginx转发后端的坑。OpenEuler的SELinux默认策略中,httpd相关的布尔值默认是不允许网络请求的。

# 检查是否开启 getsebool httpd_can_network_connect # 开启 setsebool -P httpd_can_network_connect 1

-P参数让它永久生效。如果不开这个,Nginx到Tomcat的转发会被SELinux拦下来,表现就是501/502,而Nginx和Java日志里都没有明显异常,纯粹是环境问题。这条经验值好几个小时。

7.6 服务开机自启的完整方案

部署完成后,四个服务的开机自启都要配置好,不能依赖人工手工拉起。

systemctl enable mysqld systemctl enable redis systemctl enable nginx

Java应用这里有些人喜欢用nohup+rc.local,我说实话非常不推荐。rc.local的启动顺序不可控,而且没有守护进程功能,Java进程崩了不会自动拉起。更规范的做法是写一个systemd服务文件:

cat > /etc/systemd/system/myapp.service <<'EOF' [Unit] Description=My Spring Boot Application After=network.target mysqld.service redis.service Wants=mysqld.service redis.service [Service] Type=simple User=appuser Group=appuser WorkingDirectory=/data/myapp ExecStart=/usr/bin/java -Xms512m -Xmx1024m -jar /data/myapp/myapp.jar ExecStop=/bin/kill -s TERM $MAINPID SuccessExitStatus=143 Restart=always RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now myapp

注意After=mysqld.service redis.service只是保证MySQL和Redis的服务单元被触发,并不保证它们真正就绪。所以Java应用里要有重连机制,启动时数据库暂时连不上也要能重试,不能一失败就退出。Spring Boot的HikariCP默认初始化失败会快速失败,可以在配置里加spring.datasource.hikari.initialization-fail-timeout=60000或者干脆设成-1让它无限重试。

8. 写在最后:几个可能影响你决策的细节

整套环境从系统安装到四个组件全部调通,我大概花了半天时间。对比之前在CentOS 7上从零部署的流程,openEuler 24.03 LTS的整体感觉是“熟悉又不完全一样”。熟悉的是RPM生态、systemd管理、路径结构,不完全一样的是默认软件源里的版本号、个别工具的依赖行为和SELinux策略。

有几个细节我觉得有实际参考价值:

  • 升级内核和驱动前先备份。openEuler的内核是自维护的,升级有风险。如果你用到了一些特殊的硬件驱动或内核模块,升级前先在测试机验证,不要在生产直接dnf update一把梭。
  • openEuler源中某些软件的包名和CentOS不一样。比如Nginx、Redis这种都是直接同名,但有些工具会带后缀,装之前先dnf search一下,别凭老经验硬装。
  • 如果你是从CentOS的yum习惯转过来的,openEuler的dnf命令参数几乎无缝,yum命令本身在24.03上也能用(它是dnf的别名兼容)。脚本里的yum install xxx不用特意改。
  • 遇到问题优先看官方文档。openEuler的文档站内容很全,包括系统管理、软件安装、迁移指南,很多问题不用去百度查二手答案,直接翻官方文档反而更快。

如果看到这里你想给现有的CentOS机器做迁移,我给的建议是先挑一台非核心业务机器,按这套流程完整跑一遍,确认你的应用兼容性没问题,再批量切换。别看这个过程简单,在系统版本切换这种事情上,测试环境再充分都不为过。

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

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

立即咨询