애플리케이션 서비스 구성분석-MOCI

cybertramp

2019/10/28

Categories: app-analysis Tags: MOCI

애플리케이션 서비스 구성

1. 모씨(MOCI)

먼저 NRISE라는 회사이며, 위피와 모씨를 개발한 회사.

소통형 SNS 서비스로 카드 형식으로 게재하며, 꼬리에 꼬리를 무는 형식으로 되어 있는 서비스이다. 인스타그램처럼 해시태그를 사용할 수 있으며, 해당 카드를 근처에, 관심있는, 인기있는, 새로운으로 분류된 카테고리를 통해 볼 수 있다. 각 카드에는 답글에 해당하는 카드를 달 수 있으며, 하트를 통해 “좋아요” 기능이 존재한다. 카드는 작성자, 내용, 위치정보, 작성시간, 좋아요, 답글링크, 답글개수가 속성으로 있는듯 하다. 익명이라는 장점을 통해 인기가 있는 듯하다.

비슷한 어플: 속삭임, 우주챗, 아무, 마인드카페, 위피

1) 서비스 구성

서비스 구성은 16년 2월 3일 글인 “모씨 개발 수첩” 글을 참고 하여 정리한다. 회사 내에서 실질적으로 사용하는 장비는 맥 미니 서버 한 대라고한다. 이 서버는 iOS/Android 클라이언트의 자동 빌드를 위해 보유한다고 한다.

호스팅

OS

해당 OS에는 ixgbevf 모듈 2.11.3k가 설치되어 있다고 한다. ixgbevf는 EC2에서 intel 82599VF 인터페이스를 사용하는 경우에서 향상된 네트워킹을 제공한다고 한다. 아마 당시에 커널에 최신 ixgbevf 모듈이 포함되어 있지 않아서 설치해서 사용하는것 같다.

Application Server

서버에서 동작하는 모든 어플리케이션은 Python으로 작성

메인 시스템 + 관리 시스템으로 구성

메인 어플리케이션은 Flask 기반으로 구현되어 PostgreSQL DB는 SQLAlchemy와 Alembic을 통해 연결, 관리 되고 있음. 관리 시스템의 경우 Django로 구현

메인 시스템의 경우 경량 프레임워크 + 라이브러리의 조합으로 구성되어 있고, 관리 시스템은 최대한 높은 생산성을 보장해 주는 풀 스택 프레임워크를 도입했다고 볼수 있음 => Flask와 Django

WSGI(Web Server Gateway Interface: 파이썬에서 웹 서버와 통신하기 위한 인터페이스) 구현체로는 uWSGI(uWSGI은 WSGI 구현체 중 가장 앞선 성능을 가짐)를 이용하고 process 별 수행 성능 편차를 최대한 막기 위해서 gevent loop engine 을 적용하여 사용.

다양한 비동기 작업 및 지연 작업, Cache-DB 간 동기화 작업을 위해 Celery가 많은 곳에서 사용되고 있음. Celery는 concurrency pool 로 gevent 를 적용하여 운용 중.

모든 uWSGI는 Nginx로 reverse proxying 되어 최종적으로 서비스

DB

다양한 DB가 유기적으로 연결되어 동작됨

메인 DB로 PostgreSQL 9.4를 사용, 서비스와 관련된 모든 데이터들이 저장됨

해당 DB는 특성상 다른 DB에 비해 부하가 있을 경우에 체크해야 할 튜닝 포인트가 여러 곳이 존재, 이유는 데몬이 멀티 스레드가 아닌 멀티 프로세스 형태로 동작하기 때문이라 추측

성능을 맟추기 위해 오토 배큠, 커넥션 풀링, 커널 리소스 등 다양한 부분에 대한 튜닝이 이루어짐

멀티 프로세스 형태로 동작하는 만큼 커넷션 풀링은 굉장히 중요한 요소, PgBouncer 를 통한 커넥션 풀링을 설정하여 사용

vntouch 툴을 통해 데이터 파일이 어느 정도 액세스 되고 있는지를 확인하고 조치를 함

수 억장의 카드에 포함되어 있는 해시태그 검색을 PostgreSQL에 적용하여 “LIKE” 검색을 시도하는 경우 상당한 퍼포먼스 저하가 발생하여 MySQL을 포크한 MariaDB를 사용하기로 했다고 한다.

