チュートリアル:geo 分散型データベースを実装する (Azure SQL Database)

適用対象:Azure SQL Database

SQL Database 内のデータベースおよびクライアント アプリケーションをリモート リージョンにフェールオーバーするよう構成し、フェールオーバー計画をテストします。 学習内容は次のとおりです。

  • フェールオーバー グループを作成します。
  • SQL Database 内のデータベースを照会する Java アプリケーションを実行する
  • [テスト フェールオーバー]

Azure サブスクリプションをお持ちでない場合は、開始する前に無料アカウントを作成してください。

前提条件

注意

この記事では、Azure と対話するために推奨される PowerShell モジュールである Azure Az PowerShell モジュールを使用します。 Az PowerShell モジュールの使用を開始するには、「Azure PowerShell をインストールする」を参照してください。 Az PowerShell モジュールに移行する方法については、「AzureRM から Az への Azure PowerShell の移行」を参照してください。

重要

PowerShell Azure Resource Manager モジュールは Azure SQL Database で引き続きサポートされますが、今後の開発はすべて Az.Sql モジュールを対象に行われます。 これらのコマンドレットについては、「AzureRM.Sql」を参照してください。 Az モジュールと AzureRm モジュールのコマンドの引数は実質的に同じです。

このチュートリアルに取り組む前に、次のものがインストールされていることを確認してください。

重要

このチュートリアルの手順を実行しているコンピューターのパブリック IP アドレスを使用するようにファイアウォール規則を確実に設定してください。 データベース レベルのファイアウォール ルールは、セカンダリ サーバーに自動的にレプリケートされます。

詳細については、データベース レベルのファイアウォール規則の作成に関するページを参照してください。ご利用のコンピューターのサーバー レベルのファイアウォール規則に使用する IP アドレスを調べる場合は、サーバーレベルのファイアウォールの作成に関するページを参照してください。

フェールオーバー グループを作成する

既存のサーバーと別のリージョンにある新しいサーバーとの間で、Azure PowerShell を使用してフェールオーバー グループを作成します。 その後、そのフェールオーバー グループにサンプル データベースを追加します。

重要

このサンプルには、Azure PowerShell Az 1.0 以降が必要です。 Get-Module -ListAvailable Az を実行して、インストールされているバージョンを確認します。 インストールする必要がある場合は、Azure PowerShell モジュールのインストールに関するページを参照してください。

Connect-AzAccount を実行して Azure にサインインします。

フェールオーバー グループを作成するには、次のスクリプトを実行します。

$admin = "<adminName>"
$password = "<password>"
$resourceGroup = "<resourceGroupName>"
$location = "<resourceGroupLocation>"
$server = "<serverName>"
$database = "<databaseName>"
$drLocation = "<disasterRecoveryLocation>"
$drServer = "<disasterRecoveryServerName>"
$failoverGroup = "<globallyUniqueFailoverGroupName>"

# create a backup server in the failover region
New-AzSqlServer -ResourceGroupName $resourceGroup -ServerName $drServer `
    -Location $drLocation -SqlAdministratorCredentials $(New-Object -TypeName System.Management.Automation.PSCredential `
    -ArgumentList $admin, $(ConvertTo-SecureString -String $password -AsPlainText -Force))

# create a failover group between the servers
New-AzSqlDatabaseFailoverGroup –ResourceGroupName $resourceGroup -ServerName $server `
    -PartnerServerName $drServer –FailoverGroupName $failoverGroup –FailoverPolicy Automatic -GracePeriodWithDataLossHours 2

# add the database to the failover group
Get-AzSqlDatabase -ResourceGroupName $resourceGroup -ServerName $server -DatabaseName $database | `
    Add-AzSqlDatabaseToFailoverGroup -ResourceGroupName $resourceGroup -ServerName $server -FailoverGroupName $failoverGroup

geo レプリケーションの設定は、Azure portal でデータベースを選択し、 [設定]>[geo レプリケーション] の順に選択することで変更することもできます。

Geo-replication settings

