Belajar Yii - Caching & Performance
Series/Belajar Yii/Episode 11
Episode 11 of 27

Belajar Yii - Caching & Performance

Mengoptimalkan performa aplikasi Yii dengan caching bertingkat: data caching lewat component File, Redis, Memcached, dan APCu; query caching untuk query berat; fragment caching untuk potongan view; serta HTTP caching dengan Last-Modified dan ETag di level browser.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Di episode-episode sebelumnya aplikasi kalian sudah berfungsi penuh: CRUD, form, autentikasi, dan API. Sekarang pertanyaannya berubah dari "apakah berfungsi?" menjadi "apakah bertahan saat ribuan user?" Jawabannya ada pada caching — menyimpan hasil komputasi yang mahal agar tidak diulang.

Yii menangani caching dengan cara yang sangat terstruktur: satu komponen cache yang seragam, dan empat lapis penggunaannya — data caching (hasil query/hitung), query caching (SQL mentah yang di-cache database), fragment caching (potongan view), dan HTTP caching (di level browser). Kita bedah semuanya di episode ini.

Memilih Cache Component

Semua lapis caching memakai component cache. Perbedaannya hanya di backend penyimpanan. Template basic memakai FileCache; untuk production, pilih yang sesuai:

config/web.php - opsi cache component
// FileCache - default template, tanpa dependensi eksternal
'cache' => [
    'class' => 'yii\caching\FileCache',
    'cachePath' => '@runtime/cache',
],
 
// APCu - paling cepat untuk single server
'cache' => [
    'class' => 'yii\caching\ApcCache',
    'useApcu' => true,
],
 
// Redis - untuk multi server dan session sharing
'cache' => [
    'class' => 'yii\redis\Cache',
    'redis' => 'redis',   // component redis (episode 21)
],
 
// Memcached - backend cache klasik
'cache' => [
    'class' => 'yii\caching\MemcachedCache',
    'servers' => [
        ['host' => '127.0.0.1', 'port' => 11211],
    ],
],
BackendKecepatanMulti-serverSetup
FileCacheRendahTidakTanpa dependensi
APCuTertinggi (in-memory)TidakEkstensi PHP
MemcachedTinggiYaServer memcached
RedisTinggiYaServer redis (episode 21)

Mulai dari FileCache saat belajar, lalu pindah ke Redis saat production — kita detailkan Redis di episode 21.

Data Caching

Data caching adalah penyimpanan nilai arbitrer dengan masa berlaku (TTL). Pola dasarnya:

Data caching dasar
use Yii;
 
// simpan: query mahal dihitung sekali
Yii::$app->cache->set('top_posts', Post::find()->limit(5)->all(), 60);
 
// ambil
$topPosts = Yii::$app->cache->get('top_posts');
 
// hapus
Yii::$app->cache->delete('top_posts');

Namun pola yang lebih idiomatis adalah getOrSet — cek cache, hitung jika kosong:

Pola getOrSet
$topPosts = Yii::$app->cache->getOrSet('top_posts', function () {
    return Post::find()
        ->where(['status' => 'published'])
        ->orderBy(['read_count' => SORT_DESC])
        ->limit(5)
        ->all();
}, 300);

getOrSet menggabungkan get, hitung, dan set dalam satu pemanggilan — menjaga kode tetap bersih dan mencegah cache stampede (banyak request menghitung nilai yang sama saat cache kosong).

Tip

Aturan penting data caching: nama kunci harus spesifik dan versi-aware. top_posts akan basi jika logika berubah — gunakan top_posts_v2, atau sertakan identitas variabel seperti top_posts:user:{id}. Saat ada event yang mengubah data (misal post baru), panggil Yii::$app->cache->delete('top_posts') agar cache tidak menampilkan data basi.

Query Caching

Query caching otomatis meng-cache hasil query database untuk durasi tertentu — kalian tidak perlu menyentuh kode query-nya sama sekali:

Query caching
use Yii;
 
$result = Yii::$app->db->cache(function ($db) {
    return Post::find()->with('comments')->all();  // di-cache otomatis
}, 60);

Bisa juga diaktifkan global di konfigurasi:

config/web.php - query cache global
'db' => [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=blog',
    'username' => 'root',
    'password' => '',
    'enableQueryCache' => true,
    'queryCacheDuration' => 60,
    'queryCache' => 'cache',   // pakai component cache
],

Query caching bekerja per-DB-connection: dalam blok cache(), semua query DQL di-cache, sedangkan DML (INSERT/UPDATE) otomatis membatalkan cache. Efektif untuk query JOIN berat yang jarang berubah.

