Node.js 및 CPU 집약적 요청 생성하거나 수천 개의 이미지

Node.js HTTP 서버로 땜질을 시작했고 실제로 서버 측 자바 스크립트를 작성하고 싶지만 웹 응용 프로그램에 Node.js를 사용하지 못하게됩니다.

전체 비동기 I / O 개념을 이해하지만 이미지 조작 또는 대용량 데이터 세트 정렬과 같이 절차 적 코드가 CPU를 많이 사용하는 에지 사례에 대해서는 다소 우려하고 있습니다.

내가 알기로 서버는 사용자 목록보기 또는 블로그 게시물보기와 같은 간단한 웹 페이지 요청에 매우 빠릅니다. 그러나 그래픽을 생성하거나 수천 개의 이미지 크기를 조정하는 CPU 집약적 인 코드 (예 : 관리자 백엔드)를 작성하려면 요청이 매우 느려집니다 (몇 초). 이 코드는 비동기 적이 지 않으므로 느린 요청이 완료 될 때까지 몇 초 동안 서버에 들어오는 모든 요청이 차단됩니다.

한 가지 제안은 CPU 집약적 작업에 웹 워커를 사용하는 것이 었습니다. 그러나 웹 작업자가 별도의 JS 파일을 포함하여 작동하기 때문에 깨끗한 코드를 작성하기가 어려울 것입니다. CPU 집약적 코드가 객체의 메소드에있는 경우 어떻게해야합니까? CPU를 많이 사용하는 모든 메소드에 대해 JS 파일을 작성하는 것은 짜증납니다.

또 다른 제안은 자식 프로세스를 생성하는 것이었지만 코드를 유지 관리하기가 더 어려워졌습니다.

이 (인식 된) 장애물을 극복하기위한 제안이 있습니까? CPU가 많은 작업을 비동기식으로 실행하면서 Node.js로 깨끗한 객체 지향 코드를 작성하는 방법은 무엇입니까?



답변

필요한 것은 작업 대기열입니다! 웹 서버에서 오래 실행되는 작업을 옮기는 것은 좋은 일입니다. 각 작업을 “별도의”js 파일로 유지하면 모듈 성과 코드 재사용이 촉진됩니다. 장기적으로 디버그하고 유지 관리하기 쉽도록 프로그램을 구성하는 방법에 대해 생각하게 만듭니다. 작업 대기열의 또 다른 이점은 작업자를 다른 언어로 작성할 수 있다는 것입니다. 작업을 팝업하고 작업을 수행 한 후 응답을 다시 작성하십시오.

이 같은 https://github.com/resque/resque

여기 그들이 왜 그것을 빌드했는지에 대한 github의 기사 http://github.com/blog/542-introducing-resque


답변

이것은 웹 서버의 정의에 대한 오해입니다. 클라이언트와 “대화”하는 데만 사용해야합니다. 로드가 많은 작업은 독립 실행 형 프로그램에 위임해야합니다 (물론 JS로 작성할 수도 있음).
아마 더럽다고 말할 수도 있지만 이미지 크기 조정에 걸린 웹 서버 프로세스가 더 나쁘다는 것을 확신합니다 (아파치가 다른 쿼리를 차단하지 않는 경우에도 마찬가지입니다). 그럼에도 불구하고 코드 중복을 피하기 위해 공통 라이브러리를 사용할 수 있습니다.

편집 : 나는 비유를 생각해 냈습니다. 웹 애플리케이션은 식당이어야합니다. 웨이터 (웹 서버)와 요리사 (작업자)가 있습니다. 웨이터는 고객과 접촉하고 메뉴를 제공하거나 일부 요리가 채식인지 설명하는 등 간단한 작업을 수행합니다. 반면에 그들은 더 힘든 일을 부엌에 위임합니다. 웨이터는 간단한 일만하기 때문에 신속하게 대응하며 요리사는 업무에 집중할 수 있습니다.

여기서 Node.js는 한 번에 많은 요청을 처리 할 수있는 유능하지만 유능한 웨이터가 될 것이며 Apache는 각각 하나의 요청을 처리하는 멍청한 웨이터가 될 것입니다. 이 Node.js 웨이터가 요리를 시작하면 즉시 재앙이됩니다. 그럼에도 불구하고 요리는 부엌의 혼돈과 점진적인 책임감 감소는 말할 것도없고 많은 아파치 웨이터들조차 지칠 수있었습니다.


답변

