本文介紹如何使用robocopy工具實現阿里云文件存儲NAS SMB協議文件系統之間的數據遷移。
前提條件
擁有一個存有數據的SMB協議文件系統,并且擁有一個專有網絡類型掛載點。
背景信息
Robocopy是Windows系統自帶的目錄復制命令,該功能可以創建兩個文件結構完全的鏡像副本而不復制任何不需要的重復文件,同時還允許您保留所有相關文件信息,包括日期、時間戳等等。
費用說明
NAS與NAS之間的遷移,會涉及如下費用:
準備工作
NAS文件系統之間進行數據遷移時,需要云服務器可以同時訪問源NAS和目的NAS。因此,您需要確保通過同一個阿里云專有網絡VPC可以同時訪問兩個NAS。
查看源文件系統掛載點信息。
配置目標文件系統掛載點。
文件系統同地域
目標文件系統與源文件系統的掛載點屬于同一VPC下時,在獲取目標掛載點信息后,即可參照實施遷移進行數據遷移。
目標文件系統與源文件系統的掛載點不屬于同一VPC下時,可以采用以下三種方式準備掛載點:
在目標地域和可用區創建新的文件系統,自動創建新的掛載點。具體操作,請參見通過控制臺創建通用型NAS文件系統。
說明如果您購買按量付費的通用型NAS(容量型/性能型/高級型)SMB協議文件系統,請選擇與源掛載點相同的VPC網絡和虛擬交換機,即可自動生成目標掛載點。在新的文件系統創建之后,可以購買資源包進行抵扣,以節省費用。
在已有的文件系統上創建新的掛載點。具體操作,請參見添加掛載點。
通過云企業網將目標掛載點與源掛載點的VPC網絡互相連通。具體操作,請參見通過云企業網實現同地域跨VPC掛載NAS。
文件系統跨賬號或跨地域
如果您的目標文件系統與源文件系統的掛載點信息不在同一個賬號或同地域下時,則需通過云企業網將您的VPC網絡互相連通。具體操作,請參見通過云企業網實現跨賬號跨地域掛載NAS。
實施遷移
在準備好源和目標掛載點后,創建新的ECS,同時掛載兩個SMB協議文件系統后,使用Robocopy工具進行復制即可實現數據遷移。遷移數據的操作如下所示。
掛載源和目標文件系統。
重要推薦購買新的臨時ECS執行遷移操作。如果使用已有的ECS執行遷移操作,會與正在運行的業務爭搶CPU和網絡帶寬資源。
登錄ECS管理控制臺單擊創建實例后,配置如下重要信息。
網絡及可用區:選擇源文件系統所在的地域及可用區。
實例規格:一般選擇最低規格即可。
鏡像:選擇Windows Server版本,建議您選擇2019版本 。
存儲:單擊共享盤NAS(選填)下方的添加文件存儲進行配置,詳情請參考下圖示例。
說明如果源和目標掛載點都在同一個VPC網絡中,可以在ECS購買頁面中配置NAS掛載信息,ECS啟動后,源和目標NAS文件系統會自動掛載。
如果源和目標掛載點不在同一個VPC網絡或同一地域或同一賬號中時,在ECS購買頁面中只需配置源文件系統。在ECS完成創建后,手動掛載目標文件系統。關于手動掛載目標文件系統的操作,請參見掛載SMB協議文件系統。
在ECS創建成功后,源和目標NAS文件系統掛載完成,請執行以下命令確認。
net use
如果掛載成功,界面會顯示以下信息。源文件系統掛載到了Z盤,目標文件系統掛載到了Y盤。
狀態 本地 遠程 網絡 ------------------------------------------------------------------------------ OK Y: \\29e9c24****-eab13.cn-wulanchabu.nas.aliyuncs.com\myshare MicrosoftWindowgNetwork OK Z: \\29fe7f4****-txr31.cn-wulanchabu.nas.aliyuncs.com\myshare MicrosoftWindowgNetwork
遷移數據。
執行以下命令,將源文件系統(Z盤)中的數據遷移到目標文件系統(Y盤)中。
robocopy Z:\ Y:\ /e /w:5 /z /mt:32
說明僅遷移指定目錄下的數據,不包括指定目錄。
重要字段說明如下,請根據實際情況替換。
參數
說明
/mt
設置并發的線程數。默認值為8。
取值為1~128。
本文示例32個線程進行多線程復制。
/w
設置每次錯誤重試的間隔秒數。
/z
開啟斷點續傳。
/e
拷貝所有子目錄(包括空目錄)。
/copyall
復制所有的文件信息。包含:
數據
屬性
時間戳
訪問控制列表(ACL)
所有者信息
審計信息
說明如果您想加速遷移海量數據(例如,10 T以上的上億小文件),可通過在windows ECS上安裝最新的Python程序執行遷移。具體操作,請參見如何加速遷移數據至NAS SMB協議文件系統。
檢查遷移結果。
遷移完后,執行以下Robocopy命令,檢查目標文件系統是否與源文件系統一致。
ROBOCOPY Z:\ Y:\ /e /l /ns /njs /njh /ndl /fp /log:reconcile.txt
重要字段說明如下,請根據實際情況替換。
/e:僅列出目錄(包括空目錄)。
/l:不修改或復制文件,僅記錄差異。
/fp:指在日志中包括文件的完整路徑(僅在省略/ndl時有必要)。
/ns:指不在日志中包括文件大小。
/ndl:指不在日志中包括文件夾。
/njs:指不包括作業摘要。
/njh:不包括作業頭。
/log:reconcile.txt:將遷移結果寫入reconcile.txt日志中。如果已存在,將覆蓋現有日志。
切換應用到新的文件系統
在數據遷移完成后,如果您需要將現有業務從舊的文件系統切換到新的文件系統上,請在所有ECS和容器上卸載舊的文件系統,然后掛載新的文件系統。
使用ECS直接掛載NAS文件系統。
執行
net use
記錄現有NAS掛載信息,注意NAS掛載到的本地盤符。執行命令,卸載舊的文件系統。
net use Z: /delete
掛載命令中的盤符(Z:),請根據實際掛載盤符進行替換。
說明執行 net use * /delete命令,手動卸載Windows系統中所有已掛載的文件系統。
執行net use * /delete /y命令,自動卸載Windows系統中所有已掛載的文件系統。
掛載新文件系統到原本的盤符。更多有關掛載參數的信息,請參見掛載SMB協議文件系統。
啟動訪問NAS的進程,確認讀寫正常。
修改auto_mount.bat中的自動掛載信息,將舊的掛載點替換為新的掛載點。
使用Windows容器掛載NAS文件系統。
修改現有YAML配置文件,將舊的掛載點替換為新掛載點。
用修改后的配置文件生成新pod,確認其掛載新的文件系統成功并可正常讀寫。
回收使用舊的文件系統的所有pod。
在業務切換到新的文件系統后,請繼續保留舊的文件系統的數據至少一個星期。不要立刻刪除舊的文件系統里的數據,以避免因數據誤刪除或誤同步而造成數據丟失。
常見問題
如何加速遷移數據至NAS SMB協議文件系統
如果您需要加速遷移海量數據(例如,10 T以上的上億小文件,單個文件100K左右的文件),同時也在往同樣的SMB文件系統中寫入大量的業務數據。您可通過在windows ECS上安裝最新的Python程序執行遷移。具體操作如下:
下載并安裝最新的Python程序。
設置Python執行路徑到系統環境變量PATH中(例如,C:\Python27)。
set PATH=%PATH%;C:\python27
您也可以執行
where python
命令,查看python的安裝路徑。如下圖所示。將如下所示的migration.py腳本拷貝到阿里云ECS實例的本地目錄。例如C:\。
#!/usr/bin/python import os import random import string import sys, getopt import datetime import time def execute_cmd(cmd): print('\tExecuting cmd: %s' % cmd) count = 0 rc = 0 while (count < 3*60): rc = os.system(cmd) if (rc != 0): count += 1 time.sleep(1) continue else: break if rc != 0: print('\tFailed to execute cmd: %s. rc:%d' %(cmd, rc)) return def migrate_subdirs(srcPath, dstPath, rangeBegin, rangeEnd, ignoreFile): currTimeStr = datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S") print('Start to migrate from %s to %s for subdir range[%s, %s] at %s.\n' %(srcPath, dstPath, rangeBegin, rangeEnd, currTimeStr)) index = 0 for entry in os.listdir(srcPath): if os.path.isdir(os.path.join(srcPath, entry)): if index >= rangeBegin and index <= rangeEnd: srcSubDir = srcPath + "\\" + entry dstSubDir = dstPath + "\\" + entry print('\tBegin of migrating from the %d th dir %s to %s.' %(index, srcSubDir, dstSubDir)) cmd = "robocopy \"" + srcSubDir + "\" \"" + dstSubDir + "\" /e /w:5 /z /mt:32" if ignoreFile.strip(): cmd += " /XF \"" + ignoreFile + "\"" cmd += " >> robocopy.log" execute_cmd(cmd) print('\tEnd of migrating from %s to %s.\n' %(srcSubDir, dstSubDir)) index += 1 print('Finish to migrate from %s to %s for subdir range[%s, %s] at %s.\n' %(srcPath, dstPath, rangeBegin, rangeEnd, datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S"))) def migrate_regfiles(srcPath, dstPath, ignoreFile): currTimeStr = datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S") print('Start to migrate from %s to %s for regular files at %s.\n' %(srcPath, dstPath, currTimeStr)) for entry in os.listdir(srcPath): if os.path.isfile(os.path.join(srcPath, entry)): print('\tBegin of migrating %s from %s to %s.\n' %(entry, srcPath, dstPath)) cmd = "attrib -R \"" + dstPath + "\\\\" + entry + "\"" execute_cmd(cmd) cmd = "copy \"" + srcPath + "\\\\" + entry + "\" \"" + dstPath + "\" /Y" if ignoreFile.strip(): cmd += " /XF \"" + ignoreFile + "\"" cmd += " >> robocopy.log" execute_cmd(cmd) print('\tEnd of migrating %s from %s to %s' %(entry, srcPath, dstPath)) print('Finish to migrate from %s to %s for regular files at %s.\n' %(srcPath, dstPath, datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S"))) def main(argv): srcPath = '' dstPath = '' range = '' ignoreFile = '' try: opts, args = getopt.getopt(argv,"hs:d:r:i:f",["srcPath=","dstPath=","range=","ignore="]) except getopt.GetoptError: print('migration.py -s <source path> -d <destination path> [-r BeginIndex:EndIndex | -f] [-i ignoredFile]') print('example: migration.py -s x:\pic -d z:\pic [-r 0:100]') sys.exit(2) subdironly = False fileonly = False for opt, arg in opts: if opt == '-h': print('migration.py -s <source path> -d <destination path> [-r BeginIndex:EndIndex | -f] [-i ignoredFile]') sys.exit() elif opt in ("-s", "--srcPath"): srcPath = arg elif opt in ("-d", "--dstPath"): dstPath = arg elif opt in ("-r", "--range"): range = arg subdironly = True elif opt in ("-f", "--file"): fileonly = True elif opt in ("-i", "--ignore"): ignoreFile = arg if not srcPath.strip() or not dstPath.strip(): print('migration.py -s <source path> -d <destination path> [-r BeginIndex:EndIndex | -f] [-i ignoredFile]') sys.exit() if subdironly and fileonly: print('migration.py -s <source path> -d <destination path> [-r BeginIndex:EndIndex | -f] [-i ignoredFile]') sys.exit() if not fileonly: if not range.strip(): rangeBegin = 0 rangeEnd = sys.maxsize-1 else: rangeBegin, rangeEnd = (int(x) for x in range.split(":")) if rangeBegin < 0 or rangeEnd >= sys.maxsize or rangeEnd < rangeBegin: print('migration.py -s <source path> -d <destination path> [-r BeginIndex:EndIndex | -f] [-i ignoredFile]') print('example: migration.py -s x:\pic -d z:\pic -r 0:99') sys.exit() migrate_subdirs(srcPath, dstPath, rangeBegin, rangeEnd, ignoreFile) if not subdironly: migrate_regfiles(srcPath, dstPath, ignoreFile) if __name__ == "__main__": main(sys.argv[1:])
遷移數據。命令格式:
python ./migration.py -s <source path> -d <destination path> [-r BeginIndex:EndIndex | -f] [-i ignoredFile]
。命令格式中主要參數說明如下表所示。
參數
說明
-s <source path>
指定源文件系統掛載點的目錄。例如
-s Z:\
,表示為源文件系統掛載點的目錄為Z盤根目錄。-d <destination path>
指定目標文件系統的掛載點目錄。例如
-d Y:\
,表示目標文件系統的掛載點目錄為Y盤根目錄。-r BeginIndex:EndIndex
指定要遷移的文件范圍,從
BeginIndex
到EndIndex
,例如-r 1:100
,表示要遷移的文件列表為1到100。-f
指定只遷移源文件系統目錄中的第一層的普通文件。
遷移源文件系統目錄中的所有文件,忽略范圍限制。
-i ignoredFile
指定源文件系統目錄中無需遷移的文件。例如
-i ignored.txt
,表示不遷移文件名為ignored.txt
的文件。說明缺省時,不需要設置-r或-f,script會順序Robocopy所有子目錄后再copy第一層的普通文件。如果希望利用多客戶端的cpu/network來并發加速遷移不同的子目錄,在所有客戶端都可以訪問同一個源盤時,可以指定遷移的子目錄的range,比如第一個客戶端使用
-r 0:9999
, 第二個客戶端使用-r 10000:19999
等等。例如,將源文件系統Z:\中的數據遷移至目標文件系統的Y:\。示例如下:
python ./migration.py -s Z:\ -d Y:\