本文介紹同賬號和跨賬號下(包括同區域和跨區域)的數據復制常見問題以及排查方法。
為什么無法創建數據復制規則?
權限問題
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。
無地域屬性Bucket跨區域復制是否收費?
收費。無地域屬性Bucket進行跨區域復制時也會產生跨區域流量費用、請求費用等費用。