Caching

NexaUI framework menyediakan sistem caching yang powerful untuk meningkatkan performa aplikasi dengan menyimpan data yang sering diakses.

Pengenalan Caching

Caching adalah teknik untuk menyimpan sementara data yang sering diakses untuk mengurangi waktu pemrosesan dan beban database. NexaUI menyediakan beberapa driver caching yang dapat digunakan sesuai kebutuhan aplikasi Anda.

Manfaat Caching

  • Mengurangi waktu respons aplikasi
  • Mengurangi beban pada database
  • Meningkatkan skalabilitas aplikasi
  • Mengoptimalkan penggunaan sumber daya server
  • Menyediakan fallback data saat database tidak tersedia

Driver Caching

NexaUI mendukung beberapa driver caching yang dapat dikonfigurasi:

  • File Cache: Menyimpan cache dalam file sistem
  • Memory Cache: Menyimpan cache dalam memory aplikasi (runtime only)
  • Redis: Menggunakan Redis sebagai penyimpanan cache
  • Memcached: Menggunakan Memcached sebagai penyimpanan cache
  • Database: Menyimpan cache dalam tabel database

Konfigurasi Driver

Konfigurasi driver caching dapat dilakukan di file konfigurasi aplikasi:


// Konfigurasi cache di config/cache.php
return [
    'default' => 'file',  // Driver default
    
    'drivers' => [
        'file' => [
            'path' => STORAGE_PATH . '/cache',
            'extension' => '.cache',
            'ttl' => 3600  // Default time-to-live dalam detik
        ],
        'memory' => [
            'ttl' => 600  // Default time-to-live dalam detik
        ],
        'redis' => [
            'host' => '127.0.0.1',
            'port' => 6379,
            'password' => null,
            'database' => 0,
            'ttl' => 3600
        ],
        'memcached' => [
            'servers' => [
                [
                    'host' => '127.0.0.1',
                    'port' => 11211,
                    'weight' => 100
                ]
            ],
            'ttl' => 3600
        ],
        'database' => [
            'table' => 'cache',
            'connection' => 'default',
            'ttl' => 3600
        ]
    ]
];
        

Penggunaan Dasar Cache

NexaUI menyediakan API yang sederhana untuk mengakses dan mengelola cache:


// Mendapatkan instance cache dengan driver default
$cache = $this->Cache();

// Mendapatkan instance cache dengan driver tertentu
$redisCache = $this->Cache('redis');

// Menyimpan item ke cache
$cache->set('user:1', $userData, 3600);  // key, value, ttl (dalam detik)

// Mengambil item dari cache
$userData = $cache->get('user:1');

// Mengambil dengan default value jika tidak ada
$userData = $cache->get('user:1', ['name' => 'Guest']);

// Cek apakah item ada di cache
if ($cache->has('user:1')) {
    // Item ada di cache
}

// Menghapus item dari cache
$cache->delete('user:1');

// Menghapus semua item cache
$cache->flush();
        

Remember Method

Method remember sangat berguna untuk menyimpan hasil fungsi ke cache jika belum ada:


// Mendapatkan data dari cache atau menyimpannya jika belum ada
$userData = $cache->remember('user:1', 3600, function() {
    // Fungsi ini hanya dijalankan jika cache tidak ditemukan
    return $this->Storage('users')->where('id', 1)->first();
});
        

Caching Model Data

Menggunakan cache dengan model untuk meningkatkan performa query database:


class UserModel extends NexaModel
{
    protected $table = 'users';
    
    // Mendapatkan user dengan caching
    public function getUserWithCache($id)
    {
        $cacheKey = "user:{$id}";
        $cache = $this->Cache();
        
        return $cache->remember($cacheKey, 3600, function() use ($id) {
            return $this->Storage('users')->where('id', $id)->first();
        });
    }
    
    // Mendapatkan semua users dengan caching
    public function getAllUsersWithCache()
    {
        $cacheKey = "users:all";
        $cache = $this->Cache();
        
        return $cache->remember($cacheKey, 1800, function() {
            return $this->Storage('users')->get();
        });
    }
    
    // Update user dan hapus cache
    public function updateUserAndClearCache($id, $data)
    {
        $result = $this->Storage('users')->where('id', $id)->update($data);
        
        if ($result) {
            // Hapus cache untuk user ini
            $this->Cache()->delete("user:{$id}");
            
            // Hapus cache untuk semua users
            $this->Cache()->delete("users:all");
        }
        
        return $result;
    }
}

// Penggunaan
$userModel = new UserModel();

// Mendapatkan user dari cache atau database
$user = $userModel->getUserWithCache(1);

// Update user dan hapus cache
$userModel->updateUserAndClearCache(1, ['name' => 'John Doe']);
        

Cache Tags

Beberapa driver cache (Redis, Memcached) mendukung tags untuk mengelompokkan item cache:


// Mendapatkan cache dengan tag support
$cache = $this->Cache('redis');

// Menyimpan item dengan tags
$cache->tags(['users', 'profile'])->set('user:1', $userData, 3600);

