434 lines
15 KiB
Markdown
434 lines
15 KiB
Markdown
# MAC关联OLT流程改进建议
|
|
|
|
## 文档信息
|
|
- **分析时间**: 2026年4月2日
|
|
- **分析对象**: `MAC关联OLT流程.md`
|
|
- **分析重点**: 与系统设计匹配度、40个OLT设备扩展性
|
|
- **目标读者**: 后端开发同事
|
|
|
|
## 一、当前流程分析
|
|
|
|
### 1.1 文档描述流程
|
|
1. 远程连接OLT设备 → 执行`dis onu slot 1`命令
|
|
2. 解析返回的ONU设备信息
|
|
3. 提取MAC地址、距离、端口、状态信息
|
|
4. 将信息展示给前端并关联到OLT
|
|
|
|
### 1.2 系统实现现状
|
|
**匹配度评分**: 70%
|
|
|
|
| 功能点 | 文档描述 | 系统实现 | 状态 |
|
|
|--------|----------|----------|------|
|
|
| SSH连接 | 远程连接OLT | `SSHService.connect()` | ✅ 已实现 |
|
|
| 命令执行 | `dis onu slot 1` | `execute_command()` | ✅ 已实现 |
|
|
| 分页处理 | "---- More ----" | 空格键继续 | ✅ 已实现 |
|
|
| MAC地址提取 | 1484-778f-cb20格式 | `parse_onu_status()` | ✅ 已实现 |
|
|
| 状态解析 | Up/Offline | 解析状态字段 | ✅ 已实现 |
|
|
| 距离提取 | 12384米 | ❌ 未实现 | ❌ 缺失 |
|
|
| 端口解析 | Onu1/0/2:1 | ❌ 未完整解析 | ⚠️ 需改进 |
|
|
| 数据关联 | 关联到OLT | `olt_id`外键 | ✅ 已实现 |
|
|
|
|
### 1.3 主要问题
|
|
1. **数据提取不完整**: 当前只解析状态,未提取距离和详细端口信息
|
|
2. **数据库字段缺失**: 缺少`distance`字段存储距离信息
|
|
3. **端口解析不足**: 需要从"Onu1/0/2:1"解析为`slot_number`和`port_number`
|
|
|
|
## 二、40个OLT设备扩展性挑战
|
|
|
|
### 2.1 当前方案问题(串行执行)
|
|
| 问题 | 影响程度 | 说明 |
|
|
|------|----------|------|
|
|
| 执行效率低 | 高 | 40个OLT串行检查,预计20-40分钟 |
|
|
| SSH连接开销 | 中 | 每个OLT独立连接,建立/断开开销大 |
|
|
| 网络延迟累积 | 中 | 网络不佳的OLT会阻塞整个流程 |
|
|
| 资源占用 | 中 | 可能同时维护多个SSH连接 |
|
|
| 错误传播 | 高 | 一个OLT失败可能影响后续检查 |
|
|
|
|
### 2.2 性能预估
|
|
| 方案 | 40个OLT检查时间 | 资源占用 | 实现复杂度 | 推荐度 |
|
|
|------|----------------|----------|------------|--------|
|
|
| 当前串行 | ~20-40分钟 | 低 | 低 | ⭐ |
|
|
| 并行10并发 | ~2-4分钟 | 中 | 中 | ⭐⭐⭐⭐⭐ |
|
|
| 并行20并发 | ~1-2分钟 | 高 | 高 | ⭐⭐⭐ |
|
|
|
|
## 三、改进方案建议
|
|
|
|
### 3.1 方案一:并行处理 + 连接池(推荐)
|
|
|
|
#### 3.1.1 架构设计
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ Celery主任务 │───▶│ OLT检查任务分发 │───▶│ 并行执行检查 │
|
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ SSH连接池管理 │◄───│ 连接复用机制 │◄───│ 并发控制(10) │
|
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
```
|
|
|
|
#### 3.1.2 核心组件
|
|
1. **任务分发器**: 将40个OLT检查拆分为独立Celery任务
|
|
2. **连接池管理器**: 复用SSH连接,减少建立/断开开销
|
|
3. **并发控制器**: 限制最大并发数(建议10个)
|
|
4. **结果聚合器**: 收集各OLT检查结果,统一存储
|
|
|
|
#### 3.1.3 代码实现建议
|
|
|
|
**A. SSH连接池实现**
|
|
```python
|
|
# app/services/ssh_pool.py
|
|
import paramiko
|
|
from typing import Dict, Optional
|
|
from threading import Lock
|
|
|
|
class SSHConnectionPool:
|
|
"""SSH连接池,支持连接复用"""
|
|
|
|
def __init__(self, max_connections: int = 10):
|
|
self.pool: Dict[str, paramiko.SSHClient] = {}
|
|
self.lock = Lock()
|
|
self.max_connections = max_connections
|
|
|
|
def get_connection(self, host: str, username: str, password: str) -> paramiko.SSHClient:
|
|
"""获取或创建SSH连接"""
|
|
key = f"{host}:{username}"
|
|
|
|
with self.lock:
|
|
if key in self.pool:
|
|
client = self.pool[key]
|
|
# 检查连接是否仍然有效
|
|
try:
|
|
transport = client.get_transport()
|
|
if transport and transport.is_active():
|
|
return client
|
|
except:
|
|
pass
|
|
|
|
# 创建新连接
|
|
if len(self.pool) >= self.max_connections:
|
|
# 清理最久未使用的连接
|
|
self._cleanup_oldest()
|
|
|
|
client = paramiko.SSHClient()
|
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
client.connect(hostname=host, username=username, password=password, timeout=30)
|
|
|
|
self.pool[key] = client
|
|
return client
|
|
|
|
def _cleanup_oldest(self):
|
|
"""清理最久未使用的连接"""
|
|
# 简化实现:清理第一个连接
|
|
if self.pool:
|
|
key = next(iter(self.pool))
|
|
try:
|
|
self.pool[key].close()
|
|
except:
|
|
pass
|
|
del self.pool[key]
|
|
```
|
|
|
|
**B. 增强的解析器**
|
|
```python
|
|
# app/services/onu_parser.py
|
|
import re
|
|
from typing import Dict, List, Optional
|
|
from dataclasses import dataclass
|
|
|
|
@dataclass
|
|
class ONUInfo:
|
|
"""ONU设备完整信息"""
|
|
mac_address: str
|
|
status: str # online/offline
|
|
distance_m: Optional[int] = None # 距离(米)
|
|
slot_number: Optional[int] = None # 插槽号
|
|
port_number: Optional[int] = None # 端口号
|
|
loid: Optional[str] = None # LOID
|
|
model: Optional[str] = None # 设备型号
|
|
|
|
class ONUParser:
|
|
"""增强的ONU信息解析器"""
|
|
|
|
@staticmethod
|
|
def parse_output(output: str) -> List[ONUInfo]:
|
|
"""解析OLT命令输出"""
|
|
devices = []
|
|
lines = output.split('\n')
|
|
|
|
current_slot = None
|
|
|
|
for line in lines:
|
|
# 检测新的插槽区域
|
|
slot_match = re.search(r'Olt(\d+)/(\d+)/(\d+)', line)
|
|
if slot_match:
|
|
current_slot = int(slot_match.group(1))
|
|
continue
|
|
|
|
# 跳过表头行
|
|
if 'MAC' in line and 'LOID' in line:
|
|
continue
|
|
|
|
# 解析设备行
|
|
device = ONUParser._parse_device_line(line, current_slot)
|
|
if device:
|
|
devices.append(device)
|
|
|
|
return devices
|
|
|
|
@staticmethod
|
|
def _parse_device_line(line: str, slot: Optional[int]) -> Optional[ONUInfo]:
|
|
"""解析单行设备信息"""
|
|
# 匹配MAC地址
|
|
mac_match = re.search(r'([0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4})', line, re.IGNORECASE)
|
|
if not mac_match:
|
|
return None
|
|
|
|
mac = mac_match.group(1).lower()
|
|
|
|
# 提取状态
|
|
status = 'offline'
|
|
if 'Up' in line:
|
|
status = 'online'
|
|
|
|
# 提取距离
|
|
distance = None
|
|
dist_match = re.search(r'(\d+)\s*Dist\(M\)', line)
|
|
if dist_match:
|
|
distance = int(dist_match.group(1))
|
|
|
|
# 提取端口信息
|
|
slot_num, port_num = None, None
|
|
port_match = re.search(r'Onu(\d+)/(\d+)/(\d+):(\d+)', line)
|
|
if port_match:
|
|
slot_num = int(port_match.group(1))
|
|
port_num = int(port_match.group(4))
|
|
|
|
# 提取LOID
|
|
loid = None
|
|
loid_match = re.search(r'\s+(\d+)\s+', line)
|
|
if loid_match:
|
|
loid = loid_match.group(1)
|
|
|
|
return ONUInfo(
|
|
mac_address=mac,
|
|
status=status,
|
|
distance_m=distance,
|
|
slot_number=slot_num or slot,
|
|
port_number=port_num,
|
|
loid=loid
|
|
)
|
|
```
|
|
|
|
**C. 并行检查任务**
|
|
```python
|
|
# app/tasks/parallel_check_tasks.py
|
|
from celery import group
|
|
from app.tasks.check_tasks import check_single_olt
|
|
from app.models.device import OLTDevice
|
|
from sqlalchemy.orm import Session
|
|
|
|
def check_all_olts_parallel(db: Session, max_concurrent: int = 10):
|
|
"""并行检查所有OLT设备"""
|
|
# 获取所有OLT设备
|
|
olts = db.query(OLTDevice).all()
|
|
|
|
if not olts:
|
|
return {"message": "没有可检查的OLT设备"}
|
|
|
|
# 创建任务组
|
|
tasks = []
|
|
for olt in olts:
|
|
tasks.append(check_single_olt.s(olt.id))
|
|
|
|
# 分批执行,控制并发数
|
|
results = []
|
|
for i in range(0, len(tasks), max_concurrent):
|
|
batch = tasks[i:i + max_concurrent]
|
|
job = group(batch)
|
|
result = job.apply_async()
|
|
results.extend(result.get()) # 等待批次完成
|
|
|
|
return {
|
|
"total_olts": len(olts),
|
|
"completed": len([r for r in results if r.get("success")]),
|
|
"failed": len([r for r in results if not r.get("success")]),
|
|
"results": results
|
|
}
|
|
```
|
|
|
|
### 3.2 方案二:数据库优化
|
|
|
|
#### 3.2.1 新增字段建议
|
|
```sql
|
|
-- 在onu_devices表中新增字段
|
|
ALTER TABLE onu_devices ADD COLUMN IF NOT EXISTS distance_m INTEGER;
|
|
ALTER TABLE onu_devices ADD COLUMN IF NOT EXISTS loid VARCHAR(50);
|
|
ALTER TABLE onu_devices ADD COLUMN IF NOT EXISTS model VARCHAR(100);
|
|
ALTER TABLE onu_devices ADD COLUMN IF NOT EXISTS last_seen TIMESTAMP;
|
|
|
|
-- 在olt_devices表中新增字段
|
|
ALTER TABLE olt_devices ADD COLUMN IF NOT EXISTS max_concurrent INTEGER DEFAULT 5;
|
|
ALTER TABLE olt_devices ADD COLUMN IF NOT EXISTS check_timeout INTEGER DEFAULT 60;
|
|
```
|
|
|
|
#### 3.2.2 数据模型更新
|
|
```python
|
|
# app/models/device.py - 更新ONUDevice模型
|
|
class ONUDevice(Base):
|
|
__tablename__ = "onu_devices"
|
|
|
|
# 现有字段...
|
|
distance_m = Column(Integer) # 新增:距离(米)
|
|
loid = Column(String(50)) # 新增:LOID
|
|
model = Column(String(100)) # 新增:设备型号
|
|
last_seen = Column(TIMESTAMP) # 新增:最后在线时间
|
|
|
|
# 索引优化
|
|
__table_args__ = (
|
|
Index('idx_mac_olt', 'mac_address', 'olt_id'),
|
|
Index('idx_status_checked', 'status', 'last_seen'),
|
|
)
|
|
```
|
|
|
|
### 3.3 方案三:监控与告警增强
|
|
|
|
#### 3.3.1 检查任务监控
|
|
```python
|
|
# app/services/monitor_service.py
|
|
class CheckMonitor:
|
|
"""检查任务监控服务"""
|
|
|
|
@staticmethod
|
|
def get_check_stats(db: Session):
|
|
"""获取检查统计信息"""
|
|
stats = {
|
|
"total_olts": db.query(OLTDevice).count(),
|
|
"total_onus": db.query(ONUDevice).count(),
|
|
"online_onus": db.query(ONUDevice)
|
|
.join(DeviceStatusHistory)
|
|
.filter(DeviceStatusHistory.status == 'online')
|
|
.distinct().count(),
|
|
"recent_checks": db.query(DeviceStatusHistory)
|
|
.order_by(DeviceStatusHistory.checked_at.desc())
|
|
.limit(10).all()
|
|
}
|
|
return stats
|
|
|
|
@staticmethod
|
|
def check_olt_health(olt: OLTDevice) -> Dict:
|
|
"""检查OLT健康状态"""
|
|
# 测试连接
|
|
ssh = SSHService(olt.ip_address, olt.username, olt.password)
|
|
try:
|
|
start_time = time.time()
|
|
ssh.connect()
|
|
connect_time = time.time() - start_time
|
|
|
|
# 执行简单命令测试
|
|
output = ssh.execute_command("display version")
|
|
|
|
return {
|
|
"olt_id": olt.id,
|
|
"status": "healthy",
|
|
"connect_time": connect_time,
|
|
"response_time": len(output) / 1024, # KB/s
|
|
"timestamp": datetime.utcnow()
|
|
}
|
|
except Exception as e:
|
|
return {
|
|
"olt_id": olt.id,
|
|
"status": "unhealthy",
|
|
"error": str(e),
|
|
"timestamp": datetime.utcnow()
|
|
}
|
|
finally:
|
|
ssh.close()
|
|
```
|
|
|
|
## 四、实施计划建议
|
|
|
|
### 4.1 第一阶段:基础改进(1-2天)
|
|
1. 增强ONU信息解析器,提取完整字段
|
|
2. 更新数据库模型,新增必要字段
|
|
3. 修改现有检查逻辑,存储完整信息
|
|
|
|
### 4.2 第二阶段:并行化改造(3-5天)
|
|
1. 实现SSH连接池
|
|
2. 改造Celery任务为并行执行
|
|
3. 添加并发控制和错误处理
|
|
4. 测试10个OLT并发场景
|
|
|
|
### 4.3 第三阶段:优化与监控(2-3天)
|
|
1. 添加检查任务监控
|
|
2. 实现健康检查机制
|
|
3. 优化数据库查询性能
|
|
4. 添加告警通知功能
|
|
|
|
### 4.4 第四阶段:压力测试(1-2天)
|
|
1. 模拟40个OLT并发检查
|
|
2. 测试网络异常情况
|
|
3. 验证系统稳定性
|
|
4. 性能调优
|
|
|
|
## 五、风险与应对
|
|
|
|
### 5.1 技术风险
|
|
| 风险 | 可能性 | 影响 | 应对措施 |
|
|
|------|--------|------|----------|
|
|
| OLT连接超时 | 中 | 高 | 实现超时重试机制 |
|
|
| 并发连接过多 | 低 | 中 | 限制最大并发数 |
|
|
| 内存泄漏 | 低 | 高 | 添加连接池清理机制 |
|
|
| 数据库锁竞争 | 中 | 中 | 优化事务处理,使用批量操作 |
|
|
|
|
### 5.2 业务风险
|
|
| 风险 | 可能性 | 影响 | 应对措施 |
|
|
|------|--------|------|----------|
|
|
| 检查结果不一致 | 低 | 中 | 添加数据校验机制 |
|
|
| 检查时间过长 | 中 | 高 | 实现增量检查,优化查询 |
|
|
| 用户等待时间 | 中 | 中 | 提供进度查询接口 |
|
|
|
|
## 六、预期收益
|
|
|
|
### 6.1 性能提升
|
|
- **检查时间**: 从20-40分钟缩短到2-4分钟(10倍提升)
|
|
- **资源利用率**: SSH连接复用减少50%连接开销
|
|
- **系统稳定性**: 错误隔离避免单点故障影响全局
|
|
|
|
### 6.2 功能增强
|
|
- **数据完整性**: 完整记录距离、端口、LOID等信息
|
|
- **监控能力**: 实时监控检查任务状态和OLT健康度
|
|
- **扩展性**: 支持未来扩展到更多OLT设备
|
|
|
|
### 6.3 运维改善
|
|
- **故障诊断**: 详细的检查日志和错误信息
|
|
- **性能分析**: 检查任务性能统计和趋势分析
|
|
- **容量规划**: 基于实际负载的资源规划依据
|
|
|
|
## 七、后续建议
|
|
|
|
### 7.1 短期建议(1个月内)
|
|
1. 实现基础并行检查功能
|
|
2. 完成数据库字段扩展
|
|
3. 添加基础监控告警
|
|
|
|
### 7.2 中期建议(1-3个月)
|
|
1. 实现智能调度(基于OLT负载和网络状况)
|
|
2. 添加检查结果分析和报表
|
|
3. 集成自动化运维工具
|
|
|
|
### 7.3 长期建议(3-6个月)
|
|
1. 机器学习预测设备故障
|
|
2. 自动化故障恢复机制
|
|
3. 多数据中心部署支持
|
|
|
|
---
|
|
|
|
**文档维护**:
|
|
- 本文档应随系统改进同步更新
|
|
- 重大架构变更需更新本文档
|
|
- 实际实施中的调整应记录在案
|
|
|
|
**联系方式**:
|
|
- 如有疑问或建议,请通过项目沟通渠道反馈
|
|
- 实施过程中遇到问题及时记录并分享解决方案 |