Skip to content

멀티 벤더 IoT 연동 설계하기 (1편) - Adapter 패턴으로 통합하기

시리즈: 멀티 벤더 IoT 연동 설계하기

1 / 2편
  1. 11편 - Adapter 패턴으로 통합하기지금 읽는 중
  2. 22편 - Event-Driven Architecture로 확장하기
다른 시리즈 전체 보기 →
멀티 벤더 IoT 연동 설계하기 (1편) - Adapter 패턴으로 통합하기
목차

여러 제조사의 기기를 한 서비스에서 제어해야 했습니다. 같은 문 열기 요청이라도 인증 방식, 장치 식별자, 응답과 상태 갱신 방식이 달랐습니다. 제조사가 늘어날 때마다 서비스 코드의 분기를 고치는 구조로는 기기 하나의 변경이 다른 제조사의 로직에 영향을 줄 수 있었습니다.

네 제조사 연동을 공통 추상화 계층으로 묶고 제조사별 변환을 분리했습니다. 경력 기록에는 신규 제조사 온보딩이 2주에서 2일로 줄어든 것으로 남아 있습니다. 작업 범위와 숙련도가 같은 통제 실험의 수치는 아니므로 모든 연동이 2일 안에 끝난다는 보장은 아닙니다. 이전 글의 여섯 제조사와 어댑터 1~2ms 수치는 이 기록과 대조할 수 없어 정정합니다.

공통 인터페이스에서 숨길 것과 드러낼 것

서비스가 알아야 하는 것은 “이 장치를 제어해 달라”는 업무 요청이지 각 제조사의 요청 필드명이 아닙니다. 제조사에 맞춘 변환은 어댑터가 담당하되, 장치별 지원 기능과 실패 의미까지 같다고 가장하면 안 됩니다.

// 실제 업체 코드가 아닌 경계 설명용 예시
interface DeviceAdapter {
    boolean supports(DeviceType type);
    ControlResult control(DeviceId id, DeviceCommand command);
}

호출자는 기기의 제조사와 기능을 확인해 구현을 선택합니다. 지원하지 않는 명령을 조용히 성공으로 처리하지 않고 명시적으로 거부해야 합니다. 공급자마다 타임아웃, 인증 만료, 비동기 접수와 실제 적용 결과가 다를 수 있으므로 공통 결과에도 접수·적용·실패를 구분할 수 있는 여지가 필요합니다.

예를 들어 API에서 200을 받았다는 사실은 기기가 실제로 문을 열었다는 뜻과 다를 수 있습니다. 어떤 업체가 어떤 코드를 반환했는지는 공개 가능한 실제 자료 없이 이 글에 가상의 명세로 단정하지 않겠습니다.

어댑터만으로 해결되지 않았던 구독 만료

추상화는 업체별 호출을 정리했지만 상태 동기화 문제까지 자동으로 해결하지는 못했습니다. 한 제조사의 도어락은 구독이 만료되는 상황을 처리하지 못해 동작 상태가 제대로 유지되지 않았습니다.

브로커 로그를 분석해 만료와 재구독의 관계를 찾고 자동 재구독 로직을 적용했습니다. 경력 기록 기준 정상 동작 대상은 1,500개 호실 중 약 600개에서 전체 1,500개로 회복됐습니다. 이 숫자는 해당 현장의 기록이며 다른 설치 환경에서도 동일한 결과를 보장하는 지표는 아닙니다.

재구독에서 확인할 질문은 네 가지입니다.

  • 연결이 살아 있어도 구독 자체가 만료됐는가? 마지막 수신 시각과 구독 상태를 따로 관찰해야 합니다.
  • 재구독이 중복 실행되거나 순서가 뒤집혀도 안전한가? 현재 세대의 구독과 만료 시각을 구분해야 합니다.
  • 브로커 장애나 인증 실패가 계속될 때 재시도를 무한히 몰아치지 않는가? 상한·지연·경보가 필요합니다.
  • 재연결 사이에 빠진 상태를 어떻게 채우는가? 가능한 경우 공급자의 현재 상태 조회와 대사를 검토해야 합니다.

이 질문들은 동일 유형의 시스템을 검증하기 위한 기준입니다. 당시 시스템에 이 항목이 모두 구현됐다는 뜻은 아닙니다.

같은 장치의 동시 제어

동일 장치에 제어 요청이 겹치면 외부 기기와 우리 DB에서 관찰한 순서가 달라질 수 있습니다. 당시에는 동일 장치에 대한 동시 제어를 줄이기 위해 Redisson 분산 락을 사용했습니다.

락은 요청을 직렬화하기 위한 수단이지 외부 API와 DB를 하나의 트랜잭션으로 만들어 주지는 않습니다. 락 만료 전에 작업이 끝나지 않거나 외부 호출은 성공하고 로컬 저장은 실패할 수 있습니다. 장치 식별자 기준의 락 범위, 대기·만료 시간, 응답 유실 시 재조회와 중복 명령 정책을 함께 설계해야 합니다. 특히 문 열기 같은 명령을 무조건 재시도하면 위험할 수 있으므로 명령 종류별로 복구 정책을 구분해야 합니다.

새 제조사 연동을 검증한다면

공통 인터페이스만 구현하면 끝이 아닙니다. 인증 갱신, 명령별 지원 여부, 타임아웃 뒤 성공 여부, 장치 오프라인과 재연결, 중복 요청, 상태 이벤트의 누락·역순을 공급자별로 검증해야 합니다. 다섯 개 신규 사이트 연동 과정에서도 오프라인 감지와 재갱신이 별도의 과제였습니다.

온보딩 기간이 줄어든 배경은 분기문을 없앤 것만이 아니라, 어디를 구현하고 어떤 경계를 시험해야 하는지 공통 구조가 생긴 데 있습니다. 공통화가 공급자의 차이를 없애지는 않으므로, 다른 점을 한곳에 모으고 실패를 관찰할 수 있게 만드는 것이 더 중요했습니다.

기기 상태 변화 이후 알림·통계를 분리할 때의 선택은 2편: 이벤트 기반 확장에서 이어집니다. 그 글에서 다루는 Spring의 프로세스 내부 이벤트와 Kafka 같은 영속 메시지 브로커는 전달 보장이 다릅니다.


Ramsbaby
Written byRamsbaby
이 블로그는 직접 개발/운영하는 블로그이므로 당신을 불쾌하게 만드는 불필요한 광고가 없습니다.

#My Github#소개 페이지#Blog OpenSource Github