// Mengambil item dengan tags
$userData = $cache->tags(['users', 'profile'])->get('user:1');

// Menghapus semua item dengan tag tertentu
$cache->tags(['users'])->flush();
        

Catatan: File cache dan memory cache tidak mendukung tags.

Cache Invalidation

Strategi untuk invalidasi cache yang efektif:

Time-based Invalidation

Menggunakan TTL (Time-to-Live) untuk otomatis menghapus cache setelah periode tertentu:


// Cache akan otomatis invalid setelah 1 jam
$cache->set('latest-posts', $posts, 3600);
        

Event-based Invalidation

Menghapus cache ketika data berubah:


class PostModel extends NexaModel
{
    protected $table = 'posts';
    
    // Mendapatkan post dengan cache
    public function getPostWithCache($id)
    {
        return $this->Cache()->remember("post:{$id}", 3600, function() use ($id) {
            return $this->Storage('posts')->where('id', $id)->first();
        });
    }
    
    // Update post dan invalidate cache
    public function updatePost($id, $data)
    {
        $result = $this->Storage('posts')->where('id', $id)->update($data);
        
        if ($result) {
            // Invalidate cache untuk post ini
            $this->Cache()->delete("post:{$id}");
            
            // Invalidate cache lain yang terkait
            $this->Cache()->delete("latest-posts");
            $this->Cache()->delete("category-posts:{$data['category_id']}");
            
            // Jika menggunakan tags
            if ($this->Cache() instanceof RedisCache) {
                $this->Cache()->tags(['posts'])->flush();
            }
        }
        
        return $result;
    }
}
        

Version-based Invalidation

Menggunakan versi untuk invalidasi cache:


class CategoryModel extends NexaModel
{
    protected $table = 'categories';
    
    // Mendapatkan versi cache
    private function getCacheVersion($categoryId)
    {
        $versionKey = "category:{$categoryId}:version";
        $version = $this->Cache()->get($versionKey, 1);
        return $version;
    }
    
    // Increment versi cache
    private function incrementCacheVersion($categoryId)
    {
        $versionKey = "category:{$categoryId}:version";
        $version = $this->Cache()->get($versionKey, 0) + 1;
        $this->Cache()->set($versionKey, $version);
        return $version;
    }
    
    // Mendapatkan posts dalam category dengan versioned cache
    public function getCategoryPosts($categoryId)
    {
        $version = $this->getCacheVersion($categoryId);
        $cacheKey = "category:{$categoryId}:posts:v{$version}";
        
        return $this->Cache()->remember($cacheKey, 3600, function() use ($categoryId) {
            return $this->Storage('posts')
                        ->where('category_id', $categoryId)
                        ->get();
        });
    }
    
    // Update category dan invalidate cache dengan increment versi
    public function updateCategory($categoryId, $data)
    {
        $result = $this->Storage('categories')->where('id', $categoryId)->update($data);
        
        if ($result) {
            // Increment versi cache (invalidate versi sebelumnya)
            $this->incrementCacheVersion($categoryId);
        }
        
        return $result;
    }
}
        

Cache Middleware

NexaUI menyediakan middleware untuk caching response HTTP:


// Mendaftarkan middleware di routes/web.php
$router->group(['middleware' => ['cache:60']], function($router) {
    $router->get('/blog', 'BlogController@index');
    $router->get('/blog/{id}', 'BlogController@show');
});

// Implementasi middleware cache
class CacheMiddleware
{
    public function handle($request, $next, $ttl = 30)
    {
        // Generate cache key berdasarkan URL dan query parameters
        $cacheKey = 'response:' . md5($request->getUrl() . serialize($request->getQuery()));
        
        // Cek apakah response sudah ada di cache
        $cache = app()->make('cache');
        $cachedResponse = $cache->get($cacheKey);
        
        if ($cachedResponse !== null) {
            return $cachedResponse;
        }
        
        // Jalankan request dan cache response
        $response = $next($request);
        $cache->set($cacheKey, $response, (int)$ttl);
        
        return $response;
    }
}
        

Best Practices

  • Gunakan caching untuk data yang sering diakses dan jarang berubah
  • Set TTL yang sesuai dengan frekuensi perubahan data
  • Gunakan prefix pada cache key untuk menghindari konflik
  • Implementasikan strategi invalidasi cache yang tepat
  • Gunakan tags untuk mengelompokkan cache yang berhubungan
  • Monitor penggunaan cache dan performa aplikasi
  • Pertimbangkan untuk menggunakan distributed cache untuk aplikasi yang berjalan di multiple server

Debugging Cache

NexaUI menyediakan tools untuk debugging cache:


// Mendapatkan informasi tentang cache
$cacheInfo = $this->Cache()->getInfo();

// Mendapatkan semua keys di cache (hanya beberapa driver yang mendukung)
$keys = $this->Cache()->getKeys();

// Mengaktifkan debug mode
$this->Cache()->setDebug(true);

// Mendapatkan log cache operations
$cacheLog = $this->Cache()->getDebugLog();