サンプル プロジェクトを実行する

  1. コンソールで次のコマンドを実行して Maven プロジェクトを作成します。

    mvn archetype:generate "-DgroupId=com.sqldbsamples" "-DartifactId=SqlDbSample" "-DarchetypeArtifactId=maven-archetype-quickstart" "-Dversion=1.0.0"
    
  2. Y」と入力して Enter キーを押します。

  3. 新しいプロジェクトのディレクトリに移動します。

    cd SqlDbSample
    
  4. お好みのエディターを使用して、プロジェクト フォルダーの pom.xml ファイルを開きます。

  5. 以下の dependency セクションを追加して、Microsoft JDBC Driver for SQL Server 依存関係を追加します。 この依存関係を、上位の dependencies セクション内に貼り付けてください。

    <dependency>
      <groupId>com.microsoft.sqlserver</groupId>
      <artifactId>mssql-jdbc</artifactId>
     <version>6.1.0.jre8</version>
    </dependency>
    
  6. dependencies セクションの後に properties セクションを追加して Java バージョンを指定します。

    <properties>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
  7. properties セクションの後に build セクションを追加してマニフェスト ファイルをサポートします。

    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.0</version>
          <configuration>
            <archive>
              <manifest>
                <mainClass>com.sqldbsamples.App</mainClass>
              </manifest>
            </archive>
         </configuration>
        </plugin>
      </plugins>
    </build>
    
  8. pom.xml ファイルを保存して閉じます。

  9. ..\SqlDbSample\src\main\java\com\sqldbsamples にある App.java ファイルを開き、その内容を次のコードで置き換えます。

    package com.sqldbsamples;
    
    import java.sql.Connection;
    import java.sql.Statement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.Timestamp;
    import java.sql.DriverManager;
    import java.util.Date;
    import java.util.concurrent.TimeUnit;
    
    public class App {
    
       private static final String FAILOVER_GROUP_NAME = "<your failover group name>";  // add failover group name
    
       private static final String DB_NAME = "<your database>";  // add database name
       private static final String USER = "<your admin>";  // add database user
       private static final String PASSWORD = "<your password>";  // add database password
    
       private static final String READ_WRITE_URL = String.format("jdbc:" +
          "sqlserver://%s.database.windows.net:1433;database=%s;user=%s;password=%s;encrypt=true;" +
          "hostNameInCertificate=*.database.windows.net;loginTimeout=30;",
          FAILOVER_GROUP_NAME, DB_NAME, USER, PASSWORD);
       private static final String READ_ONLY_URL = String.format("jdbc:" +
          "sqlserver://%s.secondary.database.windows.net:1433;database=%s;user=%s;password=%s;encrypt=true;" +
          "hostNameInCertificate=*.database.windows.net;loginTimeout=30;",
          FAILOVER_GROUP_NAME, DB_NAME, USER, PASSWORD);
    
       public static void main(String[] args) {
          System.out.println("#######################################");
          System.out.println("## GEO DISTRIBUTED DATABASE TUTORIAL ##");
          System.out.println("#######################################");
          System.out.println("");
    
          int highWaterMark = getHighWaterMarkId();
    
          try {
             for(int i = 1; i < 1000; i++) {
                 //  loop will run for about 1 hour
                 System.out.print(i + ": insert on primary " +
                    (insertData((highWaterMark + i)) ? "successful" : "failed"));
                 TimeUnit.SECONDS.sleep(1);
                 System.out.print(", read from secondary " +
                    (selectData((highWaterMark + i)) ? "successful" : "failed") + "\n");
                 TimeUnit.SECONDS.sleep(3);
             }
          } catch(Exception e) {
             e.printStackTrace();
       }
    }
    
    private static boolean insertData(int id) {
       // Insert data into the product table with a unique product name so we can find the product again
       String sql = "INSERT INTO SalesLT.Product " +
          "(Name, ProductNumber, Color, StandardCost, ListPrice, SellStartDate) VALUES (?,?,?,?,?,?);";
    
       try (Connection connection = DriverManager.getConnection(READ_WRITE_URL);
               PreparedStatement pstmt = connection.prepareStatement(sql)) {
          pstmt.setString(1, "BrandNewProduct" + id);
          pstmt.setInt(2, 200989 + id + 10000);
          pstmt.setString(3, "Blue");
          pstmt.setDouble(4, 75.00);
          pstmt.setDouble(5, 89.99);
          pstmt.setTimestamp(6, new Timestamp(new Date().getTime()));
          return (1 == pstmt.executeUpdate());
       } catch (Exception e) {
          return false;
       }
    }
    
    private static boolean selectData(int id) {
       // Query the data previously inserted into the primary database from the geo replicated database
       String sql = "SELECT Name, Color, ListPrice FROM SalesLT.Product WHERE Name = ?";
    
       try (Connection connection = DriverManager.getConnection(READ_ONLY_URL);
               PreparedStatement pstmt = connection.prepareStatement(sql)) {
          pstmt.setString(1, "BrandNewProduct" + id);
          try (ResultSet resultSet = pstmt.executeQuery()) {
             return resultSet.next();
          }
       } catch (Exception e) {
          return false;
       }
    }
    
    private static int getHighWaterMarkId() {
       // Query the high water mark id stored in the table to be able to make unique inserts
       String sql = "SELECT MAX(ProductId) FROM SalesLT.Product";
       int result = 1;
       try (Connection connection = DriverManager.getConnection(READ_WRITE_URL);
               Statement stmt = connection.createStatement();
               ResultSet resultSet = stmt.executeQuery(sql)) {
          if (resultSet.next()) {
              result =  resultSet.getInt(1);
             }
          } catch (Exception e) {
           e.printStackTrace();
          }
          return result;
       }
    }
    
  10. App.java ファイルを保存して閉じます。

  11. コマンド コンソールで、次のコマンドを実行します。

    mvn package
    
  12. アプリケーションを起動します。手動で停止しない限り約 1 時間実行されるので、その間にフェールオーバー テストを実行できます。

    mvn -q -e exec:java "-Dexec.mainClass=com.sqldbsamples.App"
    
    #######################################
    ## GEO DISTRIBUTED DATABASE TUTORIAL ##
    #######################################
    
    1. insert on primary successful, read from secondary successful
    2. insert on primary successful, read from secondary successful
    3. insert on primary successful, read from secondary successful
    ...
    

[テスト フェールオーバー]

以下に示した各スクリプトを実行してフェールオーバーをシミュレートし、アプリケーションの結果を観察します。 データベースの移行中、いくつかの挿入と選択が失敗します。そのようすに注目してください。

次のコマンドを使用して、テスト中にディザスター リカバリー サーバーのロールを確認することができます。

(Get-AzSqlDatabaseFailoverGroup -FailoverGroupName $failoverGroup `
    -ResourceGroupName $resourceGroup -ServerName $drServer).ReplicationRole

フェールオーバーをテストするには、次の手順に従います。

  1. フェールオーバー グループの手動フェールオーバーを開始します。

    Switch-AzSqlDatabaseFailoverGroup -ResourceGroupName $resourceGroup `
     -ServerName $drServer -FailoverGroupName $failoverGroup
    
  2. フェールオーバー グループを再びプライマリ サーバーに戻します。

    Switch-AzSqlDatabaseFailoverGroup -ResourceGroupName $resourceGroup `
     -ServerName $server -FailoverGroupName $failoverGroup
    

次のステップ

高可用性とディザスター リカバリーのチェックリストを確認してください。

関連する Azure SQL データベースコンテンツ: