해운·항만 현장의 안전 강화를 위해 실시간 사진 분석 시스템 구축은 필수적이에요. 이 글은 Redis와 PostgreSQL을 조합하여 대용량 트래픽을 효율적으로 처리하는 캐시 전략과 데이터 파이프라인 설계 경험을 공유하며, 시스템 안정성과 성능을 동시에 확보하는 기술적 노하우를 담고 있습니다.
이 글은 검색·AI 답변·GenAI 인용에 최적화된 구조로 작성되었습니다.
우리가 Redis와 PostgreSQL을 선택한 이유
시스템의 심장과 두뇌 역할을 할 두 가지 핵심 도구를 신중하게 선택하는 것은 프로젝트의 성패를 좌우합니다. 왜 많고 많은 데이터베이스 중에서 저희는 Redis와 PostgreSQL이라는 조합에 도달했을까요? 단순히 유행을 따르거나 익숙해서 내린 결정은 아니었어요. 각자의 역할이 너무나도 명확했기 때문입니다.
PostgreSQL은 우리 시스템의 ‘기록 보관소’이자 ‘진실의 원천(Source of Truth)’ 역할을 맡았어요. 현장에서 촬영된 모든 사진의 메타데이터, AI 분석 결과, 탐지된 위험 요소 등 모든 정보는 최종적으로 PostgreSQL에 차곡차곡 쌓이게 됩니다. 데이터의 정합성과 안정적인 보관이 무엇보다 중요했기 때문에, ACID 트랜잭션을 완벽하게 지원하는 관계형 데이터베이스인 PostgreSQL은 더할 나위 없이 훌륭한 선택이었죠. 하지만 모든 요청을 이 묵직한 보관소까지 전달하는 건 비효율적일 수 있습니다.
바로 이 지점에서 Redis가 ‘최전방 공격수’처럼 등장했어요. Redis는 인메모리(In-Memory) 데이터 저장소로, 디스크에 접근하는 PostgreSQL보다 압도적으로 빠른 속도를 자랑합니다. 자주 조회되는 데이터, 예를 들어 최근 1시간 내에 분석된 위험 탐지 결과나 특정 구역의 안전 점검 현황 같은 데이터를 Redis에 캐시해두는 거죠. 덕분에 사용자는 거의 실시간에 가까운 응답 속도를 경험할 수 있었어요. 마치 도서관의 모든 책을 서고에서 찾는 게 아니라, 인기 도서를 열람실 바로 앞 서가에 비치해두는 것과 같다고 생각하면 이해가 쉬울 거예요.
요약하자면, PostgreSQL의 안정성과 Redis의 신속성을 결합하여 ‘안정’과 ‘성능’이라는 두 마리 토끼를 모두 잡는 전략을 세웠습니다.
다음 단락에서는 이 전략이 실제 데이터 흐름에 어떻게 적용되었는지 자세히 살펴볼게요.
사진 데이터, 어떻게 흘러가게 만들었을까
데이터의 흐름을 원활하게 설계하는 것은 마치 도시의 교통 시스템을 구축하는 것과 같아요. 시스템 전체의 효율성을 결정하는 이 중요한 과정은 어떻게 진행되었을까요? 저희는 데이터의 생명 주기를 고려하여 명확한 파이프라인을 구축했습니다.
먼저, 현장 작업자가 스마트폰이나 CCTV로 촬영한 사진이 시스템에 업로드되면, 이 이미지는 파일 스토리지(S3 등)에 저장되고, 관련 메타데이터(촬영 시간, 위치, 촬영자 정보 등)는 PostgreSQL에 기록됩니다. 동시에, 이 사진을 분석해달라는 요청이 메시지 큐(Message Queue)에 차곡차곡 쌓이게 돼요. 이렇게 큐를 사용하는 이유는, 사진 업로드가 폭주하더라도 AI 분석 서버가 감당할 수 있는 만큼만 작업을 처리하게 하여 시스템 전체가 마비되는 것을 방지하기 위함이었죠. 정말 중요한 방어막 같은 존재랍니다.
AI 분석 서버는 큐에서 작업을 하나씩 꺼내와 이미지 분석을 수행합니다. 안전모 착용 여부, 위험 구역 접근, 장비 결함 등을 탐지하고 그 결과를 만들어내죠. 이 분석 결과는 다시 PostgreSQL에 영구적으로 저장됩니다. 그리고 여기서 한 가지 중요한 과정이 추가돼요. 분석 결과 중에서도 ‘긴급 알림’이 필요한 위험 요소나 ‘자주 조회될 데이터’는 Redis에도 함께 저장하는 거예요. 예를 들어, ‘A구역 안전모 미착용 3회 발생’ 같은 정보는 즉시 관리자에게 전달되어야 하고, 대시보드에도 바로 표시되어야 하니까요.
요약하자면, 업로드 → 메타데이터 저장(PostgreSQL) → 분석 요청(Queue) → AI 분석 → 결과 저장(PostgreSQL) 및 핵심 결과 캐싱(Redis)의 흐름으로 데이터 파이프라인을 설계했습니다.
다음 단락에서는 이 시스템이 어떻게 폭발적인 트래픽을 견뎌냈는지 이야기해 볼게요.
트래픽 폭주! 캐시 전략으로 우아하게 넘기기
아무리 잘 만든 시스템이라도 한계를 넘어서는 트래픽 앞에서는 속수무책일 수 있어요. 특히 여러 척의 배가 동시에 입항하거나 교대 근무가 시작되는 시간대에는 사진 업로드와 조회 요청이 말 그대로 폭발적으로 증가했습니다. 어떻게 이 위기를 극복했을까요? 해답은 바로 ‘캐시 전략’에 있었습니다.
저희는 가장 보편적이면서도 효과적인 ‘Cache-Aside(Look-Aside)’ 패턴을 적용했어요. 애플리케이션이 데이터를 요청할 때의 시나리오는 다음과 같아요. 첫째, 필요한 데이터가 있는지 Redis에게 먼저 물어봅니다. 만약 Redis에 데이터가 있다면(Cache Hit), PostgreSQL까지 갈 필요 없이 바로 그 데이터를 사용자에게 전달해요. 0.1초도 안 걸리는 눈 깜짝할 사이죠! 하지만 Redis에 데이터가 없다면(Cache Miss), 어쩔 수 없이 PostgreSQL에 가서 데이터를 조회해야 합니다. 그리고 여기서 중요한 점은, 그렇게 힘들게 가져온 데이터를 사용자에게만 전달하고 끝내는 게 아니라 Redis에도 살포시 저장해두는 거예요. 다음에 똑같은 요청이 오면 더 빠르게 응답해주기 위해서죠.
Cache-Aside 패턴 핵심 로직
- 1단계 (캐시 확인): 애플리케이션은 데이터를 Redis에서 먼저 찾아요.
- 2단계 (Cache Hit): 데이터가 있으면, 즉시 클라이언트에게 반환합니다. (성공!)
- 3단계 (Cache Miss): 데이터가 없으면, PostgreSQL(원본 DB)에서 데이터를 조회해요.
- 4단계 (캐시 저장): DB에서 가져온 데이터를 Redis에 저장한 후, 클라이언트에게 반환합니다.
이 전략 덕분에 데이터베이스의 부하를 획기적으로 줄일 수 있었습니다. 실제 운영 환경에서 피크 타임에 PostgreSQL의 CPU 사용률이 80-90%까지 치솟던 것이, 캐시 전략 적용 후에는 30% 미만으로 안정화되는 놀라운 경험을 했어요. 단, 캐시 데이터와 원본 데이터 간의 일시적인 불일치가 발생할 수 있다는 점은 항상 염두에 두어야 합니다.
요약하자면, Cache-Aside 패턴을 통해 데이터베이스의 부하를 분산시키고, 피크 트래픽 상황에서도 사용자에게 빠르고 안정적인 서비스를 제공할 수 있었습니다.
하지만 속도를 얻는 대신 포기해야 하는 것도 있을까요? 데이터 일관성 문제에 대해 이야기해 볼게요.
데이터 일관성은 포기할 수 없죠
속도도 중요하지만, 잘못된 데이터를 보여주는 것만큼 끔찍한 일은 없습니다. 캐시를 사용하면 필연적으로 ‘데이터 일관성’이라는 숙제를 마주하게 돼요. PostgreSQL의 원본 데이터는 변경되었는데, Redis의 캐시 데이터는 예전 정보를 그대로 가지고 있다면 어떻게 될까요? 이 문제를 해결하기 위한 저희의 고민과 해결책을 공유할게요.
가장 간단하고 효과적인 방법은 ‘TTL(Time To Live)’을 설정하는 것이었어요. Redis에 데이터를 저장할 때, 유효 시간을 함께 주는 거죠. 예를 들어, ‘최근 10분간 위험 탐지 현황’ 데이터는 10분의 TTL을 설정합니다. 10분이 지나면 이 데이터는 Redis에서 자동으로 사라져요. 그러면 다음 요청 시에는 자연스럽게 Cache Miss가 발생하고, PostgreSQL에서 최신 데이터를 가져와 다시 Redis에 캐시하게 되는 원리입니다. 얼마나 자주 데이터가 바뀌는지, 그리고 약간의 지연을 얼마나 허용할 수 있는지에 따라 이 TTL 값을 적절히 조절하는 것이 중요해요.
더 나아가, 데이터가 업데이트될 때 캐시를 직접 지워주는 전략도 사용했습니다. 예를 들어, 관리자가 특정 위험 분석 결과를 ‘오탐’으로 처리하면, PostgreSQL의 데이터가 업데이트되는 동시에 관련된 Redis의 캐시 키(Key)를 명시적으로 삭제(DELETE)하는 로직을 추가했어요. 이렇게 하면 사용자는 즉시 변경된 최신 정보를 볼 수 있게 되죠. 이 방식은 조금 더 복잡하지만, 데이터 일관성을 더 적극적으로 유지할 수 있다는 큰 장점이 있습니다.
요약하자면, TTL 설정과 데이터 변경 시 캐시를 직접 삭제하는 두 가지 전략을 혼용하여, 성능의 이점을 누리면서도 데이터 일관성을 최대한으로 확보했습니다.
이제 마지막으로 전체 내용을 정리하고 자주 묻는 질문에 답해볼게요.
핵심 한줄 요약: 안정적인 PostgreSQL과 신속한 Redis 캐시를 조합하고, 트래픽에 맞는 캐시 전략을 적용하면 해운·항만 현장의 안전을 위한 고성능 위험 탐지 시스템을 성공적으로 구축할 수 있어요.
결국 이 경험은 기술의 선택만큼이나 그 기술을 어떻게 조화롭게 엮어내느냐가 중요하다는 점을 다시 한번 깨닫게 해주었습니다. PostgreSQL이라는 든든한 기반 위에 Redis라는 날개를 달아주고, Cache-Aside라는 영리한 조종술을 더했을 때, 비로소 시스템은 피크 트래픽이라는 거친 파도를 넘어 안정적으로 순항할 수 있었어요. 단순히 코드를 짜는 것을 넘어, 데이터의 흐름과 사용자의 경험을 함께 고민했던 시간들이 모여 더 안전한 현장을 만드는 데 작은 보탬이 되었다는 사실에 큰 보람을 느낍니다. 여러분의 프로젝트에도 오늘 나눈 이야기가 작은 영감이 되었으면 좋겠네요.
자주 묻는 질문 (FAQ)
만약 Redis 서버에 장애가 발생하면 시스템 전체가 멈추나요?
아니요, 그렇지 않습니다. Cache-Aside 패턴의 가장 큰 장점 중 하나는 캐시 서버에 장애가 나도 서비스 중단으로 이어지지 않는다는 점이에요. Redis에 연결할 수 없으면 모든 요청이 Cache Miss로 처리되어 PostgreSQL로 직접 전달될 뿐이죠. 물론 응답 속도는 느려지겠지만, 핵심 기능은 계속 동작하기 때문에 서비스의 안정성을 크게 높일 수 있습니다.
왜 다른 NoSQL이 아닌 Redis를 캐시로 선택했나요?
다양한 데이터 구조를 지원하고 속도가 매우 빠르기 때문입니다. 단순한 Key-Value 저장뿐만 아니라, 리스트, 해시, 정렬된 집합(Sorted Set) 등 다양한 자료구조를 제공해서 복잡한 캐싱 로직을 손쉽게 구현할 수 있었어요. 예를 들어, ‘위험도 순으로 상위 10개 목록’ 같은 기능을 Sorted Set을 이용해 효율적으로 처리할 수 있었죠. 이러한 유연성이 Redis를 선택한 결정적인 이유였습니다.
캐시에 저장할 데이터와 그렇지 않은 데이터는 어떻게 구분하나요?
가장 중요한 기준은 ‘조회 빈도’와 ‘데이터의 중요도’입니다. 자주 조회되지만 실시간 정합성이 아주 중요하지는 않은 데이터(예: 일일 통계, 대시보드 데이터)가 캐싱의 최우선 대상이에요. 반면, 데이터가 한 번 기록되면 거의 변경되지 않거나(예: 과거 로그), 조회 빈도가 매우 낮은 데이터는 굳이 캐시에 올려 메모리를 낭비할 필요가 없죠. 시스템의 특성을 잘 파악하고 기준을 세우는 것이 중요합니다.
이 FAQ는 Google FAQPage 구조화 마크업 기준에 맞게 작성되었습니다.