Mengoptimalkan aplikasi Python untuk Cloud Run

Panduan ini menjelaskan pengoptimalan untuk layanan Cloud Run yang ditulis dalam bahasa pemrograman Python, beserta informasi latar belakang untuk membantu Anda memahami kompromi yang terlibat pada beberapa pengoptimalan. Informasi di halaman ini melengkapi tips pengoptimalan umum, yang juga berlaku pada Python.

Sebagian besar praktik terbaik dan pengoptimalan dalam aplikasi berbasis web Python tradisional ini berkisar tentang:

  • Menangani permintaan serentak (baik I/O yang berbasis thread maupun yang tidak memblokir)
  • Mengurangi latensi respons menggunakan penggabungan koneksi dan mengelompokkan fungsi yang tidak penting. Misalnya, mengirim trace dan metrik ke tugas latar belakang.

Mengoptimalkan image container

Dengan mengoptimalkan image container, Anda dapat mengurangi waktu pemuatan dan startup. Anda dapat mengoptimalkan image dengan:

  • Hanya memasukkan ke dalam penampung apa yang dibutuhkan aplikasi Anda saat runtime
  • Mengoptimalkan server WSGI

Hanya masukkan ke dalam penampung yang diperlukan aplikasi Anda saat runtime

Pertimbangkan komponen mana yang disertakan dalam penampung, dan apakah komponen tersebut diperlukan untuk eksekusi layanan. Ada beberapa cara untuk meminimalkan image container:

  • Menggunakan image dasar yang lebih kecil
  • Memindahkan file besar ke luar penampung

Menggunakan image dasar yang lebih kecil

Docker Hub menyediakan sejumlah image dasar Python resmi yang dapat Anda gunakan, jika Anda memilih untuk tidak menginstal Python dari sumber dalam container. Server ini didasarkan pada sistem operasi Debian.

Jika Anda menggunakan image python Docker Hub, pertimbangkan untuk menggunakan versi slim. Ukuran image ini lebih kecil karena tidak dilengkapi dengan sejumlah paket yang akan digunakan untuk mem-build wheel, misalnya, yang mungkin tidak perlu Anda lakukan untuk aplikasi Anda. Misalnya, image python dilengkapi dengan compiler, preprocessor, dan utilitas inti GNU C.

Untuk mengidentifikasi sepuluh paket terbesar dalam image dasar, Anda dapat menjalankan perintah berikut:

DOCKER_IMAGE=python # or python:slim
docker run --rm ${DOCKER_IMAGE} dpkg-query -Wf '${Installed-Size}\t${Package}\t${Description}\n' | sort -n | tail -n10 | column -t -s $'\t'

Karena paket tingkat rendah ini lebih sedikit, image berbasis slim juga menawarkan lebih sedikit platform serangan untuk potensi kerentanan. Perhatikan bahwa image ini mungkin tidak menyertakan elemen yang diperlukan untuk mem-build wheel dari sumber.

Anda dapat menambahkan kembali paket tertentu dengan menambahkan baris RUN apt install ke Dockerfile. Lihat selengkapnya tentang cara menggunakan Paket Sistem di Cloud Run.

Ada juga opsi untuk penampung non-Debian. Opsi python:alpine mungkin menghasilkan penampung yang jauh lebih kecil, tetapi banyak paket Python mungkin tidak memiliki wheel yang telah dikompilasi sebelumnya yang mendukung sistem berbasis alpine. Dukungan terus ditingkatkan (lihat PEP-656), tetapi terus bervariasi. Anda juga dapat mempertimbangkan untuk menggunakan distroless base image, yang tidak berisi pengelola paket, shell, atau program lainnya.

Memindahkan file besar ke luar penampung

File besar, seperti aset media, dll., tidak perlu disertakan dalam penampung dasar.

Google Cloud menawarkan beberapa opsi hosting, seperti Cloud Storage, untuk menyimpan item besar ini. Pindahkan aset besar ke layanan ini, lalu referensikan dari aplikasi Anda pada waktu proses.

Mengoptimalkan server WSGI

Python telah menstandarkan cara aplikasi dapat berinteraksi dengan server web dengan penerapan standar WSGI, PEP-3333. Salah satu server WSGI yang lebih umum adalah gunicorn, yang digunakan di sebagian besar dokumentasi contoh.

