Oracle Database on Azure: Azure VMs, Azure NetApp Files, and Data Guard HA

Oracle Database on Azure runs on virtual machines, not a managed service. Microsoft and Oracle have a joint partnership certifying Azure as a supported Oracle Database platform, including Oracle Database@Azure delivering Exadata inside Azure datacenters. For teams running Oracle on standard Azure VMs, the right combination of VM series, Azure NetApp Files storage, Oracle Direct NFS, and Data Guard produces performance and availability matching on-premises deployments.

VM Series for Oracle

The Ebsv5 and M series are the primary choices for Oracle on Azure. Standard_E32bds_v5 (32 vCPUs, 256 GB RAM, up to 3200 MB/s remote storage throughput) is the right starting point for most OLTP workloads. The M series suits very large SGA requirements. Avoid general-purpose Dv5 instances for production Oracle: they lack the remote storage throughput and memory-to-CPU ratios Oracle needs.

Step 1: VM and Proximity Placement Group

resource "azurerm_proximity_placement_group" "oracle_ppg" {
  name                = "oracle-ppg"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  location            = var.location
}

resource "azurerm_linux_virtual_machine" "oracle_primary" {
  name                = "oracle-primary"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  location            = var.location
  size                = "Standard_E32bds_v5"
  admin_username      = "oraadmin"

  admin_ssh_key {
    username   = "oraadmin"
    public_key = var.ssh_public_key
  }

  network_interface_ids = [azurerm_network_interface.oracle_primary_nic.id]
  proximity_placement_group_id = azurerm_proximity_placement_group.oracle_ppg.id

  os_disk {
    name                 = "oracle-primary-osdisk"
    caching              = "ReadWrite"
    storage_account_type = "Premium_LRS"
    disk_size_gb         = 128
  }

  source_image_reference {
    publisher = "Oracle"
    offer     = "Oracle-Linux"
    sku       = "ol88-lvm"
    version   = "latest"
  }

  tags = { Role = "oracle-primary", Environment = "production" }
}

Step 2: Azure NetApp Files for Oracle Storage

Oracle datafiles go on Premium tier ANF volumes. Redo logs go on Ultra tier because write latency on redo logs directly determines transaction commit latency. ANF throughput is provisioned independently of capacity, which lets you size each correctly without over-provisioning either dimension.

resource "azurerm_netapp_account" "oracle" {
  name                = "oracle-netapp-account"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  location            = var.location
}

resource "azurerm_netapp_pool" "premium" {
  name                = "oracle-premium-pool"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  location            = var.location
  account_name        = azurerm_netapp_account.oracle.name
  service_level       = "Premium"
  size_in_tb          = 4
  qos_type            = "Manual"
}

resource "azurerm_netapp_pool" "ultra" {
  name                = "oracle-ultra-pool"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  location            = var.location
  account_name        = azurerm_netapp_account.oracle.name
  service_level       = "Ultra"
  size_in_tb          = 1
  qos_type            = "Manual"
}

# Datafiles on Premium tier
resource "azurerm_netapp_volume" "oracle_data" {
  name                = "oracle-data"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  location            = var.location
  account_name        = azurerm_netapp_account.oracle.name
  pool_name           = azurerm_netapp_pool.premium.name
  service_level       = "Premium"
  volume_path         = "oracle-data"
  subnet_id           = var.anf_delegated_subnet_id
  protocols           = ["NFSv4.1"]
  storage_quota_in_gb = 2048
  throughput_in_mibps = 256

  export_policy_rule {
    rule_index          = 1
    allowed_clients     = var.oracle_vm_subnet_cidr
    protocols_enabled   = ["NFSv4.1"]
    unix_read_write     = true
    root_access_enabled = true
  }
}

# Redo logs on Ultra tier for minimum write latency
resource "azurerm_netapp_volume" "oracle_redo" {
  name                = "oracle-redo"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  location            = var.location
  account_name        = azurerm_netapp_account.oracle.name
  pool_name           = azurerm_netapp_pool.ultra.name
  service_level       = "Ultra"
  volume_path         = "oracle-redo"
  subnet_id           = var.anf_delegated_subnet_id
  protocols           = ["NFSv4.1"]
  storage_quota_in_gb = 512
  throughput_in_mibps = 256

  export_policy_rule {
    rule_index          = 1
    allowed_clients     = var.oracle_vm_subnet_cidr
    protocols_enabled   = ["NFSv4.1"]
    unix_read_write     = true
    root_access_enabled = true
  }
}

Step 3: Mount ANF and Enable Oracle Direct NFS

Oracle Direct NFS bypasses the OS NFS client and communicates with the NFS server directly from the Oracle kernel. On ANF, dNFS consistently outperforms the OS NFS client because it manages its own connection pooling and eliminates OS-level caching that can interfere with Oracle’s buffer cache.

# Mount ANF volumes with nconnect=8 to open 8 TCP connections per server
mkdir -p /u02/oradata /u03/redo

mount -t nfs4 \
  -o rw,hard,intr,rsize=65536,wsize=65536,vers=4.1,nconnect=8 \
  10.1.2.10:/oracle-data /u02/oradata

mount -t nfs4 \
  -o rw,hard,intr,rsize=65536,wsize=65536,vers=4.1,nconnect=8 \
  10.1.2.11:/oracle-redo /u03/redo

# /etc/fstab entries
echo "10.1.2.10:/oracle-data /u02/oradata nfs4 rw,hard,intr,rsize=65536,wsize=65536,vers=4.1,nconnect=8 0 0" >> /etc/fstab
echo "10.1.2.11:/oracle-redo /u03/redo nfs4 rw,hard,intr,rsize=65536,wsize=65536,vers=4.1,nconnect=8 0 0" >> /etc/fstab

# Create oranfstab to enable dNFS
cat > $ORACLE_HOME/dbs/oranfstab << 'EOF'
server: anf-data
path: 10.1.2.10
export: /oracle-data mount: /u02/oradata

server: anf-redo
path: 10.1.2.11
export: /oracle-redo mount: /u03/redo
EOF

# Enable dNFS in Oracle binary
cd $ORACLE_HOME/rdbms/lib && make -f ins_rdbms.mk dnfs_on

# Verify dNFS is active after database startup
sqlplus / as sysdba <<'SQL'
SELECT svrname, dirname, nfsversion FROM v$dnfs_servers;
SELECT filename, round(iothroughput/1024/1024,2) AS throughput_mb
FROM v$dnfs_files ORDER BY iothroughput DESC;
SQL

Step 4: Data Guard Configuration

-- Run on primary as SYSDBA
-- Enable archivelog mode and Force Logging
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;
ALTER DATABASE FORCE LOGGING;

-- Data Guard parameters
ALTER SYSTEM SET log_archive_config='DG_CONFIG=(ORCL,ORCL_STB)' SCOPE=BOTH;
ALTER SYSTEM SET log_archive_dest_1=
  'LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=ORCL'
  SCOPE=BOTH;
ALTER SYSTEM SET log_archive_dest_2=
  'SERVICE=ORCL_STB ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=ORCL_STB'
  SCOPE=BOTH;
ALTER SYSTEM SET log_archive_dest_state_2=ENABLE SCOPE=BOTH;
ALTER SYSTEM SET fal_server=ORCL_STB SCOPE=BOTH;
ALTER SYSTEM SET fal_client=ORCL SCOPE=BOTH;
ALTER SYSTEM SET standby_file_management=AUTO SCOPE=BOTH;

-- Create standby control file
ALTER DATABASE CREATE STANDBY CONTROLFILE AS '/tmp/standby.ctl';
# Duplicate to standby using RMAN active duplication
# Run from standby VM
rman target sys@ORCL auxiliary sys@ORCL_STB <<'EOF'
DUPLICATE TARGET DATABASE
  FOR STANDBY
  FROM ACTIVE DATABASE
  DORECOVER
  USING COMPRESSED BACKUPSET
  NOFILENAMECHECK;
EOF

# Start managed recovery on standby
sqlplus / as sysdba <<'SQL'
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE
  USING CURRENT LOGFILE DISCONNECT FROM SESSION;

-- Verify gap and apply lag
SELECT name, value, datum_time FROM v$dataguard_stats
WHERE name IN ('transport lag', 'apply lag');
SQL

Step 5: Azure Monitor Alerts

resource "azurerm_monitor_metric_alert" "oracle_cpu" {
  name                = "oracle-primary-cpu"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  scopes              = [azurerm_linux_virtual_machine.oracle_primary.id]
  severity            = 2
  frequency           = "PT5M"
  window_size         = "PT15M"

  criteria {
    metric_namespace = "Microsoft.Compute/virtualMachines"
    metric_name      = "Percentage CPU"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 80
  }

  action { action_group_id = var.ops_action_group_id }
}

resource "azurerm_monitor_metric_alert" "anf_throughput" {
  name                = "anf-data-throughput-limit"
  resource_group_name = azurerm_resource_group.oracle_rg.name
  scopes              = [azurerm_netapp_volume.oracle_data.id]
  severity            = 2

  criteria {
    metric_namespace = "Microsoft.NetApp/netAppAccounts/capacityPools/volumes"
    metric_name      = "XioBytesWrittenTotal"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 245
  }

  action { action_group_id = var.ops_action_group_id }
}

Operational Notes

The nconnect=8 NFS mount option opens 8 TCP connections to the ANF server per mount point instead of the default 1. Without it, a single NFS connection becomes a bottleneck before ANF’s provisioned throughput limit is reached. This option is supported on Oracle Linux 8 with kernel 5.4 or newer.

ANF throughput can be increased online without downtime. If workload grows, update throughput_in_mibps in Terraform and apply. The change takes effect within seconds. This makes right-sizing at provisioning time less critical than it would be with a storage type that requires offline expansion.

For Oracle Database@Azure, the architecture differs: Oracle manages Exadata infrastructure inside Azure datacenters and you connect from Azure VMs via private peering. The configuration above covers Oracle on standard Azure VMs, which remains the most common deployment pattern for teams migrating existing on-premises Oracle installations without adopting Exadata.

Regards,
Osama

#Azure #OracleDatabase #OracleOnAzure #AzureNetAppFiles #DataGuard #Terraform #DatabaseEngineering #TechBlog #Oracle #Microsoft #CloudArchitecture #DevOps #HighAvailability #ANF #dNFS #OracleDBA #AzureMonitor #CloudDatabase #OracleLinux #HybridCloud

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.