개발/backend

[Backend] 공유 스쿠터 서비스 - 플라워로드 시스템 아키텍처 사용 기술들

나인에스 2022. 2. 23. 19:30

플라워로드 기술 블로그 : http://blog.flowerroad.ai

Notion Link : https://flyingcorp.notion.site/Backend-Feat-AWS-584a382a5bc04f509b44da7500eef0b3


이글은 2020.12.27 일 작성된 내용입니다. 현재 아래에 나열된 기술 이외에 더 많은 서비스, 기술들을 사용하고 있습니다. 

배경

저희 플라워로드 서비스는 전동 킥보드 공유서비스 시스템입니다. 개발 초기에 backend 를 어떻게 구성할지 많은 고민을 하게 되었습니다. 제가 시스템을 설계할때만해도 국내에는 전동 킥보드 공유 서비스를 하는 업체가 전혀 없고, dockless 공유 서비스(kakao T Bike같은..) 조차도 없어서 참고 할만한 대상을 찾기 위해 여기저기 많은 시스템 아키텍처를 검토 했었습니다.

처음에는 타다, Uber같은 자동차 공유 서비스의 아키텍처를 많이 검토 했었는데 결정적으로 저희 시스템과는 다른점이 있었습니다. 바로 실시간성이죠. 자동차는 계속 움직임이 있고, 이 움직임을 실시간으로 표시를 해야하지만 저희 스쿠터의 경우 그냥 정지되어 있는 스쿠터만 보여주면 되는 거였죠.

그래도, 이런 공유 서비스업체들과 쿠팡, 배민과 같은 서비스에서 사용되는 기술들도 검토를 해보고 지금과 같은 시스템을 구축하게 되었습니다.


Tech and Skills

얼마 안되는 resource로(사실...저 혼자라는...쿨럭...) 구성된 아키텍처 이지만 꽤 많은 기술들이 사용되고 있고, 기술들의 대부분의 AWS에서 운영되고 있습니다.

AWS를 사용하게 된 이유는 일단 infra구축에 들어가는 시간을 최대한 절약하기 위해서 입니다. 지원하는 tool, plugin들이나 reference들이 다양해서 서비스를 구축하는 시간을 매우 많이 절약해 줍니다. 이는 설계 당시 빠르게 서비스를 시장에 배포해야하는 요구조건을 만족시키기에 충분했습니다. 물론 AWS 사용중 잘못 구성하거나 사용상에 실수로 인해서 요금폭탄이 발생하기도 하지만 이는 대부분 support center에 메일을 보내서 잘 설명을 하면 실수에 의한 요금은 모두 환불 혹은 credit로 처리되기도 했습니다.

AWS

위에 설명한것 처럼 대부분의 서비스는 AWS에서 구동되고 있습니다. 다양한 서비스들을 위한 infra구축에 시간을 많이 투자 하지 않고도 여러 service/tech들을 이용할 수 있었고 이는 좀더 개발에 집중할 수 있도록 해주었습니다. 이는 설계 검토 초기에 빠르게 서비스를 시작할 수 있는 기반이 된다고 판단하고 이를 선택하게 되었습니다.

 

Google Cloud

이미지 process를 위한 vision service를 사용하고 있습니다. AWS에서도 이와 비슷한 서비스를 제공하고 있기는 하지만 여러 기술 blog나 이용 사례를 살펴 봤을때 google의 vision이 정확도가 가장 높다고 해서 채용하게 되었습니다.

 

Node.js

Spring Boot같이 다양한 방면에서 많이 사용되고 있는 framework가 검토되었지만, 시스템을 구성할때에 대부분의 서비스가 serverless환경에서 동작하도록 구성했고, 이는 AWS Lambda를 이용하도록 설계를 했기 때문에 cold boot 속도가 가장 빠른 node js를 선택하게 되었습니다. 이것 외에도 npm을 활용한 다양한 3rd party module를 활용할 수 있어서 서비스 개발에 좀더 집중 할 수 있었습니다.

Terraform

저희 서비스는 테스트를 위한 서버환경과 실제 고객님에게 서비스를 제공하는 서비스 환경 둘로 나뉘어져 있습니다. 수많은 AWS, Google cloud의 서비스들을 일일이 console을 통해서 설정 및 관리를 할 수 없기에 사용하게 되었습니다. 이를 이용함으로 또 하나의 장점은 서버 계정의 이전이 매우 수월해 졌고, 환경을 구성할 때 자주 발생하는 human error가 없어지다보니 안정적인 시스템 구성/이전/추가등이 가능했습니다.

Serverless