CPU 집약적 코드가 비동기로 실행 되는 것을 원하지 않고 병렬 로 실행하기를 원합니다 . HTTP 요청을 처리하는 스레드에서 처리 작업을 수행해야합니다. 이 문제를 해결할 수있는 유일한 방법입니다. NodeJS에서 답은 클러스터 모듈입니다., 무거운 프로세스를 수행하는 자식 프로세스를 생성합니다. (AFAIK Node에는 스레드 / 공유 메모리 개념이 없으며 프로세스이거나 아무것도 없습니다). 응용 프로그램을 구성하는 방법에 대한 두 가지 옵션이 있습니다. 8 개의 HTTP 서버를 생성하고 하위 프로세스에서 계산 집약적 인 작업을 동기식으로 처리하여 80/20 솔루션을 얻을 수 있습니다. 그렇게하는 것은 매우 간단합니다. 해당 링크에서 한 시간 정도 읽을 수 있습니다. 실제로 링크 상단의 예제 코드를 제거하면 95 %의 방법을 얻을 수 있습니다.

이를 구성하는 다른 방법은 작업 대기열을 설정하고 대기열을 통해 큰 계산 작업을 보내는 것입니다. 작업 대기열에 대한 IPC와 관련된 많은 오버 헤드가 있으므로 작업이 오버 헤드보다 상당히 큰 경우에만 유용합니다.

이 다른 답변들 중 어느 것도 클러스터를 언급 하지 않은 것에 놀랐습니다 .

배경 : 비동기 코드는 다른 곳 에서 발생할 때까지 일시 중단 되는 코드로, 코드가 깨어나 실행을 계속합니다. 느린 곳에서 발생해야하는 매우 일반적인 경우 중 하나는 I / O입니다.

비동기 코드는 작업을 담당하는 프로세서 인 경우 유용하지 않습니다 . 바로 “계산 집약적 인”작업의 경우입니다.

이제 비동기 코드는 틈새처럼 보이지만 실제로는 매우 일반적입니다. 계산 집약적 작업에는 유용하지 않습니다.

I / O 대기는 예를 들어 웹 서버에서 항상 발생하는 패턴입니다. 서버에 연결하는 모든 클라이언트는 소켓을 얻습니다. 대부분의 경우 소켓이 비어 있습니다. 소켓이 데이터를 수신 할 때까지 요청을 처리 할 때까지는 아무 작업도 원하지 않습니다. 기본적으로 Node와 같은 HTTP 서버는 이벤트 라이브러리 (libev)를 사용하여 수천 개의 열린 소켓을 추적합니다. OS는 libev에 통지 한 다음 소켓 중 하나가 데이터를 가져올 때 libJS에 통지 한 다음 NodeJS가 이벤트 큐에 이벤트를 놓으면 http 코드가이 시점에서 시작되어 이벤트를 차례로 처리합니다. 소켓에 데이터가있을 때까지 이벤트가 큐에 들어 가지 않으므로 이벤트가 데이터를 기다리지 않습니다. 이미 이벤트가 있습니다.

단일 스레드 이벤트 기반 웹 서버는 대부분의 빈 소켓 연결에서 병목 현상이 발생하고 모든 유휴 연결에 대해 전체 스레드 또는 프로세스를 원하지 않고 250k를 폴링하지 않을 때 패러다임으로 의미가 있습니다. 소켓에 데이터가있는 다음 소켓을 찾으십시오.


답변

몇 가지 접근 방식을 사용할 수 있습니다.

@Tim이 지적한 것처럼 주요 게재 로직 외부 또는 병렬에있는 비동기 작업을 만들 수 있습니다. 정확한 요구 사항에 따라 다르지만 cron 조차도 큐 메커니즘으로 작동 할 수 있습니다.

WebWorkers는 비동기 프로세스에서 작동 할 수 있지만 현재 node.js에서 지원되지 않습니다. 지원을 제공하는 몇 가지 확장이 있습니다 (예 : http://github.com/cramforce/node-worker).

표준 “필수”메커니즘을 통해 여전히 모듈과 코드를 재사용 할 수 있습니다. 작업자에게 초기 디스패치가 결과 처리에 필요한 모든 정보를 전달하도록해야합니다.


답변

사용하다 child_process하나의 솔루션이 됩니다. 그러나 생성 된 각 자식 프로세스는 Go에 비해 많은 메모리를 소비 할 수 있습니다goroutines

kue 와 같은 대기열 기반 솔루션을 사용할 수도 있습니다