스토리, 사진, 채용까지.
모두 한 곳에서 탐험하세요

쓱- 둘러보기만 해도 내가 다니는 모습이 상상되는 기업콘텐츠 꿀단지.

스토리

두근두근 첫 출근

취업 스토리

취업 성공하는 이력서와 자기소개서

...
운영 주디

영어영문,교육학과 졸업생의 리크루터 합격 키트

9,980원
...
마케팅 카밀라

관광경영학 전공자의 콘텐츠 에디터 취업 자료

15,980원
...
영업 엘라

전자공학 전공자의 세일즈 매니저 합격 자료

9,980원
...
마케팅 니키

미디어콘텐츠학과 졸업생의 콘텐츠마케터 합격 키트

9,980원
테마
스펙쌓기

마감 직전 대외활동

...
마감 O일전 ~ 25.02.17

[기업참여프로젝트] 게임원화, 일러스트/그래픽, 웹툰 취업희망자 맞춤 교육

부산예일직업전문학ㄹ교
...
마감 O일전 ~ 25.02.17

[플레이데이터] 풀스택 백엔드 개발 캠프 8기

엔코아
...
마감 O일전 ~ 25.02.17

[쌍용강북고용센터] Java를 활용한 Full-Stack개발자 양성과정

쌍용강북고용센터
...
마감 O일전 ~ 25.02.17

[멋쟁이사자처럼] 유니티 게임 개발 4기

멋쟁이사자처럼
스토리

밥블레스유

제이에스로지원 분위기 어때요?

제이에스로지원 공고 확인하셨나요?

스펙쌓기

마감 직전 공모전

...
마감 O일전 ~ 25.02.18

전라관찰사의 탄생 시민기획 프로그램 공모전

전북특별자치도 전주시
...
마감 O일전 ~ 25.02.18

2025 지역 작가 시각예술 전시사업 전시공간 제공자 모집

(재)금천문화재단
...
마감 O일전 ~ 25.02.18

별마당도서관 제7회 열린아트공모전

별마당도서관
...
마감 O일전 ~ 25.02.18

2025 오펜 스토리텔러 모집 (드라마, 영화 공모전)

(주)CJ ENM

오늘의 스택 Java 팔로우

직군에서 많이 쓰는 툴입니다. 직군 설정하기

Java 쓰는 팀

Java 활용기

2019. 04. 17. 조회수 1815

비트윈의 멀티티어 아키텍처를 위한 프레젠터 이야기 - VCNC Engineering Blog