terraform과는 별도로 AWS의 Lambda와 gateway를 구성할때에 편리하게 이용하기 위해 사용되었습니다. terraform이 있는데 serverless를 왜 사용하는가 라는 의구심이 들수 있는데 terraform은 전체 AWS 서비스들의 구성을 담당(vpc, db, codepipeline 등)하고 serverless는 codepipeline 에서 실행되어 각각의 lambda들을 deploy하기 위해 사용됩니다. 수많은 lambda를 기능별/카테고리별로 구분하고, 이를 각각의 독립된 serverless(yml)를 이용해서 deploy하기 때문에 자동화된 deploy+기능별/카테고리별 묶음 deploy + 독립된 deploy를 구성할 수 있었습니다.

MQTT

IoT의 통신을 위해서 개발된 잘 알려진 network protocol입니다. 전동킥보드나 다른 IoT기기들의 데이터를 수집하기 위해서 사용됩니다. MQTT는 기본적으로 message queue의 기술 카테고리에 해당하기 때문에 즉각적인 반응은 보장하지 않아서 IoT의 즉각적인 제어를 위해서 사용되지는 않고 있습니다.

 

WebSocket

client에서 실시간성이 필요한 데이터의 전달을 위해서 사용되고 있습니다. HTTP protocol을 이용한 REST API는 양방향 통신이 아니기 때문에 client와 실시간 interaction이 필요한 부분에서 어려움을 격다가 이를 시범적으로 사용하게 되었습니다. 이 글이 아닌 다음글 정도에서 다루게 될것 같은데 WebSocket외에도 실시간 통신을 위해 gRPC도 검토 및 시범 사용되고 있습니다.

 

Vue.js

Web based의 관리 시스템을 구현/구성하기 위해서 사용되고 있습니다. 잘 구성되어 있는 dashboard의 예제 platform이 있어서 이를 활용해서 빠르게 구현하기 위해 선택했습니다. 실제 사용자(고객)를 위해서 구현/구성되는 부분은 없고, 회사 내부적으로 전체 전동 킥보드들의 관제 및 관리를 위한 web app의 구현을 위해서 선택되었습니다.

 


AWS Service

Architecture를 검토, 구성하는 초기에 가급적이면 모든 서비스를 AWS내에서 운영하도록 구성해왔습니다. 이는 빠르게 구성해서 서비스를 시작할 수 있도록 하자는 의도에서 진행 되었고, 목표에 맞게 예상보다 빠르게 서비스를 delivery할 수 있었습니다.

아주 다양하고 많은 AWS service를 사용하고 있습니다. 이 글에서는 사용중인 service들에 대해서 간략하게 설명을 하고 사용중인 모든 서비스들의 architecture 구성에 대한 내용은 여기서 다루지는 않고 다른 포스팅에서(플라워로드 시스템 아키텍처) 좀더 자세하게 다룰 예정입니다.

VPC (Virtual Private Cloud)

AWS service들 중 외부 network로 부터 보호되어야 할 service들을 위해서 구성되었습니다. 사실 단순하게 VPC를 사용한다 라고 하기에는 구성되어 있는 내용이 좀 많아서 기회가 있다면 다름 포스팅에서 상세하게 다루고, 여기서는 간단하게 어떤 서비스들이 포함되어 있는지 나열만 하겠습니다. ECS, Aurora RDS, DynamoDB, ElastiCache, Backend, ECS, 고정 IP, Network Load Balancer, IoT Core, 특정 Lambda들을 위해서 구성되었습니다. 물론 나열된것 이외에도 EKS같이 몇몇 service들이 있으나 상세한 내용은 다음기회에 다루겠습니다.

Lambda

저희 서비스의 핵심이라고 할 수 있습니다. 모든 데이터 처리, Client의 요청/응답처리등 연결 유지 process를 제외한 모든 computing이 필요한 것들은 Lambda를 이용해서 처리하고 있습니다. code의 architecture 설계시 최대한 작은 단위의 component로 나누어서 각각의 Lambda내에서 처리하도록 설계/구현을 한 덕분에 Lambda Function의 개수가 몇십개 단위로 늘어나고 점점 더 늘어나고는 있으나 하나의 component에서 문제가 발생한다 하더라고 서비스 전체에 영향을 주는 일은 없고, 해당 component만 빠르게 수정 해서 하나의 Lambda만 업데이트하면 되니 전체 서비스가 멈추는 일이 없다는 점에서 매우 큰 장점이 있었습니다. 실제로 저희가 서비스를 시작한지 1년 8개월 정도가 지나가는데 아직 단 한번도 trouble때문에 서비스를 중단한 경우가 없습니다.

