本文介紹如何使用robocopy工具實現阿里雲Apsara File Storage NAS SMB協議檔案系統之間的資料移轉。
前提條件
擁有一個存有資料的SMB協議檔案系統,並且擁有一個專用網路類型掛載點。
背景資訊
Robocopy是Windows系統內建的目錄複寫命令,該功能可以建立兩個檔案結構完全的鏡像副本而不複製任何不需要的重複檔案,同時還允許您保留所有相關檔案資訊,包括日期、時間戳記等等。
費用說明
NAS與NAS之間的遷移,會涉及如下費用:
準備工作
NAS檔案系統之間進行資料移轉時,需要雲端服務器可以同時訪問源NAS和目的NAS。因此,您需要確保通過同一個阿里雲Virtual Private Cloud可以同時訪問兩個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:\