블로그 첫 글에서 비트윈의 시스템 아키텍처에 대해 다룬 적이 있습니다. 시스템 구성의 미래에 대한 계획으로 멀티티어 아키텍처에 대해 언급했었는데, 이는 프로토콜을 단순화시키고 배포 자동화를 가능하게 하기 위해서 클라이언트와 비즈니스 로직을 담당하는 서버 사이에 일종의 게이트웨이를 두는 것이었습니다. 그 외에도 여러 가지 필요성이 생겨 해당 역할을 담당하는 프레젠터라는 것을 만들게 되었고 비트윈의 채팅 시스템에 적용하게 되었습니다. 만드는 과정 중에 여러 기술적인 문제들이 있었고 이를 해결하기 위한 노력을 하였습니다. 이 글에서는 비트윈 시스템에서의 프레젠터에 대해 이야기 하고자 합니다.프레젠터프레젠터는 일종의 게이트웨이 입니다. 기존의 시스템에서는 클라이언트들이 ELB를 통해 채팅 서버에 직접 TCP 연결을 하였습니다. 하지만 비트윈 PC버전과 자체 푸시 서버를 만들면서 ELB로는 해결할 수 없는 부족한 점들이 생겼고, ELB의 부족한 점을 채워줄 수 있는 시스템이 필요하게 되었습니다. ELB를 대체하는 역할 외에도 다른 여러 필요했던 기능들을 제공하는 프레젠터를 만들기로 하였습니다.프레젠터는 ELB의 역할을 할 뿐만 아니라 여러 다른 기능들도 제공합니다.프레젠터의 기능패킷을 적절한 샤드로 중계비트윈에서는 커플 단위로 샤딩하여 같은 커플의 채팅 요청에 대해서는 같은 채팅 서버에서 처리하고 있습니다. Consistent Hash를 통해 커플을 여러 채팅 서버로 샤딩하고 ZooKeeper를 이용하여 이 정보를 여러 채팅 서버 간 공유합니다. 프레젠터 또한 ZooKeeper와 연결을 하여 어떤 채팅 서버가 어떤 커플을 담당하는지에 대한 정보를 알고 있도록 설계되어 있습니다. 따라서 프레젠터는 첫 연결 시 보내는 인증 패킷을 보고 해당 채팅 연결에서 오는 요청들을 어떤 채팅 서버로 보내야 할지 판단할 수 있습니다. 어떤 채팅 서버로 보낼지 판단하는 과정은 처음 한 번만 일어나며, 이후 패킷부터는 자동으로 해당 채팅 서버로 중계합니다.프레젠터의 이런 기능 덕분에 클라이언트는 더 이상 어떤 채팅 서버로 붙어야 하는지 알아내는 과정 없이 아무 프레젠터와 연결만 맺으면 채팅을 할 수 있게 되었습니다. 기존에는 클라이언트들이 여러 채팅 서버 중 어떤 서버에 붙어야 하는지 확인하는 작업을 한 후에 할당된 채팅 서버로 연결 맺어야 했습니다. 그래서 클라이언트가 채팅 서버와 연결을 맺기 위해 다소 복잡한 과정을 거쳐야 했지만, 이제는 클라이언트가 프레젠터의 주소로 연결 요청만 하면 DNS Round Robin 통해 아무 프레젠터와 연결하는 방식으로 프로토콜을 단순화할 수 있었습니다. 덕분에 새로운 채팅 서버를 띄울 때마다 ELB를 Warm-Up 시켜야 했던 기존 시스템의 문제가 없어졌습니다. 그래서 비트윈 개발팀의 오랜 염원이었던 채팅 서버 오토스케일의 가능성도 열렸습니다.많은 수의 연결을 안정적으로 유지PC버전과 푸시 서버를 만들면서 기존의 채팅 연결과 다르게 많은 수의 연결이 장시간 동안 유지 되는 경우를 처리할 수 있어야 했습니다. 기존에는 TCP 릴레이를 하도록 설정된 ELB가 연결들을 받아주었습니다. 한 머신당 6만 개 정도의 Outbound TCP 연결을 맺을 수 있는데, ELB도 트래픽에 따라 여러 대의 머신에서 돌아가는 일종의 프로그램이므로 이 제한에 걸린다고 생각할 수 있습니다. 따라서 많은 수의 연결을 맺어놓고 있어야 하는 경우 ELB에 문제가 생길 수 있다고 판단했습니다. (과거 ELB가 연결 개수가 많아지는 경우 스케일아웃이 안되는 버그 때문에 문제가 된 적이 있기도 했습니다) 또한 클라이어트 연결당 내부 연결도 하나씩 생겨야 하면 클라이언트가 연결을 끊거나 맺을 때마다 서버 내부 연결도 매번 끊거나 연결해야 하는 오버헤드가 발생합니다.이를 해결하기 위해 프레젠터에서는 TCP 연결을 Multiplexing하는 프로토콜을 구현하여 적은 수의 내부 연결로 많은 수의 클라이언트 연결을 처리할 수 있도록 하였습니다. 서버 내부에서는 고정된 개수의 몇 개의 연결만 맺어 놓고 이 연결들만으로 수많은 클라이언트 연결을 처리할 수 있습니다. 이처럼 TCP Multiplexing을 하는 것은 Finagle과 같은 다른 RPC 프로젝트에서도 지원하는 기능입니다.TCP Multiplexing 프로토콜을 통해 많은 수의 클라이언트 연결을 소수의 서버 내부 연결로 처리합니다.또한, 프레젠터는 많은 수의 SSL 연결을 처리해야 하므로 암복호화 로직을 실행하는데 퍼포먼스가 매우 중요하게 됩니다. 채팅 서버 한 대를 제거하거나 하는 경우 많은 연결이 한꺼번에 끊어지고 연이어 한꺼번에 연결을 시도하게 되는 경우가 있을 수 있는데, 이 때 대량의 SSL Handshaking을 하게 됩니다. 기존 서버들로 대량의 SSL Handshaking을 빠른 시간안에 처리하기 위해서는 높은 퍼포먼스가 필요합니다. Java로 작성된 프로그램만으로 이런 퍼포먼스 요구사항을 달성하기 어려우므로, 클라이언트와의 연결을 담당하는 부분은 OpenSSL, libevent를 이용한 C++로 코드로 작성하였습니다. 인증 패킷을 파싱하거나 패킷들을 릴레이 하는 등의 로직을 담당하는 부분은 Alfred라는 Netty를 이용하여 만든 인하우스 RPC 라이브러리를 이용해 작성되었습니다. 연결을 담당하는 부분은 TCP 연결을 유지하는 역할과 들어온 패킷들을 Netty로 작성된 모듈로 릴레이 하는 역할만 담당하므로 매우 간단한 형태의 프로그램입니다. 짧은 시간 안에 어럽지 않게 구현할 수 있었습니다.클라이언트의 연결을 받아주는 역할을 하는 부분은 C++, 실제 로직이 필요한 부분은 Java로 작성하였습니다.여러 네트워크 최적화 기술의 지원ELB에는 여러 네트워크 최적화 기술들을 아직 제공하지 않는 경우가 있습니다. 대표적으로 HTTP/2 혹은 SPDY, QUIC, TCP Fast Open 등이 있습니다. 특히 모바일 환경에서는 SSL Handshaking 등 부가적인 RTT로 인한 지연을 무시할 수 없으므로 이런 기술들을 이용한 초기 연결 시간 최적화는 서비스 퀄리티에 중요한 부분 중 하나입니다. ELB는 AWS에서 관리하는 서비스이므로 AWS에서 이런 기능들을 ELB에 적용하기 전에는 이용할 수 없지만, 프레젠터는 직접 운영하는 서버이므로 필요한 기능을 바로바로 적용하여 서비스 품질을 높일 수 있습니다. ELB에서 이미 제공하는 최적화 기술인 SSL Session Ticket이나 다른 몇몇 기술은 이미 적용되어 있고 아직 적용하지 않은 기술들도 필요에 따라 차차 적용할 예정입니다.프레젠터의 구현C++ 연결 유지 모듈프레젠터는 퍼포먼스를 위해 C++로 작성되었습니다. 이는 Pure Java를 이용한 암복호화는 프레젠터에서 원하는 정도의 퍼포먼스를 낼 수 없기 때문입니다. 처음에는 OpenSSL과 libevent를 이용해 작성된 코드를 JNI를 통해 Netty 인터페이스에 붙인 event4j라는 인하우스 라이브러리를 이용하려고 했으나, 코드가 복잡하고 유지보수가 어렵다는 점 때문에 포기하였습니다. 그 후에는 netty-tcnative를 이용해보고자 했으나 테스트 결과 연결당 메모리 사용량이 큰 문제가 있었고, 이를 수정하기에는 시간이 오래 걸릴 것 같아 포기하였습니다. 결국, 페이스북에서 오픈소스로 공개한 C++ 라이브러리인 folly를 활용하여 프레젠터를 작성하게 되었습니다. folly의 네트워크 API들이 OpenSSL과 libevent를 이용해 구현되어 있습니다.릴레이 로직프레젠터는 첫 인증 패킷을 파싱하여 릴레이할 채팅 서버를 판단하며, 이후의 패킷부터는 실제 패킷을 까보지 않고 단순 릴레이 하도록 설계하였습니다. 처음의 Netty 파이프라인에는 Alfred 프로토콜을 처리할 수 있는 핸들러들이 설정되어 있어 인증 패킷을 파싱 할 수 있으며 인증 패킷에 있는 정보를 바탕으로 어떤 채팅 서버로 패킷을 릴레이 할지 결정합니다. 그 이후 파이프라인에 있던 핸들러를 모두 제거 한 후, 읽은 byte 스트림을 Multiplexing Protocol 프레임으로 감싸서 그대로 릴레이 하는 매우 간단한 로직을 담당하는 핸들러 하나를 추가합니다. 덕분에 로직 부분의 구현도 매우 간단해질 수 있었으며, 채팅 서버에 API가 추가되거나 변경되어도 프레젠터는 업데이트할 필요가 없다는 운영상 이점도 있었습니다.Multiplexing Protocol프레젠터의 Multiplexing Protocol은 Thrift를 이용하여 직접 정의 하였으며, 비트윈 개발팀 내부적으로 사용 중인 RPC 라이브러리인 Alfred에 이 프로토콜을 구현하였습니다. Thrift를 통해 C++과 Java로 컴파일된 소스코드를 각각 프레젠터의 연결 처리 부분과 로직 처리 부분에서 이용하여 통신합니다. 프레젠터에서는 Multiplexing된 TCP 연결들을 Stream이라고 명명하였으며 이는 SPDY나 HTTP/2에서의 호칭 방법과 유사합니다. SPDY나 HTTP/2도 일종의 Multiplexing 기능을 제공하고 있으며, 프레젠터의 Multiplexing Protocol도 SPDY 프레임을 많이 참고하여 작성되었습니다.수 많은 클라이언트와의 TCP연결을 Stream으로 만들어 하나의 내부 TCP연결을 통해 처리합니다.Alfred에서는 Multiplexing 된 TCP 연결을 Netty의 Channel 인터페이스로 추상화하였습니다. Netty에서 TCP 연결 하나는 Channel 하나로 만들어지는데, 실제 Stream도 Channel 인터페이스로 데이터를 읽거나 쓸 수 있도록 하였습니다. 이 추상화 덕분에 비트윈 비즈니스 로직을 담당하는 코드에서는 Stream으로 Multiplexing 된 TCP 연결을 마치 기존의 TCP 연결과 똑같이 Channel을 이용해 사용할 수 있었습니다. 그래서 실제 비즈니스 로직 코드는 전혀 건드리지 않고 프레젠터를 쉽게 붙일 수 있었습니다.로드 밸런싱클라이언트는 Route53에서 제공하는 DNS Round Robin 기능을 이용하여 아무 프레젠터에 연결하여 채팅 요청을 날리게 됩니다. 하지만 무조건 동등하게 Round Robin 하게 되면 새로 켜지거나 하여 연결을 거의 맺지 않고 놀고 있는 프레젠터가 있는데도 연결을 많이 맺고 있는 기존 프레젠터에에 연결이 할당되는 문제가 생길 수 있습니다. 충분한 시간이 흐르면 결국에는 연결 개수는 동등하게 되겠지만, 처음부터 놀고 있는 프레젠터에 새로운 연결을 가중치를 주어 할당하면 로드를 분산되는 데 큰 도움이 될 것입니다. 그래서 Route53의 Weighted Routing Policy 기능을 이용하기로 하였습니다. 현재 연결 개수와 CPU 사용량 등을 종합적으로 고려하여 Weight를 결정하고 이를 주기적으로 Route53의 레코드에 업데이트합니다. 이런 방법으로 현재 로드가 많이 걸리는 서버로는 적은 수의 새로운 연결을 맺게 하고 자원이 많이 남는 프레젠터로 더 많은 새로운 연결이 맺어지도록 하고 있습니다.스케일 인/아웃AWS에서는 트래픽에 따라 서버 개수를 늘리기도 하고 줄이기도 하는 AutoScaling 이라는 기능이 있습니다. 프레젠터가 스케일 아웃될때에는 프레젠터가 스스로 Route53에 레코드를 추가하는 식으로 새로운 연결을 맺도록 할 수 있습니다. 하지만 스케일 인으로 프레젠터가 제거될 때에는 Route53에서 레코드를 삭제하더라도 함부로 프레젠터 서버를 종료시킬 수 없습니다. 종종 클라이언트의 DNS 캐싱 로직에 문제가 있어, Route53에서 레코드를 삭제되었는데도 불구하고 이를 업데이트하지 못해 기존 프레젠터로 연결을 시도하는 경우가 있을 수 있기 때문입니다. 따라서 프레젠터 클러스터가 스케일 인 될 때에는 기존의 모든 연결이 끊어지고 충분한 시간 동안 새로운 연결이 생기지 않은 경우에만 서버를 종료시켜야 합니다. AutoScaling Group의 LifeCycleHook을 이용하여 위와 같은 조건을 만족 시켰을 때에만 프레젠터 서버를 완전히 종료시키도록 하였습니다.못다 한 이야기프레젠터라는 이름이 이상하다고 생각하시는 분들이 있을 것으로 생각합니다. 멀티티어 아키텍처를 이야기할 때 프레젠테이션 티어, 어플리케이션 티어, 데이터베이스 티어로 구분하곤 하는데 이 프레젠테이션 티어에서 나온 이름입니다. 지금은 실제 프레젠터가 하는 역할과 프레젠테이션 티어가 보통 맡게 되는 역할에는 많은 차이가 있지만, 어쩌다 보니 이름은 그대로 가져가게 되었습니다.프레젠터에서 AutoScaling을 하기 위해 LifeCycleHook을 이용합니다. 이때 프레젠터를 위해 LifeCycleHook 이벤트를 처리하는 프로그램을 직접 짠 것이 아니라 비트윈 개발팀이 내부적으로 만든 Kharon이라는 프로그램을 이용하였습니다. Kharon은 인스턴스가 시작되거나 종료될 때 실행할 스크립트를 작성하고 인스턴스의 특정 위치에 놓는 것만으로 LifeCycleHook을 쉽게 이용할 수 있게 하는 프로그램입니다. Kharon 덕분에 비트윈 내 다양한 시스템에서 별다른 추가 개발 없이 LifeCycleHook을 쉽게 활용하고 있습니다. 후에 Kharon에 대해 자세히 다뤄보도록 하겠습니다.정리비트윈 개발팀에서는 오랫동안 유지되는 수많은 채팅 서버 연결들을 처리하고 클라이언트와 서버 간 프로토콜을 단순화시키는 등 여러 이점을 얻고자 ELB의 역할을 대신하는 프레젠터를 만들었습니다. 프레젠터를 만드는 과정에서 여러 기술적 문제가 있었습니다. 이를 해결하기 위해 C++로 연결 유지 모듈을 따로 작성하였고 Multiplexing Protocol을 따로 정의하였으며 그 외 여러 가지 기술적인 결정들을 하였습니다. 이런 과정에서 시행착오들이 있었지만 이를 발판 삼아 더 좋은 기술적 결정을 내리기 위해 고민하여 결국 기존 시스템에 쉽게 적용할 수 있고 쉽게 동작하는 프레젠터를 만들어 이용하고 있습니다.
2019. 04. 17. 조회수 1522