API Gateway

RESTful API를 이용해서 거의 모든 client의 요청을 처리하고 있기 때문에 사용되고 있습니다. serverless framework을 사용하게 되면 손쉽게 lambda와 API gateway를 연결해서 RESTful API를 구성할 수 있어서 사용하게 되었습니다. 추가로 API Key인증, Cognito 인증, Oauth 인증 등을 지원하기 때문에 사용하지 않을 수 가 없었습니다.

 

 

Cognito

사용자 계정 관리를 위해 사용하게 되었습니다. 이것을 채용한것은 사실 조금 모험에 가까웠습니다. 서비스 구성을 검토할 당시 cognito의 user pool service가 launch한지 얼마 되지도 않았고, 이를 사용하는 회사, 개인도 많지 않았습니다. 그럼에도 불구하고 MFA(Multi Factor Authentication) 지원, API Gateway 인증 지원등 AWS의 다른 service와의 연계가 쉽고, 우리 서비스에서 꼭 필요한 사용자 가입/로그인을 SMS 인증 코드를 통해서 진행하는 기능을 쉽게 구현/구성할 수 있어서 사용하게 되었습니다. 하지만 역시 이서비스는 많이 사용되지 않고 있다 보니 reference할 수 있는 내용이 많지 않고(아니..거의 없다) SDK의 manual도 부실하다보니(iOS는 없다고 보면 된다..ㅠㅠ) 기본 사용을 위한 구현은 쉬웠으나 재대로 사용하기 위해서 너무 많은 resource가 투입되어야 했었습니다. 더 놀라운것은 이 시점에도 재대로 사용하고 있는건지 모르겠다는 것입니다...

ECS

대부분의 computing 처리는 Lambda에서 하고는 있지만 전동 스쿠터용 IoT의 연결 및 통신을 처리해주는 socket server가 필요했습니다. 서비스 초기에 저희가 IoT를 제작하지 않았기 때문에 상용의 IoT를 구매해서 사용했고, 이 IoT의 통신 방식중 하나가 socket 통신으로 서버와 연결 및 data send/recv 하는 구조였습니다. 그래서 docker형태의 server를 구현했고 이를 ECR에 등록 후 ECS의 Fargate를 이용해서 server의 동작 및 관리를 진행했습니다. 업데이트시 서버의 중단 없이 진행이 가능하고, 간단한 scale up설정, 앞단에 Network LoadBalancer를 붙이고 이를 이용한 scale out또한 어렵지 않게 설정 관리 할수 있었습니다. 다만 Fargate를 검토하고 서버를 구성하는 시점에 EKS가 출시되지 않아서 K8S를 사용하지 않았다는것은 아직도 좀 아쉬움으로 남아 있습니다.

Aurora RDS

DB의 선택은 크게 고민하지 않았습니다. 결제 서비스가 연계되다 보니 DB에 Transaction이 가능해야하고, 고객 계정 관리, 스쿠터 관리등을 위해서 RDB의 사용은 필수 였습니다. 따라서, 크게 고민하지 않고 Aurora RDS + mysql5.6을 선택하게 되었습니다. 개발 초기에는 aurora serverless의 사용도 검토되었으나 serverless 형태의 Aurora는 VPC내부에만 deploy될 수 있고 직접적인 외부 public접속이 불가능 하기 때문에 현재의 provisioned service를 선택,사용중입니다.

 

AWS DynamoDB

처음에는 RDB가 있는데 DynamoDB를 사용할 필요가 있을까 라고 생각했습니다. 그런데, 각 전동 스쿠터의 IoT로 부터 전달되는 데이터가 빠르게는 5초에 한번씩 느리게는 10분에 한번씩 전달되고 있고, 해당 데이터는 전동 스쿠터의 히스토리(과거 이동 경로, 위치, 상태등)를 파악하기 위해서 저장 및 검색이 가능해야 했습니다. 전동 스쿠터의 숫자가 많아지면서 이 데이터를 RDB에 계속 저장하기에는 불합리하다고 판단되어 DynamoDB를 사용하게 되었습니다. 여담으로 MongoDB도 후보군으로 검토 되었으나 제가 구성을 진행할 당시 아쉽게도 AWS에는 MongoDB service가 없었고, 가급적 모든 서비스를 AWS내에 구성하려고 했었기 때문에 선택하지 않았습니다.

ElastiCache (Redis)

