Oracle Active Data Guardを使用したOracle Application ContinuityのJava例 (2023/07/18)

Oracle Active Data Guardを使用したOracle Application ContinuityのJava例 (2023/07/18)

https://database-heartbeat.com/2023/07/18/java-ac-adg/



はじめに


Oracleアプリケーション・コンティニュイティは、データベースの中断をエンド・ユーザーおよびアプリケーションから隠します。このブログ投稿では、SQL*Plusを使用した簡単なテストについて説明します。ただし、SQL*Plusは通常、本番で使用する実際のアプリケーションではありません。また、SQL*Plusはプールされたアプリケーションではなく、アプリケーション・コンティニュイティに接続プールを使用することをお薦めします。


このブログ投稿は、Oracle Active Data Guardへのクイック・スタートのためのUniversal Connection Pool (UCP)を持つJDBCドライバを使用する単純なJavaの例を示しています。アプリケーション・コンティニュイティには、Oracle RACまたはOracle Active Data Guardオプション・ライセンスが必要です。


本番実装の推奨事項の完全なリストは、この投稿の最後にある公式のOracleドキュメントを参照してください。


環境


  • Oracle Active Data Guardバージョン19.17およびGrid Infrastructure 19.17はOracle Cloudで実行されています。
  • Java JDK 11
  • ローカルのWindows PC上のEclipse IDE for Java Developers


データベース側

Data Guard構成の確認


Data Guard Brokerにログインし、構成を確認します。


[oracle@londonhost1 ~]$ dgmgrl / as sysdba
DGMGRL> show configuration
 
Configuration - CDB01_lhr_ad1_CDB01_lhr26k
 
  Protection Mode: MaxAvailability
  Members:
  CDB01_lhr_ad1 - Primary database
    CDB01_lhr26k  - Physical standby database
 
Fast-Start Failover:  Disabled
 
Configuration Status:
SUCCESS   (status updated 17 seconds ago)


データベース・サービスの作成


次のように、プライマリおよびスタンバイにカスタム・ロールベースのデータベース・サービスを作成します。


#on primary
[oracle@londonhost1 ~]$ srvctl add service -db CDB01_lhr_ad1 -pdb PDB01 -service acsrv.oracle.com -stopoption IMMEDIATE -replay_init_time 600 -retention 86400 -drain_timeout 10 -notification TRUE -commit_outcome TRUE -failover_restore LEVEL1 -failovertype TRANSACTION -role PRIMARY
 
[oracle@londonhost1 ~]$ srvctl start service -db CDB01_lhr_ad1 -service acsrv.oracle.com
 
#on standby
[oracle@londonhost2 ~]$ srvctl add service -db CDB01_lhr26k -pdb PDB01 -service acsrv.oracle.com -stopoption IMMEDIATE -replay_init_time 600 -retention 86400 -drain_timeout 10 -notification TRUE -commit_outcome TRUE -failover_restore LEVEL1 -failovertype TRANSACTION -role PRIMARY


アプリケーション・コンティニュイティは、-failover_restore LEVEL1 -failovertype TRANSACTIONによって有効になります。


サービスはプライマリでのみ起動されます。スイッチオーバーまたはフェイルオーバー後、サービスはプライマリになった後、リモート側で自動的に起動されます。


データベース・ユーザーの作成


ユーザーおよびテスト用の単純な表を作成します。


[oracle@londonhost1 ~]$ sqlplus / as sysdba
 
SQL> alter session set container=pdb01;
Session altered.
 
SQL> create user acusr identified by VerySecretPW__2023 quota unlimited on users;
User created.
 
SQL> grant connect to acusr;
Grant succeeded.
 
SQL> create table acusr.actab (text varchar2(128));
Table created.


高速アプリケーション通知の有効化(FAN)


FANポート(通常は6200)は、データベース側で開く必要があります。



クライアント側では、推奨される接続文字列を使用する場合、FANはGrid Infrastructure 12c、Oracle Database 12cおよびOracleクライアント12c以降から自動構成されます。次を参照してください。



クライアント側

JDKのインストール


