[컴][NodeJs] CPU Intensive job 을 Node.js 에서 처리할 때

노드js nodejs 에서 싱글 쓰레드 / single thread job / cpu 사용량이 큰 작업 처리 방법 / node multi / nodejs / multi / multi thread  / multithread

CPU Intensive job 을 Node.js 에서 처리할 때

node js - single thread

기본적으로 single thread 로 알려져 있는데, 이것은 약간 이해를 잘 못 할 수 있어서 간단한 설명을 하자면, ref. 2 에서 여기 를 보면 node js 의 구성을 살짝 엿볼 수 있는데, libeio 를 통해 thread pool 을 만들어서 사용한다. (ref. 3)
그렇기 때문에 이것이 single threaded 인 것은 user 의 source code 를 run 하는 부분을 이야기 한다. 아래 코드를 예로 들면 user 의 code 부분은 하나의 thread 에서 동작한다. 하지만 fs.readFile 같은 부분은 Thread Pool 로 던져질 것이다. 그리고 response 가 오기까지 또 이 single thread 는 console.log('right after') 부분으로 처리할 수 있게 되는 것이다.
var fs = require('fs');  
fs.readFile(‘/files/help.txt’, function(err, buf) {  
    console.log('done');
});
console.log('right after');
from : ref. 1

cpu intensive job

그러므로 nodejs 로 만든 server 들은 기본적으로 single thread 로 user request 를 처리하게 된다. 하지만 만약 request 하나에서 cpu intensive 한 작업을 처리하는 경우가 있는 request 에 대해서는 nodejs 에서 처리가능한 request 양이 급격히 줄어들 수 밖에 없다. 이런 문제점에 대한 해결책에 대한 이야기가 아래 글들에 담겨있다.
대략적인 내용은 cluster 를 사용해서 request 마다 process 를 하나 더 만들어서 cpu intensive job 을 그쪽으로 넘기는 것인데, 문제는 이것이 너무 많은 memory 를 할당해야 한다는 것이다. 그래서 cluster 와 queue(kue library) 를 이용해서 일종의 process pool 을 만들어서 사용하는 해결책을 제시한다.

여담으로, 이 방법들을 살펴보고 있으려니까 아주 오래전에 linux 에서 c 로 server programming 을 하던 때의 생각이 난다.

node js http server timeout

nodejs v6.x 에서 일단 기본 timeout 이 2 분으로 설정되어 있다고 한다. 즉, request 를 보낸지 2분후 까지 response 가 없으면 error 가 된다. 이 timeout 내에 더 많은 request 를 처리하기 위해서라도 "cluster 의 사용"은 필요할 듯 하다.
 

See Also

References

  1. Introduction to NodeJS, A SSJS: Part II - EventLoop Explained
  2. https://youtu.be/L0pjVcIsU6A?t=366
    • 동영상에서는 Node.js 의 철학? 을 알 수 있다.
  3. javascript - Nodejs Event Loop - Stack Overflow
  4. Cluster | Node.js v12.3.1 Documentation

[컴] 해외 유명 IT 기업 연봉


넷플릭스 연봉 / netflix 복지 / netflix salayr /

넷플릭스 연봉


대략 $300,000 달러/연






[컴] 딜로이트의 2018년 글로벌 CIO 설문 조사 결과

리딩그룹 / 디지털 리딩 / IT회사 / 선두기업

딜로이트의 2018년 글로벌 CIO 설문 조사 결과


디지털 선도 기업(digital vanguard organizations)은 2가지 차별화된 특징을 갖고 있다.
  1. 명확하게 정의된 디지털 전략 a clearly defined digital strategy 
  2. 신기술 활용과 디지털 역량 구축 작업을 IT 조직이 이끌도록 한다 an IT organization viewed by the business as a leader in harnessing emerging technologies and building digital capabilities.
  • 디지털 선도 기업은 글로벌 IT 기업 중 9.7%만이 해당한다.
  • 디지털 선도 기업의 디지털 리더가 다른 기업과 다른점 
    • 업무 우선순위priorities
    • 마음가짐mindsets
    • 문화적 특성cultural attributes

디지털 선도기업의 특징

  1. 성장에 대한 마음가짐Growth mindset
  2. 확대/축소적 관점
  3. 최고의 인재를 유입시키는 문화
    •  디지털 리더 조직의 절반 이상(55%)이 창의적이고 의욕을 고취하는 환경 덕분에 인재를 유지할 수 있었다고 답했다.
    • 조직 문화가 최고의 기술 인재를 유입, 유지, 참여시키는 데 핵심이라는 사실을 알고 있다.
    • 디지털 리더 조직의 절반 이상(55%)이 창의적이고 의욕을 고취하는 환경 덕분에 인재를 유지할 수 있었다고 답했다.
  4. 탄탄한 기술 기반
  5. 강력한 참여 계획

References

  1. '디지털 선도' 기업의 5가지 특징 - CIO Korea, 2019-05-09
  2. 5 ways leading organizations excel at digital | CIO, 2019-05-03

