High Availability & Disaster Recovery
Overview: Các yếu tố cần cân nhắc
RPO vs RTO Tradeoffs
| Công nghệ | RPO | RTO | Readable Secondary | Transparent Failover | Chi phí |
|---|---|---|---|---|---|
| Always On AG (Sync) | ~0 (zero data loss) | < 30 giây | Có (Enterprise) | Có (với listener) | Cao |
| Always On AG (Async) | Vài giây | < 30 giây | Có (Enterprise) | Manual | Cao |
| FCI | ~0 (shared storage) | 1-5 phút | Không | Có (WSFC) | Rất cao |
| Log Shipping | Vài phút - giờ | 30-60 phút | Có (STANDBY) | Không (manual) | Thấp |
| Database Mirroring (deprecated) | ~0 (Sync) | < 30 giây | Không | Có (với witness) | Trung bình |
| Replication (Transactional) | Vài giây | Tùy | Có | Không | Trung bình |
| Azure Auto-failover Groups | Vài giây | < 1 phút | Có | Có | Cao |
Synchronous vs Asynchronous Replication
Synchronous (Đồng bộ):
Primary → Commit → Ghi log local → Gửi log đến Secondary
← Nhận ACK từ Secondary
→ Primary chỉ commit xong khi Secondary đã nhận và hardened log
→ RPO = 0 (zero data loss), nhưng latency tăng theo network
Asynchronous (Bất đồng bộ):
Primary → Commit → Ghi log local → Return to client
→ Gửi log đến Secondary (background)
→ Primary không chờ Secondary → latency thấp
→ RPO > 0 (có thể mất vài giây data khi failover)
Always On Availability Groups (AG)
Giải pháp HA cao cấp nhất của SQL Server (Enterprise Edition), cung cấp:
- Database-level HA (không phải instance-level như FCI)
- Readable secondaries
- Automatic failover
- Hỗ trợ Azure (Hybrid scenarios)
Kiến trúc
┌─────────────────────────────────────┐
│ Windows Server Failover Cluster │
│ │
┌──────────────┐ │ ┌──────────┐ ┌──────────┐ │
│ Application │──┼─▶│ Listener │ │ WSFC │ │
└──────────────┘ │ │ (VNN) │ │ Quorum │ │
│ │ └────┬─────┘ └──────────┘ │
│ │ │ │
│ │ ┌────▼─────────────────────────┐ │
│ │ │ AG Group │ │
│ │ │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ │ Primary │ │Secondary │ │ │
└──────────┼──┤ │ Replica │◀▶│ Replica │ │ │
Read/Write │ │ │ (Node 1) │ │ (Node 2) │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────┘
┌─────────────────┐ ┌───────────────────┐
│ Read-Only │─────▶│ Secondary Replica │
│ Applications │ │ (Node 2) │
└─────────────────┘ └───────────────────┘
Cấu hình AG cơ bản
-- Trên Primary: Enable AlwaysOn (phải restart SQL Server sau)
-- Thực hiện qua SSMS hoặc PowerShell:
-- Enable-SqlAlwaysOn -ServerInstance "SQL01" -Force
-- Bước 1: Tạo Master Key và Certificate (cho endpoint encryption)
USE master;
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'StrongP@ssword!';
CREATE CERTIFICATE AG_Cert
WITH SUBJECT = 'AG Endpoint Certificate',
START_DATE = '20260101',
EXPIRY_DATE = '20360101';
-- Bước 2: Tạo Endpoint
CREATE ENDPOINT HADR_endpoint
STATE = STARTED
AS TCP (LISTENER_PORT = 5022, LISTENER_IP = ALL)
FOR DATABASE_MIRRORING (
AUTHENTICATION = CERTIFICATE AG_Cert,
ENCRYPTION = REQUIRED ALGORITHM AES,
ROLE = ALL
);
-- Bước 3: Backup cert để dùng trên secondary
BACKUP CERTIFICATE AG_Cert
TO FILE = '\\Shared\Certs\AG_Cert.cer';
-- Trên Secondary: tạo login, cert, endpoint tương tự
-- Bước 4: Tạo Availability Group (trên Primary)
CREATE AVAILABILITY GROUP [AG_Production]
WITH (
AUTOMATED_BACKUP_PREFERENCE = SECONDARY, -- Backup trên secondary
DB_FAILOVER = ON, -- Failover khi health check fail
DTC_SUPPORT = NONE,
CLUSTER_TYPE = WSFC
)
FOR DATABASE [ProductionDB], [SalesDB]
REPLICA ON
N'SQL01'
WITH (
ENDPOINT_URL = N'TCP://SQL01.domain.com:5022',
AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
FAILOVER_MODE = AUTOMATIC,
SEEDING_MODE = AUTOMATIC,
SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY,
READ_ONLY_ROUTING_URL = N'TCP://SQL01.domain.com:1433')
),
N'SQL02'
WITH (
ENDPOINT_URL = N'TCP://SQL02.domain.com:5022',
AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
FAILOVER_MODE = AUTOMATIC,
SEEDING_MODE = AUTOMATIC,
SECONDARY_ROLE (ALLOW_CONNECTIONS = READ_ONLY,
READ_ONLY_ROUTING_URL = N'TCP://SQL02.domain.com:1433')
);
-- Trên Secondary: join AG
ALTER AVAILABILITY GROUP [AG_Production] JOIN;
ALTER AVAILABILITY GROUP [AG_Production] GRANT CREATE ANY DATABASE;
Monitoring AG Status
-- Xem trạng thái AG
SELECT
ag.name AS availability_group,
ar.replica_server_name,
ar.availability_mode_desc,
ar.failover_mode_desc,
ars.role_desc,
ars.synchronization_health_desc,
ars.connected_state_desc
FROM sys.availability_groups ag
JOIN sys.availability_replicas ar ON ag.group_id = ar.group_id
JOIN sys.dm_hadr_availability_replica_states ars ON ar.replica_id = ars.replica_id;
-- Xem log send queue và redo queue
SELECT
db_name(drs.database_id) AS database_name,
drs.log_send_queue_size AS log_send_queue_kb,
drs.log_send_rate AS log_send_rate_kb_s,
drs.redo_queue_size AS redo_queue_kb,
drs.redo_rate AS redo_rate_kb_s,
drs.synchronization_state_desc
FROM sys.dm_hadr_database_replica_states drs;
-- Manual failover (khi cần maintenance trên Primary)
ALTER AVAILABILITY GROUP [AG_Production] FAILOVER;
Availability Group Listener
-- Tạo listener (sau khi AG đã tạo)
ALTER AVAILABILITY GROUP [AG_Production]
ADD LISTENER N'AG_Listener' (
WITH IP ((N'192.168.1.100', N'255.255.255.0')),
PORT = 1433
);
-- Connection string dùng listener (ứng dụng kết nối đến đây, không quan tâm Primary là node nào)
-- "Server=AG_Listener,1433;Database=ProductionDB;Integrated Security=True;
-- ApplicationIntent=ReadWrite;MultiSubnetFailover=True"
-- Read-only routing (kết nối ReadOnly → tự động redirect đến secondary)
-- "Server=AG_Listener,1433;Database=ProductionDB;Integrated Security=True;
-- ApplicationIntent=ReadOnly"
-- Cấu hình read-only routing list
ALTER AVAILABILITY GROUP [AG_Production]
MODIFY REPLICA ON N'SQL01'
WITH (PRIMARY_ROLE (
READ_ONLY_ROUTING_LIST = (N'SQL02', N'SQL01') -- Ưu tiên SQL02 cho read
));
ALTER AVAILABILITY GROUP [AG_Production]
MODIFY REPLICA ON N'SQL02'
WITH (PRIMARY_ROLE (
READ_ONLY_ROUTING_LIST = (N'SQL01', N'SQL02')
));
Always On Failover Cluster Instances (FCI)
Instance-level HA, khác với AG (database-level).
┌─────────────────────────────────────┐
│ Windows Server Failover Cluster │
│ │
┌──────────────┐ │ ┌──────────┐ ┌──────────┐ │
│ Application │──┼─▶│ VNN │ │ WSFC │ │
└──────────────┘ │ │ (Virtual │ │ Quorum │ │
│ │ Network │ └──────────┘ │
│ │ Name) │ │
│ └────┬─────┘ │
│ │ │
│ ┌────▼────────────────────────┐ │
│ │ SQL Server FCI Instance │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Node 1 │ │ Node 2 │ │ │
│ │ │ (Active) │ │(Passive) │ │ │
│ │ └────┬─────┘ └──────────┘ │ │
│ │ │ │ │
│ │ ┌────▼──────────────────┐ │ │
│ │ │ Shared Storage │ │ │
│ │ │ (SAN / Azure Shared │ │ │
│ │ │ Disk / S2D) │ │ │
│ │ └───────────────────────┘ │ │
│ └────────────────────────────┘ │
└─────────────────────────────────────┘
Đặc điểm FCI:
- Tất cả nodes chia sẻ cùng một storage
- Chỉ một node Active tại một thời điểm
- Failover: SQL Server instance chuyển sang node khác (shared storage vẫn accessible)
- Không có readable secondary
- Protect toàn bộ SQL Server instance (tất cả databases, SQL Agent jobs, logins)
- License: chỉ cần license cho active nodes
Log Shipping
Giải pháp HA đơn giản, chi phí thấp — automated backup → copy → restore.
┌─────────────┐ Backup Log ┌─────────────┐
│ Primary │─────────────────▶ │ Monitor │
│ (Source) │ │ Server │
└──────┬──────┘ └──────┬──────┘
│ │
│ Backup files (shared folder) │ Alert if delay
│ │
▼ ▼
┌──────────────┐ Copy + Restore ┌──────────────┐
│ .trn files │──────────────────▶ │ Secondary │
│ (Share) │ │ (DR Server) │
└──────────────┘ └──────────────┘
-- Cấu hình Log Shipping qua SSMS hoặc T-SQL
-- Primary: setup backup job
-- Primary database phải ở FULL recovery model
EXEC master.dbo.sp_add_log_shipping_primary_database
@database = N'ProductionDB',
@backup_directory = N'\\BackupShare\LogShipping',
@backup_share = N'\\BackupShare\LogShipping',
@backup_job_name = N'LSBackup_ProductionDB',
@backup_retention_period = 4320, -- 3 days (minutes)
@backup_threshold = 60, -- Alert nếu backup delay > 60 phút
@threshold_alert_enabled = 1,
@history_retention_period = 5760; -- Keep history 4 days
-- Secondary: setup copy + restore jobs
EXEC master.dbo.sp_add_log_shipping_secondary_database
@secondary_database = N'ProductionDB',
@primary_server = N'SQL01',
@primary_database = N'ProductionDB',
@restore_delay = 0,
@restore_mode = 0, -- 0 = NORECOVERY, 1 = STANDBY (readable)
@disconnect_users = 0,
@restore_threshold = 45, -- Alert nếu restore delay > 45 phút
@threshold_alert_enabled = 1,
@history_retention_period = 5760;
-- Xem trạng thái Log Shipping
SELECT
primary_database,
backup_threshold,
time_since_last_backup,
last_backup_file
FROM msdb.dbo.log_shipping_monitor_primary;
SELECT
secondary_database,
restore_threshold,
time_since_last_restore,
last_restored_file
FROM msdb.dbo.log_shipping_monitor_secondary;
Standby Mode: Secondary Read-Only
-- Restore với STANDBY: secondary database read-only (nhưng disconnect khi restore job chạy)
RESTORE LOG ProductionDB
FROM DISK = 'D:\LogShipping\ProductionDB_Log.trn'
WITH STANDBY = 'D:\LogShipping\Standby_Undo.bak';
-- Database trở thành read-only, users có thể query
-- Khi job restore log kế tiếp: disconnect users, apply log, back to read-only
Database Mirroring (Deprecated nhưng vẫn được hỏi)
Lưu ý: Deprecated từ SQL Server 2012, removed trong Azure SQL. Dùng AG thay thế.
┌──────────────┐ sync/async ┌──────────────┐
│ Principal │◀────────────▶│ Mirror │
│ (Primary) │ │ (Secondary) │
└──────┬───────┘ └──────────────┘
│ │
└──────────────────────────────┤
│ │
┌────▼────┐ │
│ Witness │◀─────────┘
│(optional│
│for auto │
│failover)│
└─────────┘
| Mode | Ý nghĩa |
|---|---|
| High Safety (Synchronous) | + Witness → Automatic failover; không có witness → Manual |
| High Performance (Asynchronous) | Không có witness, manual failover, có thể mất data |
Replication
Sao chép dữ liệu giữa databases — không phải HA mà là data distribution.
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Publisher │─▶│ Distributor │─▶│ Subscriber │
│ (Source) │ │ (Metadata + │ │ (Destination│
│ │ │ queue) │ │ copy) │
└─────────────┘ └──────────────┘ └─────────────┘
So sánh các loại Replication
| Loại | Hoạt động | RPO | Use Case |
|---|---|---|---|
| Snapshot | Copy toàn bộ data định kỳ | Hours | Lookup tables, ít thay đổi |
| Transactional | Stream từng transaction | Giây | Real-time reporting, OLAP offload |
| Merge | Sync 2 chiều, conflict resolution | Phút | Mobile, distributed updates |
| Peer-to-Peer | Multi-master transactional | Giây | Geo-distributed OLTP (phức tạp) |
-- Xem replication status
SELECT * FROM distribution.dbo.MSdistribution_status;
-- Check replication latency (để monitor)
-- Thêm tracer token
EXEC sp_posttracertoken
@publication = N'MyPublication',
@tracer_token_syntax = N'This is a tracer token %s',
@publisher_db = N'PublisherDB';
Azure SQL High Availability
Built-in HA (PaaS)
Azure SQL Database / Managed Instance có HA built-in — không cần cấu hình:
- General Purpose / Standard: storage-level redundancy, failover ~30 giây
- Business Critical / Premium: AG-like, local SSD, readable secondaries, failover < 30 giây
- Hyperscale: scale-out reads với nhiều read replicas
Active Geo-Replication
-- Tạo readable secondary ở region khác (Azure SQL Database)
-- Thực hiện qua Azure Portal hoặc PowerShell:
-- New-AzSqlDatabaseSecondary -ResourceGroupName "rg1"
-- -ServerName "primaryserver" -DatabaseName "mydb"
-- -PartnerResourceGroupName "rg2" -PartnerServerName "secondaryserver"
-- Failover thủ công
-- Set-AzSqlDatabaseSecondary -ResourceGroupName "rg2"
-- -ServerName "secondaryserver" -DatabaseName "mydb" -Failover
-- Hoàn toàn qua T-SQL với ALTER DATABASE (trong Azure SQL)
ALTER DATABASE mydb FAILOVER;
Auto-failover Groups
-- Auto-failover group: wrapper trên geo-replication + listener endpoint
-- Connection string: không cần biết primary/secondary
-- "Server=group-name.database.windows.net;Database=mydb;..."
-- Read-only: "Server=group-name.secondary.database.windows.net;..."
Database Snapshots như một cơ chế bảo vệ tạm thời
-- Tạo snapshot trước khi maintenance lớn
CREATE DATABASE ProductionDB_PreMaintenance
ON (NAME = 'ProductionDB_Data',
FILENAME = 'D:\Snapshots\ProdDB_PreMaintenance.ss')
AS SNAPSHOT OF ProductionDB;
-- Sau maintenance nếu có vấn đề → revert
RESTORE DATABASE ProductionDB
FROM DATABASE_SNAPSHOT = 'ProductionDB_PreMaintenance';
-- Snapshot KHÔNG phải backup thực sự:
-- - Phụ thuộc source database
-- - Không protect khỏi server failure
-- - Không thể backup/restore riêng lẻ
Q&A - Phỏng vấn High Availability
Junior Level
Q1: Always On AG và FCI khác nhau thế nào?
| Always On AG | FCI | |
|---|---|---|
| Scope | Database-level | Instance-level |
| Storage | Mỗi replica có storage riêng | Shared storage |
| Readable secondary | Có (Enterprise) | Không |
| License | Per-core tất cả replicas | Chỉ active nodes |
| Failover granularity | Từng database/AG | Toàn bộ instance |
Q2: Log Shipping là gì? Khi nào nên dùng?
Log Shipping tự động backup transaction log từ Primary, copy sang Secondary server, và restore. Secondary ở NORECOVERY hoặc STANDBY (read-only).
Dùng khi: ngân sách hạn chế, RPO 15-60 phút là chấp nhận được, cần readable DR server. Không dùng khi cần RPO gần zero hoặc automatic failover.
Q3: Sự khác biệt giữa synchronous và asynchronous AG?
- Synchronous: Primary chờ Secondary hardened log trước khi commit → RPO = 0, nhưng độ trễ tăng (chỉ dùng trong cùng datacenter hoặc low-latency WAN)
- Asynchronous: Primary không chờ Secondary → RPO > 0 (có thể mất vài giây data), nhưng không ảnh hưởng latency → dùng cho geo-distributed DR replicas
Mid Level
Q4: Readable Secondary trong AG hoạt động thế nào? Có vấn đề gì?
Secondary replica apply log từ Primary. Khi nhận log nhưng chưa apply, queries trên secondary đọc data cũ → potential dirty reads? Không — secondary dùng row versioning (snapshot isolation) để queries đọc consistent snapshot, không block redo operations.
Vấn đề:
- Snapshot isolation sử dụng
tempdbtrên secondary → monitortempdbusage - Queries nặng trên secondary có thể ảnh hưởng redo process (thường không đáng kể)
- Data có thể lag vài milliseconds so với Primary
Q5: AG Listener làm gì? Transparent failover hoạt động thế nào?
Listener là Virtual Network Name (VNN) hoặc Distributed Network Name (DNN) — application kết nối đến Listener, không kết nối trực tiếp đến node. Khi failover:
- Secondary become Primary
- Listener routing update (< vài giây với DNN)
- Application reconnect đến Listener → tự động kết nối đến Primary mới
Application phải handle reconnection (retry logic). Connection string cần MultiSubnetFailover=True để reconnect nhanh trong multi-subnet AG.
Q6: Khi nào chọn Always On AG vs Azure Active Geo-Replication?
- On-premises / SQL Server trong VM: Always On AG
- Azure SQL Database: Active Geo-Replication hoặc Auto-failover Groups (PaaS, managed)
- Azure SQL Managed Instance: Auto-failover groups (AG built-in, managed)
- Hybrid (on-prem + Azure): AG với Azure replica (Disaster Recovery to Azure)
Senior Level
Q7: Thiết kế HA/DR solution cho ứng dụng banking: RPO = 0, RTO < 1 phút, có DR site?
Solution:
- Primary DC: Always On AG với 2 nodes, synchronous commit, automatic failover
- Node 1: Primary
- Node 2: Synchronous secondary (same DC, auto failover)
- DR DC: Node 3, asynchronous commit (cross-DC, RPO = vài giây)
- Windows Server Failover Cluster: spanning cả 2 DCs
- Listener: DNN (vì DNN nhanh hơn VNN khi failover)
RPO:
- Trong cùng DC (Node 1 → 2): RPO = 0 (synchronous)
- DR failover (Node 1/2 → 3): RPO = vài giây (asynchronous)
RTO:
- Trong DC: < 30 giây (automatic failover)
- DR failover: < 1 phút (manual hoặc WSFC cross-DC failover)
Q8: AG split-brain scenario là gì? WSFC quorum giải quyết thế nào?
Split-brain: Hai nodes mất kết nối với nhau nhưng cả hai đều nghĩ mình là Primary → cả hai process writes → data divergence.
WSFC Quorum ngăn chặn split-brain: một node/cluster chỉ active khi đạt quorum (majority):
- Node Majority: > 50% nodes votes
- Node and File Share Majority: nodes + file share witness vote
- Node and Disk Majority: nodes + disk witness vote
- Cloud Witness (SQL Server 2016+): Azure Blob Storage làm witness
Nếu một DC bị cô lập và không đạt quorum → nodes đó tự shut down SQL Server → không thể process writes → no split-brain.
Q9: Làm thế nào để achieve zero-downtime maintenance trên AG Primary?
Planned maintenance (patch, hardware):
- Force failover to secondary (pre-check secondary health)
- Thực hiện maintenance trên node cũ (giờ là secondary)
- Về sau failover lại về original node (nếu cần)
- Với read-only routing: ứng dụng đọc không bị ảnh hưởng
Online maintenance options:
- Index rebuild với
ONLINE = ON: không block reads/writes - Index maintenance per-partition: không cần lock toàn bảng
- Statistics update:
ASYNC_STATS_UPDATE(SQL Server 2017+) - Schema changes: cần test carefully, có thể cần maintenance window