57
Node.js + Websocket 프프프프 프프프 2016. 03. 11 / 파파파

Node.js + Websocket 삽질기

Embed Size (px)

Citation preview

Page 1: Node.js + Websocket 삽질기

Node.js + Websocket 프로젝트 삽질기2016. 03. 11 / 파프리카

Page 2: Node.js + Websocket 삽질기

| 회사소개

파프리카 . 2013 년 3 월 15 일 시작된 반도의 _ 흔한 _ 웹 _ 개발 _ 회사입니다 .웹서비스 개발을 중심으로 , 모바일 , HTML5 컨텐츠 제작 등을 하고 있습니다 .

SBSCNBC 인터렉티브 주식 정보 웹사이트 및 앱 개발 ,LG 전자 R&D 센터 차량용 반응형 하이브리드앱 개발 ,LG 전자 R&D 센터 프리즘 서비스 웹프론트 개발 ,아동용 HTML5 인터렉티브 컨텐츠 개발 ,각종 중 / 소규모 웹사이트 개발 등

틈새 공지투자자 : 모집중사장여친 : ( 급구 )00 명 상시모집중

Page 3: Node.js + Websocket 삽질기

슈퍼 . 다이나믹 . 인터렉티브 . 모던 .웹 . 프로젝트( 고객의 눈높이 )

Page 4: Node.js + Websocket 삽질기

Super dynamic..what?

어쨌든 , 개발은 계속되어야 한다 .쭈우우우우우우우우우우우우욱 ~

Page 5: Node.js + Websocket 삽질기

| 초기 아키텍트 : SIMPLE IS THE BEST

Goal 12/31

AWS EC2Browse

r

Socket.io

Node.js

NginX

OracleSocket.io

HTML/CSS/JS/Media FTP

Page 6: Node.js + Websocket 삽질기

| 프론트 설계 : MVP 패턴

Goal 12/31

https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter

다이나믹하고 인터렉티브한 프론트를 제대로 소화하기 위해 상태관리 및 잦은 수정 등에 유리한 MVP 을 적극 활용하기로 함 .프론트 코딩을 보다 구조화 할 수 있다 .

Page 7: Node.js + Websocket 삽질기

| 프론트 설계 : MVP 패턴 도입배경

Goal 12/31

기획상 모바일웹의 뷰의 레이아웃은 PC 웹과 상이하다 .

PC 신형브라우저 VIEW 모바일웹 VIEW

공통 PRESENTER( 필요시 일부 오버라이드 )

공통 MODEL

공통부 재활용원을 그리려다 .. 수전증

PC 구형브라우저 VIEW

Page 8: Node.js + Websocket 삽질기

| 웹소켓

Goal 12/31

Ajax Long Polling 방식은 HTTP 오버헤드에 재접속 속도도 느릴테고…별도의 서버 설정도 필요할테고…

무엇보다 ,

슈퍼다이나믹인터렉티브모던웹프로젝트에 어울리지 않잖아 ?

그리고…웹소켓을 어떻게든 써보고 싶은 불타오르는 욕망

Page 9: Node.js + Websocket 삽질기

| Node.js

Goal 12/31

( 근거없음 )

역시… Node.js 를 어떻게든 써보고 싶은 불타오르는 욕망

Node.js 라는 이름만으로도… .

슈퍼다이나믹인터렉티브모던웹프로젝트에 어울리잖아 ?

Page 10: Node.js + Websocket 삽질기

| Node.js + Socket.io

Goal 12/31

사실 프로젝트 이전에 초간단 채팅 어플리케이션을 만들어 봤습니다 .Publish/Subscribe 패턴으로 제공되는 간결한 API 에 푹 빠졌고그 달콤함과 Node.js 의 빠른 코드작성 능력에 한번 더 눈이 멀고…

( 복선ㅎ ) 그 달콤함에 취해 앞일을 낙관하게 되는데…

Page 11: Node.js + Websocket 삽질기

| Redis

Goal 12/31

사이트의 제공데이터를 실시간으로 빠르게 전파하고유저의 데이터입력이 없는 ( 그런데 왜 인터렉티브 ?)스냅샷 형태의 데이터를 제공하는 특성

