Kinerja aplikasi sangat penting untuk keberhasilan produk Anda. Dalam lingkungan di mana pengguna mengharapkan waktu respons situs web kurang dari satu detik, konsekuensi dari aplikasi yang lambat dapat diukur dalam dolar dan sen. Meskipun Anda tidak menjual apa pun, pemuatan halaman yang cepat meningkatkan pengalaman mengunjungi situs Anda.
Segala sesuatu yang terjadi di server antara saat menerima permintaan hingga saat ia mengembalikan respons meningkatkan jumlah waktu yang diperlukan untuk memuat halaman. Sebagai aturan umum, semakin banyak pemrosesan yang dapat Anda hilangkan di server, semakin cepat kinerja aplikasi Anda. Caching data setelah diproses dan kemudian disajikan dari cache saat diminta berikutnya adalah salah satu cara untuk menghilangkan stres pada server. Dalam tutorial ini, kami akan mengeksplorasi beberapa faktor yang menghambat aplikasi Anda, dan kami akan mendemonstrasikan cara mengimplementasikan caching dengan Redis untuk melawan efeknya.
Bonus Gratis: Klik di sini untuk mendapatkan akses ke Panduan Sumber Daya Pembelajaran Django (PDF) gratis yang menunjukkan kepada Anda tip dan trik serta perangkap umum yang harus dihindari saat membangun aplikasi web Python + Django.
Apa itu Redis?
Redis adalah penyimpanan struktur data dalam memori yang dapat digunakan sebagai mesin caching. Karena menyimpan data dalam RAM, Redis dapat mengirimkannya dengan sangat cepat. Redis bukan satu-satunya produk yang bisa kita gunakan untuk caching. Memcached adalah sistem caching dalam memori populer lainnya, tetapi banyak orang setuju bahwa Redis lebih unggul daripada Memcached di sebagian besar situasi. Secara pribadi, kami menyukai betapa mudahnya menyiapkan dan menggunakan Redis untuk tujuan lain seperti Redis Queue.
Memulai
Kami telah membuat aplikasi contoh untuk memperkenalkan Anda pada konsep caching. Aplikasi kami menggunakan:
- Django (v1.9.8)
- Bilah Alat Debug Django (v1.4)
- django-redis (v4.4.3)
- Redis (v3.2.0)
Instal Aplikasi
Sebelum Anda mengkloning repositori, instal virtualenvwrapper, jika Anda belum memilikinya. Ini adalah alat yang memungkinkan Anda menginstal dependensi Python spesifik yang dibutuhkan proyek Anda, memungkinkan Anda menargetkan versi dan pustaka yang diperlukan oleh aplikasi Anda secara terpisah.
Selanjutnya, ubah direktori ke tempat Anda menyimpan proyek dan kloning contoh repositori aplikasi. Setelah selesai, ubah direktori ke repositori kloning, lalu buat lingkungan virtual baru untuk aplikasi contoh menggunakan mkvirtualenv
perintah:
$ mkvirtualenv django-redis
(django-redis)$
CATATAN: Membuat lingkungan virtual dengan
mkvirtualenv
juga mengaktifkannya.
Instal semua dependensi Python yang diperlukan dengan pip
, lalu periksa tag berikut:
(django-redis)$ git checkout tags/1
Selesaikan penyiapan aplikasi contoh dengan membangun database dan mengisinya dengan data sampel. Pastikan untuk membuat pengguna super juga, sehingga Anda dapat masuk ke situs admin. Ikuti contoh kode di bawah ini lalu coba jalankan aplikasi untuk memastikannya berfungsi dengan benar. Kunjungi halaman admin di browser untuk mengonfirmasi bahwa data telah dimuat dengan benar.
(django-redis)$ python manage.py makemigrations cookbook
(django-redis)$ python manage.py migrate
(django-redis)$ python manage.py createsuperuser
(django-redis)$ python manage.py loaddata cookbook/fixtures/cookbook.json
(django-redis)$ python manage.py runserver
Setelah Anda menjalankan aplikasi Django, pindah ke instalasi Redis.
Instal Redis
Unduh dan instal Redis menggunakan instruksi yang disediakan dalam dokumentasi. Atau, Anda dapat menginstal Redis menggunakan manajer paket seperti apt-get atau buatan rumahan tergantung pada OS Anda.
Jalankan server Redis dari jendela terminal baru.
$ redis-server
Selanjutnya, mulai antarmuka baris perintah (CLI) Redis di jendela terminal yang berbeda dan uji apakah itu terhubung ke server Redis. Kami akan menggunakan Redis CLI untuk memeriksa kunci yang kami tambahkan ke cache.
$ redis-cli ping
PONG
Redis menyediakan API dengan berbagai perintah yang dapat digunakan pengembang untuk bertindak di penyimpanan data. Django menggunakan django-redis untuk menjalankan perintah di Redis.
Melihat aplikasi contoh kami di editor teks, kami dapat melihat konfigurasi Redis di settings.py mengajukan. Kami mendefinisikan cache default dengan CACHES
pengaturan, menggunakan django-redis . bawaan cache sebagai backend kami. Redis berjalan pada port 6379 secara default, dan kami menunjuk ke lokasi itu di pengaturan kami. Satu hal terakhir yang perlu disebutkan adalah django-redis menambahkan nama kunci dengan awalan dan versi untuk membantu membedakan kunci yang serupa. Dalam hal ini, kami telah mendefinisikan awalan menjadi "contoh".
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient"
},
"KEY_PREFIX": "example"
}
}
CATATAN :Meskipun kami telah mengonfigurasi backend cache, tidak ada fungsi tampilan yang mengimplementasikan caching.
Kinerja Aplikasi
Seperti yang kami sebutkan di awal tutorial ini, semua yang dilakukan server untuk memproses permintaan memperlambat waktu buka aplikasi. Overhead pemrosesan menjalankan logika bisnis dan rendering template bisa menjadi signifikan. Latensi jaringan memengaruhi waktu yang diperlukan untuk mengkueri database. Faktor-faktor ini ikut bermain setiap kali klien mengirim permintaan HTTP ke server. Saat pengguna memulai banyak permintaan per detik, efek pada kinerja menjadi nyata saat server bekerja untuk memproses semuanya.
Saat kami menerapkan caching, kami membiarkan server memproses permintaan sekali dan kemudian kami menyimpannya di cache kami. Karena permintaan untuk URL yang sama diterima oleh aplikasi kami, server menarik hasil dari cache alih-alih memprosesnya lagi setiap kali. Biasanya, kami menetapkan waktu untuk menampilkan hasil yang di-cache, sehingga data dapat diperbarui secara berkala, yang merupakan langkah penting untuk diterapkan guna menghindari penyajian data yang basi.
Anda harus mempertimbangkan untuk menyimpan hasil permintaan dalam cache jika kasus berikut ini benar:
- merender halaman melibatkan banyak kueri database dan/atau logika bisnis,
- laman ini sering dikunjungi oleh pengguna Anda,
- datanya sama untuk setiap pengguna,
- dan datanya tidak sering berubah.
Mulai dengan Mengukur Kinerja
Mulailah dengan menguji kecepatan setiap halaman di aplikasi Anda dengan membandingkan seberapa cepat aplikasi Anda mengembalikan respons setelah menerima permintaan.
Untuk mencapai ini, kami akan meledakkan setiap halaman dengan ledakan permintaan menggunakan loadtest, generator beban HTTP, dan kemudian memperhatikan tingkat permintaan. Kunjungi tautan di atas untuk menginstal. Setelah diinstal, uji hasilnya terhadap /cookbook/
Jalur URL:
$ loadtest -n 100 -k http://localhost:8000/cookbook/
Perhatikan bahwa kami memproses sekitar 16 permintaan per detik:
Requests per second: 16
Ketika kita melihat apa yang dilakukan kode, kita dapat membuat keputusan tentang bagaimana membuat perubahan untuk meningkatkan kinerja. Aplikasi membuat 3 panggilan jaringan ke database dengan setiap permintaan ke /cookbook/
, dan setiap panggilan membutuhkan waktu untuk membuka koneksi dan menjalankan kueri. Kunjungi /cookbook/
URL di browser Anda dan perluas tab Django Debug Toolbar untuk mengonfirmasi perilaku ini. Temukan menu berlabel “SQL” dan baca jumlah kueri:
buku masak/services.py
from cookbook.models import Recipe
def get_recipes():
# Queries 3 tables: cookbook_recipe, cookbook_ingredient,
# and cookbook_food.
return list(Recipe.objects.prefetch_related('ingredient_set__food'))
buku masak/views.py
from django.shortcuts import render
from cookbook.services import get_recipes
def recipes_view(request):
return render(request, 'cookbook/recipes.html', {
'recipes': get_recipes()
})
Aplikasi ini juga merender template dengan logika yang berpotensi mahal.
<html>
<head>
<title>Recipes</title>
</head>
<body>
{% for recipe in recipes %}
<h1>{{ recipe.name }}</h1>
<p>{{ recipe.desc }}</p>
<h2>Ingredients</h2>
<ul>
{% for ingredient in recipe.ingredient_set.all %}
<li>{{ ingredient.desc }}</li>
{% endfor %}
</ul>
<h2>Instructions</h2>
<p>{{ recipe.instructions }}</p>
{% endfor %}
</body>
</html>
Terapkan Caching
Bayangkan jumlah total panggilan jaringan yang akan dilakukan aplikasi kita saat pengguna mulai mengunjungi situs kita. Jika 1.000 pengguna menekan API yang mengambil resep buku masak, maka aplikasi kita akan meminta database 3.000 kali dan template baru akan dirender dengan setiap permintaan. Jumlah itu hanya bertambah seiring skala aplikasi kami. Untungnya, tampilan ini adalah kandidat yang bagus untuk caching. Resep dalam buku masak jarang berubah, jika pernah. Selain itu, karena melihat buku masak adalah tema utama aplikasi, API yang mengambil resep dijamin akan sering dipanggil.
Pada contoh di bawah ini, kami memodifikasi fungsi tampilan untuk menggunakan caching. Saat fungsi berjalan, ia memeriksa apakah kunci tampilan ada di cache. Jika kuncinya ada, maka aplikasi mengambil data dari cache dan mengembalikannya. Jika tidak, Django menanyakan database dan kemudian menyimpan hasilnya dalam cache dengan kunci tampilan. Pertama kali fungsi ini dijalankan, Django akan mengkueri database dan merender template, dan kemudian juga akan membuat panggilan jaringan ke Redis untuk menyimpan data dalam cache. Setiap panggilan berikutnya ke fungsi akan sepenuhnya melewati database dan logika bisnis dan akan menanyakan cache Redis.
contoh/settings.py
# Cache time to live is 15 minutes.
CACHE_TTL = 60 * 15
buku masak/views.py
from django.conf import settings
from django.core.cache.backends.base import DEFAULT_TIMEOUT
from django.shortcuts import render
from django.views.decorators.cache import cache_page
from cookbook.services import get_recipes
CACHE_TTL = getattr(settings, 'CACHE_TTL', DEFAULT_TIMEOUT)
@cache_page(CACHE_TTL)
def recipes_view(request):
return render(request, 'cookbook/recipes.html', {
'recipes': get_recipes()
})
Perhatikan bahwa kami telah menambahkan @cache_page()
dekorator untuk fungsi tampilan, bersama dengan waktu untuk hidup. Kunjungi /cookbook/
URL lagi dan periksa Bilah Alat Django Debug. Kami melihat bahwa 3 kueri basis data dibuat dan 3 panggilan dibuat ke cache untuk memeriksa kunci dan kemudian menyimpannya. Django menyimpan dua kunci (1 kunci untuk header dan 1 kunci untuk konten halaman yang diberikan). Muat ulang halaman dan amati bagaimana aktivitas halaman berubah. Kali kedua, 0 panggilan dilakukan ke database dan 2 panggilan dilakukan ke cache. Halaman kami sekarang dilayani dari cache!
Saat kami menjalankan kembali pengujian kinerja, kami melihat bahwa aplikasi kami memuat lebih cepat.
$ loadtest -n 100 -k http://localhost:8000/cookbook/
Caching meningkatkan total beban, dan kami sekarang menyelesaikan 21 permintaan per detik, yang berarti 5 lebih banyak dari baseline kami:
Requests per second: 21
Memeriksa Redis dengan CLI
Pada titik ini kita dapat menggunakan Redis CLI untuk melihat apa yang disimpan di server Redis. Di baris perintah Redis, masukkan keys *
perintah, yang mengembalikan semua kunci yang cocok dengan pola apa pun. Anda akan melihat kunci bernama “example:1:views.decorators.cache.cache_page”. Ingat, "contoh" adalah awalan kunci kita, "1" adalah versinya, dan "views.decorators.cache.cache_page" adalah nama yang Django berikan pada kuncinya. Salin nama kunci dan masukkan dengan get
memerintah. Anda akan melihat string HTML yang dirender.
$ redis-cli -n 1
127.0.0.1:6379[1]> keys *
1) "example:1:views.decorators.cache.cache_header"
2) "example:1:views.decorators.cache.cache_page"
127.0.0.1:6379[1]> get "example:1:views.decorators.cache.cache_page"
CATATAN: Jalankan
flushall
perintah pada Redis CLI untuk menghapus semua kunci dari penyimpanan data. Kemudian, Anda dapat menjalankan kembali langkah-langkah dalam tutorial ini tanpa harus menunggu cache habis masa berlakunya.
Penutup
Memproses permintaan HTTP mahal, dan biaya itu bertambah seiring popularitas aplikasi Anda. Dalam beberapa kasus, Anda dapat sangat mengurangi jumlah pemrosesan yang dilakukan server Anda dengan menerapkan caching. Tutorial ini menyentuh dasar-dasar caching di Django dengan Redis, tetapi itu hanya menelusuri permukaan topik yang kompleks.
Menerapkan caching dalam aplikasi yang kuat memiliki banyak jebakan dan kesulitan. Mengontrol apa yang di-cache dan untuk berapa lama itu sulit. Pembatalan cache adalah salah satu hal yang sulit dalam Ilmu Komputer. Memastikan bahwa data pribadi hanya dapat diakses oleh pengguna yang dituju adalah masalah keamanan dan harus ditangani dengan sangat hati-hati saat melakukan caching.
Bonus Gratis: Klik di sini untuk mendapatkan akses ke Panduan Sumber Daya Pembelajaran Django (PDF) gratis yang menunjukkan kepada Anda tip dan trik serta perangkap umum yang harus dihindari saat membangun aplikasi web Python + Django.
Bermain-main dengan kode sumber dalam aplikasi contoh dan saat Anda terus mengembangkan dengan Django, ingatlah untuk selalu mengingat kinerja.