처음 Redis를 사용하게 된것은 Redis의 기능중 Geocode에 따른 거리 검색이 가능 하다는 이유였습니다. 이때 당시만해도 MySql 5.6 버전이 Aurora에서 사용할 수 있는 최신 버전이 였고, 5.6버전에서는 geocode나 json data format를 지원하지 않았습니다. 앱에서 고객님의 반경 2~3km내의 스쿠터를 빠르게 검색해서 표출해야 하는 저희 서비스에서는 geocode 검색이 거의 필수라고 생각되어서 사용하게 되었고, 현재는 거리 검색에 의한 데이터 추출 뿐만 아니라 앱(client)에 전달되어야 하는 최신 updated 된 전동스쿠터의 데이터, 좌표데이터, 지역데이터, 필수 flag등 모든 최신 정보를 caching 및 관리하고 있습니다.

CodePipeline

우리 서비스의 대부분은 AWS에서 운영되고 있습니다. 이 Lambda와 API Gateway의 deploy 및 update를 자동화하기 위해서 검토 되었습니다. 결과적으로 이를 이용해서 deploy/ update 시 unit test를 진행할 수 있고, test pass된 artifact의 적용에 대한 최종 승인 대기 또한 가능했습니다. 실제 서비스에서는 CodePipeline이 모니터링 하는 source repository(release repository branch)에 코드가 업데이트 되면 triggering 되어 빌드, 테스트, 승인대기를 거치게 됩니다. 이후 담당자 혹은 관리자가 승인을 하는 경우 서비스가 update deploy됩니다. CodePipeline또한 lambda와 동일한 기능별/카테고리별로 나눠져서 진행 되기 때문에 해당 시점에서 필요한 부분만 업데이트도 가능합니다. 당연하겠지만 Lambda기반의 서비스이기 때문에 서비스 중단없이 업데이트가 진행 됩니다.

S3

데이터의 저장이나 이미지의 저장을 위해서 사용됩니다. 서비스의 특성상 사용 종료시 스쿠터의 주차확인을 위해서 사진을 찍게 되는데 이때 이미지의 저장용도가 주된 사용이유 이고, 이 외에도 DynamoDB의 데이터 Backup, Data Analysis용 임시 데이터 저장 등에 사용되고 있습니다.

 

 

IoT Core

MQTT를 사용하는 전동 스쿠터 IoT의 연결 유지 및 데이터 interaction을 위해서 사용되고 있습니다. Mosquitto를 사용하거나 Sprint Boot의 plugin을 사용해서 MQTT를 구성하는 것보다 매우 간편하게 이용 및 구성 할 수 있는 장점이 있습니다. 다만 이를 사용하기 위해서는 IoT에 인증서의 설치 및 인증과정이 필수인데 IoT HW의 성능이 매우 낮다면 사용할 수 없거나 직접 low level의 porting 구현을 해야하기 때문에 사용하기 쉽지 않다는 단점이 있습니다.

 

이외에도 domain service를 위한 Route53, plugin이나 tool에 의해서 사용되는 service들인 CloudFormation, CodeBuild, CodePipeLine 등도 있습니다. 서비스 모니터링/로그 분석/trouble shouting을 위한 CloudWatch, log Insight, X-ray , QuickSight들, Big Data analysis/ML을 위한 Athena, SageMaker , EMR, Kinesis, Glue, Data Pipeline등도 사용되고 있으나 이들은 서비스에 직접적인 영향이 없기 때문에 여기서 다루지는 않았습니다.

위에 설명한 것처럼 대부분의 서비스를 AWS내에서 구현, 구동, 관리를 하다보니 AWS에 dependency가 너무 끈끈해졌고, 이는 더 괜찮은 성능 혹은 요금제가 있는 다른 provider로의 이동을 쉽지 않게 하는 원인이 되었습니다. 이에 대한 해결책(ex. lambda —> K8S)을 구성하고는 있지만 resource의 투입이 필요한 내용이라 아직은 원할하게 진행되지는 않고 있습니다.

마치며...

플라워로드 Backend 시스템에 사용된 기술에 대해서 나열하고 간단하게 설명을 적어봤습니다.

글을 적다보니 처음 예상보다 내용이 많아져서 하나의 포스팅으로 끝내기에는 무리가 있어보이네요. 그래서 이 글 작성중에 이글은 서론격으로 어떤 것을 사용하는지에 대해서만 언급하는 정도의 얘기만하고, 다음 포스팅에서 이 기술들로 플라우로드 시스템이 어떤 work flow를 가지고 어떻게 굴러가는지에 대해서 한번 다루고, 사용된 AWS 서비스들은 어떻게 구성되었는지에 대해서 다룰 예정입니다. 아마 앞으로 두개 정도의 포스팅이 더 추가 될것 같네요.