Performance Anti Pattern

Performance Anti Pattern #

Playbook yang berjalan 45 menit untuk 20 server adalah masalah nyata — feedback loop yang lambat menghambat iterasi, dan deployment yang lama meningkatkan risiko. Sebagian besar playbook yang lambat bukan karena operasi yang inheren lambat, melainkan karena anti pattern yang bisa diperbaiki tanpa mengubah logika: gathering facts yang tidak diperlukan, loop yang membuat koneksi SSH baru per iterasi, atau operasi yang dijalankan secara serial padahal bisa paralel. Artikel ini membahas pola-pola tersebut.

Anti Pattern 1: Gathering Facts di Semua Play #

# ANTI-PATTERN: facts dikumpulkan di setiap play meski tidak digunakan
- name: Restart services
  hosts: all
  # gather_facts: true ← default! Menghabiskan 1-3 detik per host
  tasks:
    - name: Restart nginx
      systemd:
        name: nginx
        state: restarted
    # Task ini tidak menggunakan ansible_* variable apapun!
    # Tapi Ansible tetap connect ke setiap host dulu untuk kumpulkan facts
# BENAR: nonaktifkan gathering jika tidak diperlukan
- name: Restart services
  hosts: all
  gather_facts: false   # Hemat 1-3 detik × jumlah host
  tasks:
    - name: Restart nginx
      systemd:
        name: nginx
        state: restarted

Untuk playbook dengan banyak play, aktifkan caching fact agar tidak dikumpulkan berulang:

# ansible.cfg
[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_fact_cache
fact_caching_timeout = 3600

Anti Pattern 2: Loop yang Membuat Koneksi Baru Per Iterasi #

# ANTI-PATTERN: loop dengan task yang setiap iterasi butuh koneksi terpisah
- name: Install packages satu per satu
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - postgresql-15
    - redis-server
    - certbot
    - fail2ban
  # Ansible perlu melakukan 5 operasi package manager terpisah!
  # Setiap iterasi = satu round-trip ke managed node
# BENAR: operasi batch dalam satu task
- name: Install semua packages sekaligus
  apt:
    name:
      - nginx
      - postgresql-15
      - redis-server
      - certbot
      - fail2ban
    state: present
    update_cache: true
  # Satu operasi apt — jauh lebih cepat

Prinsip yang sama berlaku untuk file, copy, template — cari cara untuk mengelompokkan operasi yang sejenis.


Anti Pattern 3: Forks Default yang Terlalu Rendah #

# ANTI-PATTERN: biarkan forks di nilai default
# ansible.cfg (atau tidak ada ansible.cfg)
# forks = 5   ← default! Hanya 5 host paralel

# Untuk infrastruktur 100 host: 100/5 = 20 batch
# Jika setiap batch 30 detik, total = 10 menit hanya karena forks terlalu rendah
# BENAR: sesuaikan forks dengan kapasitas control node
# ansible.cfg
[defaults]
forks = 20   # Mulai dari sini, naikkan sampai CPU control node mulai 70-80%
# Monitor CPU control node saat playbook berjalan untuk menemukan nilai optimal
ansible-playbook site.yml &
watch -n1 'ps aux | grep ansible | head -5; echo "---"; uptime'

Anti Pattern 4: SSH yang Tidak Dioptimasi #

# ANTI-PATTERN: mengabaikan optimasi SSH
# ansible.cfg
[ssh_connection]
# Tidak ada optimasi — setiap task membuat koneksi SSH baru
# BENAR: aktifkan pipelining dan multiplexing
# ansible.cfg
[ssh_connection]
pipelining = true
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r

[defaults]
forks = 20

pipelining menghilangkan overhead transfer module: bisa memangkas 30-50% waktu eksekusi untuk play dengan banyak task pendek. ControlMaster menggunakan kembali koneksi SSH yang sudah ada.


Anti Pattern 5: Delegate_to Localhost yang Berulang Tanpa run_once #

# ANTI-PATTERN: task delegate_to localhost dieksekusi per-host tanpa run_once
- name: Ambil token dari vault
  uri:
    url: "https://vault.internal/v1/auth/token"
    method: POST
    body_format: json
    body:
      role_id: "{{ vault_role_id }}"
      secret_id: "{{ vault_secret_id }}"
  register: vault_token
  delegate_to: localhost
  # Ini dieksekusi 50 kali (sekali per host) meski token-nya sama!
# BENAR: gunakan run_once untuk operasi yang hasilnya sama untuk semua host
- name: Ambil token dari vault (sekali saja)
  uri:
    url: "https://vault.internal/v1/auth/token"
    method: POST
    body_format: json
    body:
      role_id: "{{ vault_role_id }}"
      secret_id: "{{ vault_secret_id }}"
  register: vault_token
  delegate_to: localhost
  run_once: true              # Dieksekusi sekali, hasilnya tersedia untuk semua host
  no_log: true

Anti Pattern 6: Tidak Menggunakan Profiling untuk Debug Bottleneck #

# ANTI-PATTERN: menebak di mana bottleneck tanpa mengukur
# "Playbook saya lambat, mungkin karena packages banyak..."
# (mengutak-atik tanpa data)
# BENAR: aktifkan profiling untuk mengukur sebelum mengoptimasi
# ansible.cfg
[defaults]
callbacks_enabled = profile_tasks, profile_roles, timer
# Jalankan playbook dan baca output profiling:
# Thursday 15 March 2024  (...) 0:12:45
# ===============================================
# Gathering Facts ------------------- 45.23s    ← Terbesar! Aktifkan fact caching
# Install required packages --------- 38.19s    ← Kedua! Coba batch install
# Deploy SSL certificates ----------- 12.44s    ← Perlu dioptimasi?
# Configure nginx ------------------- 3.21s
# ...

# Fokus optimasi pada task dengan waktu terbesar, bukan asumsi

Ringkasan #

  • gather_facts: false untuk play yang tidak menggunakan variabel ansible_* — penghematan nyata terutama untuk infrastruktur besar.
  • Install packages dalam satu task dengan list, bukan loop — satu panggilan apt untuk 10 package jauh lebih cepat dari 10 panggilan apt satu per satu.
  • Naikkan forks dari default 5 ke setidaknya 20 — ini sering menjadi bottleneck terbesar untuk infrastruktur dengan banyak host.
  • pipelining = true dan ControlMaster di ansible.cfg — dua optimasi SSH yang memberikan dampak besar dengan konfigurasi minimal.
  • run_once: true untuk operasi delegate_to: localhost yang hasilnya sama untuk semua host — hindari memanggil API eksternal N kali untuk sesuatu yang hanya perlu satu kali.
  • Gunakan profile_tasks callback sebelum mengoptimasi — ukur dahulu, identifikasi bottleneck nyata, baru perbaiki. Jangan menebak.

← Sebelumnya: Security Anti Pattern   Berikutnya: CI/CD Anti Pattern →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact