판교인들의 히치하이커-PangYo 개발기

안녕하세요.
판교인들의 히치하이커-PangYo를 리드하며 백엔드를 개발하고 있는 정상일(humbroll)입니다.

판교 테크노밸리로 이사

작년 말이었습니다. 저희 팀이 ‘교통지옥’으로 흉흉하던 판교로 이사한다는 소문이 돌았습니다. 당시 판교는 600여 개의 회사에 다니는 5만여 명의 임직원들이 출퇴근을 하고 있는 상황에서 주차공간 부족, 대중교통 부족, 사옥에서 판교역까지의 거리 등이 큰 문제로 회자되고 있었습니다. 새로운 서비스를 고민하던 차에 국내 최대 테크노밸리라는 판교의 교통 문제야말로 IT 기술로 해결해볼 만한 가치가 있겠다고 판단했습니다. 

카풀로 해결해볼 수 있을까?

해결 방안은 ‘카풀’이었습니다. 이전부터 카풀 서비스는 웹이나 스마트폰 앱으로 많이 존재했었지만 국내에 카풀에 대한 패권을 잡은 서비스는 없었습니다. 스마트폰 보급률이 낮을 때는 웹을 통해서 비동기로 카풀 멤버를 찾아 헤맸다면, 현재는 그 판이 달라졌지만 그에 맞는 잘 만들어진 카풀 서비스가 나오지 않았다고 판단했습니다. 그래서 기존 카풀 서비스들이 어떤 문제가 무엇인지 찾았고 현재 판에서 그 해결책을 고민했습니다.

P1. 신뢰 – “어떻게 믿고 저 사람 차를 타지?/저 사람을 태우지?”
S1. 판교 입주 회사 이메일 인증 – 단시간에 상대방의 신뢰를 얻는 것은 실명이나 전화번호가 아닌 소속이다. 같은 판교 테크노밸리에 입주한 회사에 다니는 임직원임이 입증되면 최소한의 신뢰는 보장된다.

P2. 카풀 멤버 찾기 불편함 – “내가 가는 길에 내려줄 수 있는 멤버를 어떻게 빨리 찾지?”
S2. 드라이버가 목적지로 가는 길에 경유할 수 있는 히치하이커(승객)를 매칭 시켜 주자.

P3. 출발 시간 – “매번 카풀 멤버와 시간 맞추기 부담스러워!”
S3. 출퇴근 시간대는 정해져 있다. 번거롭게 예약할 필요 없이, 히치하이킹하듯이 내가 집에 가는 바로 그 때 실시간으로 매칭 시켜 주자.

P4. 서로의 위치 – “서로의 위치를 물어보기 번거로워!”
S4. 카풀이 맺어지면 서로의 위치를 실시간으로 보여주자.

P5. 부담감 – “너무 돌아갈 거 같아서 부담스러워 ”
S5. 최대한 경유지로 매칭 시켜주는 것에 더하여 드라이버가 카풀 요청을 수락하기 전에 카풀을 하면 원래 경로보다 얼마나 돌아가야 하는지 보여주자.

바로 위에 해결 방법들을 구현하기 위한 기본적인 기능들을 설계하면서 개발을 동시에 진행했습니다. 문서작업은 거의 없이 개발자 세 명이 연필과 지우개로 기획을 수정하며 빠르게 개선해 나갔습니다. 다음 사진은 서비스 구현을 마쳤을 때 정리했던 기획서 전부입니다.

이렇게 짧은 주기로 세 명의 개발자(고명석-iOS, 김으뜸-Android, 정상일-Backend)와 함께 100일 동안 기획/개발하여 올해 4월에 4개 회사만을 대상으로 오픈하였고, 그 이후 회사 등록 신청을 받아 현재는 80여 개의 회사 판교 테크노밸리 임직원이 퇴근길에 PangYo를 이용하여 지금까지 36135KM를 카풀했습니다.

PangYo 아키텍처

다음 그림은 개략적인 PangYo 백엔드 아키텍처이며, 그 위에서 드라이버와 히치하이커가 카풀이 맺어졌을 때 서로의 위치를 실시간으로 스트리밍 하는 워크 플로어입니다. 카풀이 맺어지면 나의 좌표는 소켓을 통해 송신되고 검색엔진에 인덱싱됨과 동시에 pub/sub tier를 거쳐서 나의 카풀 멤버의 지도에 표시(publish) 됩니다.

Coordinates streaming workflow

각 tier의 역할 및 기술을 개략적으로 설명하면 다음과 같습니다.

Web, API, Scheduler tier – Rails
PangYo의 API, 웹페이지, 퇴근 시간대에 카풀 수요를 정리해서 알려주는 Job 프로세스, 드라이버와 히치하이커의 매칭 알고리즘 등 핵심 기능을 포함합니다.
주요 트랜잭션이 빈번히 일어나는 가장 복잡하고 중요한 tier입니다.

SeachEngine tier – ElasticSearch
목적지 검색을 위한 POI 정보와 함께 실시간 위치 스트리밍을 위해서 클라이언트와 소켓을 통해 수신하는 현재 위치 정보에 대한 색인 및 텍스트/위치 검색 기능을 제공합니다. 검색 엔진 특성상 다른 tier에 비해서 memory bound 하기 때문에 별도의 서버 군을 이중화하여 구축했습니다.

Pub/Sub, Cache tier – Redis
PangYo에서 Redis의 pub/sub 기능은 핵심적인 역할을 합니다. 특정 채널(목적지, 카풀 멤버 위치, 카풀 채팅방, 카풀 광장)의 내용이 업데이트 되면 실시간으로 구독자들에게 데이터를 전달합니다. Redis pub/sub은 구독(subscribe) 채널 명을 plaintext 뿐만 아니라 와일드카드(*)를 이용한 패턴으로도 등록할 수 있습니다. 이는 채널 명에 prefix를 정의하여 채널의 계층 구조를 만드는데 용이합니다.
또한 인메모리 key-value 저장소라는 이점을 살려 지나친 요청 throttling을 위한 카운트 데이터 관리 및 채팅 로그를 캐싱 합니다.

Socket tier – Node.js(socket.io)
실시간(카풀 요청, 채팅, 현재 위치) 기능에 쓰이는 소켓 통신을 담당합니다. 앱이 실행되면 기본적으로 소켓 커넥션이 맺어지며, 이 커넥션을 통해서 모든 실시간성 데이터가 송수신 됩니다.
Socket.io는 소켓의 가장 어려운 점인 커넥션 관리를 편리하게 해줍니다. 다만 Socket.io를 사용하면서 주의해야 할 점은 소켓 커넥션이 끊길 시 외부 연동들에 대한 후처리(pub/sub의 unsubscribe, redis connection 등)에 빈틈이 생기기 쉽다는 점입니다. 예를 들어 redis에 대한 커넥션을 명시적으로 종료시키지 않으면 redis의 max connection에 금세 올라 프로세스가 죽는 문제가 생길 수 있으니 주의해야 합니다. 

각 tier에서 사용할 기술셋을 선택한 기준은,
* POC(Proof of Concept)가 이미 충분히 되어 있는 기술이어야 하고
* 서버 개발을 한 명이 해야 했고 모수가 5만여 명으로 시작하는 작은 서비스였기 때문에 제가 충분히 익숙하거나 빠르게 배울 수 있는지
였습니다.
이 모든 tier는 AWS 위에 VPC(Virtual Private Cloud)에 올라가 있어 기본적인 모니터링을 CloudWatch를 쓰지만 프로세스/네트워크/디스크 등 물리 장비 리소스 사용량, API 트랜잭션 응답 속도/외부연동 부 속도 등의 상세 모니터링은 Newrelic을 이용합니다. 배포는 Capistrano, 클라이언트 에러 모니터링은 Testflight와 Newrelic, 서버 에러 모니터링은 Airbrake, 광고유입을 통한 접근 통계 모니터링은 GA(Google Analytics)를 이용합니다.

구현

