Node.js 및 CPU 집약적 요청


215

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

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

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

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

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

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


2
올리비에, 당신은 내가 생각했던 것과 똑같은 질문을했다. Java에서는 고정 스레드 ExecutorService를 사용하고 모든 크기 조정 작업을 전달하고 모든 연결이 끝날 때까지 기다릴 수 있습니다. 노드에서 노드를 제한하는 외부 모듈로 작업을 섞는 방법을 알지 못했습니다. 예) 한 번에 최대 동시 작업 수는 2입니다. 이 작업을 수행하는 우아한 방법을 찾았습니까?
리야드 칼

답변:


55

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

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

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


35
노드 세계에 특별히 초점을 맞춘 질문에서 왜 Ruby 라이브러리에 연결합니까?
Jonathan Dumaine

1
@JonathanDumaine 작업 대기열을 잘 구현 한 것입니다. 루비 코드를 제거하고 자바 스크립트로 다시 작성하십시오. 이익!
Simon Stender Boisen

2
나는 이것을 위해 기어 맨의 큰 팬입니다. 기어 맨 노동자는 새로운 직업을 위해 기어 맨 서버를 폴링하지 않습니다. 새로운 일자리는 즉시 노동자에게 밀려납니다. 매우 반응이 좋은
Casey Flynn

1
실제로 누군가 노드 노드로 포팅했습니다 : github.com/technoweenie/coffee-resque
FrontierPsycho

@pacerier, 왜 그렇게 말합니까? 당신은 무엇을 제안합니까?
luis.espinal

289

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

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

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


6
웹 서버가 다중 스레드 또는 다중 프로세스이고 둘 이상의 동시 요청을 처리 할 수있는 환경에서는 단일 요청에 몇 초를 보내는 것이 일반적입니다. 사람들은 그것을 기대하게되었습니다. 오해는 node.js가 "일반적인"웹 서버라는 것입니다. node.js를 사용하면 프로그래밍 모델을 약간 조정해야하며 여기에는 "비정기 실행"작업을 일부 비동기 작업자에게 푸시하는 작업이 포함됩니다.
Thilo

13
모든 요청에 ​​대해 자식 프로세스를 생성하지 마십시오 (node.js의 목적을 상실 함). 무거운 요청 내부에서만 작업자를 스폰하십시오. 또는 무거운 배경 작업을 node.js 이외의 다른 경로로 라우팅하십시오.
Thilo

47
좋은 비유, mbq!
랜스 피셔

6
하, 정말 좋아합니다. "Node.js : 나쁜 관행이 잘못 작동"
ethan

7
@mbq 나는 비유를 좋아하지만 약간의 작업을 사용할 수 있습니다. 전통적인 멀티 스레드 모델은 웨이터이자 요리사 인 사람입니다. 일단 주문이 접수되면, 그 사람은 다른 주문을 처리하기 전에 돌아가서 식사를 요리해야합니다. node.js 모델에는 노드가 웨이터로, 웹 워커가 요리사로 있습니다. 웨이터는 작업자가보다 시간이 많이 걸리는 작업을 관리하는 동안 요청 가져 오기 / 해결을 처리합니다. 더 크게 확장해야하는 경우 주 서버를 노드 클러스터로 만들고 CPU 집약적 작업을 milti 스레드 처리를 위해 구축 된 다른 서버로 리버스 프록시하십시오.
Evan Plaice

16

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

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

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

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

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

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

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

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


정답이어야합니다 .... 8 개의 클러스터를 생성하는 솔루션은 8 코어가 필요합니까? 또는 여러 서버가있는로드 밸런서.
Muhammad Umer

또한 두 번째 솔루션에 대해 배우고 대기열을 설정하는 좋은 방법입니다. 큐의 개념은 매우 간단하지만 프로세스와 외부 큐 간의 메시징 부분입니다.
Muhammad Umer

맞습니다. 어떻게 든 다른 핵심 작업을해야합니다. 이를 위해서는 또 다른 핵심이 필요합니다.
masonk

다시 : 대기열. 실질적인 답변은 작업 대기열을 사용하는 것입니다. 노드에 사용 가능한 것이 있습니다. 나는 그들 중 어느 것도 사용하지 않았으므로 추천 할 수 없습니다. 궁금한 점은 작업자 프로세스와 큐 프로세스가 결국 소켓을 통해 통신한다는 것입니다.
masonk

7

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

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

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

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


0

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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.