滑らかな移行デザインを達成するためにNFS TBレベルデータ

多くのソフトリンクがあるので、ひどい仕打ちを変更する場所がない場合は、ストレージ・パス内のプラットフォームのコードの移行は、その後、変化したかのように、元のプラットフォームは、変わらずは/ mnt / ccdbfsをマウントします。

だから、最初のデュアル書き込みデザインは、古いデータは/ mnt / ccdbfsとは/ mnt / MFSをコピーするときに新しいデータを書き込むことは、データの整合性を確保する一方であることを確認します。そして、すべてのようには/ mnt / ccdbfsが新しく建てられmoosefsマスターサーバーをマウントし、コピーされた何の差分を観察されず、その後、マウントに切り替えます。

inotifyをファイルシステム監視機構。
データミラーリングは、rsyncのツールのLinuxシステムです。リモートサポートローカル複製、または、他のSSHと同期のrsyncホストを同期させることができ、高速増分バックアップツールSyncを使用してください。

そこシステムのcpコマンドを一時的に変更に続いて、ユーザ・グループと権限の双子の問題があり、その後、完全にカットバックプレーに切り替えます。

以下の最初の2つのプログラムが、ほとんどの人が使用するオンラインプログラムは、変更を最大限に研究し始めたが、実際の発見、弱さの非常に大規模なカタログの同期、光はinotifyは、長い時間のために、そしてSaowan後に新しいファイルを掃除します検出問題も発生する可能性があります。最後に、同期戦略なしに遅延同期+差分を導入し、変更するいくつかのファイルを得るために、ログレベルの古いNFSサービスを変更し、最後のプログラムです。

オカレンスは、以下のccdbfs古いNFSサービス、新しいNFSサービスの代わりにMFSを表します。

inotifyの+のrsync

ファイル・ディレクトリの少量、より速く、それらをコピーし、以下のコードのために。

しかし、大規模なカタログのために、一緒に弱さを、コードをスキャンします。そして、イベントの認識が繰り返されます。

copy_ccdbfs_update_to_mfs.sh

# rsync auto sync script with inotify
# 2019/03/21

# configs
source_path=/mnt/ccdbfs/
target_path=/mnt/mfs/
rsync_bin=/usr/bin/rsync
INOTIFY_EXCLUDE='aladata.*'


cd $(dirname $0)

RSYNC_EXCLUDE=$(pwd)/rsync_exclude.lst

current_date=$(date +%Y-%m-%d_%H%M%S)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)

log_file=$(pwd)/runcopy.log.${current_date}
inotifywait_bin=$(pwd)/inotifywait

inotify_fun(){
    ${inotifywait_bin} -mrq --timefmt '%Y/%m/%d-%H:%M:%S' --format '%T %w %f' \
     --exclude ${INOTIFY_EXCLUDE} -e modify,create,move,attrib ${source_path} \
    | while read file
        do
            ${rsync_bin} -auvrtzopgP --exclude-from=${RSYNC_EXCLUDE} --progress --bwlimit=800000 ${source_path} ${target_path}
        done
}

#inotify log
inotify_fun &> ${log_file} &

inotifyを+カスタムコピーするスクリプト

change_file.listに新しい光監視スクリプトファイル変更イベントを開始するinotifyを。

カスタムスクリプトを読み、コピーを制御するためのロジックをコピーします。
inotify_ccdbfs_change.sh

# find ccdbfs change with inotify, export to file
# 2019/03/21

# configs
source_path=/mnt/ccdbfs/
INOTIFY_EXCLUDE='.*(\.swx|\.swp)$|aladata.*'

cd $(dirname $0)
current_date=$(date +%Y-%m-%d_%H%M%S)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)
inotifywait_bin=$(pwd)/inotifywait

${inotifywait_bin} -mrq --timefmt '%Y/%m/%d-%H:%M:%S' --format '%w%f %e %T' \
    --exclude ${INOTIFY_EXCLUDE} -e create,close_write ${source_path} \
| while read line
    do
        echo ${line} >> $(pwd)/change_file.list
    done &

change_file.list

/mnt/mfs/dirtest4 CREATE,ISDIR 2019/03/21-22:30:06
/mnt/mfs/dirtest4/5 CREATE,ISDIR 2019/03/21-22:30:06
/mnt/mfs/a.test CLOSE_WRITE,CLOSE 2019/03/21-22:30:17
/mnt/mfs/c.test CLOSE_WRITE,CLOSE 2019/03/21-22:30:24
/mnt/mfs/aa CREATE 2019/03/21-22:30:45
/mnt/mfs/aa CLOSE_WRITE,CLOSE 2019/03/21-22:30:45

inotify_ccdbfs_change_cp.py

# -*- coding: utf-8 -*-
# 持续读取inotify_ccdbfs_change.sh监控到的变化文件change_file.list,从ccdbfs同步到mfs
# 2019/03/22
import os
import time


SOURCE_ROOT = '/mnt/ccdbfs'
TARGET_ROOT = '/mnt/mfs'

def deal_ori_change_file_list():
    '''获取change_file.list文件得到变化文件list
       顺便追加change_file.list到change_file.bak
       然后清空change_file.list
    '''
    change_file_path = os.getcwd() + '/change_file.list'
    change_file_back_path = os.getcwd() + '/change_file.bak'
    with open(change_file_path) as f:
        row_list = f.read().splitlines()
    # 追加备份
    os.system('echo "" >> ' + change_file_back_path)  # 相当于换行
    os.system('cat ' + change_file_path + ' >> ' + change_file_back_path)

    # 清空原change_file.list
    os.system('cat /dev/null > ' + change_file_path)

    return row_list


def uniq_row_list(row_list):
    '''对获取到的原始row_list拆分和保序去重
       返回 dir_list, file_list
    '''
    dir_list = []
    file_list = []

    for row in row_list:
        try:
            obj, effect, _ = row.split(' ')
            if 'ISDIR' in effect:
                if obj not in dir_list:
                    dir_list.append(obj)
            else:
                if obj not in file_list:
                    file_list.append(obj)
        except:
            print(str(time.time()) + 'uniq_row_list except')

    return dir_list, file_list


def copy_change(dir_list, file_list):
    '''在mfs中复制ccdbfs中的变化
       先复制创建目录,再复制
    '''
    # 优先在mfs中创建没有的目录,再去复制文件
    for a_dir in dir_list:
        dst = a_dir.replace(SOURCE_ROOT, TARGET_ROOT)
        if os.path.exists(dst) == False:
            os.system('mkdir -p ' + dst)
    
    for a_file in file_list:
        dst_file = a_file.replace(SOURCE_ROOT, TARGET_ROOT)
        # 防止目标地址目录没创建
        (file_path,file_name) = os.path.split(dst_file)
        if os.path.exists(file_path) == False:
            os.system('mkdir -p ' + file_path)
        # 复制文件或者软链接
        os.system('cp -d ' + a_file + ' ' + dst_file)


if __name__ == '__main__':
    last_time = 0
    while True:
        change_file_path = os.getcwd() + '/change_file.list'
        change_file_back_path = os.getcwd() + '/change_file.bak'
        # 获取change_file.list文件得到变化文件list
        with open(change_file_path) as f:
            row_list = f.read().splitlines()

        # 执行备份条件是 变化记录满100条 或 间隔5s且有变化记录
        # 所以当没满100条,且没满5s的时候,或者满了5s但是没有变化记录,不进行后面的备份
        if len(row_list) < 100:
            if time.time() - last_time < 5:
                print('row_list < 100 and delta_time < 5')
                time.sleep(1)
                continue
            elif len(row_list) == 0:
                print('delta_time > 5 but row_list == 0')
                time.sleep(1)
                continue

        # 满足条件,开始备份
        print('cp start')
        last_time = time.time()
        # 追加备份历史记录
        os.system('echo "" >> ' + change_file_back_path)  # 相当于换行
        os.system('cat ' + change_file_path + ' >> ' + change_file_back_path)
        # 清空原change_file.list
        os.system('cat /dev/null > ' + change_file_path)

        dir_list, file_list = uniq_row_list(row_list)
        print('dir_list: ', dir_list)
        print('file_list: ', file_list)
        copy_change(dir_list, file_list)
        time.sleep(1)

インクリメンタル書き込みダブル、差分レプリケーション戦略(プログラムの実用的な操作)

NFS古いログ+カスタムダブル書き込みスクリプトの魚

cp_ccdbfs_change.py増分更新は、同期スクリプトをデュアル書きます。クラスタの事務機、古いccdbfsの1組は、書き込みを開始があります。

ダブルので、変更ログファイルのゲインを決定するためにスクリーニング:

  • テストを発見し、何の問題をコピーしませんが、時間をかけて、レコードのクリーンアップコピー、どのようなファイルの修正時刻をチェックしようとして、読み出し動作、またはまったく同じログを生成し、新しいポストはグローバルマップに追加されます、削除、ので、この言葉には、無限ループに余裕はありません削除されます。
  • コピー後に提案を変更しようとする、そのレコードを削除しませんが、クエリ時間を変更しない、スキップ、ポーリングスレッドレコードから取り出したときに、時間が0で、0にログ時間を維持します。
  • このファイルは、ログをトリガーした後に再び変更された場合は、新しいタイムトリガログに時間前に、最後の証明のコピー0であるかどうかを見るが、今新たに改訂され、その後、再ブラシafter'll。
  • それがディレクトリである場合なお、1として保存された時間は、処理はもはやありません。
  • メモリは記憶されている地図情報は、単にファイルの内容をファイルではないので、それを作る、そして多くの場合、伐採によって生成されたディレクトリまたはクエリの修正時間に行く必要があります。
  • 上記この場合、ディレクトリは除外することができるが、ファイルのために、または、クエリ時間ので、変更ログレコードを生成し、log_timeをリフレッシュ。また、記録マップが設けられている検査(又はコピーワンス検査終了時間である)、二つの結合決意しなければなりません。
# -*- coding: utf-8 -*-
# 持续读取从ccdbfs日志捞取出来的变更文件,并同步到mfs对应路径下
# 2019/03/26
import os
import time
import sys
import subprocess
import threading

CCDBFS_LOG_PATH = '/home/work/nfs_client/log/Client.log'
SOURCE_ROOT = '/mnt/ccdbfs'
TARGET_ROOT = '/mnt/mfs'
CCDBFS_SAVE_ROOT = '/disk'
CCDBFS_SEARCH_TOOLS_ROOT = '/home/work/copy_ccdbfs_to_mfs/output'

EXCLUDE_LIST = ['/mnt/ccdbfs/aladata']

DELAY_DEAL_TIME = 120

MAP_DICT = {}  # 存储有变更的文件信息
INODE_PATH_DICT = {}  # 提供存储和查询inode对应路径用
FINISHED_DICT = {}  # 存储复制过的文件信息,值记录上次检查完成时间,值为1表示不再做检查

def myprint(*args):
    ltime = time.localtime(time.time())
    now_time = time.strftime("%Y-%m-%d %H:%M:%S, ", ltime)        
    print(now_time, args)


def copy_change(obj_path):
    '''在mfs中复制ccdbfs中的变化
    '''
    try:
        target_path = obj_path.replace(SOURCE_ROOT, TARGET_ROOT)
        # 先在mfs目标路径下判断路径是否存在,没有则创建
        (file_path,file_name) = os.path.split(target_path)
        if os.path.exists(file_path) == False:
            os.system('mkdir -p ' + file_path)

        # 复制文件或者软链接
        # -p 修改时间和访问权限也复制到新文件
        # -d 复制时保留链接
        # -u 源文件修改时间更新才复制
        os.system("""sh -c 'nohup cp -pdu "%s" "%s" &'""" % (obj_path, target_path))
    except:
        myprint('cp change error: ' + obj_path)

def extract_dir_objname(log_buff):
    '''从日志语句中提取出父目录以及存储对象名
    '''
    try:
        tmplist = log_buff.split(' ')
        log_time = '2019-' + tmplist[1] + ' ' + tmplist[2]
        log_time_stamp = time.mktime(time.strptime(log_time, "%Y-%m-%d %H:%M:%S:"))
        # 去掉 parentDirInode:0xa0000000101b9c32, 的多余字符
        dir_inode = tmplist[8].replace('parentDirInode:', '').replace(',', '')
        # 只取出存储对象名字
        objname = tmplist[9].replace('\n','').split(':')[1]
        return log_time_stamp, dir_inode, objname
    except:
        myprint('extract_dir_objname error, ' + log_buff)
        return None, None, None


def tail_log_add_map():
    '''
    Desc: 持续捞取文件变更日志,并将满足条件的变更存入全局MAP_DICT
    '''
    # 持续捞取长这样的日志,必须包含 ]Lookup, 有逗号
    # DEBUG: 03-26 11:45:56:  Client * 15176 [ccdb:NFSClient.cpp:625:15176]Lookup, parentDirInode:0xa0000001198bee40, dentryName:filelinktest
    p = subprocess.Popen('tail -F ' + CCDBFS_LOG_PATH, shell=True, stdout=subprocess.PIPE)
    while True:
        buff = p.stdout.readline()
        # 克服直接在Popen中grep有问题的办法
        if ']Lookup,' not in buff:
            continue
        if buff == '' and p.poll() != None:
            break
        
        log_time_stamp, dir_inode, objname = extract_dir_objname(buff)
        if (log_time_stamp == None) or (dir_inode == None) or (objname == None):
            continue

        # 若不存在,添加之
        map_value = MAP_DICT.get(dir_inode + '+' + objname)
        if  map_value == None:
            MAP_DICT[dir_inode + '+' + objname] = log_time_stamp
        else:
            last_finished_time = FINISHED_DICT.get(dir_inode + '+' + objname)
            # 之前复制完成log_time变成了0,再次有修改才变换这里的log_time
            # 上次检测或者复制完成10s内,视为读操作,不修改log_time
            if last_finished_time == None:
                # FINISHED_DICT无记录,表示要去检测
                last_finished_time = 0
            if (map_value == 0) and (time.time() - last_finished_time > 10):
                    MAP_DICT[dir_inode + '+' + objname] = log_time_stamp