위에서 설명한 아키텍처 위에서 PangYo의 기능들을 어떻게 구현했는지 간략히 설명하겠습니다.

목적지 수집 – lazy collecting
PangYo에서는 POI를 미리 수집하지 않습니다. 드라이버가 히치하이커 모집을 시작하면, 그때야 T map 실시간 경로 기준 반경 1.5km 내에 있는 지하철역과 행정구역(동/리/가)을 수집합니다. 예를 들어 잠실역을 목적지로 할 경우 잠실동, 석촌역, 송파역, 신천역 등이 경유지가 됩니다. 이 경유지 POI를 기준으로 히치하이커들의 요청을 드라이버들에게 전달해줍니다. 처음부터 모든 역과 행정구역을 수집해놓으면 실제로는 간 적이 없는 더미 데이터가 쌓일 것이 우려되어 실제 카풀이 있을 때에만 저장하기로 했습니다. 다음 그림은 지금까지 그렇게 수집된 1600여 개의 POI들입니다.

목적지 매칭
잠실역을 목적지로 한 드라이버의 경우 다음과 같은 POI들이 수집되며, 해당 POI들에 대한 히치하이킹을 요청이 드라이버에게 전달됩니다.

이 POI들은 TMap의 실시간 교통상황을 반영한 경유지들의 합집합입니다. 이 때문에 실제로 드라이버들이 경유하기 힘든 곳의 히치하이킹 요청이 온다는 피드백이 많았습니다. 그에 대한 개선으로, 경유가 가장 용이한 출발지와 목적지의 반경 3KM 밖에 있을 경우에는, 경로를 기준으로 내각 80도 밖에 있는 POI는 매칭에서 제외하는 등 로직을 고도화했습니다.

상태 유지
PangYo는 실시간 서비스이기 때문에 최신 상태를 보여주는 로직이 필수입니다. 이를 위해서 앱이 포그라운드(foreground)로 올라오면 항상 piggyback 데이터를 통해 현재 상태를 화면에 반영합니다. Piggyback은 불필요한 HTTP 커넥션 빈도를 줄이기 위해서 사용되며, 앱 부트업에 필요한 모든 데이터와 최신 상태가 포함되어 있습니다. 앱을 포그라운드로 올린 후에는 현재 연결된 소켓을 통한 데이터 스트리밍으로 최신 상태로 계속 업데이트됩니다.

이 외에도 드라이버가 히치하이킹 요청을 받았을 때 얼마나 돌아가야 하는지 볼 수 있는 기능 또한 기존 카풀 서비스들이 제공하지 못하는 점들이었습니다.

최소의 가정과 기획으로 구현했던 이런 기능과 함께 출시한 후에도 지속적인 사용자 피드백을 받아 기능을 개선해나갔습니다. 그 중 가장 주요 업데이트는 현재 카풀 수요를 보여주고 카풀 멤버들끼리 대화를 할 수 있는 채팅 기능이었습니다. 다행히도 채팅 구현에 핵심이 되는 소켓과 pub/sub이 이미 구축되어 있어서 일주일 만에 채팅 기능을 붙일 수 있었습니다.
현재도 사용자 피드백을 통해 크고 작은 기능 개선이 이루어지고 있습니다.

마치며

기존에 오프라인의 비즈니스들의 한계비용들이 높은 스마트폰 보급률과 IT 기술을 통해 점점 낮아지고 있습니다. 우리가 지금까지 실생활에서 겪고 있던 수많은 문제점들을 IT 기술이 풀어줄 여지가 많습니다.

개발자로서 직접 PangYo 서비스를 기획/개발/운영하면서 겪었던 경험들이 앞으로 더 좋은 O2O(Online to Offline) 서비스를 만드는데 도움이 될 것이라고 기대합니다.

PangYo를 만들면서 위에 적은 내용 외에도 여러 개발(그리고 개발 외) 에피소드들이 많지만 산뜻한 스크롤을 위해 이쯤에서 줄입니다.

정상일 New Biz Creation 그룹

PangYo를 만들고 있습니다.

Facebook Twitter LinkedIn Google+ 

공유하기