2026年5月28日 星期四

ORA-28374 錯誤分析

在 Oracle 資料庫建立 TDE Key 時,除了會在 wallet 目錄中產生 Key 之外,資料庫的 SYSTEM tablespace 與 control file 也會同步記錄對應的 Key Entry 。即使資料庫中尚未有任何物件進行加密,只要建立過 TDE Key ,相關的 Key 紀錄就會永久保留在 SYSTEM tablespace 中。當資料庫執行加解密操作時,會比對資料庫內所記錄的 Key 與 wallet 中的 Key Entry 是否一致;若兩者不相符,就會出現 ORA-28374: typed master key not found in wallet 的錯誤訊息,也就是資料庫無法在 wallet 中找到對應的 Master Key。


在建立 TDE Key 之後,資料庫與 wallet 會同步建立對應的 Key Entry ,使用 administer key management 建立 Key 如下 :

SQL> alter system set wallet_root='/u01/app/oracle/admin/orcl/wallet' scope=spfile;

SQL> shutdown immediate

SQL> startup

SQL> alter system set tde_configuration='KEYSTORE_CONFIGURATION=FILE';

SQL> administer key management create keystore identified by welcome1;

SQL> administer key management set keystore open identified by welcome1; 

SQL> administer key management set key identified by welcome1 with backup;

SQL> administer key management create auto_login keystore from keystore identified by welcome1;

SQL> administer key management set keystore close identified by welcome1;


建立之後可以透過幾個地方查詢 Key Entry :

 

1. 查詢 v$encryption_keys ,這個會直接解析 wallet 的 TDE Key

SQL> select key_id,activation_time,keystore_type,key_use from v$encryption_keys;

 

2. orapki 查詢 wallet ,結果與 v$encryption_keys 相同

$ orapki wallet display -wallet /u01/app/oracle/admin/orcl/wallet/tde


3. 查詢 system tablespace ,這邊主要是紀錄 master key

SQL> set linesize 150

SQL> column name format a40

SQL> column masterkeyid_base64 format a60

