Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 49 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 케어밋 - 쉽고 빠르게 만나는 집 근처 요양 일자리
# 👵🏻 케어밋 - 쉽고 빠르게 만나는 집 근처 요양 일자리

<img width="900" alt="ppt_표지" src="https://github.com/user-attachments/assets/a022bac8-ad7e-4948-a796-7b1522c617dd">

Expand Down Expand Up @@ -56,20 +56,20 @@
</p>

🖥️ **고정 IP 및 외부 접근 설정**
Ubuntu가 설치된 노트북에서 **DHCP 설정을 비활성화**하여 내부 IP를 고정하고,
공유기에서 **포트 포워딩**을 통해 외부에서 접속 가능한 홈 서버 환경을 구축하였습니다.<br>
Ubuntu가 설치된 노트북에서 DHCP 설정을 비활성화하여 내부 IP를 고정하고,
공유기에서 포트 포워딩을 통해 외부에서 접속 가능한 홈 서버 환경을 구축하였습니다.<br>

🌐 **Dynamic DNS를 통한 도메인 연결**
공인 IP가 주기적으로 변경되는 문제를 해결하기 위해,
**Dynamic DNS 서비스를 사용**하여 IP 변경 시에도 도메인으로 서버에 안정적으로 접근할 수 있도록 구성했습니다.<br>
Dynamic DNS 서비스를 사용하여 IP 변경 시에도 도메인으로 서버에 안정적으로 접근할 수 있도록 구성했습니다.<br>

🔐 **보안 설정 및 SSL 처리**
- SSH 접속은 **RSA 키 기반 인증**으로 보안을 강화하였습니다.
- 443 포트로 들어오는 HTTPS 요청에 대해서는 **Nginx에서 SSL Termination**을 적용해 암호화를 처리하였습니다.<br>
- SSH 접속은 RSA 키 기반 인증으로 보안을 강화하였습니다.
- 443 포트로 들어오는 HTTPS 요청에 대해서는 Nginx에서 SSL Termination을 적용해 암호화를 처리하였습니다.<br>

🔁 **Nginx 리버스 프록시 구성**
Nginx에서 `/caremeet-dev`, `/caremeet` 등의 경로에 따라
각기 다른 포트에서 실행 중인 **개발용 및 운영용 애플리케이션 서버**로 트래픽을 분기하였습니다.
각기 다른 포트에서 실행 중인 개발용 및 운영용 애플리케이션 서버로 트래픽을 분기하였습니다.
<br>
<br>
<br>
Expand All @@ -82,27 +82,54 @@ Nginx에서 `/caremeet-dev`, `/caremeet` 등의 경로에 따라


✅ **리버스 프록시 및 보안 구성**
Nginx를 통해 외부 요청을 수신하고, URL 경로(`/caremeet-dev`, `/caremeet`)에 따라 트래픽을 개발 환경과 운영 환경으로 분기하도록 리버스 프록시를 설정했습니다.
또한, HTTPS 및 WebSocket Secure(wss)에 대해 SSL 인증서를 적용하여 **보안 통신**을 지원하였습니다.<br>

Nginx를 통해 외부 요청을 수신하고, URL 경로(`/caremeet-dev`, `/caremeet`)에 따라 트래픽을 개발 환경과 운영 환경으로 분기하도록 리버스 프록시를 설정했습니다. 또한, HTTPS 및 WebSocket Secure(wss)에 대해 SSL 인증서를 적용하여 보안 통신을 지원하였습니다.<br>
<br><br>
🔒 **내부 리소스 보안 강화**
MySQL, Redis 등 내부 리소스는 외부에서 직접 접근할 수 없도록 구성하고, **SSH 터널링**을 통해서만 접근 가능하게 설정하여 네트워크 보안성을 높였습니다.<br>

MySQL, Redis 등 내부 리소스는 외부에서 직접 접근할 수 없도록 구성하고, SSH 터널링을 통해서만 접근 가능하게 설정하여 네트워크 보안성을 높였습니다.<br>
<br><br>
⚙️ **CI/CD 자동화 구성**
GitHub Actions를 활용해 CI/CD 파이프라인을 자동화하였고, 빌드된 이미지는 **AWS ECR (Elastic Container Registry)** 에 저장된 후 배포되었습니다.<br>
GitHub Actions를 활용해 CI/CD 파이프라인을 자동화하였고, 빌드된 이미지는 AWS ECR (Elastic Container Registry) 에 저장된 후 배포되었습니다.<br>
<br><br>
📡 **Redis 활용**<br>
Redis는 단순 캐시를 넘어, 실시간 처리와 데이터 조회 최적화를 위한 핵심 컴포넌트로 다음과 같이 활용되었습니다:

- **채팅 Pub/Sub 메시지 브로커 및 세션 저장소**
Redis의 Pub/Sub 구조를 통해 채팅 메시지를 실시간으로 중계하고,<br>
채팅 중인 유저 세션 정보를 저장하여 알림 전송 시 수신 대상 필터링이 가능하도록 구현하였습니다.

- **읽음 처리 Write 최소화 전략**
Redis에는 채팅방별 최신 메시지 시퀀스와 사용자별 마지막 읽은 시퀀스를 저장하였고,
이를 기반으로 잦은 업데이트 쿼리( MySQL의 is_read 컬럼 업데이트)를 제거하였습니다.

- **채팅방 목록 조회 최적화 (JOIN 제거)**<br>
Redis에 저장된 채팅방별 메시지 시퀀스 정보와 MySQL의 채팅방 * 메시지 데이터를 조합하여
복잡한 JOIN 없이 채팅방 목록, 안읽은 메시지 개수 및상태를 효율적으로 조회할 수 있도록 구성하였습니다.
이를 통해 슬로우 쿼리를 유발하던 JOIN 연산을 제거하고, 응답 속도를 개선하였습니다.

- **위치 기반 공고 조회**
기존의 ST_Buffer 기반 MySQL 공간 쿼리를 제거하고, Redis의 GEO 자료구조를 활용하여
사용자의 현재 위치 기준 반경 내 공고 조회 성능을 크게 향상시켰습니다.

<br><br>
🗄️ **MySQL 활용**<br>
MySQL은 핵심 비즈니스 데이터를 안정적으로 관리하고, Redis와의 조합을 통해 실시간성과 정합성을 모두 충족시키는 기반 저장소로 활용되었습니다.

📡 **Redis 활용**
채팅 세션 저장소 및 Pub/Sub 메시지 브로커로 사용되어, 실시간 채팅 전송 및 수신을 지원하였습니다.
- **핵심 비즈니스 데이터 저장소**
사용자, 센터, 센터장, 채팅방, 채팅 메시지 등 주요 엔터티를 MySQL에 저장하여 데이터 정합성과 일관성을 유지하였습니다.

채팅 메시지 시퀀스 데이터를 Redis에 저장하고,
이를 MySQL의 채팅방 메타데이터와 조합하여
사용자의 채팅방 목록을 효율적으로 조회할 수 있도록 구성하였습니다.
- **최적화된 조회 쿼리 설계**
- 카디널리티를 고려한 인덱스 설계 및 실행 계획(EXPLAIN) 분석을 통해 주요 조회 성능을 개선하였습니다.
- 채팅방 목록 조회 시, LATERAL JOIN을 활용하여 각 채팅방의 최신 메시지를 효율적으로 가져오는 쿼리 구조를 구성하였습니다.
- Time-based UUID를 직접 생성하여 기본 키로 사용함으로써 추후 Replication 환경에서도 안정적인 Row 기반 복제를 지원할 수 있도록 두고,
Spring Data JPA의 save 메서드 실행 후 발생하는 불필요한 ID 조회 쿼리를 제거하였습니다.

또한, GEO 기반 자료구조를 통해
사용자의 위치를 기준으로 주변 공고 및 채팅방을 빠르게 조회하는
고속 처리 쿼리 모델로도 활용되었습니다.
Redis는 다음과 같은 하이브리드 구조로 활용되었습니다:
- **데이터 무결성과 동시성 제어**
- 애플리케이션 레벨에서 발생할 수 있는 중복 요청과 경쟁 조건을 방지하기 위해, 중복이 발생할 수 있는 필드에 Unique 인덱스를 설정하여 동시성 문제를 예방하였습니다.

- **불필요한 데이터 정리 자동화**
- 2주 이상 경과한 크롤링 공고 데이터는 자동으로 삭제되도록 스케줄러 + MySQL 이벤트 프로시저(Event + Stored Procedure)를 통해
데이터를 주기적으로 정리하는 자동화 로직을 구현하였습니다.

<br>
<br>
<br>
Expand Down