Saya sudah mulai bermain-main dengan server HTTP Node.js dan sangat suka menulis Javascript sisi server tetapi ada sesuatu yang menghalangi saya untuk mulai menggunakan Node.js untuk aplikasi web saya.
Saya mengerti keseluruhan konsep I / O async tapi saya agak khawatir tentang kasus tepi di mana kode prosedural sangat intensif CPU seperti manipulasi gambar atau mengurutkan set data besar.
Seperti yang saya pahami, server akan sangat cepat untuk permintaan halaman web sederhana seperti melihat daftar pengguna atau melihat posting blog. Namun, jika saya ingin menulis kode intensif CPU (di bagian belakang admin misalnya) yang menghasilkan gambar atau mengubah ukuran ribuan gambar, permintaan akan sangat lambat (beberapa detik). Karena kode ini bukan async, setiap permintaan yang datang ke server selama beberapa detik itu akan diblokir sampai permintaan lambat saya selesai.
Satu saran adalah menggunakan Pekerja Web untuk tugas-tugas intensif CPU. Namun, saya khawatir pekerja web akan kesulitan untuk menulis kode bersih karena ini bekerja dengan memasukkan file JS yang terpisah. Bagaimana jika kode intensif CPU terletak di metode objek? Agak menyebalkan untuk menulis file JS untuk setiap metode yang intensif CPU.
Saran lain adalah menelurkan proses anak, tetapi itu membuat kodenya semakin tidak terpelihara.
Adakah saran untuk mengatasi hambatan (yang dirasakan) ini? Bagaimana Anda menulis kode berorientasi objek bersih dengan Node.js sambil memastikan tugas berat CPU dijalankan async?
sumber
Jawaban:
Yang Anda butuhkan adalah antrian tugas! Memindahkan tugas jangka panjang Anda dari server web adalah hal yang BAIK. Menyimpan setiap tugas dalam file js "terpisah" mempromosikan modularitas dan penggunaan kembali kode. Ini memaksa Anda untuk berpikir tentang bagaimana menyusun program Anda dengan cara yang akan membuatnya lebih mudah untuk debug dan pemeliharaan dalam jangka panjang. Manfaat lain dari antrian tugas adalah para pekerja dapat ditulis dalam bahasa yang berbeda. Lakukan saja tugas, kerjakan, dan tulis kembali jawabannya.
sesuatu seperti ini https://github.com/resque/resque
Berikut adalah artikel dari github tentang mengapa mereka membangunnya http://github.com/blog/542-introducing-resque
sumber
Ini adalah kesalahpahaman tentang definisi server web - itu hanya digunakan untuk "berbicara" dengan klien. Tugas berat harus didelegasikan ke program mandiri (yang tentu saja dapat juga ditulis dalam JS).
Anda mungkin mengatakan bahwa itu kotor, tetapi saya jamin proses server web macet dalam mengubah ukuran gambar hanya lebih buruk (bahkan untuk katakanlah Apache, ketika itu tidak memblokir pertanyaan lain). Namun, Anda dapat menggunakan perpustakaan umum untuk menghindari redundansi kode.
EDIT: Saya telah membuat analogi; aplikasi web harus sebagai restoran. Anda memiliki pelayan (server web) dan koki (pekerja). Pelayan berhubungan dengan klien dan melakukan tugas-tugas sederhana seperti menyediakan menu atau menjelaskan jika beberapa hidangan vegetarian. Di sisi lain mereka mendelegasikan tugas yang lebih sulit ke dapur. Karena pelayan hanya melakukan hal-hal sederhana, mereka merespons dengan cepat, dan koki dapat berkonsentrasi pada pekerjaan mereka.
Node.js di sini akan menjadi pelayan tunggal tetapi sangat berbakat yang dapat memproses banyak permintaan pada suatu waktu, dan Apache akan menjadi sekelompok pelayan bodoh yang hanya memproses satu permintaan saja. Jika pelayan Node.js yang satu ini akan mulai memasak, itu akan menjadi bencana langsung. Tetap saja, memasak juga bisa melelahkan bahkan pasokan besar pelayan Apache, tidak menyebutkan kekacauan di dapur dan penurunan responsif secara progresif.
sumber
Anda tidak ingin kode intensif CPU Anda untuk menjalankan async, Anda ingin menjalankannya secara paralel . Anda perlu menyelesaikan pekerjaan pemrosesan dari utas yang melayani permintaan HTTP. Ini satu-satunya cara untuk mengatasi masalah ini. Dengan NodeJS jawabannya adalah modul cluster, untuk proses melahirkan anak untuk melakukan angkat berat. (AFAIK Node tidak memiliki konsep utas / memori bersama; prosesnya atau tidak sama sekali). Anda memiliki dua opsi untuk bagaimana Anda menyusun aplikasi Anda. Anda bisa mendapatkan solusi 80/20 dengan menelurkan 8 server HTTP dan menangani tugas komputasi intensif secara serempak pada proses anak. Melakukan itu cukup sederhana. Anda dapat mengambil satu jam untuk membacanya di tautan itu. Bahkan, jika Anda hanya merobek kode contoh di bagian atas tautan itu, Anda akan mendapatkan 95% dari perjalanan ke sana.
Cara lain untuk menyusun ini adalah dengan mengatur antrian pekerjaan dan mengirim tugas komputasi besar melalui antrian. Perhatikan bahwa ada banyak overhead yang terkait dengan IPC untuk antrian pekerjaan, jadi ini hanya berguna ketika tugas-tugasnya jauh lebih besar daripada overhead.
Saya terkejut bahwa tidak ada jawaban lain yang menyebutkan cluster.
Latar Belakang: Kode asinkron adalah kode yang ditangguhkan hingga sesuatu terjadi di tempat lain , di mana kode tersebut bangun dan melanjutkan eksekusi. Satu kasus yang sangat umum di mana sesuatu yang lambat harus terjadi di tempat lain adalah I / O.
Kode asinkron tidak berguna jika prosesor Anda yang bertanggung jawab untuk melakukan pekerjaan. Itulah yang terjadi dengan tugas-tugas "komputasi intensif".
Sekarang, sepertinya kode asinkron adalah niche, tetapi sebenarnya itu sangat umum. Kebetulan tidak berguna untuk tugas-tugas intensif komputasi.
Menunggu pada I / O adalah pola yang selalu terjadi di server web, misalnya. Setiap klien yang terhubung ke server Anda mendapatkan soket. Sebagian besar soketnya kosong. Anda tidak ingin melakukan apa pun sampai soket menerima beberapa data, pada titik mana Anda ingin menangani permintaan tersebut. Di bawah tenda server HTTP seperti Node menggunakan perpustakaan acara (libev) untuk melacak ribuan soket terbuka. OS memberi tahu libev, dan kemudian libev memberi tahu NodeJS ketika salah satu soket mendapatkan data, dan kemudian NodeJS menempatkan suatu peristiwa pada antrian acara, dan kode http Anda mulai pada saat ini dan menangani peristiwa satu per satu. Acara tidak dimasukkan ke dalam antrian sampai soket memiliki beberapa data, sehingga acara tidak pernah menunggu data - itu sudah ada untuk mereka.
Server web berbasis peristiwa tunggal berulir masuk akal sebagai paradigma ketika kemacetan menunggu pada sekelompok koneksi soket yang sebagian besar kosong dan Anda tidak ingin seluruh utas atau proses untuk setiap koneksi idle dan Anda tidak ingin polling 250k Anda soket untuk menemukan yang berikutnya yang memiliki data di dalamnya.
sumber
Beberapa pendekatan yang bisa Anda gunakan.
Sebagai catatan @Tim, Anda dapat membuat tugas asinkron yang berada di luar atau sejajar dengan logika penyajian utama Anda. Tergantung pada kebutuhan Anda yang sebenarnya, tetapi bahkan cron dapat bertindak sebagai mekanisme antrian.
WebWorkers dapat bekerja untuk proses async Anda tetapi mereka saat ini tidak didukung oleh node.js. Ada beberapa ekstensi yang memberikan dukungan, misalnya: http://github.com/cramforce/node-worker
Anda masih dapat melakukannya, Anda masih dapat menggunakan kembali modul dan kode melalui mekanisme "wajib" standar. Anda hanya perlu memastikan bahwa pengiriman awal ke pekerja melewati semua informasi yang diperlukan untuk memproses hasilnya.
sumber
Penggunaan
child_process
adalah salah satu solusi. Tetapi setiap proses anak yang dilahirkan dapat mengkonsumsi banyak memori dibandingkan dengan Gogoroutines
Anda juga dapat menggunakan solusi berbasis antrian seperti kue
sumber