← Semua pembelajaran / Go Nol β†’ Enterprise
Fase 10 Β· Deploy di AWS

RDS & Aurora untuk aplikasi Go

Database terkelola menghilangkan pekerjaan operasional, tapi tidak menghilangkan keputusan: berapa koneksi, ke endpoint mana, dan apa yang terjadi pada pool-mu saat failover berlangsung.

Intisari

  • Aurora punya cluster endpoint (selalu writer) dan reader endpoint (menyebar ke replica).
  • Pakai dua *sql.DB terpisah β€” satu untuk tulis, satu untuk baca β€” supaya beban baca pindah tanpa mengubah kode domain.
  • ConnMaxLifetime wajib: tanpa itu, pool tetap memegang koneksi ke instans lama setelah failover (Fase 4).
  • Replica punya lag: baca-setelah-tulis harus diarahkan ke writer.
  • Aurora Serverless v2 bagus untuk beban tidak menentu; instans tetap lebih murah untuk beban stabil.

Endpoint dan perannya

toko.cluster-abc123.ap-southeast-1.rds.amazonaws.com          ← WRITER
toko.cluster-ro-abc123.ap-southeast-1.rds.amazonaws.com       ← READER (menyebar)
toko-instance-1.abc123.ap-southeast-1.rds.amazonaws.com       ← instans tertentu
                                                                (jangan dipakai aplikasi)
type DB struct {
	Tulis *pgxpool.Pool
	Baca  *pgxpool.Pool
}

func Buka(ctx context.Context, cfg config.Config) (*DB, error) {
	tulis, err := bukaPool(ctx, cfg.DSNWriter, 20)
	if err != nil {
		return nil, err
	}

	// Reader boleh punya pool lebih besar: kueri baca biasanya lebih pendek,
	// dan replica-nya bisa lebih dari satu.
	baca, err := bukaPool(ctx, cfg.DSNReader, 30)
	if err != nil {
		tulis.Close()
		return nil, err
	}
	return &DB{Tulis: tulis, Baca: baca}, nil
}
// Repository memutuskan pool mana β€” domain tidak perlu tahu (Fase 5).
func (r *Repo) Ambil(ctx context.Context, id int64) (Produk, error) {
	return ambil(ctx, r.db.Baca, id)      // boleh sedikit basi
}

func (r *Repo) Simpan(ctx context.Context, p Produk) error {
	return simpan(ctx, r.db.Tulis, p)
}

// Baca-setelah-tulis WAJIB ke writer: replica bisa tertinggal.
func (r *Repo) AmbilSetelahTulis(ctx context.Context, id int64) (Produk, error) {
	return ambil(ctx, r.db.Tulis, id)
}

Replication lag adalah sumber bug yang membingungkan pengguna. Pengguna menyimpan perubahan, halaman berikutnya membaca dari replica yang tertinggal 200 ms, dan perubahannya "hilang". Aturan praktis: setelah operasi tulis, baca berikutnya dalam permintaan yang sama β€” dan biasanya juga permintaan berikutnya dari pengguna itu β€” harus ke writer.

Failover

t=0    Instans writer bermasalah
t=5    Aurora mempromosikan reader jadi writer baru
t=6    DNS cluster endpoint menunjuk instans baru (TTL ~5 detik)
t=6    ❌ Pool aplikasi MASIH memegang 20 koneksi ke instans lama
       β†’ semua tulisan gagal "cannot execute INSERT in a read-only transaction"
       β†’ dan TIDAK pulih sendiri, karena koneksinya tidak pernah kedaluwarsa

βœ… Dengan ConnMaxLifetime = 5 menit:
   koneksi dibuang bertahap, DNS di-resolve ulang, pool pindah sendiri
cfg.MaxConnLifetime = 5 * time.Minute       // lebih pendek dari biasanya
cfg.MaxConnIdleTime = 1 * time.Minute
cfg.HealthCheckPeriod = 30 * time.Second