Mengoptimalkan gunicorn

Tambahkan CMD berikut ke Dockerfile untuk mengoptimalkan pemanggilan gunicorn:

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

Jika Anda mempertimbangkan untuk mengubah setelan ini, sesuaikan jumlah pekerja dan thread berdasarkan per aplikasi. Misalnya, coba gunakan sejumlah pekerja yang sama dengan core yang tersedia dan pastikan ada peningkatan performa, lalu sesuaikan jumlah thread. Menetapkan terlalu banyak pekerja atau thread dapat memiliki dampak negatif, seperti latensi cold start yang lebih lama, lebih banyak memori yang digunakan, permintaan yang lebih kecil per detik, dll.

Secara default, gunicorn membuat pekerja dan memproses port yang ditentukan saat memulai, bahkan sebelum mengevaluasi kode aplikasi Anda. Dalam hal ini, Anda harus menyiapkan pemeriksaan startup kustom untuk layanan Anda, karena pemeriksaan startup default Cloud Run segera menandai instance container sebagai responsif segera setelah mulai memproses di $PORT.

Jika ingin mengubah perilaku ini, Anda dapat memanggil gunicorn dengan setelan --preload untuk mengevaluasi kode aplikasi sebelum memproses. Hal ini dapat membantu:

  • Mengidentifikasi bug runtime serius pada waktu deployment
  • Menghemat resource memori

Anda harus mempertimbangkan apa yang dimuat sebelumnya oleh aplikasi sebelum menambahkannya.

Server WSGI lainnya

Anda tidak dibatasi untuk menggunakan gunicorn untuk menjalankan Python dalam container. Anda dapat menggunakan server web WSGI atau ASGI apa pun, selama penampung memproses $PORT port HTTP, sesuai dengan Kontrak runtime penampung.

Alternatif umum mencakup uwsgi, uvicorn, dan waitress.

Misalnya, file bernama main.py yang berisi objek app, pemanggilan berikut akan memulai server WSGI:

# uwsgi: pip install pyuwsgi
uwsgi --http :$PORT -s /tmp/app.sock --manage-script-name --mount /app=main:app

# uvicorn: pip install uvicorn
uvicorn --port $PORT --host 0.0.0.0 main:app

# waitress: pip install waitress
waitress-serve --port $PORT main:app

Ini dapat ditambahkan sebagai baris CMD exec di Dockerfile, atau sebagai entri web: di Procfile saat menggunakan buildpack Google Cloud.

Mengoptimalkan aplikasi

Dalam kode layanan Cloud Run, Anda juga dapat mengoptimalkan waktu startup dan penggunaan memori yang lebih cepat.

Mengurangi thread

Anda dapat mengoptimalkan memori dengan mengurangi jumlah thread, yaitu dengan cara menggunakan strategi reaktif yang tidak memblokir dan menghindari aktivitas latar belakang. Selain itu, hindari menulis ke sistem file, seperti yang disebutkan di halaman tips umum.

Jika Anda ingin mendukung aktivitas latar belakang di layanan Cloud Run, setel CPU layanan Cloud Run agar selalu dialokasikan. Hal ini memungkinkan Anda menjalankan aktivitas latar belakang di luar permintaan dan tetap memiliki akses CPU.

Mengurangi tugas startup

Aplikasi berbasis web Python dapat memiliki banyak tugas untuk diselesaikan selama startup, misalnya, pramuat data, pemanasan cache, pembuatan kumpulan koneksi, dll. Tugas ini menjadi lambat saat dijalankan secara berurutan. Namun, jika ingin dijalankan secara paralel, Anda harus meningkatkan jumlah core CPU.

Cloud Run saat ini mengirimkan permintaan pengguna yang sebenarnya untuk memicu instance cold start. Pengguna yang memiliki permintaan ditetapkan ke instance yang baru dimulai mungkin akan mengalami penundaan yang lama. Cloud Run saat ini tidak memiliki pemeriksaan "kesiapan" untuk menghindari pengiriman permintaan ke aplikasi yang belum siap.

Langkah selanjutnya

Untuk tips lainnya, lihat