하지만 MariaDB는 몇가지 단점을 가진다.

NoSQL 계에서 가장 유명. 주로 BSon 형태로 데이터를 쉽게 쓰고, 읽을 수 있는곳에서 사용된다.

예를 들면 카드에 대한 조회수는 RDBMS(MariaDB, PostgreSQL 등)에 기록되고, 카드를 조회한 사용자의 로그는 MongoDB에 기록하여 메인 DB의 부하를 분산하는 용도로 사용한다.

MongoDB 3.0 부터 도입된 WiredTiger 스토리지 엔진으로 인해 데이터 저장 효율이 비약적으로 향상되었다고한다.

AWS에서 제공하는 NoSQL 데이터베이스이다. Read/Write 양에 따라 가격이 책정되어 손쉽게 스케일을 키우고 줄이고가 가능하다. 하지만 인덱스, 쿼리가 매우 제한적이여서 아마 현재 시점에서는 MongoDB를 사용하고 DynamoDB는 사용하지 않는듯 하다. 해당 글에서도 초기 부분에 한해 사용되었다고 한다.

Storage

이용자들이 생성하는 수 억장의 카드 이미지는 AWS S3 에 저장됨. S3에 업로드된 수백 테라 바이트의 이미지는 AWS CloudFront CDN으로 배포됨. CloudFront 특별히 가격이 저렴하거나 하지는 않지만 다음과 같은 장점을 가짐

Cache

주력 캐시 서버로 Redis를 사용. 애플리케이션 내부의 자체적인 샤딩 루틴을 통해 여러 대의 Redis 서버 인스턴스에 다양한 데이터가 분산 저장되며, 히트 되지 않는 경우 자동으로 DB로 부터 당겨오도록 되어 있음

모씨(Moci) 앱은 주요 데이터들을 Redis 서버에 먼저 데이터를 set하고 일정한 딜레이 후에 캐시 서버에서 DB로 데이터를 저장하도록하는 루틴들이 포함되어 있음. 이때 Redis 서버에 있는 동일한 데이터에 여러 커넥션이 동시에 데이터를 set하여 데이터 정합성 문제를 일으키지 않도록 하기 위해 여러 큐 형태의 파이프 라인 코드가 동작하고 있음

Celery의 broker로 최초에 Redis를 이용했으나, 트래픽 급증과 함께 안정성 문제가 발생하여 RabbitMQ 클러스터를 구성. 실제로 Redis는 트래픽이 적을 경우 충분한 성능을 내지만, 트래픽이 급증하는 경우 Redis의 in-memory DB 특성으로 인해 불안감 발생 가능. RabbitMQ 클러스터는 초당 수백 메가 바이트의 트래픽을 안정적으로 소화하며 단 한번의 장애 없이 안정적으로 브로커 기능을 해줌

LoadBalancing/AutoScale

어플리케이션 서버는 AWS ELB로 트래픽을 분산 처리. ELB의 큰 장점은 ELB에 물려있는 서버들의 부하를 체크하여 AutoScale 옵션을 연동할 수 있다는 점이다. 이 기능 덕분에 App 서버 인스턴스 수를 항상 부하에 맞게 조절이 가능하다고 한다.

단점으로는 idle timeout을 3600초 까지만 설정할 수 있다는 것인데, RabbitMQ 클러스터에 접속하는 Celery worker들의 경우 문제를 발생 시켰다고 한다. 이로 인해 RabbitMQ 클러스터의 경우 ELB가 아닌 HaProxy를 이용하여 로드밸런싱을 하도록 설정했다고 한다. HaProxy의 경우 사실 상 무제한의 idle timeout을 설정할 수 있기 때문.

검색 엔진으로는 AWS CloudSearch와 ElasticSearch를 사용. 현재 AWS CloudSearch => ElasticSearch로 마이그레이션을 진행중. 지리 정보 관련한 데이터 질의는 초기엔 MongoDB의 Geolocation 쿼리를 이용했으나 현재는 ElasticSearch 기반으로 변경한 상태

Monitoring

여러 모니터링 툴을 사용

2) 부가

이 중 2명이 서버 개발을 담당

comments powered by Disqus