# 실시간 인기 급상승 장소 찾기 ## 개요 - 실시간으로 생성되는 리뷰들을 분석해서 현재 인기있는 장소들을 순위화 시켜서 보여주는 프로젝트입니다. 서버는 nodejs로 웹 페이지는 리액트를 통해서 구현하였습니다. 분석은 1시간 단위로 생성되는 리뷰 수와 90일 단위로 분석되는 장소의 추천도를 통해서 순위를 매겼습니다. 프로그램 실행로직을 간단히 말하면 서버가 실행되고 워커 쓰레드를 통해서 랜덤으로 1초에 5개의 리뷰 데이터를 생성하고, 메인쓰레드에서 분석을 진행하는데 몽고db의 aggregate연산을 통해서 최근 1시간의 데이터를 분석해서 랭킹을 부여하고, 미리 분석된 90일치의 데이터를 통해서 기준에 못미치는 장소는 패널티를 주는 방식으로 구현하였습니다. 90일치의 데이터 분석은 매일 00시 혹은 서버가 실행될때 수행합니다. ## 기억에 남는 내용들 - 몽고 DB를 사용한 이유 - 이번 프로젝트에서 어느정도 리뷰의 필드들이 주어졌지만 그 외에도 제가 생각하는 지표들을 추가할 수 있기때문에 유연한 스키마 구조를 잡기위해서가 첫번째 이유고, 매번 대용량의 데이터를 읽어와서 분석해야하는 작업인 만큼 mongodb의 속도가 더 빠를것이라고 판단하였습니다. - 내가 사용한 지표들 - 실시간으로 생성되는 리뷰 수 = 인기도 - 리뷰 평점, 사진이 없는 리뷰, 1회 방문 여부, 부정적 댓글에 피드백 - 왜 1시간 단위로 분석을 했는지 - 리뷰의 랭킹 순위가 현재 상황을 표현해주는걸 목표로 삼았는데, 일상 생활에서 가장 많이 마주칠수 있었던 상황이 식사시간 이여서 식사 시간을 보통 2시간으로 잡음. 좀 더 집중도를 높이기 위해서 1시간으로 잡음 - 누적 데이터 분석 기간을 90일로 잡은 이유 - 누적된 데이터를 분석하는데 과거의 데이터는 의미가 없다고 생각했음 그래서 최근 데이터를 분석하기로 결정. 그러면 최근의 기준이 되는 날짜를 몇일로 잡을지 고민, 통계청 자료를 찾아봤는데 우리나라의 사업체가 대략 450만개 정도 있었음. 거기서 농업,어업 이런 리뷰가 쓰일수 없는 장소를 제외하고 대략 300만개 정도가 있었음. 각 장소별로 10개의 리뷰는 있어야 한다고 생각을해서 처음에는 3000만개를 잡았고, 또 어떤 곳에는 리뷰가 집중되고, 어떤 곳에는 리뷰가 안쓰일수도 있으니 1.5배를 잡아서 4500만개로 추정해서 90일치로 잡음 - express를 사용한 이유 - 한달이라는 시간동안 눈에보이는 결과물을 만들기위해서. - 워커 쓰레드를 사용한 이유 - 워커쓰레드를 사용하기 좋을때는 cpu를 많이 사용하는 작업을할때 사용하기 좋음 - 랜덤 리뷰 생성은 cpu를 많이 사용하는 작업은 아니지만 그런 작업이 많이 발생하기때문에 누적되서 cpu를 많이 사용하는 작업으로 판단하였음 - 내가 개선한 내용 - 데이터베이스 90일치 분석 개선 - 기존 90일치를 한번에 분석하던것을 매일 매일 나눠서 분석하는것으로 개선 - 날짜 체크 - aggregate 개선을 시도했지만 실패 - 시간 가중치 도입 - 데이터가 갑자기 사라진다거나 이런걸 방지하기 위해서 시간가중치 도입 - 더 개선할 내용 - 기능 추가 - 지역별 검색 기능 - 추천기능도 있는데 장소가 없는건 이상함 - 예를들어 서울에서 추천장소를 보는데 부산이나 제주도 이런 장소들이 나오는건 맞지 안흠 - 몽고DB 텍스트 검색 기능 구현한다면 어떻게 할지 고민해보기 - 어뷰징 방지 기능 - 표준편차는 적은데 리뷰 평점은 놓은 경우 - 유저 도입 - 한 사용자가 여러 장소의 리뷰를 단기간에 계속 올리는 경우 - 유저가 하루는 경기도 다음날을 제주도 이런식으로 장소의 일관성이 없는 경우 - 웹소켓 도입 고려 - 사용자가 많아진다면 웹 소켓 도입도 생각해볼만한 주제 --------------------------------------------------------- 리뷰 분석 설명 A : 왜 express를 사용? B : 일단 요구사항에 nodejs 서버가 쓰여있어서 koa랑 express를 고민했었다. 둘다 거의 비슷하지만 한달이라는 짧은 기간동안 결과물을 내야겠다는 생각으로 그래도 익숙한 express를 사용하였다. A : 그렇다면 koa의 장점이 뭐라고 생각하는가? B : 직접 사용해본적은 없어서 그냥 알고있는 지식으로만 말씀드리면, 일단 async/await을 지원한다. 기존 express에서는 middleware 를 통해서 에러를 처리하는데 async/await을 지원하지 않아서 async 함수에서 에러가 발생하면 middleware로 넘어가지 않는다. 그래서 직접 try-catch로 감싸서 middleware를 호출해주어야 한다.koa에서는 async 함수 내에서 에러가 발생하면 middleware로 넘어가진다. A : 또 다른 장점은 없는가? B : 벤치마킹 상으로는 속도가 빠르다고 했는데 왜인지 정확히 찾지는 못했다. A : Express의 장점은 무엇인가 B : koa나 express나 엄청 큰 차이점이 있다고 생각하지는 않는다. express를 쓴다면 nodeJS의 장점때문에 쓴다고 생각한다. A : NodeJs의 어떤 장점때문에 쓰인다고 생각하는가? B : NodeJS의 가장 큰 장점은 비동기 event Driven 방식이라고 생각한다. A : 비동기 event Driven 방식에 대해서 짧게 설명 부탁한다. B : call stack에 들어온 task를 수행하면서 IO작업이나, 네트워크 작업같은 비동기 작업의 경우 libuv로 위임하고 비동기 작업이 끝난 후 실행되야하는 callback 함수의 경우 비동기 작업이 끝나면 event Queue로 들어와 callstack이 빌때까지 기다렸다가 callstack이 비는경우 수행한다. A : 싱글 쓰레드와 멀티 쓰레드의 장단점은? B : 싱글 쓰레드만의 장점이라기 보다 비동기 작업이 중요한것 같다. 멀티쓰레드의 경우 IO작업은 진행하는동안 CPU를 차지하고 있어 뒤에 오는 작업들이 연달아 지연되는 반면 , 비동기 방식의 경우 시간이 오래걸리는 작업들을 다른 쓰레드에 위임하기 때문에 뒤에오는 작업이 밀리지가 않는다. A : 멀티 프로세스와 멀티 쓰레드와의 차이점은? B : 멀티 프로세스의 경우 장점은 안정성이다. 하나의 프로세스가 종료되도 다른 프로세스에는 영향을 안미친다. 단점은 context switch가 발생하기때문에 속도가 느리고 프로세스간 통신을 하는 경우 복잡한 방법이 필요하다(파일을 이용하거나 메모리를 이용하거나 파이프라인을 이용하는 방법) 반면의 멀티쓰레드의 경우 같은 힙 메모리를 공유하기 때문에 쓰레드간 통신이 쉽고 컨텍스트 스위치 비용이 적다. 하지만 같은 자원을 공유하기 때문에 만약 쓰레드가 같은 공간을 동시에 접근하는 경우 문제가 발생할 수 있기때문에 동기화 과정이 필요하다. A : 동기화를 어떻게 하는가? B : 세마포어를 활요하는걸로 알고 있다. A : 세마포어 **찾아보자** A : 컨텍스트 비용이 큰 이유는 무엇인가? B : 프로세스는 전체적인 공간의 컨텍스트 스위칭이 발생하는 반면에 쓰레드는 스택 영역만 변경하면 된다. 스택영역이 다른 영역인 힙,코드 데이터 영역에 비해 적기때문에 비용이 적다고 생각한다. 이것도 컨텍스트 비용이라고 해야할지 모르겠는데 프로세스간 컨텍스트 스위칭이 발생하면 TLB나 cpu 캐시를 초기화라는걸로 알고있다. 그래서 프로세스간 컨텍스트 스위칭이 발생하면 매번 다시 캐시를 저장해야하기때문에 비용이 큰것같다. A : worker 쓰레드 모듈(libuv의 worker X)의 동작방식을 아는가? B : V8 엔진의 ISolation을 통해서 독립된 공간을 나누어 event loop나 Heap, libuv 모듈등 하나의 node환경을 구성하는것으로 알고 있다. A : worker 쓰레드모듈 사용한 이유는? B : 일단 Woker 쓰레드를 사용해야하는 조건은 Cpu intensive한 작업을 하는 경우라고 알고 있다. 랜덤 리뷰 생성의 경우 CPU는 적게 사용하고 IO 작업이 위주이지만, 초당 5개를 생성하면 하나의 작업은 적더라도 전체적으로는 많은게 아닐까 라는 생각을 했다. A : 왜 MongoDB를 사용하였는가? B : 리뷰가 초당 5TPS면 하루에 생성되는 양이 50만개정도로 알고있다. 이런 대용량의 데이터를 처리하는데 MongoDB가 적당하다고 생각했다. A : MongoDB가 왜 대용량 데이터에 적합한가? B : 데이터가 대용량이라는 말은 양적으로도 많지만, 트래픽도 그 만큼 많다고 이해하였다. mongodb는 일단 데이터양적으로도 scale out이 가능하고 트래픽 처리 속도도 빠르다고 알고 있다. A : MongoDB의 트래픽 처리 속도는 왜 빠른가? B : 일단 RDMBS는 데이터 정합성을 엄격하게 검사하지만, 몽고DB의 경우 정합성 검사를 엄격하게 하지 않기때문이 어느정도 있는것같고, 몽고DB의 memory mapped 방식도 어느정도 영향이 있을거같다. A : memory mapped 방식이 어떤 방식인가? B : 데이터 처리를 할때 데이터를 메모리에 올려서 처리후 비동기적으로 디스크에 쓰는 방법으로 알고있다. A : 저 방법의 문제점은 없는가? B : 메모리에 파일을 올려서 처리하는 방법인 만큼 비동기적으로 파일에 쓰여지기전에 날아가게 되면 데이터 손실이 올수도있고, 메모리 공간을 많이 차지하게 되면 다른 프로세스의 영향을 미칠수 있는것으로 알고있다. A : RDBMS는 scale out이 사용 불가능한가? B : RDBMS도 사용이 가능한걸로 알고있다. 대신에 사용자가 직접 구현해야하는걸로 알고 있다. A : 개선할 사항은 무엇이라고 생각하는가 B : 지역별 검색기능이 필수라고 생각한다. 제가 생각하기로 장소 순위를 보는 목적은 방문할 생각을 가지고 본다고 생각하는데, 내가 서울에 있는데 부산의 장소가 나오거나, 제주도의 장소가 나온다고 하면 의미가 없는 서비스라고 생각한다. A : 그렇다면 구현을 어떻게 할것인가 B : mongo DB에서 한글 text index가 지원되지 않기때문에 시군구 별로 데이터를 split해서 넣는 방법으로 구현해야될것 같다. A : 서버와 클라이언트 통신 방법은 어떻게 구현하였는가? B : polling 방식으로 구현하였다. 웹소켓 B+ tree