Node.js ve CPU yoğun istekleri


215

Node.js HTTP sunucusu ile tamir etmeye başladım ve gerçekten sunucu tarafı Javascript yazmayı seviyorum, ancak bir şey beni web uygulamam için Node.js kullanmaya başlamamı engelliyor.

Bütün zaman uyumsuz I / O kavramını anlıyorum ama biraz yordamsal kod görüntü işleme veya büyük veri kümeleri sıralama gibi CPU yoğun olduğu uç durumlarda endişe ediyorum.

Anladığım kadarıyla, sunucu, kullanıcıların bir listesini görüntülemek veya bir blog gönderisini görüntülemek gibi basit web sayfası istekleri için çok hızlı olacaktır. Ancak, grafik üreten veya binlerce görüntüyü yeniden boyutlandıran çok CPU yoğun kod yazmak istiyorsanız (örneğin yönetici arka ucunda), istek çok yavaş olacaktır (birkaç saniye). Bu kod zaman uyumsuz olmadığından, bu birkaç saniye boyunca sunucuya gelen her istek yavaş isteğimi tamamlayana kadar engellenir.

Bir öneri CPU yoğun görevler için Web Workers kullanmaktı. Ancak, web çalışanları, ayrı bir JS dosyası ekleyerek çalıştığı için temiz kod yazmayı zorlaştıracağımdan korkuyorum. CPU yoğun kodu bir nesnenin yönteminde bulunuyorsa ne olur? CPU yoğun olan her yöntem için bir JS dosyası yazmak berbat.

Başka bir öneri, bir çocuk sürecinin ortaya çıkmasıydı, ancak bu, kodu daha az sürdürülebilir hale getiriyor.

Bu (algılanan) engeli aşmak için herhangi bir öneriniz var mı? CPU ağır görevlerinin zaman uyumsuz olarak yürütüldüğünden emin olurken Node.js ile temiz nesneye yönelik kod nasıl yazılır?


2
Olivier, aklımda olan aynı soruyu (düğüme yeni eklenen) ve özellikle görüntüleri işlemeyle ilgili olarak sordunuz. Java'da sabit bir iş parçacığı ExecutorService kullanabilir ve tüm yeniden boyutlandırma işlerini iletebilir ve tüm bağlantıdan bitirmek için bekleyebilirim, düğümde, işi sınırlayan bir harici modüle nasıl karıştıracağımı anlayamadım (hadi say) aynı anda maksimum 2 eşzamanlı işlem sayısı. Bunu yapmanın zarif bir yolunu buldunuz mu?
Riyad Kalla

Yanıtlar:


55

İhtiyacınız olan şey bir görev kuyruğu! Uzun süren görevlerinizi web sunucusundan çıkarmak İYİ bir şeydir. Her görevi "ayrı" js dosyasında tutmak modülerliği ve kodun yeniden kullanılmasını destekler. Programınızı, uzun vadede hata ayıklamayı ve bakım yapmayı kolaylaştıracak şekilde nasıl yapılandıracağınızı düşünmeye zorlar. Görev kuyruğunun bir diğer yararı da işçilerin farklı bir dilde yazılabilmeleridir. Sadece bir görevi başlatın, işi yapın ve yanıtı tekrar yazın.

böyle bir şey https://github.com/resque/resque

İşte github'dan neden inşa ettikleri hakkında bir makale http://github.com/blog/542-introducing-resque


35
Düğüm dünyasına özel olarak dayanan bir soruda neden Ruby kütüphanelerine bağlantı veriyorsunuz?
Jonathan Dumaine

1
@JonathanDumaine Bir görev kuyruğunun iyi bir uygulamasıdır. Ruby kodunu yazın ve javascript ile yeniden yazın. KAR!
Simon Stender

2
Bunun için büyük bir dişli tutkunuyum, dişli çark işçileri yeni işler için dişli çark sunucusunu yoklamıyor - yeni işler anında işçilere itiliyor. Çok duyarlı
Casey Flynn

1
Aslında, birisi onu düğüm dünyasına taşıdı: github.com/technoweenie/coffee-resque
FrontierPsycho

@pacerier, neden böyle söyledin? Ne öneriyorsun?
luis.espinal

289

