# 🚀 部署指南

> 版本: 1.0
> 更新时间: 2026-03-04

## 📋 目录

1. [环境要求](#环境要求)
2. [快速部署](#快速部署)
3. [生产环境部署](#生产环境部署)
4. [Docker部署](#docker部署)
5. [数据库迁移](#数据库迁移)
6. [监控与日志](#监控与日志)
7. [故障排查](#故障排查)

## 🔧 环境要求

### 最低要求

| 组件 | 版本要求 | 说明 |
|------|----------|------|
| Java | 17+ | 推荐使用OpenJDK 17或21 |
| PostgreSQL | 12+ | 推荐使用14或15 |
| Redis | 6.0+ | 生产环境必需 |
| Maven | 3.8+ | 构建工具 |
| 内存 | 2GB+ | 推荐4GB |
| 磁盘 | 10GB+ | 包含日志和数据 |

### 推荐配置

**开发环境：**
- CPU: 2核
- 内存: 4GB
- 磁盘: 20GB SSD

**生产环境：**
- CPU: 4核+
- 内存: 8GB+
- 磁盘: 50GB+ SSD
- 负载均衡器（可选）
- 数据库主从复制（推荐）

## ⚡ 快速部署

### 1. 克隆代码

```bash
git clone https://github.com/your-org/mosquito.git
cd mosquito
```

### 2. 配置数据库

```bash
# 创建数据库
psql -U postgres -c "CREATE DATABASE mosquito;"
psql -U postgres -c "CREATE USER mosquito_user WITH PASSWORD 'your_password';"
psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE mosquito TO mosquito_user;"
```

### 3. 配置环境变量

```bash
# 复制配置模板
cp src/main/resources/application-dev.yml.example src/main/resources/application-dev.yml

# 编辑配置文件
vi src/main/resources/application-dev.yml
```

### 4. 构建项目

```bash
# 跳过测试快速构建
mvn clean package -DskipTests

# 或者运行完整测试
mvn clean package
```

### 5. 启动应用

```bash
java -jar target/mosquito-1.0.0.jar --spring.profiles.active=dev
```

应用将在 `http://localhost:8080` 启动。

## 🏭 生产环境部署

### 1. 准备工作

**创建专用用户：**

```bash
sudo useradd -r -s /bin/false mosquito
sudo mkdir -p /opt/mosquito
sudo chown mosquito:mosquito /opt/mosquito
```

**配置PostgreSQL：**

```sql
-- 创建生产数据库
CREATE DATABASE mosquito_prod;
CREATE USER mosquito_prod WITH PASSWORD 'strong_password_here';
GRANT ALL PRIVILEGES ON DATABASE mosquito_prod TO mosquito_prod;

-- 配置连接池
ALTER SYSTEM SET max_connections = 200;
ALTER SYSTEM SET shared_buffers = '2GB';
ALTER SYSTEM SET effective_cache_size = '6GB';
SELECT pg_reload_conf();
```

**配置Redis：**

```bash
# 编辑Redis配置
sudo vi /etc/redis/redis.conf

# 设置密码
requirepass your_redis_password

# 设置最大内存
maxmemory 1gb
maxmemory-policy allkeys-lru

# 启用持久化
save 900 1
save 300 10
save 60 10000

# 重启Redis
sudo systemctl restart redis
```

### 2. 配置应用

创建 `/opt/mosquito/application-prod.yml`：

```yaml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mosquito_prod
    username: mosquito_prod
    password: ${DB_PASSWORD}
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000

  data:
    redis:
      host: localhost
      port: 6379
      password: ${REDIS_PASSWORD}
      lettuce:
        pool:
          max-active: 20
          max-idle: 10
          min-idle: 5

  flyway:
    enabled: true
    baseline-on-migrate: true

app:
  api-key:
    encryption-key: ${API_KEY_ENCRYPTION_KEY}
  rate-limit:
    per-minute: 100
  poster:
    cache-enabled: true

logging:
  level:
    root: INFO
    com.mosquito.project: INFO
  file:
    name: /var/log/mosquito/application.log
    max-size: 100MB
    max-history: 30
```

### 3. 创建systemd服务

创建 `/etc/systemd/system/mosquito.service`：

```ini
[Unit]
Description=Mosquito Activity Tracking Service
After=network.target postgresql.service redis.service

[Service]
Type=simple
User=mosquito
Group=mosquito
WorkingDirectory=/opt/mosquito

Environment="JAVA_OPTS=-Xms2g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
Environment="DB_PASSWORD=your_db_password"
Environment="REDIS_PASSWORD=your_redis_password"
Environment="API_KEY_ENCRYPTION_KEY=your_32_char_encryption_key"

ExecStart=/usr/bin/java $JAVA_OPTS \
  -jar /opt/mosquito/mosquito-1.0.0.jar \
  --spring.profiles.active=prod \
  --spring.config.location=/opt/mosquito/application-prod.yml

Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
```

### 4. 部署应用

```bash
# 复制JAR文件
sudo cp target/mosquito-1.0.0.jar /opt/mosquito/
sudo chown mosquito:mosquito /opt/mosquito/mosquito-1.0.0.jar

# 创建日志目录
sudo mkdir -p /var/log/mosquito
sudo chown mosquito:mosquito /var/log/mosquito

# 重新加载systemd
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start mosquito

# 设置开机自启
sudo systemctl enable mosquito

# 检查状态
sudo systemctl status mosquito
```

### 5. 配置Nginx反向代理

创建 `/etc/nginx/sites-available/mosquito`：

```nginx
upstream mosquito_backend {
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

server {
    listen 80;
    server_name api.example.com;

    # 重定向到HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    access_log /var/log/nginx/mosquito_access.log;
    error_log /var/log/nginx/mosquito_error.log;

    client_max_body_size 10M;

    location / {
        proxy_pass http://mosquito_backend;
        proxy_http_version 1.1;

        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_set_header Connection "";

        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;

        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }

    location /actuator/health {
        proxy_pass http://mosquito_backend;
        access_log off;
    }
}
```

启用配置：

```bash
sudo ln -s /etc/nginx/sites-available/mosquito /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```

## 🐳 Docker部署

### 1. Dockerfile

创建 `Dockerfile`：

```dockerfile
FROM eclipse-temurin:17-jre-alpine

LABEL maintainer="your-email@example.com"
LABEL version="1.0.0"

# 创建应用目录
WORKDIR /app

# 复制JAR文件
COPY target/mosquito-1.0.0.jar app.jar

# 创建非root用户
RUN addgroup -S mosquito && adduser -S mosquito -G mosquito
RUN chown -R mosquito:mosquito /app
USER mosquito

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1

# 暴露端口
EXPOSE 8080

# JVM参数
ENV JAVA_OPTS="-Xms512m -Xmx1g -XX:+UseG1GC"

# 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
```

### 2. Docker Compose

创建 `docker-compose.yml`：

```yaml
version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    container_name: mosquito-postgres
    environment:
      POSTGRES_DB: mosquito
      POSTGRES_USER: mosquito
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mosquito"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: mosquito-redis
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

  app:
    build: .
    container_name: mosquito-app
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      SPRING_PROFILES_ACTIVE: prod
      SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/mosquito
      SPRING_DATASOURCE_USERNAME: mosquito
      SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
      SPRING_DATA_REDIS_HOST: redis
      SPRING_DATA_REDIS_PASSWORD: ${REDIS_PASSWORD}
      API_KEY_ENCRYPTION_KEY: ${API_KEY_ENCRYPTION_KEY}
    ports:
      - "8080:8080"
    volumes:
      - app_logs:/app/logs
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:
  app_logs:
```

### 3. 启动Docker环境

```bash
# 创建.env文件
cat > .env << EOF
DB_PASSWORD=your_db_password
REDIS_PASSWORD=your_redis_password
API_KEY_ENCRYPTION_KEY=your_32_char_encryption_key
EOF

# 构建镜像
docker-compose build

# 启动服务
docker-compose up -d

# 查看日志
docker-compose logs -f app

# 检查状态
docker-compose ps
```

## 🗄️ 数据库迁移

### Flyway自动迁移

应用启动时会自动执行Flyway迁移：

```yaml
spring:
  flyway:
    enabled: true
    baseline-on-migrate: true
    locations: classpath:db/migration
```

### 手动迁移

```bash
# 查看迁移状态
mvn flyway:info

# 执行迁移
mvn flyway:migrate

# 回滚（需要Flyway Pro）
mvn flyway:undo
```

### 迁移脚本位置

```
src/main/resources/db/migration/
├── V1__Create_activities_table.sql
├── V2__Create_api_keys_table.sql
├── V3__Create_daily_activity_stats_table.sql
├── ...
└── V20__Add_share_tracking_fields.sql
```

### 生产环境迁移最佳实践

1. **备份数据库**

```bash
pg_dump -U mosquito_prod -h localhost mosquito_prod > backup_$(date +%Y%m%d_%H%M%S).sql
```

2. **在测试环境验证**

```bash
# 恢复到测试环境
psql -U mosquito_test -h localhost mosquito_test < backup.sql

# 运行迁移
mvn flyway:migrate -Dflyway.url=jdbc:postgresql://localhost:5432/mosquito_test
```

3. **执行生产迁移**

```bash
# 停止应用（可选，取决于迁移类型）
sudo systemctl stop mosquito

# 执行迁移
mvn flyway:migrate -Dflyway.url=jdbc:postgresql://localhost:5432/mosquito_prod

# 启动应用
sudo systemctl start mosquito
```

## 📊 监控与日志

### Spring Boot Actuator

启用健康检查和指标：

```yaml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: when-authorized
```

访问端点：
- 健康检查: `http://localhost:8080/actuator/health`
- 指标: `http://localhost:8080/actuator/metrics`
- Prometheus: `http://localhost:8080/actuator/prometheus`

### 日志配置

`logback-spring.xml`：

```xml
<configuration>
    <springProfile name="prod">
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>/var/log/mosquito/application.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>/var/log/mosquito/application.%d{yyyy-MM-dd}.log</fileNamePattern>
                <maxHistory>30</maxHistory>
                <totalSizeCap>10GB</totalSizeCap>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>

        <root level="INFO">
            <appender-ref ref="FILE" />
        </root>
    </springProfile>
</configuration>
```

### 监控工具集成

**Prometheus + Grafana：**

```yaml
# prometheus.yml
scrape_configs:
  - job_name: 'mosquito'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']
```

## 🔍 故障排查

### 常见问题

**1. 应用无法启动**

```bash
# 检查日志
sudo journalctl -u mosquito -n 100 --no-pager

# 检查端口占用
sudo netstat -tlnp | grep 8080

# 检查数据库连接
psql -U mosquito_prod -h localhost -d mosquito_prod -c "SELECT 1;"
```

**2. Redis连接失败**

```bash
# 检查Redis状态
sudo systemctl status redis

# 测试连接
redis-cli -a your_redis_password ping

# 检查配置
redis-cli -a your_redis_password CONFIG GET requirepass
```

**3. 数据库迁移失败**

```bash
# 查看Flyway状态
mvn flyway:info

# 修复失败的迁移
mvn flyway:repair

# 手动执行SQL
psql -U mosquito_prod -h localhost -d mosquito_prod -f src/main/resources/db/migration/V20__xxx.sql
```

**4. 内存不足**

```bash
# 查看JVM内存使用
jcmd <pid> VM.native_memory summary

# 调整JVM参数
sudo vi /etc/systemd/system/mosquito.service
# 修改: Environment="JAVA_OPTS=-Xms2g -Xmx4g"

sudo systemctl daemon-reload
sudo systemctl restart mosquito
```

### 性能调优

**JVM参数优化：**

```bash
JAVA_OPTS="
  -Xms2g -Xmx4g
  -XX:+UseG1GC
  -XX:MaxGCPauseMillis=200
  -XX:+HeapDumpOnOutOfMemoryError
  -XX:HeapDumpPath=/var/log/mosquito/heapdump.hprof
  -XX:+PrintGCDetails
  -XX:+PrintGCDateStamps
  -Xloggc:/var/log/mosquito/gc.log
"
```

**数据库连接池：**

```yaml
spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
```

## 📚 相关资源

- [配置指南](./CONFIGURATION_GUIDE.md) - 详细配置说明
- [API文档](./api.md) - API接口文档
- [开发指南](./DEVELOPMENT_GUIDE.md) - 开发环境搭建

---

**文档版本**: 1.0
**最后更新**: 2026-03-04