Pub/Sub Channel 제공

역시… Redis 를 어떻게든 써보고 싶은 불타오르는 욕망

슈퍼다이나믹인터렉티브모던웹프로젝트에 어울리는 메모리 DB

Page 12: Node.js + Websocket 삽질기

프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프 로 토 타 이 핑 프로토타이핑

성공적 ?

Goal 12/31

Page 13: Node.js + Websocket 삽질기

“ 왜 이렇게 쉬워 ?”

Goal 12/31

Page 14: Node.js + Websocket 삽질기

“ 그래 , 그럴리 없지 ...”

Goal 12/31

그럴리 없지 ...

Page 15: Node.js + Websocket 삽질기

Goal 12/31

AWS EC2

Node.jsSocket.

io

AWSLBS

아마존 LBS 에서 WebSocket 을 지원할 수 있는Sticky Session 을 지원하지 않았다 .

| AMAZON LBS

Browser

Socket.io AWS EC2

Node.jsSocket.

io

Page 16: Node.js + Websocket 삽질기

Goal 12/31

며칠의 삽질과 기도 (?) 끝에 구글신의 신탁이 있었으니 ..

Page 17: Node.js + Websocket 삽질기

Goal 12/31

HAProxyHAProxy is free, open source software that provides a high availability load balancer and proxy server for TCP and HTTP-based applications that spreads requests across multiple servers.[2] It is written in C[3] and has a reputation for being fast and efficient (in terms of processor and memory usage).[4]

HAProxy is used by a number of high-profile websites including GitHub, Bitbucket,[5] Stack Overflow,[6] Reddit, Tumblr, Twitter[7][8] and Tuenti[9] and is used in the OpsWorks product from Amazon Web Services.[10]

https://en.wikipedia.org/wiki/HAProxy

무슨 말인지 1 도 모르겠지만 ... 어쨌든

| 들어는 보았나 ! 질풍발란서 ! H.A.P.R.O.X.Y

Page 18: Node.js + Websocket 삽질기

Goal 12/31

HAProxy

HAProxy 에서 TCP 기반의 웹소켓을 StickySession 방식으로 설정하는데도 많은 삽질이 뒤따랐다 .

소통원활 ! 사이다 ! x100

Browser

Socket.io

AWS EC2

Node.jsSocket.

io

AWS EC2

Node.jsSocket.

io

| 구세주 HAProxy

Page 19: Node.js + Websocket 삽질기

“ 그런데 , 그럴리 없지 ...”

Goal 12/31

이제 됐네 , 됐어 .

Page 20: Node.js + Websocket 삽질기

Goal 12/31

우리에게도 이런 일이 일어났습니다 . 어플리케이션이 숨지는데 이유는 모르겠고

| Node.js 의 반란

Page 21: Node.js + Websocket 삽질기

Goal 12/31

각종 커뮤니티 , 구글신의 신탁을 기대해 봐도 답은 또렷하지 않고Try catch 로 도배를 해보아도 에러의 내용은 알 수 없으니팀원들의 눈동자에는 마치 미지의 세계에서 낯선 존재를 만났을 때의 공포가…

프로세스가 죽으면 다시 살리는 각종 툴을 써봐도 이 상태로 출시할 수는 없고

오랑캐 Node.js 무용론 ,Java 회귀론 등 척화배척사상이 힘을 얻어 갈 무렵

| Node.js 의 반란 _ 시즌 2

Page 22: Node.js + Websocket 삽질기

Goal 12/31

바다 밖 어딘가에는 Node 기반 상용 서비스가 있다는 전설 같은 이야기를 믿고진시황이 불노초를 찾듯 , 장혁이 추노하듯 버그를 다시 찾아나서게 되는데…

오랑캐 Node.js가 비동기식 Callback 형태의 동작임을 다시금 깨닫게 된다 .

| Node.js 의 반란 _ 시즌 3

Page 23: Node.js + Websocket 삽질기

Goal 12/31

비동기메커니즘에서의 Callback 이란 무엇인가 !

비동기식 호출의 요체로서 호출자의 스택이 모두 끝나기전에는 호출되지 않는 특성물론 , 싱글스레드에서만 .

