設定邏輯複製和解碼

您可以在 PostgreSQL 適用的 Cloud SQL 中使用邏輯複製和解碼功能。這些功能可啟用邏輯複製工作流程和變更資料擷取 (CDC) 工作流程。

如需複製作業的一般資訊,請參閱「關於 Cloud SQL 中的複製作業」。

簡介

PostgreSQL 執行邏輯複製時,會使用邏輯解碼功能,從 WAL 記錄檔中擷取串流至副本的變更。解碼後的變更與基礎實體儲存格式無關。這些變更只會反映 SQL 層級的資料變更,包括 INSERT、UPDATE 和 DELETE。這種與儲存層的獨立性提供極大的彈性,並讓變更串流的消費者能夠使用各種功能。

邏輯複製是建構在邏輯解碼基礎上的旗艦功能。

PostgreSQL 的實體複製功能要求來源和目的地資料庫必須是相同版本,但邏輯複製功能可跨 PostgreSQL 主要版本進行複製。Cloud SQL 中的邏輯複製功能支援 pglogical 擴充功能 (適用於所有 PostgreSQL 版本),以及 PostgreSQL 的原生邏輯複製功能 (已在 PostgreSQL 10 中新增)。

您可以使用不同的外掛程式,設定變更的串流格式。這可讓您靈活運用變更資料擷取 (CDC) 架構。舉例來說,wal2json 擴充功能可將資料庫中的所有變更以 JSON 格式串流至消費者。Cloud SQL 支援內建的 pgoutput 解碼器、test_decoding contrib 模組和 wal2json。Cloud SQL 目前支援兩種 wal2json 變體的 JSON 輸出內容 - format-version 1 會將整個交易編碼為單一 JSON 物件,而 format-version 2 則會為每個指令輸出一個 JSON 物件。這些外掛程式可將資料複製到非 PostgreSQL 資料庫。

設定 PostgreSQL 執行個體

PostgreSQL 會將額外資訊寫入預先寫入記錄 (WAL),藉此支援邏輯解碼。

在 Cloud SQL 中,您需要將 cloudsql.logical_decoding 旗標設為 on,才能啟用這項功能。這項設定與標準 PostgreSQL 中使用的設定不同。如要變更外部 PostgreSQL 執行個體,請將 wal_level 設定參數設為 logical,啟用這項功能。

如果您打算使用 pglogical 擴充功能,必須將 pglogical 新增至 shared_preload_libraries。由於 Cloud SQL 不允許直接修改這個旗標,因此請將 cloudsql.enable_pglogical 設為 on,啟用 pglogical。(在 VM 上,sudo apt-get install postgresql-13-pglogical ),然後重新啟動資料庫。

如果您使用 pglogical 在兩個 PostgreSQL 執行個體之間複製資料,只需要在主要執行個體上啟用邏輯解碼功能,副本執行個體則不需要 (除非該執行個體本身是其他副本的主要執行個體)。不過,您必須在兩個執行個體上啟用 pglogical 擴充功能。 如需「主要」和「備用資源」這兩個詞彙的用法和含義範例,請參閱「關於 Cloud SQL 中的複製功能」。

啟用網路連線

確認主要執行個體接受來自副本執行個體的連線。

主要 備用資源 設定
Cloud SQL (公開 IP) Cloud SQL (公開 IP) 將副本的輸出 IP 位址新增至主要執行個體的授權網路
Cloud SQL (私人 IP) Cloud SQL (私人 IP) 如果兩個執行個體位於同一個 Google Cloud 專案,請將副本虛擬私有雲網路的已分配 IP 範圍新增至代管執行個體的授權網路

如要在 Google Cloud 控制台中找出分配的 IP 範圍,請按照下列步驟操作:

  1. 前往「VPC networks」(VPC 網路) 頁面
  2. 選取您使用的 VPC 網路。
  3. 選取 [Private service connection] (私人服務連線) 分頁標籤。
  4. 選取「已分配的 IP 範圍」分頁標籤。
外部 Cloud SQL 您可以使用 Database Migration Service
Cloud SQL 外部 詳情請參閱「設定外部備用資源」一節。

取得副本執行個體的傳出 IP 位址

如果副本執行個體是 Cloud SQL 執行個體,且具有公開 IP 位址,請按照下列步驟取得其傳出 IP 位址。

