版权声明: https://blog.csdn.net/zhuangzi123456/article/details/81451955
一,需求
1,大量图片需要做异地灾备,大约有上百万张图片,而且还会往上增加,每张图片大小在5M-10M左右;
2,环境说明:服务器是群辉存储,操作系统功能受限制,跟centos系统使用有诸多不同;
二,实施方案
1,设置crontab任务
#backup data to Aliyun OSS
30 00 * * * root /bin/bash /volume1/scripts/findWithOSS_new.sh 5 #这里的数字5表示启用5个python上传图片的后台进程
50 00 * * * root source /etc/profile && /bin/bash /volume1/scripts/backupToOSScrontab_new.sh
2,shell+python
findWithOSS_new.sh:查找前一天00:00-24:00变动(包括新增和修改)的图片列表;本来考虑过使用inotify+python,但经过测试发现,群辉存储操作系统上没法用,然后改成了find命令来查找;
backupToOSScrontab_new.sh:图片上传进程实现多进程;
backupToOSS_new.py:图片上传脚本,基于阿里云提供的oss操作python的模块;
3,python版本:2.7.3
三,脚本代码
1,脚本findWithOSS_new.sh:
#!/bin/bash
#Filename: findWithOSS_new.sh
#Author: XXXXXX
set -m
monitoredDir='/volume1/存档/[存档]2018新'
outputDir='/volume1/scripts/datadir'
osslogDir='/volume1/scripts/osslogs'
dataFile=filelist.log
fnum="$1"
#当天开始时间00:00:00
todayDate=$(date -d " " +"%Y%m%d")
yesterDate=$(date -d "yesterday" +"%Y%m%d")
#每天生成前一天的变动文件名称列表文件
find ${monitoredDir} -daystart -ctime 1 -type f | grep -v 'Thumbs.db' &>> ${outputDir}/${dataFile}-${yesterDate}
#把上面生成的完整文件列表拆分成fnum个文件
/bin/split -n l/${fnum} -d "${outputDir}/${dataFile}-${yesterDate}" "${outputDir}/${dataFile}-${yesterDate}-"
#清除60天前的文件
find ${outputDir} -mtime +60 -type f -exec rm -rf {} \;
find ${osslogDir} -mtime +60 -type f -exec rm -rf {} \;
2,脚本backupToOSScrontab_new.sh:
#!/bin/bash
#Filename: backupToOSScrontab.sh
#Author: XXXXXXXX
#Description:该脚本用来运行多个python脚本来上传文件到阿里云的OSS,可以立即为一个调度脚本;
#调试用
set -m
monitoredDir='/volume1/存档/[存档]2018新'
scriptsDir='/volume1/scripts'
outputDir="${scriptsDir}/datadir"
osslogDir="${scriptsDir}/osslogs"
dataFile=filelist.log
yesterDate=$(date -d "yesterday" +"%Y%m%d")
cd ${osslogDir}
#对拆分后的小文件名称列表做个遍历,然后对应每一个文件分别启动一个python脚本上传对应的文件名称列表
for i in $(ls ${outputDir}/${dataFile}-${yesterDate}-*)
do
inum=${i##*-}
/bin/python ${scriptsDir}/backupToOSS_new.py "${i}" "${inum}" &
done
3,脚本backupToOSS_new.py:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
#Filename: backupToOSS_new.py
#Author:XXXXXX
#Description:该脚本用于把给定的文件传输到阿里云的OSS中,代码中判断,如果出现异常断开,则会尝试重新建立连接传输。
import os
import datetime
import time
import commands
import oss2
import logging
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
cmdYsd = 'date -d "yesterday" +"%Y%m%d"'
oYsd = commands.getoutput(cmdYsd)
ossError = "/volume1/scripts/osslogs/ossError.log"
ossTransferedFiles = "/volume1/scripts/osslogs/ossTransferedFiles.log"
#findWithOSS.sh脚本生成的前一天变动文件的名称列表文件拆分出来的一个小文件
dataFile = sys.argv[1]
logging.basicConfig(filename=ossError + "-" + oYsd + "-" + sys.argv[2], level=logging.ERROR)
#把要传输的文件名称列表导入为python列表
fileListFile = open(dataFile, 'r')
fileList = fileListFile.readlines()
fileListFile.close()
def login():
# 首先初始化AccessKeyId、AccessKeySecret、Endpoint等信息。
# 通过环境变量获取,或者把诸如“<你的AccessKeyId>”替换成真实的AccessKeyId等。
#
# 以杭州区域为例,Endpoint可以是:
# http://oss-cn-hangzhou.aliyuncs.com
# https://oss-cn-hangzhou.aliyuncs.com
# 分别以HTTP、HTTPS协议访问。
access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID', 'XXXXXXXXXX')
access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET', 'YYYYYYYYYY')
bucket_name = os.getenv('OSS_TEST_BUCKET', 'ZZZZZZZZ')
endpoint = os.getenv('OSS_TEST_ENDPOINT', 'AAAAAAAAA')
# 确认上面的参数都填写正确了
for param in (access_key_id, access_key_secret, bucket_name, endpoint):
assert '<' not in param, '请设置参数:' + param
# 创建Bucket对象,所有Object相关的接口都可以通过Bucket对象来进行
global bucket
bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)
def transFer():
#把本地文件上传到OSS,新的Object名称存储在变量"ossName”中,ossName的命名规则:1,使用UTF-8编码;2,长度必须在1-1023字节之间;3,不能以“/”或者“\”字符开头。
with open(ossTransferedFiles + "-" + oYsd + "-" + sys.argv[2], 'a+', buffering=1024) as transLog:
for tfile in fileList:
tfile = tfile.strip()
ossName = tfile.lstrip('/')
#fexist = bucket.object_exists(ossName)
#判断文件在oss上是否存在,如果不存在则上传,这样可以避免文件重传浪费时间,可以考虑根据情况判断是否启用,如果都是新图片,则要关闭,因为会增加执行代码;
#if not fexist:
nowTime = datetime.datetime.now().strftime('%Y%m%d_%T')
status = 1
while status < 4:
try:
bucket.put_object_from_file(ossName, tfile)
transLog.write("{0} {1}\n".format(nowTime, tfile))
status = 4
except RequestError:
logging.exception("###### {0} {1} {2} times ######\n".format(nowTime, tfile, status))
status += 1
time.sleep(80)
except:
logging.exception("###### {0} {1} {2} times ######\n".format(nowTime, tfile, status))
status += 1
time.sleep(3)
if __name__ == '__main__':
login()
transFer()