1. 项目概述与部署背景
SSM(Spring+SpringMVC+MyBatis)作为JavaEE领域的经典框架组合,在企业级应用开发中占据重要地位。去年我们团队完成了一个日均访问量50万+的电商后台系统,正是基于SSM架构实现的。今天我就来复盘当时从开发环境到生产服务器的完整部署过程,包含那些官方文档里不会写的实战细节。
服务器部署本质上是在解决"开发环境代码如何变成用户可访问的服务"这个问题。与简单的本地运行不同,生产部署需要考虑性能优化、安全防护、故障恢复等关键因素。以我们项目为例,部署后的系统需要保证99.9%的可用性,这意味着全年停机时间不能超过8.76小时。
2. 环境准备与工具选型
2.1 服务器基础环境配置
我们选择CentOS 7.6作为操作系统,这个版本在稳定性和兼容性上都有很好表现。以下是初始化操作实录:
bash复制# 更新系统组件
yum update -y
# 安装基础工具集
yum install -y vim wget curl net-tools lsof
# 关闭不必要的服务
systemctl stop firewalld
systemctl disable firewalld
# 设置时区
timedatectl set-timezone Asia/Shanghai
注意:生产环境建议保留防火墙但配置好规则,我们这里关闭仅用于演示环境
2.2 Java环境部署
选择JDK8而非新版的原因在于:大多数SSM项目最初都是基于Java8开发的,升级JDK版本可能导致兼容性问题。我们使用Oracle JDK而非OpenJDK,因为某些性能监控工具需要Oracle专有API。
bash复制# 下载JDK rpm包
wget https://download.oracle.com/otn-pub/java/jdk/8u301-b09/d3c52aa6bfa54d3ca74e617f18309292/jdk-8u301-linux-x64.rpm
# 安装
rpm -ivh jdk-8u301-linux-x64.rpm
# 配置环境变量
echo 'export JAVA_HOME=/usr/java/jdk1.8.0_301-amd64' >> /etc/profile
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile
source /etc/profile
验证安装:
bash复制java -version
# 应输出:java version "1.8.0_301"
2.3 数据库环境搭建
MySQL 5.7是我们的选择,因为:
- 对MyBatis的兼容性最好
- 比5.6有显著的性能提升
- 比8.0更稳定且资源占用更低
安装步骤:
bash复制# 添加MySQL仓库
rpm -Uvh https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
# 安装服务端
yum install -y mysql-community-server
# 启动服务
systemctl start mysqld
# 获取临时密码
grep 'temporary password' /var/log/mysqld.log
# 安全配置
mysql_secure_installation
关键配置项(/etc/my.cnf):
ini复制[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
innodb_buffer_pool_size=2G # 根据内存调整
max_connections=500
3. 项目构建与部署
3.1 源码打包与优化
使用Maven进行打包时,我们采用如下命令确保生产环境配置生效:
bash复制mvn clean package -Pprod -DskipTests
这里有几个关键点:
-Pprod激活生产环境profile-DskipTests跳过测试加速打包- 建议添加
-Dmaven.compile.fork=true启用并行编译
打包后需要检查生成的war包:
bash复制# 查看文件大小
ls -lh target/*.war
# 典型SSM项目war包应在20-50MB之间
3.2 Tomcat配置与部署
我们选择Tomcat 9.x版本,与JDK8完美兼容。关键配置项(conf/server.xml):
xml复制<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="500"
minSpareThreads="20"
acceptCount="100"
URIEncoding="UTF-8"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript"/>
部署操作:
bash复制# 清理旧部署
rm -rf /usr/local/tomcat/webapps/ROOT*
# 上传新war包
cp project.war /usr/local/tomcat/webapps/ROOT.war
# 启动Tomcat
/usr/local/tomcat/bin/startup.sh
重要技巧:使用
nohup启动可以防止SSH断开导致服务停止:bash复制nohup /usr/local/tomcat/bin/startup.sh &
4. 部署后检查与优化
4.1 服务健康检查
通过多维度验证部署是否成功:
bash复制# 检查端口监听
netstat -tlnp | grep java
# 检查日志
tail -f /usr/local/tomcat/logs/catalina.out
# 接口测试
curl http://localhost:8080/api/health
4.2 性能调优实战
JVM参数配置(catalina.sh中添加):
bash复制export JAVA_OPTS="-server -Xms2G -Xmx2G -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
各参数含义:
-Xms2G -Xmx2G:堆内存初始和最大值(建议设为相同)-XX:MetaspaceSize:元空间初始大小-XX:+UseG1GC:使用G1垃圾回收器-XX:MaxGCPauseMillis:目标最大GC停顿时间
4.3 数据库连接池优化
在Spring配置文件中(applicationContext.xml):
xml复制<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialSize" value="5"/>
<property name="minIdle" value="5"/>
<property name="maxActive" value="20"/>
<property name="maxWait" value="60000"/>
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<property name="minEvictableIdleTimeMillis" value="300000"/>
</bean>
5. 运维监控与日志管理
5.1 基础监控配置
使用Spring Boot Actuator暴露监控端点:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
application.properties配置:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
5.2 日志切割方案
采用logback+logrotate组合方案。logback.xml配置示例:
xml复制<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/app.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
</appender>
6. 常见问题排查指南
6.1 启动类冲突问题
症状:Tomcat启动时报"No Spring WebApplicationInitializer types detected"
解决方案:
- 检查web.xml中是否配置了ContextLoaderListener
- 确保Spring配置类上有@Configuration注解
- 检查包扫描路径是否正确
6.2 数据库连接泄露
诊断方法:
bash复制# 查看数据库连接数
mysql> show status like 'Threads_connected';
# 查看应用连接池状态
curl http://localhost:8080/druid/index.html
预防措施:
- 所有JDBC操作必须放在try-with-resources中
- 使用MyBatis时确保SqlSession及时关闭
- 配置Druid的removeAbandoned参数
6.3 内存溢出处理
应急步骤:
- 立即dump内存快照:
bash复制jmap -dump:format=b,file=heap.hprof <pid>
- 分析工具推荐:
- Eclipse Memory Analyzer
- VisualVM
- 临时解决方案:重启服务并增加Xmx参数
7. 安全加固措施
7.1 基础安全配置
- 禁用Tomcat管理界面:
xml复制<!-- conf/web.xml中 -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Restricted</web-resource-name>
<url-pattern>/manager/*</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
- 修改shutdown端口:
xml复制<!-- conf/server.xml中 -->
<Server port="8005" shutdown="自定义复杂字符串">
7.2 SQL注入防护
MyBatis防护方案:
- 永远使用#{}而非${}
- 启用mybatis-filter:
xml复制<plugins>
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.SqlInjector"/>
</plugins>
8. 自动化部署进阶
8.1 Shell脚本示例
deploy.sh内容:
bash复制#!/bin/bash
TOMCAT_HOME=/usr/local/tomcat
WAR_FILE=target/project.war
echo "Stopping Tomcat..."
$TOMCAT_HOME/bin/shutdown.sh
echo "Cleaning old deployment..."
rm -rf $TOMCAT_HOME/webapps/ROOT*
rm -rf $TOMCAT_HOME/work/Catalina/localhost/ROOT
echo "Deploying new version..."
cp $WAR_FILE $TOMCAT_HOME/webapps/ROOT.war
echo "Starting Tomcat..."
nohup $TOMCAT_HOME/bin/startup.sh &
echo "Deployment completed!"
8.2 使用Jenkins实现CI/CD
关键配置步骤:
- 安装Git Parameter插件
- 创建自由风格项目
- 配置Git仓库地址
- 添加构建步骤:
bash复制mvn clean package -Pprod -DskipTests
ssh user@server 'bash /path/to/deploy.sh'
9. 高可用方案设计
9.1 Nginx负载均衡配置
示例配置:
nginx复制upstream tomcat_cluster {
server 192.168.1.101:8080 weight=5;
server 192.168.1.102:8080 weight=5;
server 192.168.1.103:8080 weight=1 backup;
}
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://tomcat_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
9.2 会话保持方案
方案对比:
- Nginx ip_hash(简单但不够均衡)
- Spring Session + Redis(推荐方案)
- Tomcat集群会话复制(配置复杂)
Redis配置示例:
properties复制# application.properties
spring.session.store-type=redis
spring.redis.host=redis-server
spring.redis.port=6379
10. 备份与恢复策略
10.1 数据库备份方案
每日全量备份脚本:
bash复制#!/bin/bash
DATE=$(date +%Y%m%d)
BACKUP_DIR=/data/backups
MYSQL_USER=backup
MYSQL_PASS=password
mysqldump -u$MYSQL_USER -p$MYSQL_PASS --all-databases | gzip > $BACKUP_DIR/full_$DATE.sql.gz
# 保留最近7天
find $BACKUP_DIR -name "full_*.sql.gz" -mtime +7 -delete
10.2 代码回滚机制
回滚步骤:
- 从版本控制系统获取历史版本
- 重新打包指定版本:
bash复制git checkout v1.2.3
mvn clean package -Pprod -DskipTests
- 执行标准部署流程
11. 性能监控体系搭建
11.1 Prometheus监控配置
Tomcat暴露JMX指标:
bash复制CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
prometheus.yml配置:
yaml复制scrape_configs:
- job_name: 'tomcat'
static_configs:
- targets: ['tomcat-server:9090']
11.2 告警规则示例
检测Full GC频繁:
yaml复制groups:
- name: gc.rules
rules:
- alert: FullGcFrequent
expr: sum(jvm_gc_collection_seconds_sum{action="end of major GC"}) by (instance) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "频繁Full GC (instance {{ $labels.instance }})"
12. 容器化部署方案
12.1 Dockerfile示例
dockerfile复制FROM tomcat:9-jdk8
COPY target/project.war /usr/local/tomcat/webapps/ROOT.war
ENV JAVA_OPTS="-Xms2G -Xmx2G"
EXPOSE 8080
CMD ["catalina.sh", "run"]
构建与运行:
bash复制docker build -t ssm-project .
docker run -d -p 8080:8080 --name ssm-app ssm-project
12.2 Kubernetes部署
deployment.yaml示例:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: ssm-deployment
spec:
replicas: 3
selector:
matchLabels:
app: ssm
template:
metadata:
labels:
app: ssm
spec:
containers:
- name: ssm
image: ssm-project:latest
ports:
- containerPort: 8080
resources:
limits:
memory: "4Gi"
cpu: "2"
13. 压测与性能调优
13.1 JMeter测试方案
典型测试计划要素:
- 线程组:模拟并发用户
- HTTP请求采样器:测试关键接口
- 监听器:查看结果树/聚合报告
关键指标解读:
- 吞吐量(Throughput):系统每秒处理请求数
- 响应时间(Response Time):90%线应<1s
- 错误率(Error %):应<0.1%
13.2 性能瓶颈定位
工具组合:
- Arthas:实时诊断Java应用
- VisualVM:监控JVM状态
- Slow query log:分析SQL性能
常见优化点:
- N+1查询问题
- 未使用索引的SQL
- 频繁创建的对象
- 同步锁竞争
14. 灰度发布策略
14.1 基于Nginx的灰度方案
配置示例:
nginx复制# 根据cookie分流
map $cookie_version $group {
default "prod";
"v2" "canary";
}
upstream prod {
server 192.168.1.101:8080;
}
upstream canary {
server 192.168.1.102:8080;
}
server {
location / {
proxy_pass http://$group;
}
}
14.2 全链路灰度设计
实现要点:
- 在HTTP头中传递版本标记
- 数据库读写分离(主库+灰度库)
- 缓存隔离(不同命名空间)
- MQ消息区分路由
15. 应急预案设计
15.1 故障分级标准
| 级别 | 标准 | 响应时间 |
|---|---|---|
| P0 | 核心功能不可用 | 15分钟 |
| P1 | 主要功能受影响 | 1小时 |
| P2 | 次要功能问题 | 4小时 |
| P3 | 轻微异常 | 24小时 |
15.2 回滚决策流程
- 确认故障现象
- 评估影响范围
- 检查日志和监控
- 判断是否需回滚
- 执行回滚操作
- 验证恢复情况
16. 成本优化实践
16.1 服务器选型建议
中小规模项目推荐配置:
- CPU:4核以上
- 内存:8GB起步
- 磁盘:SSD至少100GB
- 带宽:5Mbps起步
16.2 云资源使用技巧
- 使用预留实例节省成本
- 设置自动伸缩策略
- 冷数据转存对象存储
- 启用压缩减少流量消耗
17. 文档体系建设
17.1 部署手册要点
必备内容:
- 系统架构图
- 依赖组件清单
- 安装部署步骤
- 配置参数说明
- 常见问题解答
17.2 运维台账示例
| 时间 | 操作人 | 变更内容 | 影响范围 | 回滚方案 |
|---|---|---|---|---|
| 2023-08-01 | 张三 | 升级JDK到8u301 | 所有服务 | 重装旧版JDK |
18. 团队协作规范
18.1 部署checklist
上线前必须验证:
- [ ] 数据库备份已完成
- [ ] 回滚方案已准备
- [ ] 监控指标已配置
- [ ] 相关人员已通知
18.2 变更管理流程
- 提交变更申请
- 技术评审
- 准备回滚方案
- 执行变更
- 验证效果
- 完成记录
19. 新兴技术适配
19.1 国产化替代方案
可选技术栈:
- 操作系统:统信UOS/麒麟
- 数据库:达梦/OceanBase
- 中间件:东方通TongWeb
19.2 微服务改造路径
演进步骤:
- 模块拆分
- 独立数据库
- 服务注册发现
- 配置中心
- 链路追踪
20. 持续优化方向
经过多次部署实践,我总结出几个关键优化点:
- 部署脚本标准化:所有操作脚本化,避免人工操作失误
- 环境配置版本化:使用Ansible等工具管理服务器配置
- 监控全覆盖:从基础设施到应用层的完整监控
- 自动化测试:部署前必须通过自动化测试套件
最后分享一个真实案例:某次部署后发现响应时间从200ms飙升到2s,最终定位到是MySQL的innodb_buffer_pool_size配置过小。这个教训告诉我们,部署后的性能基准测试同样重要。建议建立部署前后的性能对比机制,确保每次变更都不会导致性能退化。