AB

Event Loop수전증 2

C

2) B 에서 C호출

1) A 에서 Try Catch

3) C 에서 Exception 발생

D

4) 1 번의 스택이 정리되었기 때문에 C 함수에서 Exception 이 발생해도 잡을 수가 없다 . 물론 Node.js 에서는 Domain 개념이 있기 때문에 방도가 전혀 없는 것은 아니다 .

| Node.js와 asynchronous callback mechanism

Page 24: Node.js + Websocket 삽질기

Goal 12/31

로깅강화와 예외처리 디버깅 요령 체득 등…다시 한번 상용서비스로서의 가능성을 품게 된다 .

Node.js가 불안정하다는 의견이 종종 보이지만 , 이후로는 단 한번도 원인없이 숨진적이 없기에 개발자의 역량문제로 잠정결론

| Node.js 의 반란을 진압하고…

Page 25: Node.js + Websocket 삽질기

Goal 12/31

그 이후 ,모든 것이 순조로웠다 .

눈을 뜨기 힘든 가을 보다 높은저 하늘이 기분 좋아

10 월의 어느 멋진 날에 - 김동규

Page 26: Node.js + Websocket 삽질기

Goal 12/31

오늘은 어디서 무얼 할까 창밖에 앉은 바람 한 점에도

10 월의 어느 멋진 날에 - 김동규

다들 열일했고 ,

Page 27: Node.js + Websocket 삽질기

Goal 12/31

10 월의 어느 멋진 날에 - 김동규

더 좋은 것은 없을 거야 10 월의 어느 멋진 날에

사무실은 평온했다 .

Page 28: Node.js + Websocket 삽질기

그러던 어느날 ,뜻밖의 방문

Goal 12/31

Page 29: Node.js + Websocket 삽질기

Requiem for Gaebalja

Goal 12/31

- 여기 새로운 개발요건이 있소 . 무덤은 미리 파놨으니 걱정마시오 .

그대는 일을 끝내고 눕기만 하면되오 .

“ 올 것이 왔구나”

Page 30: Node.js + Websocket 삽질기

Goal 12/31

처음에는 간단한 푸시발송 서버를 구현하려고 했으나 ,발송량이 상당할 것으로 예상되어 Amazon SNS 를 사용하기로 협상

결론적으로는 안정적이고 빠른 발송이 보장되었으며(또 )Publish/Subscribe 모델이 지원하여 Topic 기반의 관리가 가능

| 실시간 OOO 알림 : 앱 푸쉬서버 필요

Page 31: Node.js + Websocket 삽질기

Goal 12/31

기획단계에서 그렇게 필요할거다 필요할거다 랩을 해도 안듣더니이제와서 웬말이냐 !

| 재설계를 고려해야하는 요건 : 로그인

Page 32: Node.js + Websocket 삽질기

“ 이 정도야 뭐~”

Goal 12/31

| 회원가입 , 로그인 , 아이디찾기 , 비밀번호찾기 ..... 등등

Page 33: Node.js + Websocket 삽질기

그런데 말입니다 ,

Goal 12/31

“ 웹소켓에는 세션유지 기능이 없지 말입니다 .”

Page 34: Node.js + Websocket 삽질기

Goal 12/31

Redis

Preflight

Upgrade

| Socket.io, Redis, Node session module 만으로는 웹소켓의 세션 유지가 안된다 ( 눈물 )

Socket.io 에서 Preflight(Ajax) 일 때만 세션을 생성하고 ,Websocket 통신시에는 세션을 만들지 않음 . 위는 일반적인 Node.js 의 세션공유방식 (Redis 를 세션스토어로 ..)

Browser

Socket.io

Node.js

Socket.io Express

Mod.SessionSt

ore

Page 35: Node.js + Websocket 삽질기

Goal 12/31

웹소켓상의 통신구간에서 세션을 가져올 방도를 찾을 수 없었고

시간은 흘러가는데…

그래서 어쩔 수 없이…

Socket.io 에서 웹소켓 통신 중 세션 획득하신 분 연락 좀요 . 피자 배달해드림 .

