Saya memiliki proyek 10K LOC yang ditulis dalam bahasa Django dengan banyak seledri ( RabbitMQ ) untuk pekerjaan asinkronik dan latar belakang di mana diperlukan, dan sampai pada kesimpulan bahwa bagian-bagian dari sistem akan mendapat manfaat dari ditulis ulang pada sesuatu selain Django untuk konkurensi yang lebih baik . Alasannya termasuk:
- Penanganan sinyal dan objek yang bisa berubah. Terutama ketika satu sinyal memicu yang lain, menangani mereka di Django menggunakan ORM bisa mengejutkan ketika instance berubah atau menghilang. Saya ingin menggunakan beberapa pendekatan pengiriman pesan di mana data yang dikirimkan tidak berubah dalam handler ( pendekatan copy-on-write Clojure tampak bagus, jika saya melakukannya dengan benar).
- Bagian dari sistem tidak berbasis web, dan membutuhkan dukungan yang lebih baik untuk melakukan tugas secara bersamaan. Misalnya, sistem membaca tag NFC , dan ketika seseorang membaca LED menyala selama beberapa detik (tugas Seledri), suara dimainkan (tugas Seledri lainnya), dan basis data dipertanyakan (tugas lain). Ini diimplementasikan sebagai perintah manajemen Django, tetapi Django dan ORM-nya pada dasarnya bersifat sinkron dan berbagi memori terbatas (kami berpikir untuk menambah lebih banyak pembaca NFC, dan saya tidak berpikir bahwa pendekatan Django + Seledri akan bekerja lebih lama, Saya ingin melihat kemampuan lewat pesan yang lebih baik).
Apa pro dan kontra menggunakan sesuatu seperti Twisted atau Tornado dibandingkan dengan menggunakan bahasa seperti Erlang atau Clojure ? Saya tertarik pada manfaat dan kerugian praktis.
Bagaimana Anda sampai pada kesimpulan bahwa beberapa bagian sistem akan lebih baik dalam bahasa lain? Apakah Anda mengalami masalah kinerja? Seberapa parah masalah itu? Jika itu bisa lebih cepat, apakah penting bahwa itu lebih cepat?
Contoh 1: Django sedang bekerja di luar permintaan HTTP:
- Tag NFC dibaca.
- Basis data (dan mungkin LDAP) dipertanyakan, dan kami ingin melakukan sesuatu ketika data tersedia (lampu merah atau hijau, putar suara). Ini blok menggunakan Django ORM, tetapi selama ada pekerja Seledri yang tersedia itu tidak masalah. Mungkin ada masalah dengan lebih banyak stasiun.
Contoh 2: "message-passing" menggunakan sinyal Django:
- Suatu
post_delete
peristiwa ditangani, objek lain dapat diubah atau dihapus karena ini. - Pada akhirnya, pemberitahuan harus dikirim ke pengguna. Di sini, alangkah baiknya jika argumen yang diteruskan ke handler notifikasi adalah salinan objek yang dihapus atau yang akan dihapus dan dijamin tidak akan berubah pada handler. (Itu bisa dilakukan secara manual hanya dengan tidak melewatkan objek yang dikelola oleh ORM ke penangan, tentu saja.)
sumber
Jawaban:
Membuka Pikiran
Bagaimana Anda sampai pada kesimpulan bahwa beberapa bagian sistem akan lebih baik dalam bahasa lain? Apakah Anda mengalami masalah kinerja? Seberapa parah masalah itu? Jika itu bisa lebih cepat, apakah penting bahwa itu lebih cepat?
Sinkronisasi Satu-utas
Ada beberapa pertanyaan dan sumber daya web lain yang sudah berurusan dengan perbedaan, pro, dan kontra dari asynchrony single-thread vs multi-thread concurrency. Sangat menarik untuk membaca tentang bagaimana model asinkron single-thread Node.js tampil ketika I / O adalah hambatan utama, dan ada banyak permintaan yang dilayani sekaligus.
Twisted, Tornado, dan model asinkron lainnya memanfaatkan sekali utas. Karena banyak pemrograman web memiliki banyak I / O (jaringan, database, dll.), Waktu yang dihabiskan untuk menunggu panggilan jarak jauh bertambah secara signifikan. Itulah waktu yang dapat dihabiskan untuk melakukan hal-hal lain — seperti memulai panggilan basis data lain, merender halaman, dan menghasilkan data. Pemanfaatan single-thread itu sangat tinggi.
Salah satu manfaat terbesar dari asynchrony single-thread adalah menggunakan lebih sedikit memori. Dalam eksekusi multi-utas, setiap utas membutuhkan sejumlah memori yang dicadangkan. Saat jumlah utas meningkat, demikian juga jumlah memori yang diperlukan hanya agar utas ada. Karena memori terbatas, itu berarti ada batasan pada jumlah utas yang dapat dibuat pada satu waktu.
Contoh
Dalam kasus server web, berpura-pura setiap permintaan diberikan utasnya sendiri. Katakanlah 1MB memori diperlukan untuk setiap utas, dan server web memiliki 2GB RAM. Server web ini akan mampu memproses (kira-kira) 2000 permintaan kapan saja sebelum tidak ada cukup memori untuk diproses lagi.
Jika beban Anda secara signifikan lebih tinggi dari ini, permintaan akan memakan waktu yang sangat lama (ketika menunggu permintaan yang lebih lama selesai), atau Anda harus membuang lebih banyak server ke dalam kluster untuk memperluas jumlah permintaan bersamaan yang mungkin terjadi .
Multi-thread Concurrency
Konkurensi multi-utas alih-alih bergantung pada menjalankan beberapa tugas pada saat yang sama. Itu berarti bahwa jika utas diblokir menunggu panggilan database kembali, permintaan lain dapat diproses pada saat yang sama. Utilisasi thread lebih rendah, tetapi jumlah thread yang dieksekusi jauh lebih besar.
Kode multi-utas juga jauh lebih sulit untuk dipikirkan. Ada masalah dengan penguncian, sinkronisasi, dan masalah concurrency menyenangkan lainnya. Single-thread asynchrony tidak mengalami masalah yang sama.
Namun kode multi-thread jauh lebih berkinerja untuk tugas-tugas intensif CPU . Jika tidak ada peluang bagi utas untuk "menghasilkan" —seperti panggilan jaringan yang biasanya akan diblokir — model utas tunggal tidak akan memiliki konkurensi apa pun.
Keduanya hidup berdampingan
Tentu saja ada tumpang tindih antara keduanya; mereka tidak saling eksklusif. Misalnya, kode multi-utas dapat ditulis dengan cara non-pemblokiran, untuk memanfaatkan setiap utas dengan lebih baik.
Garis bawah
Ada banyak masalah lain yang perlu dipertimbangkan, tetapi saya suka memikirkan keduanya seperti ini:
Dalam kasus khusus Anda, Anda perlu menentukan jenis pekerjaan asinkron yang sedang diselesaikan, dan seberapa sering tugas-tugas itu muncul.
Tidak ada jawaban sederhana. Anda harus mempertimbangkan apa yang Anda gunakan, dan desain yang sesuai. Terkadang model single-thread asynchronous lebih baik. Di lain waktu, menggunakan sejumlah utas untuk mencapai pemrosesan paralel masif diperlukan.
Pertimbangan Lainnya
Ada masalah lain yang perlu Anda pertimbangkan juga, bukan hanya model konkurensi yang Anda pilih. Apakah Anda tahu Erlang atau Clojure? Apakah Anda pikir Anda akan mampu menulis kode multi-thread yang aman dalam salah satu bahasa ini sehingga Anda meningkatkan kinerja aplikasi Anda? Apakah perlu waktu lama untuk mempercepat salah satu bahasa ini, dan apakah bahasa yang Anda pelajari akan menguntungkan Anda di masa depan?
Bagaimana dengan kesulitan yang terkait dengan komunikasi antara kedua sistem ini? Apakah akan terlalu rumit mempertahankan dua sistem terpisah secara paralel? Bagaimana sistem Erlang akan menerima tugas dari Django? Bagaimana Erlang akan mengkomunikasikan hasil itu kembali ke Django? Apakah kinerja cukup signifikan sebagai masalah sehingga kompleksitas yang ditambahkan sepadan?
Pikiran terakhir
Saya selalu menemukan Django cukup cepat, dan digunakan oleh beberapa situs yang sangat diperdagangkan. Ada beberapa optimisasi kinerja yang dapat Anda lakukan untuk meningkatkan jumlah permintaan dan waktu respons bersamaan. Memang, saya belum melakukan apa-apa dengan Celery sejauh ini, jadi optimisasi kinerja yang biasa mungkin tidak akan menyelesaikan masalah apa pun yang mungkin Anda alami dengan tugas-tugas tidak sinkron ini.
Tentu saja, selalu ada saran untuk melemparkan lebih banyak perangkat keras pada masalahnya. Apakah biaya penyediaan server baru lebih murah daripada biaya pengembangan dan pemeliharaan subsistem yang sama sekali baru?
Saya sudah mengajukan terlalu banyak pertanyaan pada saat ini, tapi itu maksud saya. Jawabannya tidak akan mudah tanpa analisis dan perincian lebih lanjut. Mampu menganalisis masalah datang ke mengetahui pertanyaan untuk diajukan, meskipun ... jadi mudah-mudahan saya telah membantu di depan
Perasaan saya mengatakan bahwa menulis ulang dalam bahasa lain tidak perlu. Kompleksitas dan biaya mungkin akan terlalu besar.
Edit
Tanggapan untuk Tindak Lanjut
Tindak lanjut Anda menyajikan beberapa kasus penggunaan yang sangat menarik.
1. Django bekerja di luar permintaan HTTP
Contoh pertama Anda melibatkan membaca tag NFC, lalu menanyakan database. Saya tidak berpikir bahwa menulis bagian ini dalam bahasa lain akan berguna bagi Anda, hanya karena permintaan basis data atau server LDAP akan terikat oleh jaringan I / O (dan berpotensi kinerja database). Di sisi lain, jumlah permintaan bersamaan akan terikat oleh server itu sendiri, karena setiap perintah manajemen akan dijalankan sebagai prosesnya sendiri. Akan ada waktu penyiapan dan penghancuran yang mempengaruhi kinerja, karena Anda tidak mengirim pesan ke proses yang sudah berjalan. Anda akan, bagaimanapun, dapat mengirim beberapa permintaan secara bersamaan, karena masing-masing akan menjadi proses yang terisolasi.
Untuk kasus ini, saya melihat dua jalan yang bisa Anda selidiki:
'OPTIONS': {'threaded':True}
.) Mungkin ada opsi konfigurasi serupa di tingkat basis data atau tingkat Django yang dapat Anda atur untuk basis data Anda sendiri. Tidak peduli bahasa apa yang Anda gunakan untuk query database, Anda harus menunggu data ini kembali sebelum Anda dapat menyalakan LED. Kinerja kode kueri dapat membuat perbedaan, dan Django ORM tidak secepat kilat ( tapi , biasanya cukup cepat).Saya tidak yakin server web apa yang Anda gunakan untuk Django.
mod_wsgi
untuk Apache memungkinkan Anda mengonfigurasi jumlah proses dan utas dalam proses yang diminta layanan. Pastikan untuk mengubah konfigurasi server web Anda yang relevan untuk mengoptimalkan jumlah permintaan yang dapat diperbaiki.2. "Pesan-lewat" dengan sinyal Django
Kasing kedua Anda juga cukup menarik; Saya tidak yakin apakah saya punya jawaban untuk itu. Jika Anda menghapus instance model, dan ingin mengoperasinya nanti, mungkin saja membuat serial
JSON.dumps
dan kemudian membatalkan deserialisasiJSON.loads
. Tidak mungkin untuk membuat kembali sepenuhnya objek grafik nanti (menanyakan model terkait), karena bidang terkait malas dimuat dari database, dan tautan itu tidak lagi ada.Pilihan lain adalah entah bagaimana menandai objek untuk dihapus, dan hanya menghapusnya di akhir siklus permintaan / respons (setelah semua sinyal diservis). Mungkin memerlukan sinyal khusus untuk menerapkan ini, daripada mengandalkan
post_delete
.sumber
Saya melakukan beberapa pengembangan sangat skalabel sangat canggih untuk ISP AS utama . Kami melakukan beberapa nomor tranasaksi serius menggunakan server Twisted , dan itu adalah mimpi buruk kompleksitas untuk mendapatkan Python / Twisted untuk skala pada apa pun yang terikat CPU . I / O terikat bukan masalah, tetapi terikat CPU tidak mungkin. Kita dapat menyusun sistem dengan cepat, tetapi menjadikannya skala ke jutaan pengguna secara bersamaan adalah mimpi buruk konfigurasi dan kompleksitas jika diikat oleh CPU.
Saya menulis posting blog tentang hal itu, Python / Twisted VS Erlang / OTP .
TLDR; Erlang menang.
sumber
Masalah praktis dengan Twisted (yang saya sukai dan gunakan selama sekitar lima tahun):
Saya telah melakukan sedikit pekerjaan menggunakan Node.js dengan CoffeeScript dan jika kinerja bersamaan menjadi perhatian Anda maka itu mungkin layak lompatan.
Sudahkah Anda mempertimbangkan untuk menjalankan beberapa instance Django dengan beberapa pengaturan untuk menyebarkan klien di antara instance?
sumber
Saya akan menyarankan yang berikut sebelum Anda mempertimbangkan beralih ke bahasa lain.
select
) yang bagus untuk I / O di sana.Saya tidak akan menggunakan threading dengan Python setelah aplikasi memiliki prioritas dalam kinerja. Saya akan mengambil opsi di atas, yang dapat memecahkan banyak masalah seperti penggunaan kembali perangkat lunak, konektivitas dengan Django , kinerja, kemudahan pengembangan, dll.
sumber