本文介紹同帳號和跨帳號下(包括同地區和跨地區)的資料複製常見問題以及排查方法。
為什麼無法建立資料複製規則?
許可權問題
Bucket版本控制狀態不一致
開啟資料同步的源Bucket和目標Bucket的版本控制狀態必須一致,即這兩個Bucket同時處於未開啟或者已開啟版本控制。
Endpoint或者AccessKey等配置不正確
通過SDK或者ossutil等方式建立資料複製規則時,需要檢查以下配置:
檢查用於建立複製關係的源Bucket以及目標Bucket所在地區的Endpoint是否正確。更多資訊,請參見訪問網域名稱和資料中心。
檢查建立複製關係的AccessKey是否正確。更多資訊,請參見查看RAM使用者的AccessKey資訊。
為什麼源Bucket對象副本未出現在目標Bucket?
在源儲存空間(Bucket)配置了資料複製規則後,如果對象副本未出現在目標Bucket中,請參考以下幾種可能原因排查並修複問題。
時間限制
資料複製採用非同步(近即時)複製的機制,將資料複製到目標Bucket需要一定的時間,通常幾分鐘到幾小時不等,取決於資料的大小。如果要複製的對象較大,請稍等片刻,再檢查對象副本是否出現在目標Bucket中。
源Bucket配置問題
資料複製狀態是否為已開啟(Enabled)。
首碼(Prefix)是否正確。
同步指定對象:如果需要同步源Bucket中的指定對象到目標Bucket,請將Prefix設定為指定對象名稱。例如,Prefix設定為log,則僅複製log/date1.txt、log/date2.txt等以log開頭的對象。與指定Prefix不匹配的對象不會複製到目標Bucket,例如date3.txt。
同步所有對象:如果需要將源Bucket中的全部對象複製到目標Bucket時,請將Prefix置空。
複製規則限制
如果Bucket中的某個對象是另一個複製配置建立的副本,則OSS不會複製該對象。例如,您配置了Bucket A同步到Bucket B,Bucket B再同步到Bucket C,則OSS不會將從Bucket A同步到Bucket B的對象副本複製到Bucket C。
未選中複製KMS加密目標對象
在源Object或者目標Bucket使用了KMS託管祕密金鑰加密方式(即SSE-KMS,指定CMK ID)的情況下,要將Object複製到目標Bucket,則必須選中複製,並配置以下參數:
使用的KMS密鑰:為目標Object指定加密的KMS密鑰。
您需要提前在KMS平台建立一個與目標Bucket相同地區的KMS密鑰。具體操作,請參見建立密鑰。
授權角色:授權一個RAM角色對目標Object執行KMS加密操作。
建立角色:建立RAM角色對目標Object執行KMS加密,角色名稱格式為
kms-replication-源Bucket名稱-目標Bucket名稱
。AliyunOSSRole:使用AliyunOSSRole角色對目標Object執行KMS加密。若您之前未建立AliyunOSSRole角色,當您選擇此項時,OSS將自動建立AliyunOSSRole角色。
說明如果是您建立的角色或者修改角色許可權時,請確保授予角色
AliyunOSSFullAccess
的許可權,否則可能導致資料無法複製。
您可以通過HeadObject和GetBucketEncryption分別查詢源Object和目標Bucket的加密狀態。
如何驗證複製完成後目標Bucket與源Bucket的資料是否一致?
您可以通過以下代碼驗證複製完成後目標Bucket與源Bucket的資料一致性。
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.model.*;
import com.aliyun.oss.OSSException;
import com.aliyuncs.exceptions.ClientException;
public class Demo {
public static void main(String[] args) throws ClientException {
// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// srcEndpoint填寫Bucket所在地區對應的Endpoint。
String srcEndpoint = "https://oss-cn-hangzhou.aliyuncs.com";
OSSClient srcClient = new OSSClient(srcEndpoint , credentialsProvider);
// 填寫源Bucket名稱。
String srcBucketName = "src-replication-bucket";
// destEndpoint填寫Bucket所在地區對應的Endpoint。
String destEndpoint = "https://oss-cn-beijing.aliyuncs.com";
OSSClient destClient = new OSSClient(destEndpoint, credentialsProvider);
// 填寫目標Bucket名稱。
String destBucketName = "dest-replication-bucket";
// 源Bucket與目標Bucket處於非版本控制狀態時,通過listObjectsV2列舉源Bucket被複製的檔案。
// 源Bucket與目標Bucket處於開啟或暫停版本控制狀態時,通過listVersions列舉源Bucket被複製的檔案。
ListObjectsV2Result result;
ListObjectsV2Request request = new ListObjectsV2Request(srcBucketName);
do {
result = srcClient.listObjectsV2(request);
for (OSSObjectSummary summary : result.getObjectSummaries())
{
String objectName = summary.getKey();
ObjectMetadata srcMeta;
try {
// 擷取源Bucket被複製檔案的中繼資料。
srcMeta = srcClient.headObject(srcBucketName, objectName);
} catch (OSSException ossException) {
if (ossException.getErrorCode().equals("NoSuchKey")) {
continue;
} else {
System.out.println("head src-object failed: " + objectName);
}
continue;
}
ObjectMetadata destMeta;
try {
// 擷取複製到目標Bucket的檔案中繼資料。
destMeta = destClient.headObject(destBucketName, objectName);
} catch (OSSException ossException) {
if (ossException.getErrorCode().equals("NoSuchKey")) {
System.out.println("dest-object not exist: " + objectName);
} else {
System.out.println("head dest-object failed: " + objectName);
}
continue;
}
// 檢查源Bucket與目標Bucket複製檔案的CRC是否一致。
Long srcCrc = srcMeta.getServerCRC();
String srcMd5 = srcMeta.getContentMD5();
if (srcCrc != null) {
if (destMeta.getServerCRC() != null) {
if (!destMeta.getServerCRC().equals(srcCrc)) {
System.out.println("crc not equal: " + objectName
+ " | srcCrc: " + srcCrc + " | destCrc: " + destMeta.getServerCRC());
}
continue;
}
}
// 檢查源Bucket與目標Bucket複製檔案的MD5是否一致。
if (srcMd5!= null) {
if (destMeta.getContentMD5() != null) {
if (!destMeta.getContentMD5().equals(srcMd5)) {
System.out.println("md5 not equal: " + objectName
+ " | srcMd5: " + srcMd5 + " | destMd5: " + destMeta.getContentMD5());
}
continue;
}
}
// 檢查源Bucket與目標Bucket複製檔案的ETag是否一致。
if (srcMeta.getETag() == null || !srcMeta.getETag().equals(destMeta.getETag())) {
System.out.println("etag not equal: " + objectName
+ " | srcEtag: " + srcMeta.getETag() + " | destEtag: " + destMeta.getETag());
}
}
request.setContinuationToken(result.getNextContinuationToken());
request.setStartAfter(result.getStartAfter());
} while (result.isTruncated());
}
}
是否支援複製傳遞?
不支援。例如,Bucket A配置了到Bucket B的資料複製規則(本樣本中提及的資料複製規則包括跨地區或者同地區複製),Bucket B配置了到Bucket C的資料複製規則,則Bucket A的資料僅複製到Bucket B,不會複製到Bucket C。
如果要將Bucket A的資料複製到Bucket C,則您還需要為Bucket A配置到Bucket C的資料複製規則。
有種特殊情況,如果Bucket A和Bucket B同時開啟了歷史複製,在歷史複製未完成時,有可能存在新寫入Bucket A的資料被歷史複製的任務掃描到,從而複製到Bucket C中。
OSS Bucket雙向同步是否會有迴圈複製的風險?
不會有風險。Bucket A與Bucket B之間配置雙向複製關係後,通過複製關係從Bucket A到Bucket B的資料(包括新增和歷史資料),不會再次從Bucket B複製到Bucket A。同理,通過複製關係從Bucket B到Bucket A的資料(包括新增和歷史資料),不會再次從Bucket A複製到Bucket B。
源Bucket通過生命週期規則指定刪除的檔案,目標Bucket是否會同步刪除這些檔案?
源Bucket資料複製策略指定為增/改 同步,則源Bucket通過生命週期規則指定刪除的檔案,目標Bucket不會同步刪除這些檔案。
源Bucket資料複製策略指定為增/刪/改 同步,則源Bucket通過生命週期規則指定刪除的檔案,目標Bucket也會同步刪除這些檔案。
說明如果您在目標Bucket仍然可以找到源Bucket通過生命週期指定刪除的檔案,並非是增/刪/改 同步的資料複製策略不生效,可能是您通過目標Bucket手動寫入了與源Bucket刪除的同名檔案。
為什麼歷史資料複製進度長時間顯示為0%?
歷史資料複製進度並非即時更新,需要等待所有檔案掃描完成後才會複製更新。如果您Bucket內的檔案數量較多(例如達到上億層級),則可能需要等待數小時才會更新歷史資料複製進度。歷史資料複製進度未更新,並不代表歷史資料沒有複製到目標Bucket。
您可以通過查看目標Bucket的儲存容量以及複製流入和流出流量產生的變化,確認源Bucket內的歷史資料是否已開始複製到目標Bucket。關於查看目標Bucket的儲存容量以及複製流入和流出流量的具體步驟,請參見查詢Bucket層級的用量情況。
暫停版本控制狀態下的Bucket是否支援資料複製?
不支援。僅允許對同時處於非版本化或開啟版本控制狀態的兩個Bucket開啟資料複製。
如果目標Bucket採用KMS加密,是否收取KMS加密的密碼編譯演算法API費用?
如果目標Bucket採用KMS加密,會收取KMS加密的密碼編譯演算法API費用。費用詳情,請參見KMS計費說明。
開啟資料複製後,是否支援關閉?
支援。您可以通過單擊規則右側的關閉複製來停止資料複製。
關閉複製後,已複製的資料將被保留在目標Bucket中,源Bucket中的增量資料將不再複製到目標Bucket。