| NPM 리파지토리를 탈탈 털어봐도…

Page 36: Node.js + Websocket 삽질기

Goal 12/31

웹소켓용 세션관리 모듈을 직접 만듦

_ 사족 : 세션 모듈명은 FkingSession 이지만 이것은 수제임을 강조하기 위해 은유적으로 햄버거의 이름을 차용한 것으로 , FantastickBurgerKingSession 의 약자임을 밝힙니다 . 이상한거 아님 . 참고로 다른 업체에서 소스 인수인계해 갔는데 별말없는거 보면… 하 .

| Trick or Threat

Redis

onconnection

oncookie

Browser

Socket.io

Node.js

Socket.io Express

수제세션 - 모듈

수제 세션 생성

주기적으로 document.cookie 로

정보 업데이트

Page 37: Node.js + Websocket 삽질기

Goal 12/31

이 모든 것은 베타런칭 불과 20 일 전이었다 .

Page 38: Node.js + Websocket 삽질기

웰컴투 헬프리카 !

Goal 12/31

Page 39: Node.js + Websocket 삽질기

메인시안 변경

소소한 기획변경Goal 12/31

| 베타런칭 10 일 전

Page 40: Node.js + Websocket 삽질기

Goal 12/31

프론트엔드 애니메이션 문제 발생 : callback, UI state

_ 비록 싱글스레드로 동작하나 비동기통신과 콜백이 난무하는 UI 의 특성_ 각 애니메이션이 끝나는 지점을 확인하여 다음 애니메이션을 진행해야 함_( 일정압박에 따른 ) 개발자의 모럴해저드 발생 , 감으로 .. 종료시간을 추측_애니메이션의 순서가 뒤엉켜 화면낸 요소들이 곂치거나 사라지는 문제발생_ 각 화면 요소 및 렌더링 엔진의 STATE점검 로직 부족

_Async 라이브러리 도입_Callback chain 전면적 리팩토링

_애니메이션 프로세스 재조정

| 모럴 헤저드

Page 41: Node.js + Websocket 삽질기

| 그리고 12 월 ..

정식오픈 7 일 연기그와중에 기획변경

Goal 12/31

Page 42: Node.js + Websocket 삽질기

_ 수시로 이뤄져야 하는 코드리뷰와 리팩토링의 부재_ 모델을 제외한 거의 모든 부분을 재작업_ 여기서 MVP 모델의 유지보수의 용이함을 체감

극심한 정신적 육체적 피로 ... 어찌보면 당연한 귀결

| 리팩토링 : 모바일웹 MVP 모델

Goal 12/31

Page 43: Node.js + Websocket 삽질기

Interlude여기까진 중간보스

Goal 12/31

Page 44: Node.js + Websocket 삽질기

| 로딩속도가 느리다고 ?

Goal 12/31

Page 45: Node.js + Websocket 삽질기

_ 웹소켓 접속과 초기 데이터의 사전 로딩의 필요상 로딩화면이 먼저 나타는 구조_ 소켓서버 구조적 결함발견 ( 불필요한 루프제거 ), 로딩속도 개선_ 초기데이터의 양이 생각보다 큼으로 초기데이터의 분할 로딩방식으로 변경_ 눈속임이지만 초기기동속도가 처음 5~6 초에서 1~3 초 대로 축소

| 리펙토링 : 점진적인 로딩방식

Goal 12/31

Page 46: Node.js + Websocket 삽질기

그리고다가오는 그 날

Goal 12/31

Page 47: Node.js + Websocket 삽질기

12 월 23 일최종보스의 등장

_ 고객사에서 email DM 발송_1분 단위 동접 4천명_예상보다 터무니없이 저조한 서버 성능

Goal 12/31

Page 48: Node.js + Websocket 삽질기

재료 1 : Publish/Subscribe 모델재료 2 : Node 의 싱글스레드재료 3 : 고용량의 Subscribe 데이터

다수 사용자

Node.js 의 채널 Subscribe 핸들러에서 서버에 접속한 모든 클라이언트에게고용량의 데이터 (2~5MB) 를 순차적으로 전송하는 과정에서 이벤트 큐 마비 .싱글스레드이므로 핸들러가 종료되기 전까지 다음 이벤트가 순환되지 못한다 .