[컴][interview] 면접 실패 사례 - 회사 입장

인터뷰 / 인터뷰의 잘못 된 점 / interview / 고용 / 면접방법의 잘못 / 실패사례 / 아마존 프라임 에어 창업자 실패 / 데니얼 부시뮬러 / 고용을 잘못 한 사례 / 드론


인터뷰 실패 사례


개인적으로 이런 글들을 좋아한다. 우린는 사실 측정할 수 없는 것들을 측정하려 많은 노력을 한다. 그리고 그 측정방법이 옳았다는 것을 증명하기 위해 잘된 경우들만을 늘어놓는다.

하지만 경험 해 본 우리는 그것이 전적으로 옳지 않다는 것을 안다. 하지만 믿을 만한 근거를 제시하기가 쉽지 않다.

그런 의미에서 이런 글들이 많아져야만 우리는 더 나은 방법을 찾을 수 있다고 생각한다.

from: ref. 1, Robert Sweeney, Founder and CEO at Facet

I turned down Daniel Buchmueller for a job at Netflix. After a 60 minute interview I was on the fence, so I concluded that he "wasn't senior enough." He went to Amazon instead where he co-founded Amazon Prime Air (their drone delivery service) and was #2 on Fast Company's "Most Creative People" list. At some point, we programmers are going to have to admit that we really can't judge another programmers technical abilities in a 60 min interview. We end up hiring programmers that are good at interviewing, but not necessarily good at doing the job. And we miss out on engineers like Daniel.

해석

나는 넷플릭스에 있을 때 Daniel Buchmueller 를 채용하지 않았다. 1시간의 인터뷰를 한 후에도 나는 확신이 들지 않았다. 그래서 나는 그가 senior 에 적합하지 않다고 결론 내렸다.

그는 대신에 Amazon 에 갔고, 그는 Amazon Prime Air (그들의 드론 배달 서비스)를 공동설립 했고 Fast Company 의 "가장 창조적인 사람" 리스트에서 2위를 차지했다.

어떤 점에서 우리 프로그래머들은 우리가 다른 프로그래머들의 기술적인 역량을 60분의 면접후에 판단할 수 없다는 것을 인정해야만 한다.

우리는 "면접에서 좋아 보이지만 일을 잘하지는 않는 프로그래머들"을 고용하는 것을 관뒀다.   그리고 우리는 (여전히?) Daniel 같은 엔지니어를 놓친다.


Refrences

  1. Robert Sweeney on LinkedIn, 2019-05-03

[컴][웹] 파이어 폭스 add-on 이 갑자기 사라졌다면

파폭 / 모질라 / 파이어 폭스 난리 / 플러그인 / 애드온 / 동작 안하는 이유 / 갑자기 동작을 안하는 이유 / 수정 방법 /


update, 2019-05-06

수정버전이 나왔다.


Firefox Add-on 대란

원인

2019년 5월 5일 쯤 인듯 하다. Mozilla 가 Firefox add-on들을 sign 할 때 사용하는 "보안 인증서(certificate)" 가 만료(expired) 됐다. 그래서 그 certificate 을 사용해서 sign 된 모든 add-on 들이 모두 disable 가 됐다.

해결책

아래 링크에서 현재 임시로 배포되는 해결책을 설치하면 된다. ref. 1 의 댓글에서 알려준 이야기다. 실제로 잘 된다. 처음에 들어가면 block됐다고 뜨지만 그 페이지에서 다시 refresh 를 하면 download 가 실행된다.
모질라 blog 에서는 Firefox study 를 이용해서 설치하라고 이야기 하지만 설치되는 시점도 몇시간 후에나 된다고 한다.

reddit 에서도 알려주는 방법중 하나는 about:config 에서 xpinstall.signatures.required option 을 다시 true 로 돌려주면 된다.

Refrences

  1. Update Regarding Add-ons in Firefox | Mozilla Add-ons Blog
  2. Here's what's going on with your Add-ons being disabled, and how to work around the issue until its fixed. : firefox

[컴][MacOS] Homebrew - package manager

홈브루 / 맥os / 맥북 / 자동 설치 / 패키지 매니저  / 간편 설치 / simple install / package manager

Homebrew

Homebrew 는 MacOS 에서 사용할 수 있는 windows 의 chocolatey 처럼 또는 linux 의 apt-get 등 처럼 package manager 이다.
위의 link 에서 간단한 사용법을 확인할 수 있다.
대체로 개발관련 package 설치에 많이 이용하지만, 일반적인 app 을 설치할 때도 App Store 를 사용하지 않고, homebrew 를 사용해서 설치할 수 있다. 아래처럼 명령어를 입력하면 firefox 를 설치할 수 있다.((Homebrew Cask))
$ brew cask install firefox

설치된 package 정보

