Caching NDB

NDB mengelola cache untuk Anda. Ada dua tingkat penyimpanan data ke dalam cache: cache dalam konteks dan gateway ke layanan penyimpanan data ke dalam cache standar App Engine, yaitu memcache. Kedua cache diaktifkan secara default untuk semua jenis entity, tetapi dapat dikonfigurasi untuk memenuhi kebutuhan tingkat lanjut. Selain itu, NDB mengimplementasikan fitur yang disebut auto-batching. Fitur ini mencoba mengelompokkan operasi bersama untuk meminimalkan perjalanan bolak-balik server.

Pengantar

Penyimpanan data ke dalam cache membantu sebagian besar jenis aplikasi. NDB secara otomatis menyimpan data ke dalam cache yang ditulis atau dibaca oleh NDB (kecuali jika sebuah aplikasi mengaturnya agar tidak melakukan pembacaan atau penulisan). Membaca dari cache lebih cepat daripada membaca dari Datastore.

Perilaku penyimpanan data ke dalam cache untuk banyak fungsi NDB dapat Anda ubah dengan meneruskan argumen Opsi Konteks. Misalnya, Anda dapat memanggil key.get(use_cache=False, use_memcache=False) untuk mengabaikan penyimpanan data ke dalam cache. Anda juga dapat mengubah kebijakan penyimpanan data ke dalam cache default pada konteks NDB seperti yang dijelaskan di bawah ini.

Perhatian: Saat Anda menggunakan Viewer Datastore Konsol Admin untuk mengubah konten Datastore, nilai yang di-cache tidak akan diperbarui. Akibatnya, cache Anda mungkin tidak konsisten. Cache dalam konteks biasanya tidak bermasalah. Untuk Memcache, sebaiknya gunakan Konsol Admin untuk mengosongkan cache.

Objek Konteks

Pengelolaan cache menggunakan class bernama Context: setiap thread dan setiap transaksi dijalankan dalam konteks baru. Karena setiap permintaan HTTP masuk memulai thread baru, setiap permintaan juga dijalankan dengan konteks baru. Untuk mengakses konteks saat ini, gunakan fungsi ndb.get_context().

Perhatian: Membagikan objek Context di antara beberapa thread atau permintaan tidak disarankan. Jangan simpan konteks sebagai variabel global. Anda dapat menyimpannya dalam variabel lokal atau thread-lokal.

Objek konteks memiliki metode untuk menetapkan kebijakan cache dan memanipulasi cache.

Cache Dalam Konteks

Cache dalam konteks hanya bertahan selama durasi satu thread. Artinya, setiap permintaan HTTP masuk akan diberi cache dalam konteks yang baru dan hanya "terlihat" oleh kode yang menangani permintaan tersebut. Jika aplikasi Anda menghasilkan thread tambahan saat menangani permintaan, thread tersebut juga akan memiliki cache dalam konteks baru yang terpisah.

Cache dalam konteks bersifat cepat dan berada di dalam memori. Saat menulis ke Datastore, fungsi NDB juga menulis ke cache dalam konteks. Saat membaca suatu entity, fungsi NDB akan memeriksa cache dalam konteks terlebih dahulu. Jika entity ditemukan di sana, interaksi Datastore tidak akan terjadi.

Saat fungsi NDB membuat kueri Datastore, daftar hasilnya diambil dari Datastore. Namun, jika ada hasil individual yang berada di cache dalam konteks, hasil tersebut akan digunakan sebagai pengganti nilai yang diambil dari kueri Datastore. Hasil kueri ditulis kembali ke cache dalam konteks jika kebijakan cache menyatakan demikian (tetapi tidak pernah ke Memcache).

Dengan mengeksekusi kueri yang berjalan lama di tugas latar belakang, cache dalam konteks mungkin saja menggunakan memori dalam jumlah besar. Hal ini karena cache menyimpan salinan setiap entity yang diambil atau disimpan dalam konteks saat ini. Untuk menghindari pengecualian memori pada tugas yang berjalan lama, Anda dapat menonaktifkan cache atau menetapkan kebijakan yang mengecualikan entity mana pun yang paling banyak menggunakan memori.

Memcache

Memcache adalah layanan penyimpanan data ke dalam cache standar App Engine. Layanan ini jauh lebih cepat daripada Datastore, tetapi lebih lambat daripada cache dalam konteks (milidetik vs. mikrodetik).

Secara default, konteks non-transaksi akan menyimpan data semua entity di memcache. Semua konteks aplikasi menggunakan server memcache yang sama dan melihat kumpulan nilai cache yang konsisten.

Memcache tidak mendukung transaksi. Dengan demikian, update yang ditujukan untuk diterapkan pada Datastore dan memcache mungkin hanya dilakukan pada salah satunya saja. Untuk menjaga konsistensi dalam situasi tersebut (mungkin dengan mengorbankan performa), entity yang diupdate akan dihapus dari memcache lalu ditulis ke Datastore. Operasi baca yang dilakukan selanjutnya akan menemukan entity yang hilang dari memcache, mengambilnya dari Datastore, lalu memperbaruinya dalam memcache sebagai efek samping dari pembacaan. Selain itu, pembacaan NDB di dalam transaksi akan mengabaikan Memcache.