Fragment Caching

Fragment caching menyimpan potongan view yang sudah di-render. Cocok untuk area yang mahal tapi jarang berubah — sidebar, header, daftar rekomendasi:

Fragment caching di view
<?php if ($this->beginCache('sidebar_recent', ['duration' => 300])): ?>
 
    <h3>Post Terbaru</h3>
    <ul>
        <?php foreach ($recentPosts as $post): ?>
            <li><?= Html::encode($post->title) ?></li>
        <?php endforeach; ?>
    </ul>
 
<?php $this->endCache(); endif; ?>

Perbedaan dari data caching: fragment cache menyimpan output HTML akhir, jadi tidak perlu re-render sama sekali. Fragmen yang bergantung pada user tertentu bisa di-key dengan parameter variasi:

Cache fragment per user
<?php if ($this->beginCache('user_menu_' . Yii::$app->user->id, ['duration' => 60])): ?>
    ... menu user ...
<?php $this->endCache(); endif; ?>

HTTP Caching

Lapis terluar dan paling hemat: memanfaatkan cache browser lewat header HTTP. Yii menyediakan filter HttpCache dengan dukungan Last-Modified dan ETag:

HTTP caching di controller
use yii\filters\HttpCache;
 
public function behaviors(): array
{
    return [
        [
            'class' => HttpCache::class,
            'lastModified' => function ($action, $params) {
                // timestamp terakhir data berubah
                return (int) Post::find()->max('updated_at');
            },
            'etagSeed' => function ($action, $params) {
                // nilai unik yang berubah saat data berubah
                $post = $this->findModel(Yii::$app->request->get('id'));
                return $post->updated_at . '|' . $post->title;
            },
        ],
    ];
}

Cara kerjanya: browser mengirim If-Modified-Since/If-None-Match. Jika data belum berubah, Yii membalas 304 Not Modified tanpa me-render halaman — penghematan maksimal di sisi server dan jaringan.

Warning

HTTP caching hanya boleh untuk halaman yang benar-benar sama untuk semua user — jangan cache halaman dashboard yang menampilkan data per-user. Kombinasi yang keliru menghasilkan kebocoran data antar user. Selalu gunakan lastModified/etagSeed berdasarkan data yang relevan dengan halaman tersebut.

Praktik: Cache Query Panas

Mari terapkan pada skenario nyata: daftar post populer di halaman beranda yang query-nya JOIN comments dan COUNT:

controllers/SiteController.php - cache query panas
public function actionIndex(): string
{
    $popular = Yii::$app->cache->getOrSet('popular_posts', function () {
        return Post::find()
            ->alias('p')
            ->select(['p.*', 'COUNT(c.id) AS comment_count'])
            ->joinWith('comments c')
            ->where(['p.status' => 'published'])
            ->groupBy('p.id')
            ->orderBy(['comment_count' => SORT_DESC])
            ->limit(5)
            ->all();
    }, 300);
 
    return $this->render('index', ['popular' => $popular]);
}

Saat post baru dibuat, batalkan cache-nya:

Invalidasi cache saat data berubah
public function afterSave($insert, $changedAttributes): void
{
    parent::afterSave($insert, $changedAttributes);
    Yii::$app->cache->delete('popular_posts');
}

Ukur dampaknya — dengan 100.000 baris di tabel posts, query JOIN COUNT di atas bisa memakan ratusan milidetik; dengan cache, request berikutnya hanya perlu beberapa milidetik karena hasil diambil dari memori.

Penutup

Inti yang harus dibawa pulang:

  • Semua caching memakai satu component cache; pilih backend sesuai kebutuhan (File → APCu → Redis).
  • Data caching (getOrSet) menyimpan nilai hasil komputasi dengan TTL dan nama kunci versioned.
  • Query caching meng-cache hasil SQL per-DB-connection tanpa mengubah kode query.
  • Fragment caching menyimpan output HTML view, ideal untuk area yang jarang berubah.
  • HTTP caching (HttpCache + Last-Modified/ETag) menghemat di level browser.
  • Invalidate cache di afterSave agar data tidak basi.

Di episode 12 selanjutnya, kita memindahkan kerja berat ke belakang layar: queue & background tasksyiisoft/yii2-queue dengan driver Redis, DB, AMQP, dan SQS, konsep job, cara mem-push dan memproses pekerjaan asinkron seperti email dan laporan, serta scheduling worker. Sampai jumpa di episode 12!

Belajar Yii - Caching & Performance | Belajar Yii