비트윈의 스티커 시스템 구현 이야기 - VCNC Engineering Blog

 비트윈에는 커플들이 서로에게 감정을 더욱 잘 표현할 수 있도록 스티커를 전송할 수 있는 기능이 있습니다. 이를 위해 스티커 스토어에서 다양한 종류의 스티커를 제공하고 있으며 사용자들은 구매한 스티커를 메시지의 첨부파일 형태로 전송을 할 수 있습니다. 저희가 스티커 시스템을 구현하면서 맞딱드린 문제와 이를 해결한 방법, 그리고 프로젝트를 진행하면서 배운 것들에 대해 소개해 보고자 합니다.스티커 시스템 아키텍처비트윈에서 스티커 기능을 제공하기 위해 다양한 구성 요소들이 있습니다. 전체적인 구성은 다음과 같습니다.비트윈 서버: 이전에 소개드렸었던 비트윈의 서버입니다. 비트윈의 채팅, 사진, 기념일 공유 등 제품내의 핵심이 되는 기능을 위해 운영됩니다. 스티커 스토어에서 구매한 스티커는 비트윈 서버를 통해 상대방에게 전송할 수 있습니다.스티커 스토어 서버: 스티커를 구매할 수 있는 스토어를 서비스합니다. 스티커 스토어는 웹페이지로 작성되어 있고 아이폰, 안드로이드 클라이언트와 유기적으로 연동되어 구매 요청 등을 처리합니다. 처음에는 Python과 Flask를 이용하여 구현하려 하였으나 결국엔 서버 개발자들이 좀 더 익숙한 자바로 구현하기로 결정하였습니다. Jetty와 Jersey를 사용하였고, HTML을 랜더링하기 위한 템플릿 엔진으로는 Closure Template을 이용하였습니다. ORM으로는 Hibernate/JPA, 클라이언트와 웹페이지간 연동을 위해서 Cordova를 이용하였습니다. EC2에서 운영하고 있으며 데이터베이스로는 RDS에서 제공하는 MySQL을 사용합니다. 이미 존재하는 솔루션들을 잘 활용하여 최대한 빨리 개발 할 수 있도록 노력을 기울였습니다.스티커 다운로드 서버: 스티커는 비트윈에서 정의한 특수한 포맷의 파일 형태로 제공됩니다. 기본적으로 수 많은 사용자가 같은 스티커 파일을 다운로드 받습니다. 따라서 AWS에서 제공하는 CDN인 CloudFront을 이용하며, 실제 스티커 파일들은 S3에서 호스팅합니다. 그런데 스티커 파일들은 디바이스의 해상도(DPI)에 따라 최적화된 파일들을 내려줘야하는 이슈가 있었습니다. 이를 위해 CloudFront와 S3사이의 파일 전송에 GAE에서 운영중인 간단한 어플리케이션이 관여합니다. 이에 대해서는 뒷편에서 좀 더 자세히 설명하도록 하겠습니다.구현상 문제들과 해결 방법들적정 기술에 대해 고민하다스티커 스토어 서버를 처음 설계할때 Flask와 SQLAlchemy를 이용하여 구현하고자 하였습니다. 개발팀 내부적으로 웹서버를 만들때 앞으로 Python과 Flask를 이용해야겠다는 생각이 있었기 때문이며, 일반적으로 Java보다는 Python으로 짜는 것이 개발 효율이 더 좋다는 것은 잘 알려진 사실이기도 합니다. 하지만 Java에 익숙한 서버 개발자들이 Python의 일반적인 스타일에 익숙하지 않아 Python다운 코드를 짜기 어려웠고, 오히려 개발하는데 비용이 더 많이 들어갔습니다. 그래서 개발 중에 다시 웹 서버는 자바로 짜게 되었고, 여러가지 스크립트들만 Python으로 짜고 있습니다. 실제 개발에 있어서 적절한 기술의 선택은 실제 프로젝트에 참여하는 개발자들의 능력에 따라 달라져야한다는 것을 알게되었습니다.스티커 파일 용량과 변환 시간을 고려하다사용자는 스티커 스토어에서 여러개의 스티커가 하나로 묶인 스티커 묶음을 구매하게 됩니다. 구매 완료시 여러개의 스티커가 하나의 파일로 압축되어 있는 zip파일을 다운로드 받게 됩니다. zip파일내의 각 스티커 파일에는 스티커를 재생하기 위한 스티커의 이미지 프레임들과 메타데이터에 대한 정보들이 담겨 있습니다. 메타데이터는 Thrift를 이용하여 정의하였습니다.스티커 zip파일 안에는 여러개의 스티커 파일이 들어가 있으며, 스티커 파일은 다양한 정보를 포함합니다카카오톡의 스티커의 경우 애니메이션이 있는 것은 배경이 불투명하고 배경이 투명한 경우에는 애니메이션이 없습니다. 하지만 비트윈 스티커는 배경이 투명하고 고해상도의 애니메이션을 보여줄 수 있어야 했습니다. 배경이 투명한 여러 장의 고해상도 이미지를 움직이게 만드는 것은 비교적 어려운 점이 많습니다. 여러 프레임의 이미지들의 배경을 투명하게 하기 위해 PNG를 사용하면 JPEG에 비해 스티커 파일의 크기가 너무 커집니다. 파일 크기가 너무 커지면 당시 3G 환경에서 다운로드가 너무 오래 걸려 사용성이 크게 떨어지기 때문에 무작정 PNG를 사용할 수는 없었습니다. 이에 대한 해결책으로 투명 기능을 제공하면서도 파일 크기도 비교적 작은 WebP를 이용하였습니다. WebP는 구글이 공개한 이미지 포맷으로 화질 저하를 최소화 하면서도 이미지 파일 크기가 작다는 장점이 있습니다. 각 클라이언트에서 스티커를 다운 받을때는 WebP로 다운 받지만, 다운 받은 이후에는 이미지 로딩 속도를 위해 로컬에 PNG로 변환한 스티커 프레임들을 캐싱합니다.그런데 출시 된지 오래된 안드로이드나 iPhone 3Gs와 같이 CPU성능이 좋지 않은 단말에서 WebP 디코딩이 지나치게 오래 걸리는 문제가 있었습니다. 이런 단말들은 공통적으로 해상도가 낮은 디바이스였고, 이 경우에는 특별히 PNG로 스티커 파일을 만들어 내려줬습니다. 이미지의 해상도가 낮기 때문에 파일 크기가 크지 않았고, 다운로드 속도 문제가 없었기 때문입니다.좀 더 나은 주소 포맷을 위해 GAE를 활용하다기본적으로 스티커는 여러 사용자가 같은 스티커 파일을 다운받아 사용하기 때문에 CDN을 이용하여 배포하는 것이 좋습니다. CDN을 이용하면 스티커 파일이 전 세계 곳곳에 있는 엣지 서버에 캐싱되어 사용자들이 가장 최적의 경로로 파일을 다운로드 받을 수 있습니다. 그래서 AWS의 S3와 CloudFront를 사용하여 스티커 파일을 배포하려고 했습니다. 또한, 여러 해상도의 디바이스에서 최적의 스티커를 보여줘야 했습니다. 이 때문에 다양한 해상도로 만들어진 스티커 파일들을 S3에 올려야 했는데 클라이어트에서 스티커 파일을 다운로드시 주소 포맷을 어떻게 가져가야 할지가 어려웠습니다. S3에 올리는 경우 파일와 디렉터리 구조 형태로 저장되기 때문에 아래와 같은 방법으로 저장이 가능합니다.http://dl.sticker.vcnc.co.kr/[dpi_of_sticker]/[sticker_id].sticker하지만, 이렇게 주소를 가져가는 경우 클라이언트가 자신의 해상도에 맞는 적절한 스티커의 해상도를 계산하여 요청해야 합니다. 이것은 클라이언트에서 서버에서 제공하는 스티커 해상도 리스트를 알고 있어야 한다는 의미이며, 이러한 정보들은 최대한 클라이언트에 가려 놓는 것이 유지보수에 좋습니다. 클라이언트는 그냥 자신의 디스플레이 해상도를 전달하기만 하고, 서버에서 적절히 계산하여 알맞은 해상도의 스티커 파일을 내려주는 것이 가장 좋습니다. 이를 위해 스티커 다운로드 URL을 아래와 같은 형태로 디자인하고자 하였습니다.http://dl.sticker.vcnc.co.kr/[sticker_id].sticker?density=[dpi_of_device]하지만 S3와 CloudFront 조합으로만 위와 같은 URL 제공은 불가능하며 따로 다운로드 서버를 운영해야 합니다. 그렇다고 EC2에 따로 서버를 운영하는 것은 안정적인 서비스 운영을 위해 신경써야할 포인트들이 늘어나는 것이어서 부담이 너무 컸습니다. 그래서, 아래와 같이 GAE를 사용하기로 하였습니다.GAE는 구글에서 일종의 클라우드 서비스(PaaS)로 구글 인프라에서 웹 어플리케이션을 실행시켜 줍니다. GAE에 클라이언트에서 요청한 URL을 적절한 S3 URL로 변환해주는 어플리케이션을 만들어 올렸습니다. 일종의 Rewrite Engine 역할을 하는 것입니다. 서비스의 안정성은 GAE가 보장해주고, S3와 CloudFront의 안정성은 AWS에서 보장해주기 때문에 크게 신경쓰지 않아도 장애 없는 서비스 운영이 가능합니다. 또한 CloudFront에서 스티커 파일을 최대한 캐싱 하며 따라서 GAE를 통해 새로 요청을 하는 경우는 거의 없기 때문에 GAE 사용 비용은 거의 발생하지 않습니다. GAE에는 클라이언트에서 보내주는 해상도를 보고 적당한 해상도의 스티커 파일을 내려주는 아주 간단한 어플리케이션만 작성하면 되기 때문에 개발 비용도 거의 들지 않았습니다.토큰을 이용해 보안 문제를 해결하다실제 스티커를 구매한 사용자만 스티커를 사용할 수 있어야 합니다. 스티커 토큰을 이용해 실제 구매한 사용자만 스티커를 전송할 수 있도록 구현하였습니다. 사용자가 스티커 스토어에서 스티커를 구매하게 되면 각 스티커에 대한 토큰을 얻을 수 있습니다. 스티커 토큰은 다음과 같이 구성됩니다.토큰 버전, 스티커 아이디, 사용자 아이디, 유효기간, 서버의 서명서버의 서명은 앞의 네 가지 정보를 바탕으로 만들어지며 서버의 서명과 서명을 만드는 비밀키는 충분히 길어서 실제 비밀키를 알지 못하면 서명을 위조할 수 없습니다. 사용자가 자신이 가지고 있는 스티커 토큰과 그에 해당하는 스티커를 비트윈 서버로 보내게 되면, 비트윈 서버에서는 서명이 유효한지 아닌지를 검사합니다. 서명이 유효하다면 스티커를 전송이 성공하며, 만약 토큰이 유효하지 않다면 스티커의 전송을 허가하지 않습니다.못다 한 이야기비트윈 개발팀에게 스티커 기능은 개발하면서 우여곡절이 참 많았던 프로젝트 중에 하나 입니다. 여러 가지 시도를 하면서 실패도 많이 했었고 덕분에 배운 것도 참 많았습니다. 기술적으로 크게 틀리지 않다면, 빠른 개발을 위해서 가장 익숙한 것으로 개발하는 것이 가장 좋은 선택이라는 알게 되어 스티커 스토어를 Python 대신 Java로 구현하게 되었습니다. 현재 비트윈 개발팀에서 일부 웹사이트와 스크립트 작성 용도로 Python을 사용하고 있지만 Python을 잘하는 개발자가 있다면 다양한 프로젝트들를 Python으로 진행할 수 있다고 생각합니다. 팀내에 경험을 공유할 수 있는 사람이 있다면 피드백을 통해 좋은 코드를 빠른 시간안에 짤 수 있고 뛰어난 개발자는 언어와 상관없이 컴퓨터에 대한 깊이 있는 지식을 가지고 있을 것이기 때문입니다.네 그렇습니다. 결론은 Python 개발자를 모신다는 것입니다.

기업문화 엿볼 때, 더팀스

로그인

/