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