常にJavaを使用している場合は、JDKがすでに使用されているはずです。Javaを初めて使用する場合:


Windowsの場合は、ここで説明するようにインストールに従います。


Linuxの場合は、インストールガイドに従うか、yumを使用できます。


sudo yum install java-11-openjdk


Eclipse IDE for Javaのインストール


お気に入りではなく、試してみたい場合は、こちらからダウンロードできます。


Windowsの場合は、インストール手順に従います。


Linuxの場合、バイナリを解凍して実行します。


tar -zxvf eclipse-java-2022-12-R-linux-gtk-x86_64.tar.gz
chmod 744 eclipse
./eclipse


JDBCおよびUCP .jarライブラリのダウンロード


JDBCおよびUCPのダウンロード・ページから、圧縮されたJDBCドライバ(ojdbc11.jar)およびコンパニオンJarsファイルojdbc11-full.tar.gzをダウンロードします。


zipファイルを抽出し、次のJARファイルをアプリケーションのCLASSPATHに追加します。


ons.jar、ojdbc11.jarおよびucp11.jar


Eclipseで、プロジェクト名を右クリックし、「Build Path」、「Configure Build Path...」の順にクリックします。



「Libraries、 Classpath」を選択し、「Add External Jars...」をクリックし、zipファイルを抽出するディレクトリから前述の.jarファイルを選択し、「Apply and Close」をクリックします。




Javaの例


次のコード例を使用して、新しいJavaクラス(AC.java)を作成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties;
 
//PoolDataSource
import oracle.jdbc.OracleConnection;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import oracle.ucp.jdbc.PoolDataSource;
 
public class AC {
 
    public static void main(String[] args) {
        usePoolDataSource();
    }
     
    public static void usePoolDataSource() {
        try {          
            //use Universal Connection Pool (UCP)
            PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
            pds.setConnectionFactoryClassName("oracle.jdbc.datasource.impl.OracleDataSource");
            pds.setConnectionPoolName("JDBC_UCP");
            //pds.setInitialPoolSize(10);
            pds.setMinPoolSize(4);
            pds.setMaxPoolSize(20);
             
            //load properties
            String PROP_FILE = "C:\Users\SPETRUS\Documents\spetrus\development\java\ACproject\src\config.properties";
            InputStream propInput = new FileInputStream(PROP_FILE);
            Properties prop = new Properties();
            prop.load(propInput);
             
            //set properties
            System.setProperty("oracle.net.tns_admin", prop.getProperty("tns_admin"));
            pds.setURL("jdbc:oracle:thin:@"+prop.getProperty("tns_alias"));
            pds.setUser(prop.getProperty("db_user"));
            pds.setPassword(prop.getProperty("db_password"));
             
            //enable FAN and connection tests
            pds.setConnectionWaitTimeout(3);
            pds.setFastConnectionFailoverEnabled(true);
            pds.setValidateConnectionOnBorrow(true);
             
            //disable auto-commit
            pds.setConnectionProperty(OracleConnection.CONNECTION_PROPERTY_AUTOCOMMIT, "false");
            pds.setConnectionProperty(OracleConnection.CONNECTION_PROPERTY_IMPLICIT_STATEMENT_CACHE_SIZE, "100");
             
            //get connection from the pool
            Connection conn = pds.getConnection();
            //conn.beginRequest(); //not needed, as connection pool sets explicit begin request boundary at getConnection()
            conn.setAutoCommit(false);
             
            //execute query
            Statement stmt = conn.createStatement();                               
            String insert = "insert into acusr.actab values ('Using Application Continuity')";
            int result = stmt.executeUpdate(insert);
            System.out.println("insert result is: " + result); 
            //stop here in bedug mode & (relocate | switchover | terminate the session)
            conn.commit();
            //conn.endRequest(); //not needed, as connection pool sets explicit end request boundary at close()
            conn.close();
            conn=null;         
        }
        catch (Exception e) {
            e.printStackTrace();
        
    }
}


この場合、config.propertiesファイルには、次の値が含まれます。


tns_admin=C:\Users\SPETRUS\Documents\spetrus\development
tns_alias=acsrv
db_user=acusr
db_password=VerySecretPW__2023


テストでは、プロパティ・ファイルを使用するのではなく、値をコードに直接配置することもできます。



接続文字列


TNS_ADMINディレクトリのtnsnames.oraファイルで、次の推奨される接続文字列を使用します。


ACSRV =
    (DESCRIPTION = (CONNECT_TIMEOUT=90)(TRANSPORT_CONNECT_TIMEOUT=3)(RETRY_COUNT=50)(RETRY_DELAY=3)
        (ADDRESS_LIST=(FAILOVER=ON)(LOAD_BALANCE=OFF)
            (ADDRESS=(PROTOCOL=TCP)(HOST=132.145.41.207)(PORT=1521))
            (ADDRESS=(PROTOCOL=TCP)(HOST=132.145.52.177)(PORT=1521))
        )
        (CONNECT_DATA=(
            SERVICE_NAME=acsrv.oracle.com)
        )
    )


ADDRESS_LISTには、プライマリ・ホストとスタンバイ・ホストが含まれます。プライマリおよびスタンバイがRACデータベースの場合は、SCANを使用します。



テスト時間


コミットが実行される前とリクエストの終了前に、2つのブレーク・ポイントを設定します。



デバッグ・モードで実行:



コミットが実行される前にプログラムが停止します。



この時点で、プライマリ・データベースにログインし、ユーザーACUSRの既存のセッションを問い合せます。


set lines 300
col db_unique_name for a15
col username for a10
col service_name for a20
 
SQL> select db_unique_name, database_role, open_mode from v$database;
 
SQL> select username, sid, serial#, service_name from gv$session where username = 'ACUSR';


ユーザーはプライマリ・データベースCDB01_lhr_ad1に接続されています。



次に、Data Guard Brokerを使用してスタンバイ・データベースにスイッチオーバーします。

DGMGRL> switchover to CDB01_lhr26k;


オプションで、WAITオプションを使用してドレイン・タイムアウトを指定できます。

DGMGRL> switchover to CDB01_lhr26k WAIT 30;


WAITオプションに値が指定されていない場合、Data Guard Brokerは、すべてのアクティブ・サービスの中で、最大構成drain_timeoutで指定された時間待機します。


指定されたドレイン・タイムアウトが経過し、スイッチオーバーが進行中になるまで待機します。


Performing switchover NOW, please wait...
New primary database "CDB01_lhr26k" is opening...
Oracle Clusterware is restarting database "CDB01_lhr_ad1" ...


Eclipseに戻り、実行を再開します。



スタンバイが新しいプライマリ・データベースに昇格するまで、実行は短期間ハングアップします。その後、実行は続行され、次のブレーク・ポイントで停止します。


最も重要なことは、サービスが停止したにもかかわらず、アプリケーションはエラー・メッセージを表示せずに継続したことです。



新しいプライマリ・データベースに接続します。



アプリケーションを中断せずにコミットが正常に完了しました:



ロールベースのカスタム・データベース・サービスは、新しいプライマリ・ホストで自動的に起動されました。


#on new primary host
[oracle@londonhost2 ~]$ srvctl status service -db cdb01_lhr26k -service acsrv.oracle.com
Service acsrv.oracle.com is running on instance(s) CDB01


まとめ


Oracle Application Continuityは、使用可能なデータベース・インスタンス上で処理中のトランザクションをリプレイすることで、エンド・ユーザーからデータベースの中断を隠します。エンド・ユーザーに対しては完全に透過的で、アプリケーション・コードの変更は不要です。


提供されているJavaコードは、JavaでOracle Application Continuityの使用を開始する例です。本番実装の場合は、Oracleが提供する手順および推奨事項に従ってください。


追加文書

コメント

このブログの人気の投稿

Oracle RACによるメンテナンスのためのドレインとアプリケーション・コンティニュイティの仕組み (2023/11/01)

Oracle Cloud Infrastructure Secure Desktopsを発表: デスクトップ仮想化のためのOracleのクラウドネイティブ・サービス (2023/06/28)

Oracle Cloudのデータベースをオブジェクト・ストレージにバックアップする3つの方法 (2021/12/13)