Untuk pemulihan yang lebih cepat, tangani error read-only transaction secara khusus: kalau muncul, tutup koneksi tersebut dan ambil yang baru. Tapi ConnMaxLifetime yang pendek sudah menutup sebagian besar kasus, dan jauh lebih sederhana.

Memilih konfigurasi

PilihanCocok kalauCatatan
RDS PostgreSQL, Single-AZPengembangan / stagingTermurah; ada jeda saat pemeliharaan
RDS PostgreSQL, Multi-AZProduksi kecil–menengahFailover 60–120 detik
Aurora PostgreSQLProduksiFailover < 30 detik; reader murah ditambahkan
Aurora Serverless v2Beban tidak menentuSkala per 0,5 ACU; mahal kalau selalu ramai

Batas koneksi

max_connections di RDS ditentukan ukuran instans:

  db.t4g.medium (4 GB)    β‰ˆ 340
  db.r6g.large  (16 GB)   β‰ˆ 1.600
  db.r6g.xlarge (32 GB)   β‰ˆ 3.000

Hitung untuk jumlah task MAKSIMUM (Fase 4):

  (MaxOpenConns Γ— task web) + (worker) + (cron) + cadangan < max_connections

  20 Γ— 20 web  = 400
  10 Γ—  4 work =  40
  10 Γ—  1 cron =  10
  cadangan     =  25   (migrasi, psql darurat, monitoring)
  ──────────────────
  total        = 475   β†’ butuh instans yang lebih besar dari t4g.medium

Autoscaling ECS bisa menjatuhkan database. Trafik naik β†’ ECS menambah task β†’ koneksi melampaui batas β†’ database menolak koneksi baru β†’ seluruh layanan gagal, termasuk task yang tadinya sehat. Batas maksimum autoscaling harus diturunkan dari kapasitas koneksi database, bukan dari anggaran saja.

Kredensial dan rotasi

Opsi A: Secrets Manager dengan rotasi terkelola
  βœ… sederhana, kredensial berputar otomatis
  ⚠️ rotasi harus memicu deployment baru, atau aplikasi harus memuat ulang

Opsi B: Autentikasi IAM ke database
  βœ… tanpa sandi sama sekali; token berumur 15 menit
  ⚠️ ada batas laju pembuatan token; perlu penanganan di kode
// TLS ke RDS bukan opsional (Fase 6)
dsn := "postgres://pengguna:sandi@host:5432/toko?sslmode=verify-full&pool_max_conns=20"

Yang harus dipantau

MetrikAlarm kalau
DatabaseConnections> 80% dari max_connections
CPUUtilization> 80% berkelanjutan
FreeableMemoryTurun terus β†’ working set melebihi RAM
ReadLatency / WriteLatency> 20 ms
AuroraReplicaLag> 1 detik
DiskQueueDepthNaik β†’ I/O jadi kemacetan
Deadlocks> 0 secara rutin (Fase 4)

Nyalakan Performance Insights sejak awal. Ia menunjukkan kueri mana yang memakan waktu database terbanyak β€” padanan terkelola dari pg_stat_statements (Fase 4), dan biasanya jawaban pertama saat p95 naik tanpa perubahan kode.

Cadangan dan pemulihan

  1. Backup otomatis minimal 7 hari; 30 hari untuk data yang menyangkut uang.
  2. Point-in-time recovery aktif β€” menyelamatkan dari DELETE tanpa WHERE.
  3. Perlindungan penghapusan aktif di produksi.
  4. Uji pemulihannya setahun sekali. Backup yang belum pernah dipulihkan bukan backup.
  5. Snapshot manual sebelum migrasi besar β€” dan sebelum setiap perubahan skema yang tidak bisa dibatalkan.

Latihan: siapkan cluster Aurora dengan satu reader, pisahkan pool baca dan tulis di aplikasimu, lalu picu failover manual dari konsol sambil mengirim trafik. Catat berapa lama sampai aplikasimu pulih sendiri β€” dengan dan tanpa ConnMaxLifetime.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.