控制台

  1. 開啟 Cloud SQL 執行個體頁面

  2. 將滑鼠游標懸停在 Cloud SQL 副本的公開 IP 位址旁邊的「更多資訊」工具提示上,然後擷取外送 IP 位址。請注意,傳出 IP 位址並非 Cloud 控制台中備用資源主要清單顯示的 IP 位址。

如果備用資源執行個體不是 Cloud SQL 執行個體,請參閱相關說明文件。

如要進一步瞭解如何取得執行個體的公開 IP 位址,請參閱「取得 Cloud SQL 副本的外送 IP 位址」。

gcloud

您可以使用下列 gcloud 指令:

gcloud sql instances describe [REPLICA_NAME] --format="default(ipAddresses)"

允許連線

如果主要執行個體是 Cloud SQL 執行個體,您可以將副本的外送 IP 位址新增為已授權網路,允許該位址存取主要執行個體。

為 PostgreSQL 9.6 和更早版本啟用複製連線

如果主要執行個體並非在 Cloud SQL 中執行,而是執行 PostgreSQL 9.6 或更早版本,請務必確保執行個體的 pg_hba.conf 檔案已設為接受複寫連線。在該檔案中加入下列程式碼行,僅供初步測試使用 all all。為提高安全性,請只允許必要的使用者和 IP 位址,如以下範例所示:

host replication all all md5

詳情請參閱「pg_hba.conf 檔案」。

建立複製使用者

如要使用邏輯解碼功能,請建立具有 REPLICATION 屬性的 PostgreSQL 使用者。

範例

CREATE USER replication_user WITH REPLICATION
IN ROLE cloudsqlsuperuser LOGIN PASSWORD 'secret';

或者,您也可以為現有使用者設定這項屬性:

ALTER USER existing_user WITH REPLICATION;

PostgreSQL 資源

使用邏輯解碼時,主要 PostgreSQL 執行個體上的背景程序會使用所選解碼外掛程式,將 WAL 變更轉換為邏輯變更,並轉送至消費者 (甚至可能是非 PostgreSQL 執行個體)。這個背景程序稱為 WAL 傳送器。 PostgreSQL 執行個體中可同時啟用的 WAL 傳送者數量,受限於 max_wal_senders 標記。這個標記預設為 10,上限會隨著 Cloud SQL 執行個體的記憶體線性成長,每 1 GB 記憶體可有 8 個 WAL 傳送者。

為確保 WAL 區段不會在傳送至所有消費者之前遭到捨棄,PostgreSQL 會使用邏輯複製運算單元追蹤哪些資料已傳送至哪些消費者 (以及用於讀取副本的實體複製運算單元)。您可以為 PostgreSQL 執行個體建立的複製運算單元數量,受限於 max_replication_slots 標記。這個旗標預設為 10,上限會隨著 Cloud SQL 執行個體的記憶體增加,每 GB 記憶體可允許 2 到 8 個複製作業時段。

下表顯示 Cloud SQL 執行個體的最大記憶體,以及該執行個體可用的最大複製時段。

記憶體上限 (GB)
複製運算單元數量上限
4
10
16
32
32
128
64
256
128
512
256
1024
512
2048
512 以上
4096

一般來說,每個消費者都有一個複製時段和 WAL 傳送者,因此這些標記應設為大致相等的值。不過,PostgreSQL 建議為 max_wal_senders 提供少量緩衝區,以便處理連線意外終止並建立新連線的情況。Cloud SQL 唯讀副本使用的實體複製功能也會用到複製時段和 WAL 傳送器,因此計算各項資源的需求數量時,請將這些資源納入考量。

PostgreSQL 原生邏輯複製和 pglogical 需要額外的背景程序,才能在主要和備用執行個體上執行。可執行的背景程序數量受 max_worker_processes 標記限制。預設值為 8,上限會隨著 Cloud SQL 執行個體的記憶體線性增加,每 GB 記憶體可增加兩個程序。這些方法使用的確切工作站程序數量,請參閱各節說明。

如果這項旗標設定過低,且複製作業失敗,記錄中顯示 worker registration failed 錯誤訊息,您可能需要提高 max_worker_processes 設定。

請注意,WAL 傳送器不會計為工作程序。為平行查詢執行作業產生的背景工作會計入,因此如果 max_worker_processes 的值設定過低,PostgreSQL 就無法運用平行查詢執行作業,您可能會遇到效能不佳的情況。