Goal 12/31

| Too much love will kill you

Page 49: Node.js + Websocket 삽질기

약 1 시간 정도의 분석 끝에 Payload 문제임을 발견노드 소켓서버의 복제 , 초기 5 개 인스턴스에서 25 개 인스턴스로 확장

서버는 일시적으로 정상화됐으나…

_2vCPU EC2 서버에서 다수 인스턴스를 돌리게 됨으로 생기는 비효율_ 근본적인 Payload문제 미해결_Payload가 해결되지 않으므로 many servers with low connections 아키텍트 유지

Goal 12/31

| 예측하지 못한 Payload 그리고 조치

Page 50: Node.js + Websocket 삽질기

Payload 를 줄이기 위한 방안 데이터압축 _js 압축스크립트의 성능 문제로 클라이언트 UI freezing 우려_클라이언트에서 web worker 도입 검토

JSON 데이터 Key 필드 축약_ 개발 가독성을 위해 Key 의 이름이 긴 편임 , 축약시 약 20~30% 데이터 감소 가능_ 그러나 , 전면적 리팩토링에 대한 시간적 부담감_ 데이터전송 부에서 Key 필드를 별도의 메타데이터로 한벌 만들고 Value 만 묶어서 보내는 방식_ 역시 전면적 리팩토링 필요

데이터의 양은 둘째치더라도 소켓채널 전송시 , 로그인 등의 액션에서 타임아웃 발생어느정도의 비효율은 감수하더라도 근간 서비스가 동작하도록 리팩토링 결정

Goal 12/31

| 2박 3 일간의 사투

Page 51: Node.js + Websocket 삽질기

회원가입 / 로그인 / 북마크 / 프로필힛트카운트 증가 등의 로직도 WebSocket 에서 동작

구조적문제점 탈피를 위한 사용자의 전송데이터 채널을 신설하기로 결정

웹소켓 채널은 오직 Server Push 용으로 용도전환

Node.js 에서 오라클 쿼리 작성 생산성이 열악하여 Java-Spring 으로 REST API 화

Goal 12/31

| Rest Server 도입

Page 52: Node.js + Websocket 삽질기

Goal 12/31

| REMIND : 초기 아키텍트

AWS EC2Browse

r

Socket.io

Node.js

NginX

OracleSocket.io

HTML/CSS/JS/Media FTP

Page 53: Node.js + Websocket 삽질기

실제로는 더 복잡함

| 최종 아키텍트

Browser

Ajax

Socket.io

AWS EC2

Node.js

NginX

OracleSocket.io

HTML/CSS/JS/Media FTP

HAProxy

AWS EC2Node.jsSocket.

io

Node.js

Rest API

Goal 12/31

Page 54: Node.js + Websocket 삽질기

처음부터 알았더라면 ...그렇게 2박 3 일간의 전투가 끝나고 ...

만약 , 초기 기획이 지금과 같았고 이러한 문제점을 미리 알았다면 …

1. 오라클 연동은 자바 - 스프링 REST ( 초반에 고민 )2. 최신버전 노드 사용 ( 오라클 Module 때문에 1.11 버전 사용 )3. WebSocket 은 서버 Push 용으로만 사용4. 어쩌면 고전적인 Ajax Long Polling 이 나았을지도

Goal 12/31

Page 55: Node.js + Websocket 삽질기

종전여러 실수가 있었으나 ,

어찌되었든 우리는 짧은 시간 동안 프로로서 문제해결을 했다 .하지만 , 전투에서는 승리했으나 전쟁에서도 승리했다 말할 수 있을까 ?

상처뿐인 영광 , 아니 상처뿐인 상처로 남았다 .

Goal 12/31

Page 56: Node.js + Websocket 삽질기

그 후 , ( 프로젝트 종료예정일이 지난 후 )

_미뤄뒀던 관리자페이지 개발_푸쉬기능 개발_ 오직 HAProxy 만이 프로젝트 내내 말썽을 일으키지 않았음

Goal 12/31

Page 57: Node.js + Websocket 삽질기

감사합니다 .