def check_map_dict():
    '''
    Desc: 轮询遍历MAP_DICT将满足条件的文件进行复制或删除记录
    '''
    global MAP_DICT
    while True:
        for k, log_time in MAP_DICT.items():
            # myprint(k, log_time)
            # log_time为0表示上一次复制或检查完成,log_time为1表示是目录永远不再检查,不用操作
            # 在复制文件前会检查,如果目录不存在会创建
            if log_time == 0 or log_time == 1:
                continue
            dir_inode, objname = k.split('+')
            # 先查全局INODE_PATH_DICT中存了路径没,没有再去查ccdbfs客户端
            dir_path = INODE_PATH_DICT.get(dir_inode)
            if dir_path == None:
                try:
                    op = os.popen("cd %s && echo 'lookup %s' | ./bin/Cli -x" % (CCDBFS_SEARCH_TOOLS_ROOT, dir_inode))
                    ret = op.read()
                    # ccdbfs客户端存的路径是/disk开头,挂载路径是/mnt/ccdbfs
                    dir_path = ret.split(' ')[5].replace(CCDBFS_SAVE_ROOT, SOURCE_ROOT)
                    INODE_PATH_DICT[dir_inode] = dir_path
                    myprint('search ccdbfs client:%s->%s' % (dir_inode, dir_path))
                except:
                    myprint('search dir path error: ' + k)
                    # 若获取不到路径,跳过这次复制
                    MAP_DICT[k] = 0
                    FINISHED_DICT[k] = time.time()
                    continue

            # 拼接文件路径
            obj_path = dir_path + objname

            # 若obj_path本身是目录,不用处理
            if os.path.isdir(obj_path) == True:
                # 修改log_time为1,当做标记用
                MAP_DICT[k] = 1
                continue

            # 排除一些不需要监控的目录
            exclude_flag = False
            for exclude in EXCLUDE_LIST:
                if exclude in dir_path:
                    exclude_flag = True
                    break
            if exclude_flag == True:
                MAP_DICT[k] = 1  # 故意置1,永不检查
                continue

            # 若是临时文件,不存在了,跳过这次复制
            if os.path.exists(obj_path) == False:
                myprint(obj_path + ' is inexistent')
                MAP_DICT[k] = 0
                FINISHED_DICT[k] = time.time()
                continue

            # 获取最新修改时间
            try:
                modify_time = os.stat(obj_path).st_mtime
            except:
                myprint('os.stat().st_mtime error: ' + obj_path)
                continue
            now_time = time.time()
            # -5秒的判断,是防止极短时间写入后,log日志时间稍大于修改时间。
            if now_time - modify_time > DELAY_DEAL_TIME and modify_time - log_time >= -5:
                # 复制同步,并修改键值表示复制过
                myprint('cp and set MAP_DICT[k]=0, FINISHED_DICT=now_time, ' + obj_path)
                copy_change(obj_path)
                MAP_DICT[k] = 0
                FINISHED_DICT[k] = now_time
            else:
                # 也不能让MAP_DICT野蛮增长,对于读操作(日志时间大于修改时间5s以上)的log,要清除掉
                if now_time - modify_time > DELAY_DEAL_TIME and log_time - modify_time > 5:
                    # 修改键值表示检查过
                    myprint('no change, set MAP_DICT[k]=0, FINISHED_DICT=now_time, ' + obj_path)
                    MAP_DICT[k] = 0
                    FINISHED_DICT[k] = now_time
            # time.sleep(2)
        time.sleep(60)

if __name__ == '__main__':
    t1 = threading.Thread(target = tail_log_add_map)
    t2 = threading.Thread(target = check_map_dict)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

copy_inexistent_file.py同じ戦略なしで全体のファイル同期の残量、。一台のマシンから別のは、NFSを起動するために新しい、古いクライアントを接続します。