使用 pg_ls_waldir () 函式,即可判斷 WAL 磁碟用量。這項功能僅限 cloudsqlsuperuser 使用者使用,例如預設管理員使用者 postgres。這項函式僅適用於 PostgreSQL 10 以上版本。

如要計算 WAL 磁碟總用量,請按照下列步驟操作:

postgres=> select * from pg_ls_waldir();
名稱 大小 修改
00000001000000000000000A 16777216 2021-08-11 15:16:49+00
000000010000000000000009 16777216 2021-08-12 06:23:24+00

(2 列)

postgres=> select pg_size_pretty(sum(size)) as "Total WAL disk usage" from pg_ls_waldir();
WAL 磁碟總用量
32 MB

(1 列)

使用外部備用資源設定邏輯複製

如需使用 pglogical 和邏輯解碼的完整範例,請參閱「 設定外部備用資源」。

使用 pglogical 設定邏輯複製

如要使用 pglogical 設定邏輯複製,必須先在主要執行個體上啟用邏輯解碼。在 Cloud SQL 執行個體上設定 cloudsql.logical_decoding=on,或在外部執行個體上設定 wal_level=logical。此外,主要和備用資源執行個體都必須啟用 pglogical;在 Cloud SQL 執行個體上設定 cloudsql.enable_pglogical=on,或在外部執行個體上將 pglogical 新增至 shared_preload_libraries。請注意,變更這些標記需要重新啟動主要和副本執行個體。

如果這些步驟發生問題,請參閱「排解 pglogical 問題」。

建立具備複製權限的使用者

使用 pglogical 時,您需要具備複製權限的使用者,以及主要和副本執行個體上的 cloudsqlsuperuser 角色。以下所述的任何指令都應由該使用者執行。

安裝 pglogical 擴充功能

您需要在主要和副本執行個體上安裝 pglogical 擴充功能。在主要伺服器上,複製使用者 (即連線至資料庫的使用者) 必須安裝此外掛程式。

CREATE EXTENSION pglogical;

在每個執行個體上建立 pglogical 節點

pglogical 節點代表實體 PostgreSQL 執行個體,並儲存該執行個體的連線詳細資料。主要和副本執行個體都必須註冊為節點:

source-instance$ SELECT pglogical.create_node(
    node_name := 'primary',
    dsn := 'host=<primary-ip> port=5432 dbname=postgres user=replication_user password=secret'
);

dest-instance$ SELECT pglogical.create_node(
    node_name := 'replica',
    dsn := 'host=<replica-ip> port=5432 dbname=postgres user=replication_user password=secret'
);

建立要複製的資料表

pglogical 擴充功能只允許將部分資料表複製到目的地。舉例來說,我們會在主要執行個體上建立虛擬資料表,並填入一些資料進行測試:

CREATE TABLE replica_test (id SERIAL PRIMARY KEY, data text);
INSERT INTO replica_test (data) VALUES ('apple'), ('banana'), ('cherry');

資料表也必須在副本執行個體上建立。

將資料表新增至複製集

為支援將不同資料集複製到不同目的地,pglogical 採用了複製集的概念。我們可以將測試資料表新增至預設複寫集。

SELECT pglogical.replication_set_add_table('default', 'replica_test', true);

建立 pglogical 訂閱項目

在目的地執行個體上建立 pglogical 訂閱項目,並提供主要執行個體的連線詳細資料。

SELECT pglogical.create_subscription(
    subscription_name := 'test_sub',
    provider_dsn := 'host=<primary-ip> port=5432 dbname=postgres user=replication_user password=replicapassword'
);

SELECT * FROM pglogical.show_subscription_status('test_sub');

如果狀態顯示為「正在複製」,表示設定成功。查詢 replica_test 資料表,確認資料已複製。在主要執行個體上插入及修改記錄,並確認這些記錄隨後會顯示在副本執行個體上。

在主要資料庫中,查詢 pg_replication_slots 資料表,查看訂閱項目建立的複寫位置。

清除所用資源

測試成功後,請使用 pglogical.drop_subscription('test_sub') 在副本上捨棄訂閱項目。確認主要節點上的複製時段也已捨棄。否則,WAL 區段會繼續累積在副本執行個體上。