Jika entity ditulis dalam transaksi, memcache tidak akan digunakan; saat transaksi di-commit, konteksnya akan mencoba menghapus semua entity tersebut dari memcache. Namun, perlu diperhatikan bahwa beberapa kegagalan dapat mencegah penghapusan ini terjadi.

Fungsi Kebijakan

Penyimpanan data ke dalam cache otomatis merupakan pilihan terbaik bagi sebagian besar aplikasi. Namun, aplikasi Anda mungkin bersifat tidak biasa sehingga perlu menonaktifkan penyimpanan data ke dalam cache otomatis untuk beberapa atau semua entity. Anda dapat mengontrol perilaku cache dengan menetapkan fungsi kebijakan. Terdapat fungsi kebijakan untuk cache dalam proses yang ditetapkan dengan

context = ndb.get_context()
context.set_cache_policy(func)

dan satu lagi untuk memcache, yang ditetapkan dengan

context = ndb.get_context()
context.set_memcache_policy(func)

Setiap fungsi kebijakan akan menerima kunci dan menampilkan hasil Boolean. Jika metode tersebut menampilkan False, entity yang diidentifikasi oleh kunci tersebut tidak akan disimpan dalam cache yang sesuai. Misalnya, untuk mengabaikan cache dalam proses untuk semua entity Account, Anda dapat menulis

context = ndb.get_context()
context.set_cache_policy(lambda key: key.kind() != 'Account')

(Namun, teruslah membaca untuk mengetahui cara yang lebih mudah untuk mencapai hal yang sama.) Untuk memudahkan, Anda dapat meneruskan True atau False, bukan fungsi yang selalu menampilkan nilai yang sama. Kebijakan default menyimpan cache semua entity.

Ada juga fungsi kebijakan Datastore yang mengatur entity mana yang ditulis ke Datastore itu sendiri:

context = ndb.get_context()
context.set_datastore_policy(func)

Fungsi ini berjalan seperti fungsi kebijakan memcache dan cache dalam konteks: jika fungsi kebijakan Datastore menampilkan False untuk kunci tertentu, entity yang sesuai tidak akan ditulis ke Datastore. (Hal ini dapat ditulis ke cache dalam proses atau memcache jika diperbolehkan oleh fungsi kebijakannya.) Hal ini dapat berguna jika Anda memiliki data yang mirip entity dan ingin disimpan ke dalam cache, tetapi tidak perlu menyimpannya di Datastore. Sama seperti kebijakan cache, Anda dapat meneruskan True atau False, bukan fungsi yang selalu menampilkan nilai yang sama.

Memcache otomatis membuat masa berlaku item habis saat berada dalam tekanan memori. Anda dapat menyetel fungsi kebijakan waktu tunggu memcache untuk menentukan masa aktif maksimum entity dalam cache:

context = ndb.get_context()
context.set_memcache_timeout_policy(func)

Fungsi ini dipanggil dengan argumen kunci dan harus menampilkan bilangan bulat yang menentukan masa aktif maksimum dalam hitungan detik; 0 atau None berarti tidak terbatas (selama server memcache memiliki cukup memori). Untuk memudahkan, Anda cukup meneruskan konstan bilangan bulat, bukan fungsi yang selalu menampilkan nilai yang sama. Lihat dokumentasi memcache untuk mengetahui informasi lebih lanjut tentang waktu tunggu.

Catatan: Tidak ada kebijakan masa aktif yang terpisah untuk cache dalam konteks: masa aktif cache sama dengan konteksnya, yaitu satu permintaan HTTP masuk. Namun, Anda dapat menghapus cache dalam proses dengan memanggil
context = ndb.get_context()
context.clear_cache()

Konteks baru dimulai dengan cache dalam proses yang kosong.

Meskipun fungsi kebijakan sangat fleksibel, dalam praktiknya sebagian besar kebijakan bersifat sederhana. Misalnya,

  • Jangan menyimpan entity ke dalam cache yang termasuk dalam class model tertentu.
  • Menyetel waktu tunggu memcache untuk entity dalam class model ini ke 30 detik.
  • Entity dalam class model ini tidak perlu ditulis ke Datastore.

Agar Anda tidak perlu menulis dan terus mengupdate fungsi kebijakan yang mudah (atau mengganti kebijakan untuk setiap operasi menggunakan opsi konteks), fungsi kebijakan default akan memperoleh class model dari kunci yang diteruskan ke fungsi tersebut dan kemudian mencari class model untuk variabel class tertentu:

Variabel Class Jenis Deskripsi
_use_cache bool Menentukan apakah akan menyimpan entity dalam cache yang sedang diproses; menggantikan kebijakan cache dalam proses default.
_use_memcache bool Menentukan apakah akan menyimpan entity dalam memcache; menggantikan kebijakan memcache default.
_use_datastore bool Menentukan apakah akan menyimpan entity di datastore; menggantikan kebijakan Datastore default.
_memcache_timeout int Masa aktif maksimum untuk entity dalam memcache; menggantikan kebijakan waktu tunggu memcache default.

Catatan: Ini adalah fitur fungsi kebijakan default untuk setiap kebijakan. Jika Anda menentukan fungsi kebijakan Anda sendiri tetapi juga ingin kembali menggunakan kebijakan default, panggil fungsi kebijakan default secara eksplisit sebagai metode statis class Context:

  • default_cache_policy(key)
  • default_memcache_policy(key)
  • default_datastore_policy(key)
  • default_memcache_timeout_policy(key)