2G 内存云服务器部署 Spring Boot + MySQL 实战:从踩坑到上线

2G 内存云服务器部署 Spring Boot + MySQL 实战:从踩坑到上线
在这里插入图片描述

2G 内存云服务器部署 Spring Boot + MySQL 实战:从踩坑到上线

前言

最近把自己的全栈博客项目部署到了腾讯云的入门级服务器(2核2G),过程中踩了不少坑。本文记录完整的部署过程和问题排查思路,希望对同样在小规格服务器上部署 Java 项目的同学有所帮助。

项目技术栈:

  • 后端:Java 17 + Spring Boot 3.2.3 + Spring Security + JPA
  • 数据库:MySQL 8.0
  • 前端:Flutter Web
  • 反向代理:Nginx 1.26
  • 容器:Docker 28.4

服务器配置:

  • 腾讯云轻量应用服务器
  • 2 核 CPU / 2GB 内存 / 50GB 磁盘
  • TencentOS Server 4 (x86_64)

一、方案一:Docker Compose 全容器化(失败)

1.1 docker-compose.yml

最初的方案是标准的全容器化部署:

services:db:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}MYSQL_DATABASE: vonblog MYSQL_USER: vonblog MYSQL_PASSWORD: ${DB_PASSWORD}ports:-"3306:3306"volumes:- mysql_data:/var/lib/mysql healthcheck:test:["CMD","mysqladmin","ping","-h","localhost"]interval: 10s timeout: 5s retries:5backend:build: ./backend depends_on:db:condition: service_healthy ports:-"8080:8080"environment:SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/vonblog?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/ShanghaiSPRING_DATASOURCE_USERNAME: vonblog SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}nginx:image: nginx:alpine depends_on:- backend ports:-"80:80"-"443:443"

1.2 问题现象

后端容器反复报错:

com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure Caused by: java.net.ConnectException: Connection refused 

1.3 排查过程

逐项排查:

# 1. MySQL 容器状态 — 正常docker compose ps# db: Up 18 minutes (healthy)# 2. DNS 解析 — 正常dockerexec vonblog-backend-1 nslookup db # Address: 172.19.0.2# 3. MySQL 用户权限 — 已授权dockerexec vonblog-db-1 mysql -uroot-p-e"GRANT ALL ON vonblog.* TO 'vonblog'@'%';"# 4. 端口监听 — MySQL 确实在监听dockerexec vonblog-db-1 ss -tlnp|grep3306

一切看起来都正常,但后端就是连不上。

1.4 根因分析

2GB 内存是瓶颈。

free -h 一看:

 total used free shared buff/cache available Mem: 1.9Gi 588Mi 643Mi 8.0Mi 916Mi 1.3Gi 

MySQL 8.0 默认配置下内存占用约 400-500MB,Spring Boot JVM 默认堆大小也是几百 MB。两个容器同时启动,加上 Docker 本身的开销,内存直接见底。

在内存不足的情况下,容器间的网络通信会出现各种诡异问题:TCP 连接建立失败、超时、被内核 OOM killer 干掉后重启等。Connection refused 只是表象,本质是资源不足。

二、方案二:混合部署(成功)

2.1 架构调整

┌─────────────────────────────────────┐ │ 腾讯云 2C2G 服务器 │ │ │ │ ┌───────────┐ ┌────────────────┐ │ │ │ Docker │ │ 宿主机 │ │ │ │ MySQL 8.0 │ │ Java 17 (jar) │ │ │ │ (容器) │ │ Nginx (systemd)│ │ │ └───────────┘ └────────────────┘ │ │ ↑ 3306 ↑ 8080 ↑ 80 │ │ └──── 127.0.0.1 ────────┘ │ └─────────────────────────────────────┘ 

核心思路:MySQL 留在 Docker(数据隔离方便),Spring Boot 和 Nginx 直接跑在宿主机上(省内存)。

2.2 步骤一:启动 MySQL 容器

docker run -d\--name vonblog-mysql \--restart always \-eMYSQL_ROOT_PASSWORD=YourRootPassword \-eMYSQL_DATABASE=vonblog \-eMYSQL_USER=vonblog \-eMYSQL_PASSWORD=YourDbPassword \-p3306:3306 \-v mysql_data:/var/lib/mysql \ mysql:8.0 \ --character-set-server=utf8mb4 \ --collation-server=utf8mb4_unicode_ci 

2.3 步骤二:安装 Java 17

# TencentOS / CentOS / RHEL 系 yum install-y java-17-openjdk-headless # 验证java-version# openjdk version "17.0.18"

2.4 步骤三:运行 Spring Boot jar

关键:限制 JVM 堆内存,2G 服务器不能让 JVM 随意扩张。

mkdir-p /opt/vonblog/uploads nohupjava-Xms256m-Xmx512m\-jar /opt/vonblog/app.jar \--spring.profiles.active=prod \--spring.datasource.url="jdbc:mysql://127.0.0.1:3306/vonblog?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false"\--spring.datasource.username=vonblog \--spring.datasource.password=YourDbPassword \> /opt/vonblog/app.log 2>&1&echo"PID: $!"

注意几个要点:

  • -Xms256m -Xmx512m:堆内存限制在 256-512MB,给系统和 MySQL 留空间
  • 127.0.0.1:3306:通过宿主机 loopback 连接 Docker 映射出来的端口
  • allowPublicKeyRetrieval=true:MySQL 8.0 默认使用 caching_sha2_password,需要这个参数

2.5 步骤四:配置 Nginx

yum install-y nginx cat> /etc/nginx/conf.d/vonblog.conf <<'EOF' server { listen 80; server_name _; client_max_body_size 10M; # 前端静态文件 root /opt/vonblog/web; index index.html; # API 反代 location /api/ { proxy_pass http://127.0.0.1:8080/api/; 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; } # 上传文件 location /uploads/ { alias /opt/vonblog/uploads/; expires 30d; } # Flutter Web SPA 路由 location / { try_files $uri $uri/ /index.html; } } EOF systemctl enable nginx systemctl start nginx 

try_files $uri $uri/ /index.html 这行很重要——Flutter Web 是 SPA 单页应用,所有路由都要回落到 index.html,否则刷新页面会 404。

2.6 效果

# 启动耗时 Started VonBlogApplication in10.393 seconds # 内存占用free-h# Mem: 1.9Gi total, ~400Mi free, ~1.1Gi used (含 buff/cache)# MySQL 容器约 300MB + JVM 约 400MB + Nginx 约 20MB + 系统约 300MB

刚好塞下,不富裕但够用。

三、前端文件传输的曲折

3.1 SCP 被断连

本地 flutter build web --release 构建完后用 SCP 上传,结果:

Connection closed by 118.x.x.x port 22 

反复尝试都被断。原因是之前多次 SSH 密码交互触发了服务器的入侵防护策略(fail2ban 或类似机制)。

3.2 解决方案:临时 HTTP 上传服务

在服务器上用 Python 起一个临时的文件接收服务:

# 服务端(服务器上执行) python3 -c " import http.server, os classH(http.server.BaseHTTPRequestHandler):defdo_PUT(self): length =int(self.headers['Content-Length'])withopen('/opt/vonblog/web.tar.gz','wb')as f: f.write(self.rfile.read(length)) self.send_response(200) self.end_headers() self.wfile.write(b'OK') os._exit(0)# 接收完自动退出 http.server.HTTPServer(('0.0.0.0',9999), H).serve_forever() " &
# 客户端(本地执行)tar-czf web.tar.gz web/ curl-X PUT --data-binary @web.tar.gz http://服务器IP:9999/upload 
# 服务端解压cd /opt/vonblog &&tar-xzf web.tar.gz 

7.8MB 的压缩包,3 秒传完。简单粗暴但有效。

⚠️ 注意:这个方案没有任何认证,仅适合临时使用,用完立即关闭端口或进程。

四、内存优化建议

如果你也在 2G 服务器上跑 Java 项目,这些参数值得关注:

4.1 JVM 参数

# 严格限制堆内存-Xms256m-Xmx512m# 如果更紧张,可以进一步压缩-Xms128m-Xmx256m# 使用 G1GC(Java 17 默认),低延迟友好-XX:+UseG1GC

4.2 MySQL 内存调优

如果 MySQL 也要省内存,可以在启动时追加参数:

docker run ... mysql:8.0 \ --innodb-buffer-pool-size=128M \ --max-connections=50\ --table-open-cache=200

4.3 Swap 兜底

2G 内存的服务器强烈建议开 Swap:

fallocate -l 2G /swapfile chmod600 /swapfile mkswap /swapfile swapon /swapfile echo'/swapfile none swap sw 0 0'>> /etc/fstab 

有 Swap 兜底,偶发的内存峰值不会直接触发 OOM killer。

五、待优化

  1. systemd 服务化:目前后端用 nohup 启动,服务器重启后不会自动恢复。应该写一个 systemd service 文件。
  2. HTTPS:用 Let’s Encrypt + certbot 配置免费 SSL 证书。
  3. 日志轮转app.log 会无限增长,需要配置 logrotate。
  4. 监控:没有任何监控,进程挂了无感知。至少应该加个健康检查脚本 + crontab。

总结

方案优点缺点适用场景
Docker Compose 全容器环境隔离、一键部署内存开销大4G+ 内存服务器
混合部署省内存、连接稳定管理稍复杂2G 内存服务器
全宿主机最省资源环境污染1G 极端场景

核心结论:小规格服务器不要迷信全容器化,够用就行。 Docker Compose 在 4G 以上内存的机器上体验很好,但在 2G 机器上,混合方案是更务实的选择。


本文基于实际项目部署经验撰写,项目技术栈:Spring Boot 3.2.3 + Flutter Web + MySQL 8.0 + Nginx + Docker

如有疑问欢迎评论交流。

Read more

卷积神经网络(CNN)进阶:经典架构解析与实战开发

卷积神经网络(CNN)进阶:经典架构解析与实战开发

卷积神经网络(CNN)进阶:经典架构解析与实战开发 💡 学习目标:掌握CNN的经典进阶架构设计思路,理解不同架构的核心创新点,能够基于经典架构开发定制化图像任务模型。 💡 学习重点:LeNet-5、AlexNet、VGGNet、ResNet的核心结构与改进逻辑,基于PyTorch实现ResNet-50并完成图像分类任务。 49.1 卷积神经网络进阶的核心驱动力 卷积神经网络从最初的简单结构发展到深度模型,核心驱动力是解决深层网络的性能瓶颈和提升特征提取的效率与精度。 在早期CNN的应用中,研究人员发现两个关键问题: 1. 网络深度增加到一定程度后,会出现梯度消失或梯度爆炸问题,导致模型无法收敛。 2. 简单堆叠卷积层的方式,会造成特征冗余和计算资源浪费,模型泛化能力受限。 ⚠️ 注意:CNN的进阶过程不是单纯的“堆层数”,而是通过结构创新、参数优化和训练技巧的结合,实现性能的突破。 ✅ 结论:经典CNN架构的每一次升级,都针对当时的技术痛点提出了创新性解决方案,掌握这些方案的设计思路,比记住网络结构更重要。 49.2 经典CNN架构深度解析 49.2.1

By Ne0inhk
SkyWalking - Spring Cloud Alibaba 全链路追踪实战

SkyWalking - Spring Cloud Alibaba 全链路追踪实战

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕SkyWalking这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获! 文章目录 * SkyWalking - Spring Cloud Alibaba 全链路追踪实战 🚀 * 1. 环境准备与核心概念 🧰 * 1.1 核心概念解析 * 1.2 环境准备 * 2. 构建 Spring Cloud Alibaba 微服务项目 🏗️ * 2.1 创建父工程 * 2.2 构建 `inventory-service`(库存服务) * 2.3 构建 `order-service`(订单服务) * 2.4 验证基础功能 * 3. 集成

By Ne0inhk
企业级web影院订票系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

企业级web影院订票系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

摘要 随着互联网技术的快速发展和数字化生活的普及,影院行业正面临着从传统线下售票向线上智能化转型的需求。观众对便捷、高效的购票体验要求日益提升,而影院管理方也需要一套功能完善、操作简便的系统来优化票务管理、排片安排和数据分析。基于此背景,开发一款企业级Web影院订票系统具有重要的现实意义。该系统能够整合线上线下资源,实现用户自助选座购票、影院动态排片、数据统计分析等功能,为影院运营提供全方位支持。关键词:影院订票系统、数字化转型、线上购票、智能化管理、企业级应用。 本系统采用SpringBoot+Vue+MyBatis架构,结合MySQL数据库,实现了前后端分离的高效开发模式。SpringBoot框架简化了后端服务的搭建,提供了稳定的RESTful API接口;Vue.js框架构建了响应式前端界面,提升了用户体验;MyBatis作为ORM工具,优化了数据库操作效率。系统功能涵盖用户注册登录、影片信息管理、场次排期、在线选座购票、订单支付、数据统计等模块,支持多角色权限管理,满足影院管理员和普通用户的不同需求。关键词:SpringBoot、Vue.js、MyBatis、MySQL、权

By Ne0inhk

低成本部署GLM-4.6V-Flash-WEB:消费级显卡也能跑通

低成本部署GLM-4.6V-Flash-WEB:消费级显卡也能跑通 在AI应用日益普及的今天,越来越多开发者希望将多模态大模型集成到自己的产品中——比如让客服系统“看懂”用户上传的截图,或让教育软件自动解析习题图片。但现实往往令人望而却步:主流视觉语言模型动辄需要A100级别的显卡、数十GB显存,云服务月成本轻松破千,个人开发者和中小企业根本难以承受。 有没有一种可能:不依赖昂贵算力,也能拥有强大的图文理解能力? 答案是肯定的。智谱AI推出的 GLM-4.6V-Flash-WEB 正是为此而来。这款模型不仅开源、轻量,还能在一张RTX 3060上稳定运行,推理延迟控制在500ms以内,真正实现了“用游戏显卡跑大模型”的平民化突破。 为什么它能这么快?技术背后的关键设计 GLM-4.6V-Flash-WEB 并非简单地压缩参数量,而是在架构层面做了大量针对性优化。它的核心依然是基于GLM系列的统一认知框架,但针对Web服务场景进行了深度重构。 整个模型采用典型的编码器-解码器结构,分为四个关键模块: 1. 轻量化视觉编码器:使用精简版ViT(Vision Transfo

By Ne0inhk