如要進一步瞭解複寫集、部分資料複寫、DDL 複寫、其他進階設定和限制,請參閱 pglogical 說明文件

資源使用情況

pglogical 擴充功能會執行多個背景程序,這些程序會計入 max_worker_processes 限制。

在穩定狀態下,啟用時會執行一個「監督員」程序,每個已安裝擴充功能的 PostgreSQL 資料庫會執行一個「管理員」程序 (例如,可能有 D 個),副本執行個體上的每個 pglogical 訂閱項目會執行一個「套用」程序 (例如,可能有 S 個)。不過,擴充功能在執行初始同步時可能會產生額外的背景工作程序,而且實際上會為執行個體中的每個資料庫產生「管理員」程序,但如果資料庫未安裝擴充功能,就會立即結束。

因此,請分配比穩定狀態下所需數量多一點的工作站程序。PostgreSQL 會將工作程序用於其他用途,例如平行查詢處理。如果 max_worker_processes 設定過低,複製作業可能會無聲無息地失敗,或 PostgreSQL 可能無法執行平行查詢處理作業。

總而言之,建議您採用下列設定:

max_worker_processes
  >= 1 + D + 8 (on the source instance)
  >= 1 + D + S + 8 (on the destination instance)
max_wal_senders >= S + 2 (on the source instance)
max_replication_slots >= S (on the source instance)

排解 pglogical 問題

無法建立 pglogical 擴充功能

嘗試安裝 pglogical 擴充功能時,可能會看到以下錯誤訊息:

ERROR:  pglogical is not in shared_preload_libraries

在 Cloud SQL 執行個體上安裝 pglogical 時,請務必設定 cloudsql.enable_pglogical=on。如果使用外部執行個體,請直接將其新增至 shared_preload_libraries 旗標,例如 shared_preload_libraries=pg_stat_statements,pglogical。這些修改需要重新啟動主要執行個體。

無法建立 pglogical 訂閱項目

建立訂閱項目時,pglogical 會先檢查是否能使用連線詳細資料連線至執行個體。系統會先嘗試建立一般連線,如果失敗,就會發生 ERROR: could not connect to the postgresql server 錯誤。

如果發生這個錯誤,請確認主要執行個體已設定為允許來自副本執行個體的連線,並確認您提供的連線詳細資料正確無誤。並提供 PostgreSQL 無法建立連線的其他詳細資料。

建立一般連線後,pglogical 會嘗試建立特殊的複寫連線。在 PostgreSQL 9.6 和更早版本中,這類連線可能會有不同的驗證設定。如果看到這則錯誤訊息:ERROR: could not connect to the postgresql server in replication mode,請更新來源執行個體上的 pg_hba.conf 檔案。

Cloud SQL 使用的 pg_hba.conf 檔案已進行必要變更;只有在連線至 Cloud SQL 未管理的外部執行個體時,才會發生這個錯誤。

或者,如果來源執行個體不允許足夠的 WAL 傳送者,複製模式連線可能會失敗。如果看到 FATAL: number of requested standby connections exceeds max_wal_senders,請增加主要執行個體上的 max_wal_senders

pglogical 訂閱項目已停止運作

pglogical 訂閱項目可能無法複製。如要解決這個問題,請先確認備用執行個體正在執行背景程序。查詢 pg_stat_activity,確認 pglogical apply 程序是否正在執行。如果不是,請檢查目的地節點上的記錄。如果看到「worker registration failed,」訊息,請提高 max_worker_processes 設定。

然後,確認主要執行個體上已建立複製作業時段。在副本執行個體上,pglogical.subscription 中的資料列包含訂閱項目嘗試建立的時段名稱,而在主要執行個體上,您可以查詢 pg_replication_slots 來確認時段是否已成功建立。

如果未建立複寫位置,請檢查主要執行個體上的記錄。

ERROR: logical decoding requires wal_level >= logical 錯誤表示 wal_level 旗標未設為 logical。如要解決這個問題,請在主要執行個體上設定 cloudsql.logical_decoding=on (如果是 Cloud SQL 執行個體)。

或者,如果執行個體是外部執行個體,請設定 wal_level=logical

否則,你可能會看到 ERROR: all replication slots are in use,以及實用的 HINT: Free one or increase max_replication_slots