설치된 app 들이나 package 들의 정보를 알고 싶을 때가 있다. 그리고 list 를 뽑아야 나중에 재설치도 쉽다.
# 모든 설치된 package 를 알려준다.[ref. 1]
$ brew list 
...
# Caskroom 을 이용해서 설치된 package 만 알려준다.
$ brew cask list
...
# dependency 로 깔린 정보들을 제외한 가장 상위 level 의 package 정보만 알려준다.
$ brew leaves

update

brew cask 로 설치된 package 는 app store 를 통한 자동 update 가 되지 않는다. 그러므로 필요한 경우에 아래처럼 udpate 를 해주면 된다.
version 정보가 없거나, app 이 자체적으로 upgrade 를 하는 경우에는 brew cask 로 update 가 되지 않는다. 이 경우에 재설치를 통해서 update 를 해주면 된다. 이것을 해주는 option 이 brew cask upgrade --greedy 이다.
$ brew cask upgrade
...
$ brew cask upgrade --greedy

list 를 재설치

아래와 같은 방법을 이용하면 된다.(참고)
$ xargs brew install < list.txt
...
$ brew install $(< list.txt )

package 의 dependency tree 확인

아래 명령어로 package 들의 dependency 를 확인할 수 있다. 보기좋게 트리모양으로 나온다. 자세한 것은 ref. 1 을 확인하자.
$ brew deps --tree --installed

References

  1. List of all packages installed using Homebrew - Ask Different

[컴][웹][js] v8 Scanner



from: https://v8.dev/blog/scanner

v8 Scanner

v8 이 소스를 파싱해서 AST 로 만든다.abstract syntax tree (AST)
이걸로 프로그램 구조를 표현한다.

v8은 complile 해야 프로그램을 실행할 수 있다.
v8 parser 은 scanner 에서 만들어놓은 token 을 소모한다.

이때 scanner 가 사용하는 character stream의 encoding 은 utf16만 지원한다.
scanner 에 input 으로 제공하기 전에 이전에 모든 encoding 을 utf16으로 convert 하는 과정을 거친다.

scanner는 이 utf16을 decode 해서 unicode 로 만들어서 사용한다.
이 decoded character 들을 이제 가져다 scanner 가 token 을 만든다.



Whitespace

2개의 token 사이에 whitespace 가 있으면 거기에 ;(semicolon)을 넣는다.(ECMAScript® 2020 Language Specification > Auto semicolon insertion)

다음 token 을 scan 하기 전까지 모든 whitespace는 skip 된다.(newline 이 발생하는지 추적하면서)

real world 에서는 대체로 js 들이 minified 돼서 여러개의 whitespace 가 연속해서 나타나는 경우가 드물다.

그래서 V8 은 whitespace 도 하나의 token 으로 취급한다. (Token::WHITESPACE) 그래서 '//' 같이 comment 가 오는 경우에도 Token::WHITESPACE 를 return 해 버린다.  그러면 paring 하는 loop 에서 다른 Token이 나올때 까지 계속 scan 을 이어나갈 수 있게 된다.

(역주: 다시 말하면, // 가 나와서 이것을 다른 token 으로 정의(Token::COMMENT) 등으로 정의해서 사용하게 되면, loop 을 한번 벗어난 후에 다시 parsing 을 시작해야 하지만, 이것을 whitespace 와 같은 속성으로 취급해 버리면, 이 overhead 를 없앨 수 있게 되는 것이다.)



V8_INLINE Token::Value Scanner::ScanSingleToken() {
  Token::Value token;
  do {
    next().location.beg_pos = source_pos();

    if (V8_LIKELY(static_cast<unsigned>(c0_) <= kMaxAscii)) {
      token = one_char_tokens[c0_];

      switch (token) {
        ...
        
        case Token::DIV:
          // /  // /* /=
          Advance();
          if (c0_ == '/') {
            uc32 c = Peek();
            if (c == '#' || c == '@') {
              Advance();
              Advance();
              token = SkipSourceURLComment();
              continue;
            }
            token = SkipSingleLineComment();
            continue;
          }
          if (c0_ == '*') {
            token = SkipMultiLineComment();
            continue;
          }
          if (c0_ == '=') return Select(Token::ASSIGN_DIV);
          return Token::DIV;
          
        ...

        case Token::WHITESPACE:
          token = SkipWhiteSpace();
          continue;

        case Token::NUMBER:
          return ScanNumber(false);

        case Token::IDENTIFIER:
          return ScanIdentifierOrKeyword();

        default:
          UNREACHABLE();
      }
    }

    if (IsIdentifierStart(c0_) ||
        (CombineSurrogatePair() && IsIdentifierStart(c0_))) {
      return ScanIdentifierOrKeyword();
    }
    if (c0_ == kEndOfInput) {
      return source_->has_parser_error() ? Token::ILLEGAL : Token::EOS;
    }
    token = SkipWhiteSpace();

    // Continue scanning for tokens as long as we're just skipping whitespace.
  } while (token == Token::WHITESPACE);

  return token;
}




Identifier scanning
Internalizing minified identifiers
Keywords
Surrogate pairs
AdvanceUntil


See Also


  1. V8 관련 글들