Bu web sunucusu tanımının yanlış anlaşılmasıdır - sadece istemcilerle "konuşmak" için kullanılmalıdır. Ağır yük görevleri bağımsız programlara devredilmelidir (tabii ki JS'de de yazılabilir).
Muhtemelen kirli olduğunu söylerdiniz, ancak görüntüleri yeniden boyutlandırmak için sıkışmış bir web sunucusu işleminin sadece daha kötü olduğunu garanti ederim (diğer sorguları engellemediğinde bile Apache diyelim). Yine de, kod fazlalığını önlemek için ortak bir kütüphane kullanabilirsiniz.

EDIT: Ben bir benzetme buldum; web uygulaması bir restoran gibi olmalıdır. Garsonlarınız (web sunucusu) ve aşçılarınız (işçiler) var. Garsonlar müşterileri ile temas halinde ve menü sağlamak veya bazı yemek vejetaryen olup olmadığını açıklamak gibi basit görevleri yapmak. Öte yandan mutfağa daha zor görevler veriyorlar. Garsonlar sadece basit şeyler yapıyorlar çünkü hızlı tepki veriyorlar ve aşçılar işlerine konsantre olabiliyorlar.

Buradaki Node.js, bir seferde birçok isteği işleyebilen tek ama çok yetenekli bir garson olacaktı ve Apache, her biri sadece bir talebi işleyen aptal garsonlar grubu olacaktı. Bu Node.js garsonu pişirmeye başlarsa, derhal bir felaket olurdu. Yine de yemek yapmak, mutfaktaki kaostan ve kademeli olarak tepki azalmasından bahsetmeden, büyük bir Apache garsonu kaynağını bile tüketebilir.


6
Web sunucularının çok iş parçacıklı veya çok işlemli olduğu ve birden fazla eşzamanlı isteği işleyebildiği bir ortamda, tek bir istek için birkaç saniye harcamak çok yaygındır. İnsanlar bunu beklemeye geldi. Yanlış anlamanın node.js'nin "normal" bir web sunucusu olduğu söyleyebilirim. Node.js'yi kullanarak programlama modelinizi biraz ayarlamanız gerekir ve buna "uzun süren" çalışmaların bazı eşzamansız çalışanlara aktarılması dahildir.
Thilo

13
Her istek için bir alt süreç oluşturmayın (bu node.js'nin amacını bozar). İşçileri yalnızca ağır isteklerinizden doğurtun. Veya ağır arka plan çalışmanızı düğüm dışındaki bir şeye yönlendirin. Js.
Thilo

47
İyi benzetme, mbq!
Lance Fisher

6
Ha, gerçekten beğendim. "Node.js: kötü uygulamaları kötü yapmak"
ethan

7
@mbq Benzetmeyi seviyorum ama biraz iş kullanabilir. Geleneksel çok iş parçacıklı model, hem garson hem de aşçı olan bir kişi olacaktır. Sipariş alındıktan sonra, o kişi başka bir siparişi yerine getirmeden önce geri dönüp yemeği pişirmelidir. Node.js modeli, garson olarak düğümlere ve aşçı olarak web işçilerine sahiptir. İşçiler daha fazla zaman harcayan görevleri yönetirken, garsonlar isteklerin getirilmesini / çözülmesini sağlar. Daha büyük ölçeklendirmeniz gerekiyorsa, ana sunucuyu bir düğüm kümesi yapar ve CPU yoğun görevlerini milti iş parçacıklı işleme için oluşturulan diğer sunuculara tersine çevirirsiniz.
Evan Plaice

16

CPU yoğun kodunuzun zaman uyumsuz olarak yürütülmesini istemezsiniz , paralel olarak da çalışmasını istersiniz . İşleme işlerini HTTP isteklerini sunan iş parçacığından çıkarmanız gerekir. Bu sorunu çözmenin tek yolu bu. NodeJS ile cevap küme modülüdür, yumurtlama için çocuk süreçleri ağır kaldırma yapmak. (AFAIK Düğümünde iş parçacığı / paylaşılan bellek kavramı yoktur; süreçler veya hiçbir şey yoktur). Uygulamanızı nasıl yapılandıracağınız konusunda iki seçeneğiniz vardır. 80 HTTP çözümünü 8 HTTP sunucusu oluşturarak ve yoğun işlem gerektiren işlemleri alt süreçlerde eşzamanlı olarak gerçekleştirebilirsiniz. Bunu yapmak oldukça basittir. Bu bağlantıdan okumak için bir saat sürebilir. Aslında, bu bağlantının üst kısmındaki örnek kodu koparırsanız, kendinizi bu yolun% 95'ine çıkaracaksınız.

Bunu yapılandırmanın diğer bir yolu, bir iş kuyruğu oluşturmak ve kuyruk üzerinde büyük hesaplama görevleri göndermektir. Bir iş kuyruğu için IPC ile ilişkili çok fazla ek yük olduğunu unutmayın, bu nedenle bu yalnızca görevler ek yükten çok daha büyük olduğunda yararlıdır.

Diğer cevapların hiçbirinin kümeden bahsetmediğine şaşırdım .

Arka plan: Eşzamansız kod, başka bir yerde bir şey olana kadar askıya alınan, kodun uyanıp yürütülmeye devam ettiği koddur. Yavaş bir şeyin başka bir yerde olması gereken çok yaygın bir durum G / Ç'dir.

Asenkron kod, işi yapmaktan sorumlu olan işlemcinizse yararlı değildir . "Yoğun bilgi işlem" görevlerinde durum böyledir.

Şimdi, eşzamansız kod niş gibi görünebilir, ancak aslında çok yaygındır. Sadece bilgi işlem yoğun görevler için yararlı olmaz.

Örneğin, G / Ç'yi beklemek her zaman web sunucularında gerçekleşen bir modeldir. Sunucu sunucunuza bağlanan her müşteri bir soket alır. Çoğu zaman soketler boştur. Bir soket bazı veriler alana kadar hiçbir şey yapmak istemezsiniz, bu noktada isteği işlemek istersiniz. Kaputun altında, Düğüm gibi bir HTTP sunucusu binlerce açık soketi takip etmek için bir olay kütüphanesi (libev) kullanıyor. İşletim sistemi libev'e bildirir ve sonra soketlerden biri veri aldığında libev NodeJS'ye bildirir ve ardından NodeJS olay kuyruğuna bir olay koyar ve http kodunuz bu noktada devreye girer ve olayları birbiri ardına işler. Soketin bazı verileri olana kadar olaylar sıraya alınmaz, bu nedenle olaylar asla veriyi beklemez - zaten onlar için oradadır.

Tek iş parçacıklı olay tabanlı web sunucuları, darboğaz çoğunlukla boş soket bağlantılarını beklerken ve her boş bağlantı için tam bir iş parçacığı veya işlem istemediğinizde ve 250k'nizi yoklamak istemediğinizde bir paradigma olarak mantıklıdır üzerinde veri bulunan bir sonrakini bulmak için soketler.


doğru cevap olmalı .... 8 kümenin ortaya çıktığı çözüm için 8 çekirdeğe ihtiyacınız var değil mi? Veya dengeleyiciyi birden çok sunucuyla yükleyin.
Muhammed Umer

ayrıca 2. sıra hakkında bilgi edinmenin iyi bir yolu nedir, kuyruk oluşturmak. Kuyruk kavramı oldukça basittir, ancak süreçler ve kuyruk olan yabancı arasındaki mesajlaşma kısmıdır.
Muhammed Umer

Doğru. İşi bir şekilde başka bir çekirdeğe almanız gerekiyor. Bunun için başka bir çekirdeğe ihtiyacınız var.
18'de masonk

Re: kuyruklar. Pratik cevap bir iş kuyruğu kullanmaktır. Düğüm için kullanılabilir bazı var. Hiç tavsiye kullanmadım. Merak cevabı, işçi süreçleri ve kuyruk süreçlerinin nihayetinde soketler üzerinden iletişim kuracağıdır.
18'de masonk

7

Birkaç yaklaşım kullanabilirsiniz.

@Tim'in belirttiği gibi, ana sunum mantığınızın dışında veya paralelinde bulunan senkronize olmayan bir görev oluşturabilirsiniz. Tam gereksinimlerinize bağlıdır, ancak cron bile bir kuyruk mekanizması olarak işlev görebilir.

WebWorkers, zaman uyumsuz işlemleriniz için çalışabilir, ancak şu anda node.js tarafından desteklenmemektedir. Destek sağlayan birkaç uzantı var, örneğin: http://github.com/cramforce/node-worker

Hala standart "gerektirir" mekanizması ile modülleri ve kodu yeniden kullanabilirsiniz olsun. Sadece çalışana ilk gönderimin sonuçları işlemek için gereken tüm bilgileri aktardığından emin olmanız gerekir.


0

Kullanım child_processbir çözümdür. Ancak ortaya çıkan her çocuk süreci, Go ile karşılaştırıldığında çok fazla bellek tüketebilirgoroutines

Kue gibi kuyruk tabanlı çözümü de kullanabilirsiniz

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.