Meningkatkan performa throughput dari aplikasi Python di Azure Functions
Saat mengembangkan untuk Azure Functions menggunakan Python, Anda perlu memahami performa fungsi Anda dan bagaimana performa tersebut memengaruhi cara aplikasi fungsi Anda diskalakan. Kebutuhanini lebih penting ketika merancang aplikasi dengan performa tinggi. Faktor utama yang perlu dipertimbangkan saat merancang, menulis, dan mengonfigurasi aplikasi fungsi Anda adalah penskalaan horizontal dan konfigurasi performa throughput.
Penskalaan horizontal
Secara default, Azure Functions secara otomatis memantau beban pada aplikasi Anda dan membuat lebih banyak instans host untuk Python sesuai kebutuhan. Azure Functions menggunakan ambang bawaan untuk berbagai jenis pemicu agar dapat memutuskan kapan harus menambahkan instans, seperti usia pesan dan ukuran antrean untuk QueueTrigger. Ambang ini tidak dapat dikonfigurasi pengguna. Untuk informasi selengkapnya, lihat Penskalaan yang digerakkan kejadian di Azure Functions.
Meningkatkan performa throughput
Konfigurasi default cocok untuk sebagian besar aplikasi Azure Functions. Namun, Anda dapat meningkatkan performa throughput aplikasi dengan menggunakan konfigurasi berdasarkan profil beban kerja Anda. Langkah pertama adalah memahami jenis beban kerja yang Anda jalankan.
Tipe beban kerja | Karakteristik aplikasi fungsi | Contoh |
---|---|---|
Terikat I/O | • Aplikasi perlu menangani banyak permintaan bersamaan. • Aplikasi memproses sejumlah besar kejadian I/O, seperti panggilan jaringan dan diska baca/tulis. |
• API Web |
Terikat CPU | • Aplikasi menjalakan komputasi jangka panjang, seperti mengubah ukuran gambar. • Aplikasi melakukan transformasi data. |
• Pemrosesan data • Inferensi pembelajaran mesin |
Karena beban kerja fungsi yang sesungguhnya biasanya merupakan campuran I/O dan CPU yang terikat, Anda harus membuat profil aplikasi di bawah beban produksi yang realistis.
Konfigurasi khusus Performa
Setelah Anda memahami profil beban kerja aplikasi fungsi Anda, berikut ini adalah konfigurasi yang dapat Anda gunakan untuk meningkatkan performa throughput fungsi Anda.
- Asinkron
- Pekerja multibahasa pemrogram
- Maksimalkan para pekerja dalam proses pekerja bahasa pemrogram
- Loop kejadian
- Penskalaan Vertikal
Asinkron
Karena Python adalah runtime rangkaian tunggal,sebuah instans host untuk Python hanya dapat memproses satu permintaan fungsi pada satu waktu secara default. Untuk aplikasi yang memproses sejumlah besar kejadian I/O dan/atau I/O yang terikat, Anda dapat melakukan peningkatan performa yang lebih baik dengan menjalankan fungsi secara asinkron.
Untuk menjalankan fungsi secara asinkron, gunakan pernyataan async def
, yang menjalankan fungsi dengan asyncio secara langsung:
async def main():
await some_nonblocking_socket_io_op()
Berikut adalah contoh fungsi dengan pemicu HTTP yang menggunakan klien http aiohttp :
import aiohttp
import azure.functions as func
async def main(req: func.HttpRequest) -> func.HttpResponse:
async with aiohttp.ClientSession() as client:
async with client.get("PUT_YOUR_URL_HERE") as response:
return func.HttpResponse(await response.text())
return func.HttpResponse(body='NotFound', status_code=404)
Fungsi tanpa async
kata kunci dijalankan secara otomatis di kumpulan utas ThreadPoolExecutor:
# Runs in a ThreadPoolExecutor threadpool. Number of threads is defined by PYTHON_THREADPOOL_THREAD_COUNT.
# The example is intended to show how default synchronous functions are handled.
def main():
some_blocking_socket_io()
Untuk mencapai manfaat penuh dari berjalannya fungsi secara asinkron, operasi/pustaka I/O/ yang digunakan dalam kode Anda perlu memiliki asinkron yang diimplementasikan juga. Menggunakan operasi I/O sinkron dalam fungsi yang didefinisikan sebagai asinkron dapat menganggu keseluruhan performa. Jika pustaka yang Anda gunakan tidak memiliki versi asinkron yang diterapkan, Anda mungkin masih mendapat manfaat dari menjalankan kode secara asinkron dengan mengelola perulangan peristiwa di aplikasi Anda.
Berikut adalah beberapa contoh pustaka klien yang telah menerapkan pola asinkron:
- aiohttp - Klien http/server untuk asyncio
- Stream API - Primitif asinkron tingkat tinggi/siap menunggu untuk bekerja dengan koneksi jaringan
- Antrean Janus - Rangkaian antrean asyncio yang aman untuk Python
- pyzmq - Pengikatan data Python untuk ZeroMQ
Memahami asinkron pada pekerja Python
Saat Anda menentukan async
di depan tanda tangan fungsi, Python menandai fungsi sebagai coroutine. Saat Anda memanggil coroutine, coroutine dapat dijadwalkan sebagai tugas ke dalam perulangan peristiwa. Ketika Anda memanggil await
dalam fungsi asinkron, ia mendaftarkan kelanjutan ke dalam perulangan peristiwa, yang memungkinkan perulangan peristiwa untuk memproses tugas berikutnya selama waktu tunggu.
Dalam Python Worker kami, pekerja berbagi perulangan peristiwa dengan fungsi pelanggan async
dan mampu menangani beberapa permintaan secara bersamaan. Kami sangat mendorong pelanggan kami untuk menggunakan pustaka yang kompatibel dengan asinkron, seperti aiohttp dan pyzmq. Mengikuti rekomendasi ini meningkatkan throughput fungsi Anda dibandingkan dengan pustaka tersebut saat diimplementasikan secara sinkron.
Catatan
Jika fungsi Anda dinyatakan sebagai async
tanpa apa pun await
di dalam implementasinya, performa fungsi Anda akan sangat terpengaruh karena perulangan peristiwa akan diblokir yang melarang pekerja Python menangani permintaan bersamaan.
Gunakan proses pekerja multibahasa pemrogram
Secara default, setiap instans host Functions memiliki proses pekerja bahasa tunggal. Anda dapat meningkatkan jumlah proses pekerja per host (hingga 10) dengan menggunakan FUNCTIONS_WORKER_PROCESS_COUNT
pengaturan aplikasi. Azure Functions kemudian mencoba mendistribusikan permintaan fungsi simultan secara merata ke seluruh pekerja.
Untuk aplikasi terikat CPU, Anda harus mengatur jumlah pekerja bahasa agar sama dengan atau lebih tinggi dari jumlah inti yang tersedia per aplikasi fungsi. Untuk mempelajari lebih lanjut, lihat SKU instans yang tersedia.
Aplikasi terikat I/O juga dapat memperoleh manfaat dari proses peningkatan jumlah pekerja di luar jumlah inti yang tersedia. Perlu diingat bahwa mengatur jumlah pekerja yang terlalu tinggi dapat memengaruhi performa keseluruhan karena peningkatan jumlah pengalihan konteks yang diperlukan.
Berlaku FUNCTIONS_WORKER_PROCESS_COUNT
untuk setiap host yang dibuat Azure Functions saat menskalakan aplikasi Anda untuk memenuhi permintaan.
Siapkan para pekerja dalam proses pekerja bahasa pemrogram secara maksimal
Seperti telah disebutkan di bagian asinkron, pekerja bahasa pemrogram Python memperlakukan fungsi dan coroutine secara berbeda. Coroutine dijalankan dalam perulangan kejadian yang sama dengan yang dijalankan pekerja bahasa pemrogram. Di sisi lain, pemanggilan fungsi dijalankan dalam ThreadPoolExecutor, yang dikelola oleh pekerja bahasa sebagai utas.
Anda dapat mengatur nilai pekerja maksimum yang diizinkan untuk menjalankan fungsi sinkronisasi menggunakan pengaturan aplikasi PYTHON_THREADPOOL_THREAD_COUNT. Nilai ini menetapkan argumen max_worker
objek ThreadPoolExecutor, yang memungkinkan Python menggunakan kumpulan rangkaian max_worker
terbanyak untuk mengeksekusi panggilan secara asinkron. PYTHON_THREADPOOL_THREAD_COUNT
berlaku untuk setiap pekerja yang dibuat host Functions, dan Python memutuskan kapan harus membuat rangkaian baru atau menggunakan kembali rangkaian diam yang ada. Untuk versi Python yang lebih lama (yaitu, 3.8
, 3.7
, dan 3.6
), max_worker
nilai disetel ke 1. Untuk Python versi 3.9
, max_worker
diatur ke None
.
Untuk aplikasi terikat CPU, Anda harus mempertahankan pengaturan ke angka rendah, mulai dari 1 dan meningkat saat Anda bereksperimen dengan beban kerja Anda. Saran ini adalah untuk mengurangi waktu yang dihabiskan untuk pengalihan konteks dan memungkinkan tugas terikat CPU selesai.
Untuk aplikasi terikat I/O, Anda akan melihat keuntungan besar dengan meningkatkan jumlah rangkaian yang bekerja pada setiap permintaan. Rekomendasinya adalah memulai dengan default Python (jumlah inti) + 4 lalu mengubah berdasarkan nilai throughput yang Anda lihat.
Untuk aplikasi beban kerja campuran, Anda harus menyeimbangkan konfigurasi FUNCTIONS_WORKER_PROCESS_COUNT
dan PYTHON_THREADPOOL_THREAD_COUNT
untuk memaksimalkan throughput. Untuk memahami apa yang paling sering dihabiskan oleh aplikasi fungsi Anda, sebaiknya profilkan dan atur nilai sesuai dengan perilakunya. Untuk mempelajari tentang pengaturan aplikasi ini, lihat Menggunakan beberapa proses pekerja.
Catatan
Meskipun rekomendasi ini berlaku untuk fungsi yang dipicu http dan non-HTTP, Anda mungkin perlu menyesuaikan konfigurasi pemicu khusus lainnya untuk fungsi yang dipicu non-HTTP guna mendapatkan performa yang diharapkan dari aplikasi fungsi Anda. Untuk informasi selengkapnya tentang ini, silakan lihat Praktik terbaik ini untuk Azure Functions yang andal.
Mengelola perulangan kejadian
Anda harus menggunakan pustaka pihak ketiga yang kompatibel dengan asyncio. Jika tidak ada pustaka pihak ketiga yang memenuhi kebutuhan Anda, Anda juga dapat mengelola perulangan kejadian di Azure Functions. Mengelola perulangan kejadian memberi Anda lebih banyak fleksibilitas dalam manajemen sumber daya komputasi, dan juga memungkinkan untuk menggabungkan pustaka I/O yang sinkron ke dalam coroutine.
Ada banyak dokumen resmi Python yang berguna yang membahas Coroutines dan Tasks dan Event Loop dengan menggunakan pustaka asinkron bawaan.
Lihat pustaka permintaan berikut sebagai contoh, cuplikan kode ini menggunakan pustakaasyncio untuk mengemas metode requests.get()
ke dalam coroutine, menjalankan beberapa permintaan web untuk SAMPLE_URL secara serentak.
import asyncio
import json
import logging
import azure.functions as func
from time import time
from requests import get, Response
async def invoke_get_request(eventloop: asyncio.AbstractEventLoop) -> Response:
# Wrap requests.get function into a coroutine
single_result = await eventloop.run_in_executor(
None, # using the default executor
get, # each task call invoke_get_request
'SAMPLE_URL' # the url to be passed into the requests.get function
)
return single_result
async def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
eventloop = asyncio.get_event_loop()
# Create 10 tasks for requests.get synchronous call
tasks = [
asyncio.create_task(
invoke_get_request(eventloop)
) for _ in range(10)
]
done_tasks, _ = await asyncio.wait(tasks)
status_codes = [d.result().status_code for d in done_tasks]
return func.HttpResponse(body=json.dumps(status_codes),
mimetype='application/json')
Penskalaan Vertikal
Anda mungkin bisa mendapatkan lebih banyak unit pemrosesan, terutama dalam operasi terikat CPU, dengan meningkatkan ke paket premium dengan spesifikasi yang lebih tinggi. Dengan unit pemrosesan yang lebih tinggi, Anda dapat menyesuaikan jumlah jumlah proses pekerja sesuai dengan jumlah inti yang tersedia dan mencapai tingkat paralelisme yang lebih tinggi.
Langkah berikutnya
Untuk informasi selengkapnya tentang pengembangan Azure Functions Phyton, lihat referensi berikut ini:
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk