diff --git a/README.md b/README.md index f0cac88b..435b12d5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 케어밋 - 쉽고 빠르게 만나는 집 근처 요양 일자리 +# 👵🏻 케어밋 - 쉽고 빠르게 만나는 집 근처 요양 일자리 ppt_표지 @@ -56,20 +56,20 @@

🖥️ **고정 IP 및 외부 접근 설정** -Ubuntu가 설치된 노트북에서 **DHCP 설정을 비활성화**하여 내부 IP를 고정하고, -공유기에서 **포트 포워딩**을 통해 외부에서 접속 가능한 홈 서버 환경을 구축하였습니다.
+Ubuntu가 설치된 노트북에서 DHCP 설정을 비활성화하여 내부 IP를 고정하고, +공유기에서 포트 포워딩을 통해 외부에서 접속 가능한 홈 서버 환경을 구축하였습니다.
🌐 **Dynamic DNS를 통한 도메인 연결** 공인 IP가 주기적으로 변경되는 문제를 해결하기 위해, -**Dynamic DNS 서비스를 사용**하여 IP 변경 시에도 도메인으로 서버에 안정적으로 접근할 수 있도록 구성했습니다.
+Dynamic DNS 서비스를 사용하여 IP 변경 시에도 도메인으로 서버에 안정적으로 접근할 수 있도록 구성했습니다.
🔐 **보안 설정 및 SSL 처리** -- SSH 접속은 **RSA 키 기반 인증**으로 보안을 강화하였습니다. -- 443 포트로 들어오는 HTTPS 요청에 대해서는 **Nginx에서 SSL Termination**을 적용해 암호화를 처리하였습니다.
+- SSH 접속은 RSA 키 기반 인증으로 보안을 강화하였습니다. +- 443 포트로 들어오는 HTTPS 요청에 대해서는 Nginx에서 SSL Termination을 적용해 암호화를 처리하였습니다.
🔁 **Nginx 리버스 프록시 구성** Nginx에서 `/caremeet-dev`, `/caremeet` 등의 경로에 따라 -각기 다른 포트에서 실행 중인 **개발용 및 운영용 애플리케이션 서버**로 트래픽을 분기하였습니다. +각기 다른 포트에서 실행 중인 개발용 및 운영용 애플리케이션 서버로 트래픽을 분기하였습니다.


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

🔒 **내부 리소스 보안 강화** -MySQL, Redis 등 내부 리소스는 외부에서 직접 접근할 수 없도록 구성하고, **SSH 터널링**을 통해서만 접근 가능하게 설정하여 네트워크 보안성을 높였습니다.
- +MySQL, Redis 등 내부 리소스는 외부에서 직접 접근할 수 없도록 구성하고, SSH 터널링을 통해서만 접근 가능하게 설정하여 네트워크 보안성을 높였습니다.
+

⚙️ **CI/CD 자동화 구성** -GitHub Actions를 활용해 CI/CD 파이프라인을 자동화하였고, 빌드된 이미지는 **AWS ECR (Elastic Container Registry)** 에 저장된 후 배포되었습니다.
+GitHub Actions를 활용해 CI/CD 파이프라인을 자동화하였고, 빌드된 이미지는 AWS ECR (Elastic Container Registry) 에 저장된 후 배포되었습니다.
+

+📡 **Redis 활용**
+Redis는 단순 캐시를 넘어, 실시간 처리와 데이터 조회 최적화를 위한 핵심 컴포넌트로 다음과 같이 활용되었습니다: + +- **채팅 Pub/Sub 메시지 브로커 및 세션 저장소** + Redis의 Pub/Sub 구조를 통해 채팅 메시지를 실시간으로 중계하고,
+ 채팅 중인 유저 세션 정보를 저장하여 알림 전송 시 수신 대상 필터링이 가능하도록 구현하였습니다. + +- **읽음 처리 Write 최소화 전략** + Redis에는 채팅방별 최신 메시지 시퀀스와 사용자별 마지막 읽은 시퀀스를 저장하였고, + 이를 기반으로 잦은 업데이트 쿼리( MySQL의 is_read 컬럼 업데이트)를 제거하였습니다. + +- **채팅방 목록 조회 최적화 (JOIN 제거)**
+ Redis에 저장된 채팅방별 메시지 시퀀스 정보와 MySQL의 채팅방 * 메시지 데이터를 조합하여 + 복잡한 JOIN 없이 채팅방 목록, 안읽은 메시지 개수 및상태를 효율적으로 조회할 수 있도록 구성하였습니다. + 이를 통해 슬로우 쿼리를 유발하던 JOIN 연산을 제거하고, 응답 속도를 개선하였습니다. + +- **위치 기반 공고 조회** + 기존의 ST_Buffer 기반 MySQL 공간 쿼리를 제거하고, Redis의 GEO 자료구조를 활용하여 + 사용자의 현재 위치 기준 반경 내 공고 조회 성능을 크게 향상시켰습니다. + +

+🗄️ **MySQL 활용**
+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)를 통해 + 데이터를 주기적으로 정리하는 자동화 로직을 구현하였습니다. +