# -*- coding: utf-8 -*-
# 平台nfs未被inotify检测到的文件迁移
# 2019/03/18
import os
import time

DIRS_LIST = []  # 记录老文件夹下不断遍历添加进来的目录名,检测完后抛出,当队列使用

# SOURCE_ROOT,TARGET_ROOT提供程序中替换目录路径用
# 为防止其他文件也用到ccdbfs字眼,所以全部执行完后
# 手动修改新mfs目录里ccdbfs软链接,而不再程序中特殊控制
SOURCE_ROOT = '/mnt/ccdbfs'
TARGET_ROOT = '/mnt/mfs'
# SOURCE_ROOT = '/mnt/srcdir'
# TARGET_ROOT = '/mnt/tardir'

EXCLUDE_LIST = ['/mnt/ccdbfs/aladata']
# EXCLUDE_LIST = ['/mnt/srcdir/aladata']

def myprint(*args):
    ltime = time.localtime(time.time())
    now_time = time.strftime("%Y-%m-%d %H:%M:%S, ", ltime)        
    print(now_time, args)


def dir_info(file_dir):
    for root, dirs, files in os.walk(file_dir):
        # myprint('root_dir:', root)  # 当前目录路径
        # myprint('sub_dirs:', dirs)  # 当前路径下所有子目录
        # myprint('files:', files)  # 当前路径下所有非目录子文件
        # 补全目录全路径
        full_path_dirs = [root + '/' + i for i in dirs]
        full_path_dirs_res = []

        # 过滤某些不拷贝的目录
        for i in full_path_dirs:
            exclude_flat = False
            for exclude in EXCLUDE_LIST:
                if exclude in i:
                    exclude_flat = True
                    break
            if exclude_flat == False:
                full_path_dirs_res.append(i)

        # 补全文件全路径
        full_path_files = [root + '/' + i for i in files]
        return full_path_dirs_res, full_path_files


def doing_copy_file(dir_path):
    '''传入原ccdbfs目录下的某文件夹路径,复制其中文件
       并将其中文件夹推入全局DIRS_LIST
    '''
    dirs, files = dir_info(dir_path)
    # 发现目录,推入DIRS_LIST
    global DIRS_LIST
    DIRS_LIST += dirs

    for src_file in files:
        # mfs下属目录中不存在该文件,才复制
        dst_file = src_file.replace(SOURCE_ROOT, TARGET_ROOT)
        if os.path.exists(dst_file) == False:
            try:
                # 防止目标地址目录没创建
                (file_path,file_name) = os.path.split(dst_file)
                if os.path.exists(file_path) == False:
                    os.system('mkdir -p ' + file_path)
                # 正式复制该文件
                myprint('cp -pdu "%s" "%s"' % (src_file, dst_file))
                os.system('cp -pdu "%s" "%s"' % (src_file, dst_file))
            except:
                myprint('copy file except: ' + dst_file)


def make_soft_link(soft_file):
    '''将ccdbfs中的软链接复制到对应mfs目录相同层级下
    '''
    try:
        dst_file = soft_file.replace(SOURCE_ROOT, TARGET_ROOT)
        if os.path.exists(dst_file) == True:
            # 存在则不用重复复制
            myprint(dst_file + 'already exists')
            return
        # 防止目标地址目录没创建
        (file_path,file_name) = os.path.split(dst_file)
        if os.path.exists(file_path) == False:
            os.system('mkdir -p ' + file_path)
        # 正式复制该软链接
        myprint('cp -pdu "%s" "%s"' % (soft_file, dst_file))
        os.system('cp -pdu "%s" "%s"' % (soft_file, dst_file))
    except:
        myprint('make soft link except, old:' + soft_file)


if __name__ == '__main__':
    # 先把源头根目录下的文件复制,以及其文件夹推入DIRS_LIST
    doing_copy_file(SOURCE_ROOT)

    # 一层一层目录遍历完,DIRS_LIST清空程序才结束
    while len(DIRS_LIST) > 0:
        current = DIRS_LIST.pop(0)
        # myprint('now doing->', current)
        if os.path.islink(current) == True:
            # 若是软链接,不进入目录,只获取软链接信息并在新mfs里创建同名软链接
            make_soft_link(current)
        else:
            # 在mfs下属文件夹中该目录不存在则创建
            dst = current.replace(SOURCE_ROOT, TARGET_ROOT)
            if os.path.exists(dst) == False:
                os.system('mkdir -p ' + dst)
            doing_copy_file(current)
           
    print('done!')

おすすめ

転載: www.cnblogs.com/xrszff/p/10960196.html