Files
algorithm/多独立服务管理实施方案.md

1775 lines
63 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 多独立 AI 算法服务管理实施方案
## 1. 方案概述
本方案旨在解决多 AI 算法服务的端口冲突、统一启停/监控、配置管理和运维效率问题,同时保持每个服务的独立性,避免单个服务故障影响其他服务。方案支持两种部署方式:无 Docker 的实现方式(使用 Supervisor和 Docker 容器化实现方式,通过「标准化 + 统一管理」的方法,实现多服务的高效管理。
本方案专门为 AI 算法工程展示平台设计,支持从代码上传、服务部署到算法能力展示的完整流程,满足用户对算法工程管理和展示的核心需求。
### 1.1 核心诉求
- **端口冲突**:为每个服务分配唯一端口,避免冲突
- **统一管理**:批量管理所有服务的启停、监控、自动重启
- **配置管理**:集中化管理公共配置,保留服务独立配置,包括 Gitea 访问配置
- **运维效率**:降低运维成本,提高服务可靠性
- **服务独立性**:单个服务故障不影响其他服务
- **代码管理**:集成 Gitea 进行代码管理和部署,支持算法工程代码上传
- **服务部署**:自动部署算法工程为 API 服务
- **算法展示**:支持使用演示数据和视频执行算法,展示算法能力
- **效果对比**:支持对比不同算法或参数的效果
### 1.2 技术栈
- **服务运行**Python/Node.js + FastAPI/HTTP Server
- **统一管理**Supervisor
- **可选**NginxAPI 网关)
- **监控**:服务健康检查 + 日志管理
- **数据库**PostgreSQL
- **缓存**Redis
- **对象存储**MinIO
- **代码管理**Gitea
- **前端**Vue 3 + TypeScript + Vite + Element Plus
- **后端**FastAPI
### 1.3 网站用途与工作流程
本网站的核心用途是展示和管理多个 AI 算法工程,通过以下三个步骤实现:
**第一步:代码管理**
- 上传 AI 算法工程代码到平台
- 将代码管理在 Gitea 仓库中
- Gitea 访问配置保存在数据库中,确保配置持久化
**第二步:服务部署与管理**
- 部署上传的算法工程为可访问的 API 服务
- 支持多服务的统一管理(启动、停止、重启)
- 生成标准化的 API 接口
- 监控服务健康状态和运行情况
**第三步:算法能力展示**
- 使用演示数据和视频等输入执行算法
- 可视化展示算法执行结果
- 对比不同算法或参数的效果
- 向客户展示 AI 算法的能力和价值
## 2. 项目架构分析
### 2.1 系统架构
```
┌─────────────────────────────────────────────────────────┐
│ 前端层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Vue 3 │ │ TypeScript │ │ Element Plus│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 后端层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ FastAPI │ │ Service │ │ Gitea │ │
│ │ │ │ Orchestrator│ │ Integration │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 服务层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Service-1 │ │ Service-2 │ │ Service-3 │ │
│ │ 端口: 8001 │ │ 端口: 8002 │ │ 端口: 8003 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 存储层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PostgreSQL │ │ Redis │ │ MinIO │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### 2.2 现有系统功能
- ✅ 服务部署(支持 Docker 和本地进程)
- ✅ 服务启动/停止/重启/删除
- ✅ 服务状态查询
- ✅ 服务日志获取
- ✅ 服务健康检查
- ✅ Gitea 集成(代码管理和部署)
- ✅ 数据库配置管理
- ✅ 前端管理界面
### 2.3 现有实现的优缺点
**优点**
- 支持两种部署模式,灵活性高
- 提供完整的服务生命周期管理
- 实现了服务健康检查和日志管理
- 集成了 Gitea 进行代码管理和部署
- 支持数据库配置管理
- 提供了完整的前端管理界面
**缺点**
- 本地进程模式下,服务管理依赖于 `ServiceOrchestrator` 进程,进程退出后无法自动管理服务
- 缺乏批量管理能力,每次操作需要单独处理每个服务
- 服务配置分散,缺乏集中化管理
- 端口管理依赖手动配置,容易冲突
## 3. 方案设计
### 3.1 整体架构
```
┌─────────────────────────────────────────────────────────┐
│ 管理层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Supervisor │ │ Nginx │ │ 配置管理 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 服务层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Service-1 │ │ Service-2 │ │ Service-3 │ │
│ │ 端口: 8001 │ │ 端口: 8002 │ │ 端口: 8003 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 基础设施层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 操作系统 │ │ 网络 │ │ 文件系统 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### 3.2 核心设计原则
1. **服务标准化**:统一目录结构、接口规范、启动方式
2. **端口独占规划**:为每个服务分配唯一端口
3. **统一管理工具**:使用 Supervisor 批量管理服务
4. **配置集中化**:抽离公共配置,保留独立配置
5. **服务独立性**:每个服务独立运行,独立管理
6. **代码管理集成**:通过 Gitea 管理服务代码和部署
## 4. 分步实现
### 4.1 第一步:数据库配置管理
#### 4.1.1 配置存储架构
为了支持在界面上配置并存储到数据库中,我们需要设计一个统一的配置管理架构:
```
┌─────────────────────────────────────────────────────────┐
│ 配置管理架构 │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 前端配置界面 │ │ 配置API层 │ │ 配置服务层 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 配置数据库 │ │ 缓存层 │ │ 配置文件 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
```
#### 4.1.2 配置数据库模型
创建统一的配置存储模型:
```python
# backend/app/models/models.py
class ServiceConfig(Base):
"""服务配置模型"""
__tablename__ = "service_configs"
id = Column(String, primary_key=True, index=True)
config_key = Column(String, nullable=False, unique=True, index=True) # 配置键
config_value = Column(JSON, nullable=False) # 配置值JSON格式
config_type = Column(String, nullable=False) # 配置类型system, service, user
service_id = Column(String, nullable=True, index=True) # 服务ID可为空系统配置
description = Column(Text, default="") # 配置描述
status = Column(String, default="active") # 状态
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
```
#### 4.1.3 配置服务实现
```python
# backend/app/services/config_service.py
class ConfigService:
"""配置服务"""
@staticmethod
def get_config(db: Session, config_key: str) -> Optional[Dict[str, Any]]:
"""获取配置"""
config = db.query(ServiceConfig).filter_by(
config_key=config_key,
status="active"
).first()
if config:
return config.config_value
return None
@staticmethod
def set_config(db: Session, config_key: str, config_value: Dict[str, Any],
config_type: str = "system", service_id: Optional[str] = None,
description: str = "") -> bool:
"""设置配置"""
try:
# 检查是否存在
existing_config = db.query(ServiceConfig).filter_by(
config_key=config_key
).first()
if existing_config:
# 更新现有配置
existing_config.config_value = config_value
existing_config.config_type = config_type
existing_config.service_id = service_id
existing_config.description = description
existing_config.status = "active"
else:
# 创建新配置
new_config = ServiceConfig(
id=f"config-{uuid.uuid4()}",
config_key=config_key,
config_value=config_value,
config_type=config_type,
service_id=service_id,
description=description,
status="active"
)
db.add(new_config)
db.commit()
return True
except Exception as e:
logger.error(f"Failed to set config: {str(e)}")
db.rollback()
return False
@staticmethod
def get_service_configs(db: Session, service_id: str) -> List[Dict[str, Any]]:
"""获取服务的所有配置"""
configs = db.query(ServiceConfig).filter_by(
service_id=service_id,
status="active"
).all()
return [
{
"key": config.config_key,
"value": config.config_value,
"type": config.config_type,
"description": config.description
}
for config in configs
]
```
#### 4.1.4 配置API接口
```python
# backend/app/routes/config.py
router = APIRouter(prefix="/config", tags=["config"])
@router.get("/{config_key}")
async def get_config(
config_key: str,
db: Session = Depends(get_db),
current_user: dict = Depends(get_current_active_user)
):
"""获取配置"""
config = ConfigService.get_config(db, config_key)
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
return {"key": config_key, "value": config}
@router.post("/{config_key}")
async def set_config(
config_key: str,
config_data: Dict[str, Any],
db: Session = Depends(get_db),
current_user: dict = Depends(get_current_active_user)
):
"""设置配置"""
success = ConfigService.set_config(
db=db,
config_key=config_key,
config_value=config_data.get("value"),
config_type=config_data.get("type", "system"),
service_id=config_data.get("service_id"),
description=config_data.get("description", "")
)
if not success:
raise HTTPException(status_code=400, detail="设置配置失败")
return {"message": "设置配置成功"}
@router.get("/service/{service_id}")
async def get_service_configs(
service_id: str,
db: Session = Depends(get_db),
current_user: dict = Depends(get_current_active_user)
):
"""获取服务配置"""
configs = ConfigService.get_service_configs(db, service_id)
return {"service_id": service_id, "configs": configs}
```
#### 4.1.5 前端配置界面
```vue
<!-- 前端配置管理组件 -->
<template>
<div class="admin-config-container">
<!-- 页面标题 -->
<h1>配置管理</h1>
<!-- 操作栏 -->
<div class="action-bar">
<el-button type="primary" @click="refreshConfigs">
<el-icon><Refresh /></el-icon>
刷新配置
</el-button>
</div>
<!-- 系统配置 -->
<el-card class="mb-4">
<template #header>
<div class="card-header">
<span>系统配置</span>
</div>
</template>
<el-form :model="systemConfigForm" label-width="120px">
<el-form-item label="部署模式">
<el-select v-model="systemConfigForm.deploymentMode" placeholder="选择部署模式">
<el-option label="本地进程" value="local"></el-option>
<el-option label="Docker" value="docker"></el-option>
<el-option label="Supervisor" value="supervisor"></el-option>
</el-select>
</el-form-item>
<el-form-item label="服务根目录">
<el-input v-model="systemConfigForm.serviceRootDir" placeholder="服务根目录"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveSystemConfig">保存配置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 服务配置 -->
<el-card>
<template #header>
<div class="card-header">
<span>服务配置</span>
<el-select v-model="selectedServiceId" placeholder="选择服务">
<el-option
v-for="service in services"
:key="service.id"
:label="service.name"
:value="service.id"
></el-option>
</el-select>
</div>
</template>
<el-form v-if="selectedServiceId" :model="serviceConfigForm" label-width="120px">
<el-form-item label="服务端口">
<el-input-number v-model="serviceConfigForm.port" :min="1000" :max="65535"></el-input-number>
</el-form-item>
<el-form-item label="服务主机">
<el-input v-model="serviceConfigForm.host" placeholder="服务主机"></el-input>
</el-form-item>
<el-form-item label="超时时间">
<el-input-number v-model="serviceConfigForm.timeout" :min="1" :max="300"></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveServiceConfig">保存配置</el-button>
</el-form-item>
</el-form>
<div v-else class="text-center text-gray-400 py-4">
请选择一个服务
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { Refresh } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import axios from 'axios'
// 状态管理
const services = ref<any[]>([])
const selectedServiceId = ref('')
// 系统配置表单
const systemConfigForm = ref({
deploymentMode: 'local',
serviceRootDir: '/opt/ai-services'
})
// 服务配置表单
const serviceConfigForm = ref({
port: 8001,
host: '0.0.0.0',
timeout: 30
})
// 加载服务列表
const loadServices = async () => {
try {
const token = localStorage.getItem('token')
if (!token) {
ElMessage.error('未登录,请重新登录')
return
}
const response = await fetch('http://0.0.0.0:8001/api/v1/services', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
})
if (!response.ok) {
throw new Error('获取服务列表失败')
}
const data = await response.json()
if (data.success) {
services.value = data.services
}
} catch (error) {
console.error('加载服务列表失败:', error)
ElMessage.error('加载服务列表失败')
}
}
// 加载系统配置
const loadSystemConfig = async () => {
try {
const token = localStorage.getItem('token')
if (!token) {
ElMessage.error('未登录,请重新登录')
return
}
const response = await fetch('http://0.0.0.0:8001/api/v1/config/deployment.mode', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
})
if (response.ok) {
const data = await response.json()
if (data.value) {
systemConfigForm.value.deploymentMode = data.value
}
}
const response2 = await fetch('http://0.0.0.0:8001/api/v1/config/service.root.dir', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
})
if (response2.ok) {
const data = await response2.json()
if (data.value) {
systemConfigForm.value.serviceRootDir = data.value
}
}
} catch (error) {
console.log('系统配置不存在,使用默认值')
}
}
// 加载服务配置
const loadServiceConfig = async (serviceId: string) => {
if (!serviceId) return
try {
const token = localStorage.getItem('token')
if (!token) {
ElMessage.error('未登录,请重新登录')
return
}
const response = await fetch(`http://0.0.0.0:8001/api/v1/config/service/${serviceId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
})
if (response.ok) {
const data = await response.json()
if (data.configs) {
const configs = data.configs
configs.forEach((config: any) => {
if (config.key === 'service.port') {
serviceConfigForm.value.port = config.value
} else if (config.key === 'service.host') {
serviceConfigForm.value.host = config.value
} else if (config.key === 'service.timeout') {
serviceConfigForm.value.timeout = config.value
}
})
}
}
} catch (error) {
console.error('加载服务配置失败:', error)
ElMessage.error('加载服务配置失败')
}
}
// 保存系统配置
const saveSystemConfig = async () => {
try {
const token = localStorage.getItem('token')
if (!token) {
ElMessage.error('未登录,请重新登录')
return
}
await fetch('http://0.0.0.0:8001/api/v1/config/deployment.mode', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
value: systemConfigForm.value.deploymentMode,
type: 'system',
description: '部署模式'
})
})
await fetch('http://0.0.0.0:8001/api/v1/config/service.root.dir', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
value: systemConfigForm.value.serviceRootDir,
type: 'system',
description: '服务根目录'
})
})
ElMessage.success('保存系统配置成功')
} catch (error) {
console.error('保存系统配置失败:', error)
ElMessage.error('保存系统配置失败')
}
}
// 保存服务配置
const saveServiceConfig = async () => {
if (!selectedServiceId.value) return
try {
const token = localStorage.getItem('token')
if (!token) {
ElMessage.error('未登录,请重新登录')
return
}
await fetch('http://0.0.0.0:8001/api/v1/config/service.port', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
value: serviceConfigForm.value.port,
type: 'service',
service_id: selectedServiceId.value,
description: '服务端口'
})
})
await fetch('http://0.0.0.0:8001/api/v1/config/service.host', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
value: serviceConfigForm.value.host,
type: 'service',
service_id: selectedServiceId.value,
description: '服务主机'
})
})
await fetch('http://0.0.0.0:8001/api/v1/config/service.timeout', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
value: serviceConfigForm.value.timeout,
type: 'service',
service_id: selectedServiceId.value,
description: '服务超时时间'
})
})
ElMessage.success('保存服务配置成功')
} catch (error) {
console.error('保存服务配置失败:', error)
ElMessage.error('保存服务配置失败')
}
}
// 刷新配置
const refreshConfigs = async () => {
await loadSystemConfig()
if (selectedServiceId.value) {
await loadServiceConfig(selectedServiceId.value)
}
ElMessage.success('配置已刷新')
}
// 监听服务选择变化
const handleServiceChange = () => {
loadServiceConfig(selectedServiceId.value)
}
// 初始化
onMounted(() => {
loadServices()
loadSystemConfig()
})
</script>
<style scoped>
.admin-config-container {
padding: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.mb-4 {
margin-bottom: 20px;
}
</style>
```
### 4.2 第二步:多服务目录标准化
#### 4.2.1 统一服务根目录
```plaintext
/opt/ai-services/ # 所有AI服务的根目录
├── config/ # 全局配置
│ ├── common.py # 公共配置
│ └── ports.py # 端口分配配置
├── logs/ # 所有服务的日志总目录
│ ├── service-1.log
│ ├── service-2.log
│ └── service-3.log
├── service-1/ # 服务1如文本分类
│ ├── ai_algorithm.py # 服务1的AI算法逻辑
│ ├── main.py # 服务1的FastAPI接口
│ ├── requirements.txt # 服务1的依赖
│ ├── config.py # 服务1的独立配置
│ └── venv/ # 服务1的虚拟环境
├── service-2/ # 服务2如图像识别
│ ├── ai_algorithm.py
│ ├── main.py
│ ├── requirements.txt
│ ├── config.py
│ └── venv/
└── service-3/ # 服务3如语音转文字
├── ...
```
#### 4.2.2 统一接口规范
所有服务必须实现以下接口:
- `POST /predict`:算法预测接口
- `GET /health`:健康检查接口
- `GET /info`:服务信息接口
#### 4.2.3 统一启动方式
所有服务使用统一的启动脚本:
```bash
# /opt/ai-services/service-1/start.sh
#!/bin/bash
cd /opt/ai-services/service-1
source venv/bin/activate
python main.py
```
### 4.3 第三步:使用 Supervisor 统一管理服务
#### 4.3.1 安装 Supervisor
```bash
# Ubuntu/Debian
apt update && apt install supervisor
# CentOS/RHEL
yum install epel-release
yum install supervisor
# 启动 Supervisor 服务
systemctl start supervisor
systemctl enable supervisor
```
#### 4.3.2 配置 Supervisor
创建统一的配置文件:
```ini
# /etc/supervisor/conf.d/ai-services.conf
[supervisord]
logfile=/opt/ai-services/logs/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/var/run/supervisord.pid
nodaemon=false
minfds=1024
minprocs=200
# 服务1文本分类8001端口
[program:ai-service-1]
name=ai-service-1
command=/opt/ai-services/service-1/start.sh
directory=/opt/ai-services/service-1
user=ubuntu
autostart=true
autorestart=true
startretries=3
stdout_logfile=/opt/ai-services/logs/service-1.log
stderr_logfile=/opt/ai-services/logs/service-1_error.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
# 服务2图像识别8002端口
[program:ai-service-2]
name=ai-service-2
command=/opt/ai-services/service-2/start.sh
directory=/opt/ai-services/service-2
user=ubuntu
autostart=true
autorestart=true
startretries=3
stdout_logfile=/opt/ai-services/logs/service-2.log
stderr_logfile=/opt/ai-services/logs/service-2_error.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
# 服务3语音转文字8003端口
[program:ai-service-3]
name=ai-service-3
command=/opt/ai-services/service-3/start.sh
directory=/opt/ai-services/service-3
user=ubuntu
autostart=true
autorestart=true
startretries=3
stdout_logfile=/opt/ai-services/logs/service-3.log
stderr_logfile=/opt/ai-services/logs/service-3_error.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
```
#### 4.3.3 Supervisor 管理命令
```bash
# 重新加载配置(新增/修改服务后执行)
supervisorctl reload
# 启动所有AI服务
supervisorctl start ai-service-*
# 启动单个服务
supervisorctl start ai-service-1
# 查看所有服务状态
supervisorctl status
# 输出示例:
# ai-service-1 RUNNING pid 1234, uptime 0:05:10
# ai-service-2 RUNNING pid 1235, uptime 0:05:08
# ai-service-3 RUNNING pid 1236, uptime 0:05:05
# 重启所有服务
supervisorctl restart ai-service-*
# 停止单个服务
supervisorctl stop ai-service-2
# 查看某个服务的日志(快速排查问题)
supervisorctl tail -f ai-service-1
```
### 4.4 第四步:配置集中化管理
#### 4.4.1 配置管理架构
采用三层配置管理架构:
1. **数据库配置**:存储在数据库中的动态配置,支持界面修改
2. **文件配置**:存储在文件中的静态配置,作为默认值
3. **环境变量**:优先级最高,用于覆盖其他配置
#### 4.4.2 配置加载流程
```python
# backend/app/config/settings.py
from pydantic_settings import BaseSettings
from typing import Optional, Dict, Any
from sqlalchemy.orm import Session
from app.models.database import SessionLocal
from app.models.models import ServiceConfig
class Settings(BaseSettings):
"""应用配置类"""
# 应用基本配置
APP_NAME: str = "智能算法展示平台"
APP_VERSION: str = "1.0.0"
DEBUG: bool = True
# 数据库配置
DATABASE_URL: str = "postgresql://admin:password@localhost:5432/algorithm_db"
# 其他配置...
# 服务管理配置
SERVICE_MANAGEMENT: Dict[str, Any] = {
"mode": "supervisor", # 服务管理模式local, docker, supervisor
"service_root_dir": "/opt/ai-services",
"supervisor_config_dir": "/etc/supervisor/conf.d",
}
class Config:
env_file = ".env"
case_sensitive = True
extra = "allow" # 允许额外的环境变量
def get_config(self, config_key: str, default: Any = None) -> Any:
"""获取配置,优先级:环境变量 > 数据库 > 文件默认值"""
# 1. 先从环境变量获取
env_value = getattr(self, config_key.upper().replace('.', '_'), None)
if env_value is not None:
return env_value
# 2. 从数据库获取
db: Session = SessionLocal()
try:
config = db.query(ServiceConfig).filter_by(
config_key=config_key,
status="active"
).first()
if config:
return config.config_value
finally:
db.close()
# 3. 返回默认值
return default
# 创建全局配置实例
settings = Settings()
```
#### 4.4.3 配置服务集成
```python
# backend/app/services/service_orchestrator.py
class ServiceOrchestrator:
"""服务编排服务"""
def __init__(self, deployment_mode="local"):
"""初始化服务编排器
Args:
deployment_mode: 部署模式,支持"docker"、"local"和"supervisor"
"""
# 从数据库获取配置
self.deployment_mode = settings.get_config("deployment.mode", deployment_mode)
self.service_root_dir = settings.get_config("service.root.dir", "/opt/ai-services")
# 其他初始化代码...
def _get_service_config(self, service_id: str) -> Dict[str, Any]:
"""获取服务配置"""
# 基础配置
base_config = {
"host": "0.0.0.0",
"port": self._get_service_port(service_id),
"timeout": 30,
"health_check_interval": 10,
}
# 从数据库获取服务特定配置
db: Session = SessionLocal()
try:
configs = db.query(ServiceConfig).filter_by(
service_id=service_id,
status="active"
).all()
for config in configs:
# 解析配置键,设置到相应的位置
if config.config_key == "service.port":
base_config["port"] = config.config_value
elif config.config_key == "service.host":
base_config["host"] = config.config_value
elif config.config_key == "service.timeout":
base_config["timeout"] = config.config_value
finally:
db.close()
return base_config
```
#### 4.4.4 配置管理最佳实践
1. **配置分类**
- `system`:系统级配置,影响所有服务
- `service`:服务级配置,仅影响特定服务
- `user`:用户级配置,与用户偏好相关
2. **配置命名规范**
- 使用点分隔的命名方式:`category.subcategory.setting`
- 示例:`service.port`, `deployment.mode`, `logging.level`
3. **配置版本管理**
- 保留配置的历史版本
- 支持配置回滚
- 记录配置修改日志
4. **配置验证**
- 对配置值进行类型检查
- 对配置值进行范围验证
- 确保配置的完整性
5. **配置安全**
- 敏感配置加密存储
- 配置访问权限控制
- 配置变更审计
### 4.5 第五步:可选优化 - 统一 API 网关
#### 4.5.1 安装 Nginx
```bash
# Ubuntu/Debian
apt update && apt install nginx
# CentOS/RHEL
yum install nginx
# 启动 Nginx 服务
systemctl start nginx
systemctl enable nginx
```
#### 4.5.2 配置 Nginx 反向代理
```nginx
# /etc/nginx/conf.d/ai-services.conf
server {
listen 80;
server_name your-server-ip; # 替换为你的服务器IP/域名
# 服务1文本分类网关路径/ai/text-classify
location /ai/text-classify/ {
proxy_pass http://127.0.0.1:8001/;
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_connect_timeout 30s;
proxy_read_timeout 30s;
}
# 服务2图像识别网关路径/ai/image-recog
location /ai/image-recog/ {
proxy_pass http://127.0.0.1:8002/;
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_connect_timeout 30s;
proxy_read_timeout 30s;
}
# 服务3语音转文字网关路径/ai/speech-to-text
location /ai/speech-to-text/ {
proxy_pass http://127.0.0.1:8003/;
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_connect_timeout 30s;
proxy_read_timeout 30s;
}
}
```
#### 4.5.3 重启 Nginx 并测试
```bash
# 检查配置是否正确
nginx -t
# 重启Nginx
systemctl restart nginx
# 测试网关调用(无需记端口,只需记路径)
curl -X POST "http://your-server-ip/ai/text-classify/predict" \
-H "Content-Type: application/json" \
-d '{"input_data": ["这是一个测试文本"], "batch_id": "test_001"}'
```
## 5. 与现有系统集成
### 5.1 集成 ServiceOrchestrator
修改现有的 `ServiceOrchestrator` 类,使其支持 Supervisor 管理模式和数据库配置:
```python
# backend/app/services/service_orchestrator.py
class ServiceOrchestrator:
"""服务编排服务"""
def __init__(self, deployment_mode="local"):
"""初始化服务编排器
Args:
deployment_mode: 部署模式,支持"docker"、"local"和"supervisor"
"""
# 从数据库获取配置
self.deployment_mode = settings.get_config("deployment.mode", deployment_mode)
self.service_root_dir = settings.get_config("service.root.dir", "/opt/ai-services")
# 其他初始化代码...
def deploy_service(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any]) -> Dict[str, Any]:
"""部署服务"""
try:
if self.deployment_mode == "supervisor":
# 使用 Supervisor 部署服务
return self._deploy_with_supervisor(service_id, service_config, project_info)
# 其他部署模式...
except Exception as e:
# 错误处理...
def _deploy_with_supervisor(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any]) -> Dict[str, Any]:
"""使用 Supervisor 部署服务"""
# 1. 创建服务目录
service_dir = self._create_service_directory(service_id)
# 2. 生成服务配置和启动脚本
self._generate_service_config(service_dir, service_id, service_config)
self._generate_start_script(service_dir, service_id)
# 3. 创建 Supervisor 配置
self._create_supervisor_config(service_id, service_dir, service_config)
# 4. 重新加载 Supervisor 配置
self._reload_supervisor()
# 5. 启动服务
self._start_supervisor_service(service_id)
# 6. 验证服务启动
if not self._verify_service_startup(service_id, service_config):
return {
"success": False,
"error": "服务启动验证失败",
"service_id": service_id,
"status": "error",
"api_url": None
}
# 7. 构建 API URL
api_url = f"http://{service_config.get('host', 'localhost')}:{service_config.get('port', 8000)}"
# 8. 保存服务配置到数据库
self._save_service_config_to_db(service_id, service_config)
return {
"success": True,
"service_id": service_id,
"status": "running",
"api_url": api_url,
"error": None
}
def _save_service_config_to_db(self, service_id: str, service_config: Dict[str, Any]):
"""保存服务配置到数据库"""
db = SessionLocal()
try:
# 保存服务端口
ConfigService.set_config(
db=db,
config_key="service.port",
config_value=service_config.get("port"),
config_type="service",
service_id=service_id,
description="服务端口"
)
# 保存服务主机
ConfigService.set_config(
db=db,
config_key="service.host",
config_value=service_config.get("host", "0.0.0.0"),
config_type="service",
service_id=service_id,
description="服务主机"
)
# 保存服务超时
ConfigService.set_config(
db=db,
config_key="service.timeout",
config_value=service_config.get("timeout", 30),
config_type="service",
service_id=service_id,
description="服务超时时间"
)
finally:
db.close()
# 其他方法...
```
### 5.2 集成配置管理
修改现有配置管理,使用数据库存储配置:
```python
# backend/app/config/settings.py
from pydantic_settings import BaseSettings
from typing import Optional, Dict, Any
from sqlalchemy.orm import Session
from app.models.database import SessionLocal
from app.models.models import ServiceConfig
class Settings(BaseSettings):
"""应用配置类"""
# 应用基本配置
APP_NAME: str = "智能算法展示平台"
APP_VERSION: str = "1.0.0"
DEBUG: bool = True
# 数据库配置
DATABASE_URL: str = "postgresql://admin:password@localhost:5432/algorithm_db"
# 其他配置...
# 服务管理配置
SERVICE_MANAGEMENT: Dict[str, Any] = {
"mode": "supervisor", # 服务管理模式local, docker, supervisor
"service_root_dir": "/opt/ai-services",
"supervisor_config_dir": "/etc/supervisor/conf.d",
}
class Config:
env_file = ".env"
case_sensitive = True
extra = "allow" # 允许额外的环境变量
def get_config(self, config_key: str, default: Any = None) -> Any:
"""获取配置,优先级:环境变量 > 数据库 > 文件默认值"""
# 1. 先从环境变量获取
env_value = getattr(self, config_key.upper().replace('.', '_'), None)
if env_value is not None:
return env_value
# 2. 从数据库获取
db: Session = SessionLocal()
try:
config = db.query(ServiceConfig).filter_by(
config_key=config_key,
status="active"
).first()
if config:
return config.config_value
finally:
db.close()
# 3. 返回默认值
return default
# 创建全局配置实例
settings = Settings()
```
### 5.3 集成服务状态查询
修改服务状态查询接口,支持 Supervisor 管理的服务:
```python
# backend/app/routes/services.py
@router.get("/status/{service_id}")
async def get_service_status(
service_id: str,
orchestrator: ServiceOrchestrator = Depends(get_orchestrator)
):
"""获取服务状态"""
try:
# 获取服务状态
status_info = orchestrator.get_service_status(service_id)
if not status_info["success"]:
raise HTTPException(status_code=404, detail=status_info.get("error", "服务不存在"))
return {
"service_id": service_id,
"status": status_info["status"],
"health": status_info["health"],
"message": "获取服务状态成功"
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
```
### 5.4 集成配置 API
添加配置管理 API 接口:
```python
# backend/app/routes/config.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import Dict, Any, List, Optional
from app.models.database import get_db
from app.services.config_service import ConfigService
from app.services.user import get_current_active_user
router = APIRouter(prefix="/config", tags=["config"])
@router.get("/{config_key}")
async def get_config(
config_key: str,
db: Session = Depends(get_db),
current_user: dict = Depends(get_current_active_user)
):
"""获取配置"""
config = ConfigService.get_config(db, config_key)
if not config:
raise HTTPException(status_code=404, detail="配置不存在")
return {"key": config_key, "value": config}
@router.post("/{config_key}")
async def set_config(
config_key: str,
config_data: Dict[str, Any],
db: Session = Depends(get_db),
current_user: dict = Depends(get_current_active_user)
):
"""设置配置"""
success = ConfigService.set_config(
db=db,
config_key=config_key,
config_value=config_data.get("value"),
config_type=config_data.get("type", "system"),
service_id=config_data.get("service_id"),
description=config_data.get("description", "")
)
if not success:
raise HTTPException(status_code=400, detail="设置配置失败")
return {"message": "设置配置成功"}
@router.get("/service/{service_id}")
async def get_service_configs(
service_id: str,
db: Session = Depends(get_db),
current_user: dict = Depends(get_current_active_user)
):
"""获取服务配置"""
configs = ConfigService.get_service_configs(db, service_id)
return {"service_id": service_id, "configs": configs}
```
## 6. Gitea 集成方案
### 6.1 Gitea 集成概述
针对所有工程都在 Gitea 上的场景,本方案提供了完整的 Gitea 集成能力,实现从代码仓库到服务部署的全流程管理。基于现有的 GiteaService 和 GiteaClient 实现,进一步完善了从代码管理到服务部署的自动化流程。
### 6.2 现有 Gitea 集成实现
当前系统已经实现了完整的 Gitea 集成功能:
- ✅ Gitea 连接配置管理
- ✅ 仓库创建、克隆、推送、拉取
- ✅ 代码上传(支持大文件处理)
- ✅ 从 Gitea 部署服务
- ✅ 错误处理和重试机制
- ✅ CI/CD 集成支持
### 6.3 Gitea 配置管理gitea_configs
#### 6.3.1 配置存储架构
系统使用 `gitea_configs` 表存储 Gitea 连接配置,实现了配置的持久化和版本管理:
```python
# backend/app/models/models.py
class GiteaConfig(Base):
"""Gitea配置模型"""
__tablename__ = "gitea_configs"
id = Column(String, primary_key=True, index=True)
server_url = Column(String, nullable=False) # Gitea服务器URL
access_token = Column(String, nullable=False) # 访问令牌
default_owner = Column(String, nullable=False) # 默认组织/用户
repo_prefix = Column(String, default="") # 仓库前缀
status = Column(String, default="active") # 状态
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
```
#### 6.3.2 配置管理实现
Gitea 配置管理通过 `GiteaService` 实现,支持配置的加载、保存和使用:
```python
# backend/app/gitea/service.py
class GiteaService:
def _load_config(self) -> Optional[Dict[str, Any]]:
"""加载Gitea配置"""
try:
db = SessionLocal()
# 从数据库中获取配置(只取第一个配置)
config = db.query(GiteaConfig).filter_by(status="active").first()
db.close()
if config:
return {
'id': config.id,
'server_url': config.server_url,
'access_token': config.access_token,
'default_owner': config.default_owner,
'repo_prefix': config.repo_prefix,
'status': config.status
}
# 配置不存在时返回默认值
return {
'server_url': getattr(settings, 'GITEA_SERVER_URL', ''),
'access_token': getattr(settings, 'GITEA_ACCESS_TOKEN', ''),
'default_owner': getattr(settings, 'GITEA_DEFAULT_OWNER', ''),
'repo_prefix': getattr(settings, 'GITEA_REPO_PREFIX', '')
}
except Exception as e:
logger.error(f"Failed to load Gitea config from database: {str(e)}")
# 出错时返回默认配置
return {
'server_url': getattr(settings, 'GITEA_SERVER_URL', ''),
'access_token': getattr(settings, 'GITEA_ACCESS_TOKEN', ''),
'default_owner': getattr(settings, 'GITEA_DEFAULT_OWNER', ''),
'repo_prefix': getattr(settings, 'GITEA_REPO_PREFIX', '')
}
def save_config(self, config: Dict[str, Any]) -> bool:
"""保存Gitea配置"""
try:
db = SessionLocal()
# 将所有现有配置设置为非活动状态
db.query(GiteaConfig).update({GiteaConfig.status: "inactive"})
# 检查是否已有配置
existing_config = db.query(GiteaConfig).first()
if existing_config:
# 更新现有配置
existing_config.server_url = config['server_url']
existing_config.access_token = config['access_token']
existing_config.default_owner = config['default_owner']
existing_config.repo_prefix = config.get('repo_prefix', '')
existing_config.status = "active"
else:
# 创建新配置
new_config = GiteaConfig(
id=f"gitea-config-{uuid.uuid4()}",
server_url=config['server_url'],
access_token=config['access_token'],
default_owner=config['default_owner'],
repo_prefix=config.get('repo_prefix', ''),
status="active"
)
db.add(new_config)
db.commit()
db.close()
# 更新内存中的配置
self.config = config
self.client = GiteaClient(
config['server_url'],
config['access_token']
)
logger.info("Gitea config saved to database successfully")
return True
except Exception as e:
logger.error(f"Failed to save Gitea config to database: {str(e)}")
return False
```
#### 6.3.3 配置使用流程
1. **配置加载**:系统启动时,`GiteaService` 会从数据库加载 Gitea 配置
2. **配置验证**:使用加载的配置初始化 `GiteaClient`,测试连接
3. **配置使用**:在仓库操作、代码上传等功能中使用配置
4. **配置更新**:通过 API 或界面更新配置,自动保存到数据库
#### 6.3.4 配置管理最佳实践
1. **配置版本控制**:系统会将旧配置标记为 `inactive`,保留配置历史
2. **配置验证**:保存配置前应测试连接,确保配置有效
3. **安全存储**:访问令牌应妥善保管,避免泄露
4. **配置备份**:定期备份 `gitea_configs` 表,防止配置丢失
#### 6.3.5 配置 API 接口
系统提供了 Gitea 配置管理的 API 接口:
- `GET /api/v1/gitea/config`:获取当前 Gitea 配置
- `POST /api/v1/gitea/config`:更新 Gitea 配置
- `GET /api/v1/gitea/test-connection`:测试 Gitea 连接状态
### 6.4 核心功能
- **配置管理**:获取、设置 Gitea 连接配置,支持环境变量和数据库存储
- **连接测试**:测试与 Gitea 服务器的连接状态
- **仓库管理**:创建、克隆、推送、拉取 Gitea 仓库
- **代码上传**:支持大量文件上传,解决 HTTP 413 错误
- **大文件处理**:支持大文件分阶段推送,优化推送性能
- **服务部署**:从 Gitea 仓库直接部署算法服务
- **算法注册**:从仓库注册算法服务到系统
### 6.5 集成架构
```
┌─────────────────────────────────────────────────────────┐
│ 管理层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Supervisor │ │ Nginx │ │ Gitea服务 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 服务层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Service-1 │ │ Service-2 │ │ Service-3 │ │
│ │ 端口: 8001 │ │ 端口: 8002 │ │ 端口: 8003 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 代码层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Gitea仓库1 │ │ Gitea仓库2 │ │ Gitea仓库3 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 基础设施层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 操作系统 │ │ 网络 │ │ 文件系统 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### 6.6 从 Gitea 部署服务的完整流程
#### 6.6.1 配置 Gitea 连接
1. **设置 Gitea 配置**
- 服务器 URL
- 访问令牌
- 默认所有者
- 仓库前缀
2. **测试连接**
```bash
# 使用现有的 GiteaService 测试连接
python -c "from app.gitea.service import gitea_service; print(gitea_service.test_connection())"
```
3. **API 接口**
```bash
# 获取 Gitea 配置
curl -X GET "http://localhost:8001/api/v1/gitea/config" -H "Authorization: Bearer <token>"
# 设置 Gitea 配置
curl -X POST "http://localhost:8001/api/v1/gitea/config" -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{
"server_url": "https://gitea.example.com",
"access_token": "your-token",
"default_owner": "owner",
"repo_prefix": "AI-"
}'
```
#### 6.6.2 仓库管理流程
1. **创建仓库**
```python
from app.gitea.service import gitea_service
repo = gitea_service.create_repository(
algorithm_id="text-classification",
algorithm_name="文本分类算法",
description="基于 BERT 的文本分类算法"
)
print(repo)
```
2. **克隆仓库**
```python
success = gitea_service.clone_repository(
repo_url="https://gitea.example.com/owner/text-classification.git",
algorithm_id="text-classification"
)
print(f"Clone success: {success}")
```
3. **推送代码**
```python
success = gitea_service.push_to_repository(
algorithm_id="text-classification",
message="Update algorithm code"
)
print(f"Push success: {success}")
```
4. **上传文件**
```bash
# 使用 API 上传文件
curl -X POST "http://localhost:8001/api/v1/gitea/repos/upload" -H "Authorization: Bearer <token>" -F "algorithm_id=text-classification" -F "files=@algorithm.py" -F "files=@model.pth"
```
#### 6.6.3 从 Gitea 部署服务
1. **通过 API 部署**
```bash
# 从 Gitea 部署服务
curl -X POST "http://localhost:8001/api/v1/services/deploy-from-gitea" -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{
"algorithm_id": "text-classification",
"repo_url": "https://gitea.example.com/owner/text-classification.git",
"branch": "main",
"service_config": {
"name": "文本分类服务",
"port": 8001,
"host": "0.0.0.0",
"timeout": 30
}
}'
```
2. **通过前端界面部署**
- 登录前端管理界面
- 进入「服务管理」页面
- 点击「从 Gitea 部署」按钮
- 填写部署信息并提交
#### 6.6.4 服务管理和监控
1. **服务状态查询**
```bash
curl -X GET "http://localhost:8001/api/v1/services/status/text-classification" -H "Authorization: Bearer <token>"
```
2. **服务日志查询**
```bash
curl -X GET "http://localhost:8001/api/v1/services/logs/text-classification?lines=100" -H "Authorization: Bearer <token>"
```
3. **服务操作**
```bash
# 启动服务
curl -X POST "http://localhost:8001/api/v1/services/start/text-classification" -H "Authorization: Bearer <token>"
# 停止服务
curl -X POST "http://localhost:8001/api/v1/services/stop/text-classification" -H "Authorization: Bearer <token>"
# 重启服务
curl -X POST "http://localhost:8001/api/v1/services/restart/text-classification" -H "Authorization: Bearer <token>"
```
## 7. 数据库设计与实现
### 7.1 数据库架构
系统使用 PostgreSQL 数据库,包含以下核心表:
1. **algorithms**:算法信息表,存储算法的基本信息
2. **algorithm_versions**:算法版本表,存储算法的不同版本
3. **roles**:角色表,存储用户角色信息
4. **users**:用户表,存储用户信息
5. **algorithm_calls**:算法调用记录表,存储算法调用的历史记录
6. **gitea_configs**Gitea配置表存储Gitea连接配置
7. **algorithm_repositories**:算法仓库表,存储算法代码仓库信息
8. **service_groups**:服务分组表,存储服务分组信息
9. **algorithm_services**:算法服务表,存储算法服务的部署信息
10. **service_configs**:服务配置表,存储服务的配置信息
### 7.2 数据关系
```
┌─────────────────┐ ┌─────────────────────┐
│ algorithms │┼──────│algorithm_versions │
└─────────────────┘ └─────────────────────┘
│ │
│ │
│ │
┌─────────────────┐ ┌─────────────────────┐
│algorithm_calls │┼──────│ users │
└─────────────────┘ └─────────────────────┘
┌─────────────────┐ ┌─────────────────────┐
│ gitea_configs │ │ roles │
└─────────────────┘ └─────────────────────┘
┌─────────────────┐ ┌─────────────────────┐
│algorithm_repos │┼──────│algorithm_services │
└─────────────────┘ └─────────────────────┘
┌─────────────────┐ ┌─────────────────────┐
│service_groups │ │ service_configs │
└─────────────────┘ └─────────────────────┘
```
### 7.3 数据库初始化
```python
# backend/init_db.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.models.database import Base
from app.models.models import Algorithm, AlgorithmVersion, Role, User, AlgorithmCall, GiteaConfig, AlgorithmRepository, ServiceGroup, AlgorithmService, ServiceConfig
# 创建数据库引擎
engine = create_engine("postgresql://admin:password@localhost:5432/algorithm_db")
# 创建所有表
Base.metadata.create_all(bind=engine)
# 创建会话
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
db = SessionLocal()
# 初始化默认角色
try:
# 检查是否已存在角色
admin_role = db.query(Role).filter_by(name="admin").first()
if not admin_role:
admin_role = Role(
id="role-admin",
name="admin",
description="管理员角色,拥有所有权限"
)
db.add(admin_role)
user_role = db.query(Role).filter_by(name="user").first()
if not user_role:
user_role = Role(
id="role-user",
name="user",
description="普通用户角色,拥有基本权限"
)
db.add(user_role)
db.commit()
print("默认角色初始化成功")
except Exception as e:
db.rollback()
print(f"初始化默认角色失败: {str(e)}")
# 关闭会话
db.close()
## 8. 总结与最佳实践
### 8.1 方案总结
本方案提供了一个完整的多独立 AI 算法服务管理解决方案,解决了端口冲突、统一管理、配置管理、运维效率和服务独立性等核心诉求。通过以下关键技术实现:
1. **服务标准化**:统一目录结构、接口规范和启动方式,提高服务的一致性和可维护性
2. **Supervisor 统一管理**:批量管理所有服务的启停、监控和自动重启,减少人工干预
3. **配置集中化**:采用数据库存储配置,支持界面修改,实现配置的动态管理
4. **Gitea 集成**:实现从代码管理到服务部署的全流程自动化,提高开发和部署效率
5. **数据库配置管理**:支持在界面上配置并存储到数据库中,实现配置的版本管理和历史追踪
### 8.2 最佳实践
1. **服务设计**
- 每个服务应保持独立,避免与其他服务产生强依赖
- 实现标准化的健康检查和服务信息接口
- 合理设置服务的超时时间和资源限制
2. **配置管理**
- 使用分层配置管理:环境变量 > 数据库配置 > 文件配置
- 为配置设置合理的命名规范,便于管理和维护
- 定期备份配置数据,防止配置丢失
3. **部署管理**
- 使用 Supervisor 管理服务,确保服务的可靠运行
- 实现服务的自动重启机制,提高服务的可用性
- 为每个服务分配唯一的端口,避免端口冲突
4. **监控与运维**
- 实现服务的健康检查和状态监控
- 集中管理服务日志,便于问题排查
- 建立服务的告警机制,及时发现和处理服务异常
5. **安全管理**
- 保护敏感配置信息,避免泄露
- 实现服务的访问控制,确保服务的安全性
- 定期更新服务依赖,修复安全漏洞
### 8.3 后续优化方向
1. **服务发现与注册**:实现服务的自动发现和注册机制,减少手动配置
2. **负载均衡**:为高流量服务添加负载均衡机制,提高服务的并发处理能力
3. **容器化部署**:结合 Docker 容器化技术,提高服务的可移植性和一致性
4. **CI/CD 集成**:实现代码提交到服务部署的自动化流程,提高开发效率
5. **监控系统**:集成 Prometheus + Grafana 等监控系统,提供更全面的服务监控
### 8.4 实施建议
1. **分阶段实施**:先在测试环境验证方案的可行性,再逐步推广到生产环境
2. **培训与文档**:为运维人员提供详细的培训和文档,确保方案的正确实施
3. **持续优化**:根据实际运行情况,持续优化服务管理方案
4. **风险评估**:在实施前进行充分的风险评估,制定应对措施
通过本方案的实施,您可以构建一个高效、可靠、易管理的多独立 AI 算法服务管理系统,为算法的开发、部署和运行提供有力的支持。