목차 (Overview)
- 연결만 잘되면 끝인 줄 알았다
- 처음부터 완벽한 아키텍처를 만들 필요가 있을까?
- MVP 개발과 실제 서비스 운영의 차이
- 초기 MVP 아키텍처 — 온프레미스 MQTT로도 충분했다
- 자전거 대여 서비스의 요구사항
- RabbitMQ와 MQTT Pub/Sub를 선택한 이유
- MQTT Topic 구조와 메시지 인터페이스
- 기본적인 자전거 대여 및 반납 흐름
- 실제 운영을 생각하니 문제가 보이기 시작했다
- 디바이스가 오프라인이 된다면?
- 서버와 실제 디바이스 상태가 서로 다르다면?
- 펌웨어 업데이트와 디바이스 관리 문제
- 고객사가 늘어날수록 복잡해지는 운영 구조
- 기술적 문제가 비즈니스에 미치는 영향
- 왜 AWS IoT Core를 선택했을까?
- 기존 MQTT 브로커를 계속 사용하면 안 될까?
- AWS, Azure 및 다른 클라우드 서비스 비교
- AWS IoT Core가 제공하는 주요 기능
- 마이그레이션을 결정할 때 고려한 기준
- 무엇을 어떻게 바꿨을까? — 개선된 아키텍처
- Thing Registry, X.509 인증서, IoT Policy
- Device Shadow를 활용한 상태 동기화
- IoT Rules, SQS, Lambda 기반 이벤트 처리
- CloudWatch 모니터링 및 장애 추적
- IoT Jobs를 활용한 OTA 관리 방향
- 기존 MQTT에서 AWS IoT Core로 옮기는 과정
- 디바이스 등록 및 인증서 구성
- 기존 Topic과 메시지 호환성
- 단계별 마이그레이션
- 테스트 및 롤백 전략
- 실제 운영 시나리오로 살펴보기
- 자전거 대여 중 연결이 끊어진다면?
- 서버와 디바이스의 설정이 다르다면?
- 배터리 부족 이벤트가 발생한다면?
- 고객사별로 디바이스를 구분해야 한다면?
- 아키텍처 개선이 비즈니스에 어떤 가치를 줄까?
- 운영 및 유지보수 부담 감소
- 장애 대응 및 상태 관리 개선
- 신규 디바이스 확장과 운영 자동화
- Before / After 비교 및 측정 지표
- 마치며 — 이번 개선을 통해 배운 점
- AWS IoT Core가 모든 문제의 정답은 아니다
- 비용과 운영 복잡성 사이의 Trade-off
- 다음 프로젝트에서 고려할 점
1. 연결만 잘되면 끝인 줄 알았다
2. 자전거 대여 서비스 설명
초기 서비스 요구사항
| 구분 | 요구사항 | 상세 내용 |
|---|---|---|
| 사용자 규모 | 초기 이용자 100~1,000명 | 기업 고객사의 직원들이 주로 이용 |
| 백엔드 서비스 | 자전거 및 대여 관리 API | 자전거 등록, 대여·반납, 사용자 인증, 결제 또는 이용료 정산 |
| 자전거 디바이스 | MCU 기반 IoT 장비 | GPS 위치, 배터리 잔량, 잠금 상태 측정 |
| 디바이스 통신 | MQTT 기반 양방향 통신 | 상태 데이터 전송 및 제어 명령 수신 |
| 모바일 앱 | 자전거 대여 서비스 | 주변 자전거 조회, 대여 및 반납, 배터리 상태 확인 |
2.1 초기 MVP 아키텍처 — 온프레미스 MQTT로도 충분했다
- 배포 환경: 일부 B2B 고객사는 클라우드보다 자체 서버나 온프레미스 환경을 선호합니다. RabbitMQ는 컨테이너 기반으로 이런 환경에도 배포할 수 있습니다.
- 비용: 기존 서버와 운영 환경을 활용할 수 있다면 초기 비용을 줄일 수 있습니다. 다만 서버 유지보수와 운영 인력의 비용도 함께 고려해야 합니다.
- 단순한 구조: 초기에는 telemetry, status, cmd, ack 정도의 Topic만으로도 기본적인 데이터 송수신과 제어가 가능합니다.
- 개발 편의성: 디바이스와 백엔드가 MQTT를 통해 메시지를 주고받는 구조가 비교적 단순하고 직관적입니다.
2.2 MQTT Topic 구조
Text
| Topic | 방향 | 역할 |
|---|---|---|
| telemetry | 자전거 → 클라우드 | GPS, 배터리, 이동 속도 |
| status | 자전거 → 클라우드 | 잠금 상태 및 동작 상태 |
| cmd | 클라우드 → 자전거 | LOCK, UNLOCK 명령 |
| ack | 자전거 → 클라우드 | 명령 실행 결과 |
2.3 MQTT 메시지 인터페이스
Json
Json
Json
Json
2.4 자전거 대여 및 반납 흐름
- 사용자가 앱에서 자전거 대여를 요청합니다.
- 백엔드에서 사용자와 자전거의 이용 가능 여부를 확인합니다.
- MQTT cmd Topic으로 잠금 해제 명령을 전송합니다.
- 자전거가 명령을 실행하고 ack를 전송합니다.
- 백엔드는 실행 결과를 확인한 후 대여를 시작합니다.
- 사용자가 반납하면 잠금 상태와 반납 조건을 확인하고 대여를 종료합니다.
3. 실제 운영을 생각하니 문제가 보이기 시작했다
3.1 디바이스가 오프라인이면 어떻게 할까?
3.2 서버와 디바이스의 상태가 서로 다르다면?
3.3 배터리가 갑자기 방전된다면?
- 마지막으로 데이터를 받은 시각
- 마지막으로 확인된 GPS 위치
- 배터리 잔량과 연결 상태
- 현재 진행 중인 대여 세션
- 통신 장애 시 대여 종료 및 요금 처리 정책
3.4 펌웨어를 업데이트하는 것도 일이었다
3.5 고객사가 늘어날수록 운영이 복잡해진다
4. 왜 AWS IoT Core를 선택했을까?
4.1 기존 MQTT 브로커를 계속 사용하면 안 될까?
4.2 어떤 클라우드 서비스를 선택할까?
| 서비스 | 장점 | 고려할 점 |
|---|---|---|
| RabbitMQ On-Premises | 기존 인프라 활용, 높은 구성 자유도 | 브로커와 디바이스 운영 기능을 직접 관리 |
| AWS IoT Core | Thing Registry, Shadow, Rules, Jobs 및 AWS 서비스 연동 | 사용량 기반 비용, AWS 의존성, 디바이스 수정 필요 |
| Azure IoT Hub | Device Twins, 메시지 라우팅, 디바이스 관리 기능 | Azure 기반 서비스와 운영 체계 검토 필요 |
| Google Cloud | 파트너 또는 별도 IoT 솔루션과 GCP 서비스 조합 가능 | 기존 Cloud IoT Core는 2023년 종료 |
| NAVER Cloud | 국내 클라우드 인프라 및 관련 서비스 활용 가능 | 기존 Cloud IoT Core와 IoT Device Hub는 2024년 종료 |
4.3 AWS IoT Core란 무엇일까?
4.4 결국 마이그레이션을 선택한 이유
- 기존 MQTT 통신 기능을 유지하면서 디바이스 관리 기능을 확장할 수 있습니다.
- Device Shadow를 통해 원하는 설정과 실제 적용된 상태를 구분하여 관리할 수 있습니다.
- Thing Registry, 인증서 및 IoT Policy를 활용해 디바이스별 접근 권한을 관리할 수 있습니다.
- IoT Rules를 통해 이벤트 처리 로직을 기존 백엔드와 분리할 수 있습니다.
- 이미 사용하고 있는 EKS, S3, RDS, CloudWatch와 연동하기 편리합니다.
- 향후 IoT Jobs를 이용하여 원격 작업과 OTA 관리 구조를 개선할 수 있습니다.
5. 무엇을 어떻게 바꿨을까? — 개선된 아키텍처
5.1 Things, X.509 인증서, IoT Policy
5.2 Device Shadow — 원하는 상태와 실제 상태를 구분하기
Json
Json
Json
5.3 IoT Rules + SQS + Lambda — 이벤트 처리 구조 분리
Sql
- 배터리 부족 이벤트를 데이터베이스에 저장
- 관리자에게 알림 전송
- 점검이 필요한 자전거 목록에 추가
- 반복된 이벤트가 발생하더라도 중복 알림 방지
5.4 CloudWatch — 문제가 발생했을 때 어디서 확인할까?
- 디바이스가 AWS IoT Core에 연결되지 않았을 수 있습니다.
- IoT Policy에서 해당 Topic 접근이 거부되었을 수 있습니다.
- 메시지는 전달되었지만 디바이스에서 실행에 실패했을 수 있습니다.
- ACK 메시지가 전달되지 않았을 수 있습니다.
- 백엔드에서 결과를 처리하는 과정에서 오류가 발생했을 수 있습니다.
5.5 IoT Jobs — OTA 관리 구조 개선
6. 기존 MQTT에서 AWS IoT Core로 옮기는 과정
6.1 먼저 기존 구조와 의존성을 확인한다
6.2 디바이스 등록과 인증서 준비
6.3 일부 디바이스부터 연결 테스트
- AWS IoT Core 연결 및 인증 성공 여부
- MQTT Publish/Subscribe 정상 동작
- 기존 Topic과 Payload 호환성
- 네트워크가 끊어진 후 재연결 동작
- 명령 실행 및 ACK 처리
- Shadow Desired/Reported 동기화
- IoT Rules와 워커의 메시지 처리
- 로그 및 오류 확인
6.4 단계적으로 전환하고 롤백도 준비한다
7. 실제 운영 시나리오로 살펴보기
7.1 자전거가 오프라인인데 사용자가 대여를 요청한다면?
7.2 디바이스가 다시 연결되었는데 설정이 다르다면?
7.3 배터리가 부족한 자전거가 발생한다면?
7.4 고객사가 서로 다른 자전거를 운영한다면?
Text
8. 아키텍처 개선이 비즈니스에 어떤 가치를 줄까?
8.1 Before / After 비교
| 개선 항목 | 기존 MQTT 구조 | 개선된 아키텍처에서 기대하는 효과 |
|---|---|---|
| 디바이스 관리 | 별도의 디바이스 관리 로직 필요 | Thing Registry 및 그룹 기반 관리 |
| 상태 동기화 | 서버와 디바이스 상태 비교 로직 직접 구현 | Shadow Desired/Reported 기반 동기화 |
| 인증 및 접근 제어 | 기존 브로커의 인증과 권한 체계 관리 | X.509 인증서 및 IoT Policy 기반 접근 제어 |
| 이벤트 처리 | 백엔드에서 직접 메시지 구독 및 처리 | IoT Rules와 SQS/Worker로 처리 분리 |
| 장애 추적 | 서비스별 로그를 직접 확인 | CloudWatch와 공통 식별자 기반 추적 |
| OTA 작업 | 별도 업데이트 및 배포 시스템 관리 | IoT Jobs를 통한 원격 작업 관리 가능 |
| 확장성 | 브로커 및 운영 인프라 확장 직접 관리 | MQTT 브로커 운영 부담 감소 |
8.2 어떤 지표를 측정하면 좋을까?
| 측정 지표 | 확인하고 싶은 내용 |
|---|---|
| 명령 실행 성공률 | 잠금/해제 명령이 실제로 성공한 비율 |
| 명령 처리 시간 | 명령 요청부터 실행 ACK까지 걸린 시간 |
| 디바이스 연결 상태 | 오프라인 디바이스 수 및 연결 복구 시간 |
| 장애 탐지 시간 | 문제가 발생한 후 발견하기까지 걸린 시간 |
| 신규 디바이스 등록 시간 | 새 자전거를 서비스에 연결하는 데 걸리는 시간 |
| OTA 업데이트 성공률 | 원격 펌웨어 업데이트 성공 비율 |
| 운영 비용 | AWS 사용료, 기존 인프라 비용 및 운영 인력 투입 시간 |
8.3 결국 비즈니스에 중요한 것은?
9. 마치며 — 이번 개선을 통해 배운 점
- 디바이스가 오프라인이 되었을 때 어떤 방식으로 복구하고 상태를 동기화할 것인지
- 명령 전송과 실제 명령 실행을 어떻게 구분하고 검증할 것인지
- 디바이스가 늘어날 때 반복적인 운영 작업을 얼마나 자동화할 수 있을지