本文目录导读:

我来分享一个预估数据迁移耗时的脚本编写方法,包含多个维度的估算策略。
基础估算脚本
#!/usr/bin/env python3
"""
数据迁移耗时预估脚本
支持多种数据源和迁移方式
"""
import time
import psutil
import subprocess
from datetime import datetime, timedelta
import argparse
import json
class MigrationEstimator:
def __init__(self, source_type='mysql', target_type='mysql'):
self.source_type = source_type
self.target_type = target_type
self.sample_data = []
self.network_speed = self.get_network_speed()
self.io_speed = self.get_io_speed()
def get_network_speed(self):
"""获取网络传输速度(MB/s)"""
try:
# 使用ping或iperf3测试网络
result = subprocess.run(
['iperf3', '-c', 'target_host', '-t', '5', '-f', 'm'],
capture_output=True, text=True, timeout=10
)
# 解析结果获取带宽
speed = self.parse_iperf_output(result.stdout)
return speed if speed > 0 else 100 # 默认100MB/s
except:
# 回退方法:测试到目标主机的延迟和带宽
try:
subprocess.run(['ping', '-c', '3', 'target_host'],
capture_output=True, timeout=10)
# 估算带宽(简化版)
return 50 # 假设50MB/s
except:
return 10 # 最保守估计10MB/s
def get_io_speed(self):
"""获取磁盘IO速度(MB/s)"""
try:
# 使用dd命令测试磁盘写入速度
result = subprocess.run(
['dd', 'if=/dev/zero', 'of=/tmp/test_speed',
'bs=1M', 'count=1024', 'oflag=dsync'],
capture_output=True, text=True, timeout=30
)
# 解析速度
for line in result.stderr.split('\n'):
if 'MB/s' in line or 'MB/s' in line:
speed = self.extract_speed(line)
return speed
return 200 # 默认200MB/s
except:
return 100 # 保守估计
def estimate_by_sample(self, data_size_gb, sample_size_mb=10):
"""基于抽样的估算方法"""
print(f"[{datetime.now()}] 开始抽样测试...")
# 生成测试数据
test_data = self.generate_sample_data(sample_size_mb)
# 测试传输速度
start_time = time.time()
self.transfer_sample(test_data)
actual_time = time.time() - start_time
# 估算总时间
sample_speed = (sample_size_mb / 1024) / actual_time # GB/s
estimated_total_time = data_size_gb / sample_speed
return estimated_total_time, actual_time, sample_speed
def estimate_by_formula(self, data_size_gb, **kwargs):
"""基于公式的估算方法"""
# 数据大小因素
size_factor = data_size_gb
# 网络因素
network_factor = 1.0
if self.network_speed < 10:
network_factor = 3.0
elif self.network_speed < 50:
network_factor = 1.5
elif self.network_speed > 100:
network_factor = 0.8
# IO因素
io_factor = 1.0
if self.io_speed < 50:
io_factor = 2.0
elif self.io_speed < 100:
io_factor = 1.5
elif self.io_speed > 500:
io_factor = 0.7
# 数据压缩率
compression_factor = kwargs.get('compression', 1.0)
# 并行度
parallel_factor = 1.0 / kwargs.get('parallel', 1)
# 额外因素
overhead_factor = 1.2 # 20%开销
estimated_time = (size_factor * network_factor * io_factor *
overhead_factor * compression_factor * parallel_factor)
return estimated_time
def estimate_by_historical(self, historical_data):
"""基于历史数据的估算"""
if not historical_data:
return None
# 计算历史平均速度
speeds = [h['size_gb'] / h['time_hours'] for h in historical_data]
avg_speed = sum(speeds) / len(speeds)
return avg_speed
def comprehensive_estimate(self, data_size_gb, **kwargs):
"""综合估算方法"""
print("="*50)
print("数据迁移耗时综合估算")
print(f"数据量: {data_size_gb} GB")
print(f"网络速度: {self.network_speed:.2f} MB/s")
print(f"IO速度: {self.io_speed:.2f} MB/s")
print("="*50)
# 方法1: 公式估算
formula_time = self.estimate_by_formula(data_size_gb, **kwargs)
print(f"公式法估算: {self.format_time(formula_time)}")
# 方法2: 抽样估算
if kwargs.get('do_sample', True):
sample_time, actual_time, speed = self.estimate_by_sample(
data_size_gb, kwargs.get('sample_size', 10)
)
print(f"抽样法估算: {self.format_time(sample_time)}")
print(f" 抽样数据量: {kwargs.get('sample_size', 10)}MB")
print(f" 抽样耗时: {actual_time:.2f}s")
print(f" 预估速度: {speed:.2f} GB/s")
# 综合评分
estimates = [formula_time]
if kwargs.get('do_sample', True):
estimates.append(sample_time)
avg_time = sum(estimates) / len(estimates)
min_time = min(estimates)
max_time = max(estimates)
return {
'data_size_gb': data_size_gb,
'estimated_time_hours': avg_time,
'time_range': (min_time, max_time),
'network_speed': self.network_speed,
'io_speed': self.io_speed,
'formula_estimate': formula_time,
'sample_estimate': sample_time if kwargs.get('do_sample', True) else None,
'confidence': 'high' if max_time - min_time < 0.5 * avg_time else 'medium'
}
def format_time(self, hours):
"""格式化时间显示"""
if hours < 1:
minutes = hours * 60
return f"{minutes:.1f} 分钟"
elif hours < 24:
return f"{hours:.1f} 小时"
else:
days = hours / 24
return f"{days:.1f} 天 ({hours:.1f} 小时)"
def generate_sample_data(self, size_mb):
"""生成测试数据"""
return b'x' * (size_mb * 1024 * 1024)
def transfer_sample(self, data):
"""模拟数据传输"""
time.sleep(0.1) # 模拟网络延迟
return True
def parse_iperf_output(self, output):
"""解析iperf输出"""
# 简化实现
return 100
def extract_speed(self, line):
"""从输出中提取速度"""
# 简化实现
return 200
def main():
parser = argparse.ArgumentParser(description='数据迁移耗时估算工具')
parser.add_argument('--size', type=float, required=True,
help='数据大小 (GB)')
parser.add_argument('--source', type=str, default='mysql',
help='源数据库类型')
parser.add_argument('--target', type=str, default='mysql',
help='目标数据库类型')
parser.add_argument('--parallel', type=int, default=1,
help='并行度')
parser.add_argument('--compression', type=float, default=1.0,
help='压缩率 (0-1)')
parser.add_argument('--no-sample', action='store_true',
help='禁用抽样测试')
parser.add_argument('--output', type=str,
help='输出文件路径 (JSON格式)')
args = parser.parse_args()
# 创建估算器
estimator = MigrationEstimator(args.source, args.target)
# 执行估算
result = estimator.comprehensive_estimate(
args.size,
parallel=args.parallel,
compression=args.compression,
do_sample=not args.no_sample
)
# 显示结果
print("\n" + "="*50)
print("估算结果汇总")
print("="*50)
print(f"数据量: {result['data_size_gb']} GB")
print(f"预计耗时: {estimator.format_time(result['estimated_time_hours'])}")
print(f"时间范围: {estimator.format_time(result['time_range'][0])} - "
f"{estimator.format_time(result['time_range'][1])}")
print(f"置信度: {result['confidence']}")
# 输出JSON
if args.output:
with open(args.output, 'w') as f:
json.dump(result, f, indent=2, default=str)
print(f"结果已保存到: {args.output}")
# 生成时间线建议
generate_timeline_suggestion(result['estimated_time_hours'])
def generate_timeline_suggestion(hours):
"""生成时间线建议"""
print("\n" + "="*50)
print("时间线建议")
print("="*50)
if hours < 1:
print("建议: 立即执行迁移")
print("最佳时间: 立即")
elif hours < 4:
print("建议: 安排在低峰时段执行")
print("最佳时间: 凌晨2:00-6:00")
elif hours < 12:
print("建议: 需要周密计划")
print("最佳时间: 周末凌晨")
print("需要准备: 回滚方案")
else:
print("建议: 分批进行迁移")
print("最佳时间: 分多个周末执行")
print("需要准备:")
print(" 1. 详细迁移计划")
print(" 2. 数据校验方案")
print(" 3. 回滚预案")
print(" 4. 监控告警配置")
# 显示预计完成时间
completion_time = datetime.now() + timedelta(hours=hours)
print(f"\n预计完成时间: {completion_time.strftime('%Y-%m-%d %H:%M:%S')}")
if __name__ == "__main__":
main()
使用示例
基本使用
# 估算10GB数据迁移 python migration_estimator.py --size 10 # 指定并行度和压缩率 python migration_estimator.py --size 100 --parallel 4 --compression 0.5 # 保存结果到JSON python migration_estimator.py --size 50 --output estimate_result.json
集成到Shell脚本
#!/bin/bash
# migration_estimate.sh
# 获取MySQL数据库大小
get_db_size() {
mysql -e "
SELECT
ROUND(SUM(data_length + index_length) / 1024 / 1024 / 1024, 2) AS size_gb
FROM information_schema.tables
WHERE table_schema = '$1';
" | tail -1
}
# 主逻辑
DB_NAME="your_database"
SIZE=$(get_db_size $DB_NAME)
echo "数据库 $DB_NAME 大小: ${SIZE}GB"
# 调用Python脚本估算
python3 migration_estimator.py --size $SIZE --parallel 4 --compression 0.8
高级功能扩展
分阶段估算
class PhasedMigrationEstimator:
"""分阶段迁移估算"""
def estimate_full_migration(self, data_size_gb):
phases = {
'schema_migration': 0.1, # 表结构迁移
'full_data_migration': 0.7, # 全量数据迁移
'incremental_sync': 0.15, # 增量同步
'validation': 0.05 # 数据校验
}
total_time = self.get_estimated_time(data_size_gb)
phase_times = {}
for phase, ratio in phases.items():
phase_times[phase] = total_time * ratio
return phase_times
实时进度监控
class ProgressMonitor:
def __init__(self, total_size_gb):
self.total = total_size_gb
self.transferred = 0
self.start_time = time.time()
def update(self, transferred_gb):
self.transferred = transferred_gb
elapsed = time.time() - self.start_time
speed = transferred_gb / elapsed
remaining = self.total - transferred_gb
eta = remaining / speed
print(f"进度: {transferred_gb:.2f}/{self.total:.2f} GB "
f"({transferred_gb/self.total*100:.1f}%) "
f"速度: {speed:.2f} GB/s "
f"剩余时间: {eta:.1f} 秒")
注意事项
- 考虑网络波动:实际速度可能变化,建议添加20%-30%的缓冲时间
- 数据库负载:迁移过程可能影响源数据库性能
- 数据校验时间:迁移后需要时间验证数据完整性
- 回滚准备:为可能的失败预留回滚时间
这个脚本提供了多种估算方法,可以根据实际情况组合使用,获得更准确的时间预估。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播