設定原生 PostgreSQL 邏輯複製

自 PostgreSQL 10 起,PostgreSQL 支援原生內建的邏輯複製功能。如要設定原生邏輯複製功能,必須在主要執行個體上啟用邏輯解碼功能,方法是在 Cloud SQL 執行個體上設定 cloudsql.logical_decoding=on,或在外部執行個體上設定 wal_level=logical。請注意,修改這些標記需要重新啟動主要執行個體。

請參閱「設定 PostgreSQL 執行個體」一節,確保執行個體已正確設定 (例如網路連線)。本頁提供概念驗證的步驟。如果在按照這些章節的步驟操作時遇到任何問題,請參閱「排解 pglogical 問題」。詳情請參閱 PostgreSQL 說明文件中的「邏輯複寫」。

建立要複製的資料表

原生 PostgreSQL 邏輯複寫支援整個資料庫或個別資料表。舉例來說,我們會在主要執行個體上建立虛擬資料表,並填入資料以進行測試。

CREATE TABLE native_test (id SERIAL PRIMARY KEY, data text);
INSERT INTO native_test (data) VALUES ('apple'), ('banana'), ('cherry');

資料表也必須在副本執行個體上建立。

在主要執行個體上建立出版品

PostgreSQL 原生邏輯複製功能會處理發布者和訂閱者。在 native_test 中發布資料:

CREATE PUBLICATION pub FOR TABLE native_test;

在備用資源執行個體上建立訂閱項目

以下是在副本執行個體上建立訂閱項目的範例:

CREATE SUBSCRIPTION sub
    CONNECTION 'host=<primary-ip> port=5432 dbname=postgres user=replication_user password=replicapassword'
    PUBLICATION pub;

您必須具備 cloudsqlsuperuser 角色,才能在副本執行個體上建立訂閱項目。建立訂閱項目後,請查詢 native_test 資料表,確認資料已顯示在副本例項中。

在主要節點上,您可以查詢 pg_replication_slots 資料表,查看訂閱項目建立的複寫時段。

清除所用資源

測試成功後,請使用 DROP SUBSCRIPTION sub; 在副本上捨棄訂閱項目。確認主要節點上的複製位置也已捨棄。否則 WAL 區段會繼續累積在主要執行個體上。

PostgreSQL 原生邏輯複製的限制

無法存取 pg_subscription 系統資料表的 subconninfo 資料欄。

執行 pg_dump 時,系統會檢查連線使用者是否具備超級使用者權限,因此無法傾印訂閱資訊。

接收變更資料擷取 (CDC) 的解碼 WAL 變更

除了 CDC 之外,邏輯解碼功能也可以從 PostgreSQL 執行個體串流處理變更。用於此作業的標準工具是 pg_recvlogical

您可以使用 pg_recvlogical 工具建立複製運算單元,並串流傳輸該運算單元追蹤的變更。變更的格式取決於您選擇的解碼外掛程式。例如:

建立複製運算單元

如要建立複製運算單元,請執行:

pg_recvlogical
  -h <instance_ip> \
  -U <replication_user> \
  -p 5432 \
  -d postgres \
  --slot test_slot \
  --create-slot \
  -P <decoder_plugin>

串流變更

在其中一個 Cloud Shell 終端機中執行下列指令:

pg_recvlogical
  -h <instance_ip> \
  -U <replication_user> \
  -p 5432 \
  -d postgres \
  --slot test_slot \
  --start \
  -f -

在另一個 Cloud Shell 終端機中,連線至資料庫並執行下列指令:

CREATE TABLE cdc_test (id SERIAL PRIMARY KEY, data text);
INSERT INTO cdc_test (data) VALUES ('apple', 'banana');
UPDATE cdc_test SET data = 'cherry' WHERE id = 2;
DELETE FROM cdc_test WHERE id = 1;
DROP TABLE cdc_test;

如果您使用 wal2json 解碼器外掛程式,第一個 Cloud Shell 終端機中會顯示類似下列的輸出內容:

{"change":[]}
{"change":[{"kind":"insert","schema":"public","table":"cdc_test","columnnames":["id","data"],"columntypes":["integer","text"],"columnvalues":[1,"apple"]},{"kind":"insert","schema":"public","table":"cdc_test","columnnames":["id","data"],"columntypes":["integer","text"],"columnvalues":[2,"banana"]}]}
{"change":[{"kind":"update","schema":"public","table":"cdc_test","columnnames":["id","data"],"columntypes":["integer","text"],"columnvalues":[2,"cherry"],"oldkeys":{"keynames":["id"],"keytypes":["integer"],"keyvalues":[2]}}]}
{"change":[{"kind":"delete","schema":"public","table":"cdc_test","oldkeys":{"keynames":["id"],"keytypes":["integer"],"keyvalues":[1]}}]}
{"change":[]}

如果您使用 test_decoding 解碼器外掛程式,第一個 Cloud Shell 終端機會顯示類似下列內容的輸出內容:

BEGIN 19460
COMMIT 19460
BEGIN 19461
table public.cdc_test: INSERT: id[integer]:1 data[text]:'apple'
table public.cdc_test: INSERT: id[integer]:2 data[text]:'banana'
COMMIT 19461
BEGIN 19462
table public.cdc_test: UPDATE: id[integer]:2 data[text]:'cherry'
COMMIT 19462
BEGIN 19463
table public.cdc_test: DELETE: id[integer]:1
COMMIT 19463
BEGIN 19464
COMMIT 19464

(您的交易 ID 可能不同)。

清除所用資源

完成測試後,請執行下列指令,捨棄您建立的複寫時段:

pg_recvlogical
  -h <instance_ip> \
  -U <replication_user> \
  -p 5432 \
  -d postgres \
  --slot test_slot \
  --drop-slot

注意事項和限制

本節中的注意事項和限制適用於 PostgreSQL 適用的 Cloud SQL 邏輯複製和解碼功能。

  • 如果執行個體已啟用連接器強制執行,則 pglogical 擴充功能無法運作。如果執行個體已設定私人服務存取權,則不受這項限制。

  • 還原已啟用 cloudsql.logical_decodingcloudsql.enable_pglogical,且目前做為邏輯複寫發布者的執行個體時,您必須先停用所有目標執行個體的複寫功能。否則,還原執行個體會失敗並顯示錯誤,但目前無法查看錯誤詳細資料。

  • 如果您還原的執行個體備份檔在備份時已啟用 cloudsql.logical_decodingcloudsql.enable_pglogical,且您要將備份檔還原至新的執行個體,則新的執行個體不會還原為備份時的複寫狀態。之後必須手動重新設定複製作業。

  • 在具有一或多個 Cloud SQL 唯讀備用資源 (使用實體複製) 的 Cloud SQL 執行個體上,如果啟用 cloudsql.logical_decodingcloudsql.enable_pglogical,唯讀備用資源也會啟用這些旗標。

    • 如果是 PostgreSQL 適用的 Cloud SQL 15 版和舊版,由於 PostgreSQL 不支援在這些舊版的唯讀副本上進行邏輯解碼,因此 Cloud SQL 唯讀副本執行個體無法做為邏輯複製的發布者。不過,為確保執行個體在升級時可做為主要執行個體的替代方案,這些舊版的唯讀備用資源執行個體仍會啟用邏輯旗標。

    • 從 PostgreSQL 適用的 Cloud SQL 16 版開始,如果主要執行個體已設定邏輯旗標,Cloud SQL 唯讀備用資源執行個體就能做為邏輯複寫的發布者。邏輯訂閱者可以是 Cloud SQL 執行個體或外部執行個體。不過,主要執行個體上的資料列刪除和清除作業可能會刪除讀取副本上邏輯解碼仍需要的元組。在這種情況下,讀取副本上的邏輯複製位置會失效,以避免不一致。

    • 在主要執行個體上啟用 cloudsql.logical_decodingcloudsql.enable_pglogical,會導致所有唯讀備用資源啟用這些標記,並在短時間內接連重新啟動主要執行個體和唯讀備用資源。為避免這種情況,並控管每個執行個體的重新啟動時間,您可以 (1) 依序在每個唯讀副本上設定標記,然後 (2) 在主要執行個體上設定標記。

    • 在主要執行個體上停用 cloudsql.logical_decodingcloudsql.enable_pglogical不會」導致所有讀取副本上的標記遭到停用。如要停用執行個體中的標記,請執行上述步驟的相反操作:(1) 停用主要執行個體中的標記,然後 (2) 依序停用每個唯讀備用資源中的標記。