Command Palette

Search for a command to run...

🖐🏻Hi
← 이력서로 돌아가기

대규모 100만+ 기기 운용 가능한 GRID 시스템 성능 업그레이드

MerlotLab.Inc · 2023.02

BackendMQTTDatabaseAWS

🛠️ Skills

  • Go, gin, mqtt-go, go-mongo-driver, viper, client-go, gorm, bunDB, go-redis
  • goconvey, gomock
  • AWS RDS(mysql v8.0), S3, MongoDB, Redis, EMQX
  • AWS EKS, ECR, Kubernetes, k9s
  • jenkins CI

✍🏻 Description

GRID를 도입하는 고객사가 늘어나면서 10만 개 처리 규모 서버 한계를 확장 시킬 필요가 있었습니다. 이에 기존 서버에서 병렬 처리와 성능 최적화가 필요한 기능을 따로 분리하여 별도 서버를 구축함으로써 100만 개 이상의 조명과 각종 기기 타입을 문제없이 수용, 서빙할 수 있는 시스템을 구현하게 됩니다. 프로젝트 초기 설계부터 개발 전반을 주도적으로 담당하였습니다. image

📝 Experience

💥 조명 10만 개를 넘어 100만 개로: Go언어 기반 MQTT 대량 메시지 동시처리 전담 서비스 개발

Feb 2023 ~ Jan 2024

What’s the issue?

단일 GRID BE 서버 구조에서는 등록 기기 상태동기를 위한 MQTT topic 메시지 상시 구독과 사용자 HTTP 기기 제어 요청을 함께 처리하고 있었음. 이는 한쪽에 문제가 생기면 다른 한쪽도 영향을 받는 종속적 리스크를 내재함. 또한 기존 싱글스레드 기반의 Node.js 서버는 동시다발 대량 MQTT 메시지 처리에 비효율적인 부분이 있음. 따라서 병렬처리에 강점이 있고 비용효율적이며, 실행속도가 빠른 Go 언어를 사용하여 성능 개선 및 추후 시스템 확장 용이성 확보 필요.

What did I do?

  • MySQL, MongoDB, Redis 3가지 DBMS 도입과 서버 내 4 계층 아키텍처, DDD(도메인 주도 개발) 자체 설계 및 적용 ⇒ MQTT topic 구독 상태 동기 로직을 Node.js → Go 언어로 100% migration하면서 구독 topic 별 비즈니스 처리, 목적에 맞는 DB 저장 등 로직 분리 및 모듈화2025년 11월 기준 깃헙 레포지토리 최다 기여 356개/545개
  • MySQL 8.0 버전 업그레이드 및 CTE(Common Table Expression) 개념 활용하는 bunDB 사용하여 엔티티 bulk update 도입 ⇒ 기존 반복 update 쿼리문 대비 데이터 저장속도 대폭 개선 (2,000개 조명 상태 업데이트 43576 ms -> 181 ms)
  • 조명 컨트롤 타워 역할의 Hub, 각종 Device, Group 등의 모든 정보 동기 처리를 단일 MQTT topic 내 처리하던 방식 → 각각의 Hub 상태동기, Group 상태동기, Device 상태동기 로직 세분화 및 payload 최적화 ⇒ DB 쓰기 관심사 분리로 기존 Node.js 서버와 함께 구동시 빈번하게 발생하는 MySQL deadlock 해결 ⇒ 임베디드 페이로드 용량 제한에 따른 디바이스 전송 정보제한 해소 및 분할발송으로 비롯되는 불완전한 상태동기 이슈 해결 ⇒ 로직 세분화 이후 기기별 상태동기 시간 개선(2,000개 기기 상태동기 로직 수행 최대 948 ms -> 387 ms)
  • 서버 내 쿠버네티스 API 통신 로직, 전용 Configmap, Sealed Secret, Deployment 매니페스토 파일 작성과 서버 ↔ jenkins 연동 ⇒ AWS ECR 생성후 EKS 연계 무중단 인프라 배포 및 볼륨 마운트 파일 로깅 파이프라인 구축 기여
  • 서버 내 MQTT client TLS 연동 연결/재연결 매커니즘 구축과 공유구독, 고루틴을 사용한 MQTT topic message 지속적, 병렬 수신 보장 및 panic recover 로직 적용 ⇒ 동일 리소스, 단일 pod 기준 10만 개 기기 제어 및 상태 동기 처리 → 100만 개+의 기기 상태동기 요청을 안정적으로 수행할 수 있는 시스템 개발 적용
  • MQTT topic 처리 시 인증받은 자사 기기 토큰 유효성 검증 및 보안 강화 페이로드 암호화 로직 적용 ⇒ 인증서 탈취시 메시지 송수신 체계 노출 위험과 기기 해킹 위험 원천 차단 기여

Retrospective points

  • 비동기 이벤트 처리에 접목시켜 MQTT topic 구독을 처리하던 기존 Node.js 서버는 당장의 부하 이슈는 없었으나, 회사에서 외주개발자의 자문을 거쳐 대량의 MQTT 메시지가 오가는 IoT 도메인 특성을 고려하여 동시성 처리와 속도가 빠른 Go 언어 기반 서버 구축을 하게 됨
  • 팀 내부적으로 기존 Node.js 기반 서버의 명확한 한계는 무엇이고 왜 Go 언어로 새롭게 구축해야 하는지 이해하는 시간이 부족했음. 고루틴을 사용한 멀티 쓰레딩으로 개선된 메시지 병렬처리 성능을 보며 Go 언어 애플리케이션 개발의 당위성 체감
  • 조명 제어 이후 DB 레코드를 동시에 업데이트하면서 발생한 deadlock은 서버 분리 및 업데이트 주체 일원화로 개선할 수 있었지만, DB isolation level 조정과 transaction 처리 보강으로는 해결이 어려웠을까 생각해봄
  • 빈번한 읽기가 일어나는 로직과 캐시 활용을 위해 Redis를 도입해 볼 수 있어서 좋았으나, 기대보다 성능이 좋게 나오지 않아 확대 도입을 하지 못했었음. 충분한 성능 테스트 이후 적절한 활용처를 늘려간다면 이로 인한 성능 개선도 기대해 볼 수 있겠다고 생각함
  • MQTT topic과 메시지 개수가 늘어나고 1초 간격으로 수집되는 데이터로 인해 AWS CloudWatch 로깅 비용이 급격히 늘어나 파일 로깅을 도입.
  • retention 정책과 rotation 정책을 세우고 PV(Persistant Volume) 연결로 AWS 서버 비용 단축을 직접적으로 체감할 수 있었음
  • MQTT broker가 재시작 될 때 client인 Go 서버가 reconnect 이후에도 브로커 이슈로 인해 구독 중인 일부 topic 메시지를 못 받는 현상이 자주 발생. 인프라 네트워크 불안정과 브로커 자체 로드밸런싱 특성 오류로 못 받는 topic 메시지도 받을 수 있게 할 자동 복구 로직을 개발하면서, 프로젝트 중 더욱 안정된 MQTT 서비스도 함께 세움