SQL> select  name,utl_raw.cast_to_varchar2( utl_encode.base64_encode('01'||substr(mkeyid,1,4))) || utl_raw.cast_to_varchar2( utl_encode.base64_encode(substr(mkeyid,5,length(mkeyid)))) masterkeyid_base64  FROM (select t.name, RAWTOHEX(x.mkid) mkeyid from v$tablespace t, x$kcbtek x where t.ts#=x.ts#);


4. 查詢 control file ,也是記錄 master key

SQL> select  utl_raw.cast_to_varchar2( utl_encode.base64_encode('01'||substr(mkeyid,1,4))) || utl_raw.cast_to_varchar2( utl_encode.base64_encode(substr(mkeyid,5,length(mkeyid)))) masterkeyid_base64  FROM (select RAWTOHEX(mkid) mkeyid from x$kcbdbk);


若是 wallet 的 Key Entry 與資料庫所記錄的 master key 不符,就會出現 ORA-28374 錯誤。舉個例子來說,把原本已經創建好的 wallet 路徑 rename ,然後重新再產生一個 key :

$ mv /u01/app/oracle/admin/orcl/wallet/tde /u01/app/oracle/admin/orcl/wallet/tde_old

SQL> shutdown immediate

SQL> startup


重新 create keystore ,在 set key 時便會產生 ORA-28374 錯誤 : 

SQL> administer key management create keystore identified by welcome1;

SQL> administer key management set keystore open identified by welcome1;

SQL> administer key management set key identified by welcome1 with backup;


這個原因就是 create keystore 會重新產生一把 master key ,這就會與原本 system tablespace 所記錄的 master key 不同 :


 不能 set key ,那麼也就無法進行任何 TDE 操作了 :


這個時候只能把原本 wallet 的 key 放回去才能正常運行了,萬一原本的 key 真的不幸丟失,可以透過設定隱藏參數 _db_discard_lost_masterkey ,忽略 lost key ,強制使用新的 key :

SQL> alter system set "_db_discard_lost_masterkey"=TRUE;

SQL> administer key management set key identified by welcome1 with backup;


設定完就會更新 system tablespace 裡面的 master key 與 wallet 一致了 :

 

不過設定隱藏參數只能在資料庫完全沒有 Tablespace 加密的情況下使用,透過這種方式來更新或是重設 TDE Key ,若是資料庫已經存在加密的 Tablespace ,那麼就必須一定要找回原本的 TDE Key ,否則已經被加密的 Tablespace 會無法使用。


因此,TDE Key 對於使用資料加密的資料庫而言非常重要。一旦 Key 遺失,被加密的物件將無法存取。由於在建立 TDE Key 的同時,當下的 Key Entry 也會寫入資料庫中,因此這個操作是不可逆的。若 TDE Key 遺失,等同於資料庫損毀;沒有對應的 Key ,即使擁有完整備份,也無法完成資料庫還原或解密操作。


因此創建完 TDE Key 之後,必須立即進行備份,使用 export encryption keys 進行備份 :

SQL> administer key management set keystore open identified by welcome1;

SQL> administer key management export encryption keys with secret "welcome1" to '/home/oracle/tde.bak' identified by welcome1;


這邊要注意的是,若是設定了 auto login 是無法進行 export encryption keys ,必須將 cwallet.sso 移除或 rename ,重開資料庫,這樣才能進行 export 。


若原本的 Key 丟失,重新創建 keystore 之後使用 import keys 將 TDE Key 還原 :

SQL> administer key management create keystore identified by welcome1;

SQL> administer key management set keystore open identified by welcome1;

SQL> administer key management import keys with secret "welcome1" from '/home/oracle/tde.bak' identified by welcome1 with backup;


因為重新 create keystore 與 import keys , v$encryption_keys 會查詢到多筆 entry ,此時必須比對資料庫的紀錄來設定正確的 Key :


使用 use encryption key 設定正確的 Key 之後,就可以 set key :

SQL> administer key management use encryption key 'AV2/kNJSJU/ZvzZ2IrNd4fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' force keystore identified by "welcome1" with backup;


keystore altered.


SQL> administer key management set key identified by welcome1 with backup;


keystore altered.


這樣就完成了 TDE Key 的還原。


除了使用 export encryption keys 進行備份之外,也可以使用 OS 命令例如 tar 直接將 wallet 目錄進行備份。


在資料庫有使用 TDE 功能的情況下, TDE Key 是非常重要的東西,務必做好備份。 

2026年4月24日 星期五

移除 AFD 設定

AFD (ASM Filter Driver) 是 Oracle 12c 開始引入的新功能,不僅能保護 ASM Disk ,設定上也相對簡單方便,不過未來在 UEK8 (Oracle Linux 9、Kernel 6.12) 及所有 kernel > 5.15 的 Linux 作業系統上, AFD 已被列為不支援;此外,自 Oracle Database 26ai 起亦不再支援 AFD 。這意味著 AFD 將無法於未來環境中使用,若升級過程中未留意此變更,可能導致 AFD driver 無法正常啟動 :

CRS-2758: Resource 'ora.driver.afd' is in an unknown state.

CRS-2807: Resource 'ora.driver.afd' failed to start automatically.

在 RAC 環境中,若是 afd driver 無法啟動,那麼所有由 AFD Disk 組成的 Disk Group 便無法使用, GI 也會因為無法存取放在 Disk Group 裡面的 Voting 與 OCR 而無法啟動,因此當前建議先將 AFD 的設定移除, ASM Disk 回歸由 udev rule 進行設定。

必須所有的 Disk Group 都沒有使用 AFD Disk 的情況下才能夠移除 AFD 設定,若 Disk Group 只有一個 AFD Disk ,則必須新增 Disk 然後替換掉 AFD Disk :

add new disk 🡪 drop afd disk 🡪 unlabel afd disk 🡪 add unlabeled afd disk back

若 Disk Group 有兩顆以上的 AFD Disk ,在空間足夠的情況下可以逐個進行替換 :

drop afd disk 🡪 unlabel afd disk 🡪 add unlabeled afd disk back 🡪 drop afd disk 🡪 unlabel afd disk 🡪 add unlabeled afd disk back 🡪 …

如此循環直到替換掉所有 AFD Disk 。

舉例來說,目前的 DATA dg 只有一個 AFD Disk :


這時候就必須要新增一個 disk 來進行替換,首先編輯 /etc/udev/rules.d/99-oracle-asmdevices.rules :

KERNEL=="sd[b-c]", OWNER="oracle", GROUP="oinstall", MODE="0660"

reload udev rule 進行生效 :

# udevadm control --reload-rules && udevadm trigger

以上RAC 所有節點都要做。

Data dg 加入新的 disk :

SQL> alter diskgroup data add disk '/dev/sdc';

 等到 rebalance 結束後 drop AFD Disk :

SQL> alter diskgroup data drop disk data1;

進入 asmcmd 將 AFD Disk 進行 unlabel :

ASMCMD> afd_unlabel DATA1

將 unlabel 過後的 disk 重新加回 Data dg :

SQL> alter diskgroup data add disk '/dev/sdb';


最後確認已經沒有存在任何 AFD Disk 之後就可以移除 AFD 設定 :


移除 AFD 設定必須停下 RAC 所有節點的 crs ,不能 rolling 更改設定 :

所有節點都要操作 :

# cd /u01/app/oracle/19.21/grid/bin

# ./crsctl stop crs

# ./acfsload stop

# export ORACLE_BASE=/u01/app/oracle

# ./asmcmd afd_deconfigure

AFD-632: Existing AFD installation detected.

AFD-634: Removing previous AFD installation.

AFD-635: Previous AFD components successfully removed.

ASMCMD-9375: error occurred when executing

  /bin/rpm -q sles-release

package sles-release is not installed

Modifying resource dependencies - this may take some time.

# ./acfsload start

# ./crsctl start crs

結束後可以執行 afddriverstate 再次確認 AFD 是否有安裝 :

狀態為 false 表示已經移除 AFD 。



2026年3月29日 星期日

Adaptive Log File Sync


Adaptive Log File Sync 為 Oracle 12c 的新功能,目的在於減少 log file sync 等待事件的延遲,其核心概念在於 user commit 後的行為模式分為兩種 : Post/wait 與 Polling 。

  • Post/wait

為 user session 執行 commit 時的預設機制。當 user 發出 commit 後,會通知 LGWR 進行 redo log 的寫入;在此期間, user session 會進入等待(sleep)狀態,待 LGWR 完成 I/O 寫入並回報後,才會喚醒該 session ;當 user session 收到 LGWR 的回應,即表示此次 commit 已完成,並可繼續後續操作。


這個模式之下好比老闆交代員工一個任務之後,老闆就不管這個任務的進度直到員工主動回報完成,也就是 user 使用 commit 賦予 LGWR 任務之後, user session 就不再管此事,直到 LGWR 告知它任務完成了。

好處是當 user session進入等待 (sleep) 時不會消耗 CPU 資源;壞處是 user session 需要等 LGWR 回報後才能喚醒,這個過程會造成些許的延遲,當 commit rate 極高時, LGWR 必須逐一發送信號給每一個在 log file sync 等待隊列中的 User Session ,這種「一對多」的喚醒工作會讓 LGWR 成為系統瓶頸。

  • Polling

為 Adaptive Log File Sync 機制中新增的模式,與 Post/wait 模式最大的差別在於, user 執行 commit 之後, user session 不會進入等待 (sleep)  模式,而是不斷的主動輪詢 LGWR 完成了沒,主動詢問 LGWR 且收到完成的訊息之後,即表示此次 commit 已完成。

這個模式用同一個比喻下,就好比老闆交代員工一個任務,並且老闆持續追蹤員工進度直到任務完成,也就是 user 使用 commit 賦予 LGWR 任務之後, user session 會主動持續關注 LGWR 是否已經完成它的任務了。

好處是 LGWR 不需要喚醒 user session 的動作,減少延遲,在高 commit rate 的場合中表現較佳;缺點是 user session 必須消耗 CPU 資源來持續輪詢 LGWR 是否完成,如果系統 CPU 資源較緊的話就不適合這個模式。

Adaptive Log File Sync 會依據系統的可用資源來自動切換這兩種模式,用以達到 log file sync 最佳的吞吐量,觀察 LGWR 的 trace 可以知道目前是使用何種模式進行 :

*** 2012-10-02 08:15:47.050

Log file sync switching to polling

Current scheduling delay is 4 usec

 

*** 2012-10-02 08:16:23.325

Log file sync switching to post/wait

Current approximate redo synch write rate is 8 per sec

從 AWR 或者是 v$sysstat 也可以觀察到是否有使用 polling 模式 :


早期這個功能剛推出的時候,於 RAC 環境可能會遭遇到 Bug 25178179 : Several sessions wait on 'log file sync' in a RAC environment ,這個 Bug 導致於 Polling 模式效能不佳,具體的現象為使用 Polling 模式、 log file sync 時間很長但 log file parallel write 時間很短。不過這個 Bug 已經於多數 12.2 的版本進行修復了,在現今的環境當中是不會再遇到這個問題。

最後提一下,如果系統 CPU 資源較緊,不希望使用到 Polling 模式,可以設定隱藏參數 "_use_adaptive_log_file_sync" = FALSE 來關閉 adaptive log file sync 功能,參數可以動態更改。