🦉 SidePro (SideProject)
- 개발자를 위한 사이드 프로젝트 공유 플랫폼 서비스 (with. 커피챗을 곁들인)
🐼 Introduction
- 주제 : 사이드 프로젝트 공유 플랫폼 (with. 커피챗)
- 기간 : 2022.07.07 (목) ~ 2022.08.04 (목)
- Team : 김선민 (Github), 김민기 (Github), 박재현 (Github), 황신혜 (Github)
- FE Repo : Sidepro-FE
- 시연 영상 : 링크
📚 Project Structure
🤝 Project-Rules
Scheduling & API
Branch Info
- main : LocalHost 실행 branch
- publish : EC2 Hosting 실행 Branch
Figma Mock-up & DB Modeling
👉 Structure
┌─SIDEPRO
├── sidepro // project
│ ├── urls.py // base url
│ ├── asgi.py // chat route setting
│ ├── settings.py // setting
│ └── ...
├── project // app
│ ├── models.py // DB Model - project, comment
│ ├── views.py // View Functions
│ ├── serializers.py // Serializers
│ ├── tests.py // Test Code
│ ├── pagination.py // pagination
│ └── ...
├── chat // app
│ ├── models.py // DB Model - status, room, chat
│ ├── views.py // View Functions
│ ├── serializers.py // Serializers
│ ├── tests.py // Test Code
│ ├── constants.py // Constants
│ ├── consumers.py // Consumer
│ ├── routung.py // Routing
│ └── ...
├── ai // app
│ ├── views.py // View Functions
│ ├── serializers.py // Serializers
│ ├── tests.py // Test Code
│ ├── cron.py // Crontab
│ └── ...
├── user // app
│ ├── models.py // DB Model - user, userprofile, ...
│ ├── views.py // View Functions
│ ├── serializers.py // Serializers
│ ├── tests.py // Test Code
│ ├── constants.py // Constants
│ └── ...
├── _utils
│ ├── auto_clean_pyc_migrate.py // Migrations
│ ├── auto_cleancode.py // Run black, isort
│ ├── auto.runserver.py // Run Server
│ ├── query_utils.py // Query Debuger
│ └── set_basedb.sql // Base DB Data
│
├── .github\workflow
│ └── be_cicd.yml // CI/CD PIPE LINE
│
├── log
│ └── a.txt // Save crontab log
│
├── nginx
│ ├── nginx.conf // nginx
│ └── Dokerfile // nginx Dokerfile
│
├── Dockerfile // Dokerfile
├── docker-compose.yaml // Doker-Compose
├── **manage.py**
└── requirements.txt
💻 Development
🎉 로그인/회원가입
- 기본 vaildation & 로그인 JWT Token 사용
🎉 프로젝트 게시판
- 프로젝트 목록 조회 (Django-Pagination)
- 프로젝트 등록 (Toast UI Editor / Image Preview)
- 프로젝트 검색, 정렬 (기술 스택 기반 검색 / 조회순, 최신순, 인기순 정렬)
- 프로젝트 상세 조회 / 수정 / 삭제 (댓글 CRUD, 북마크 ON/OFF)
🎉 커피챗 기능
- 채팅 Room 목록 (조회, 생성, 삭제)
- 채팅 소켓 연결에 따른 Room Status 관리 (Running, Pending, Stop)
- 채팅 유저 프로필 조회
- 실시간 채팅
- Websocket & Django Channels 이용
- Daphne ASGI 서버 => WS 프로토콜 요청 처리
- Redis를 이용한 실시간 메시지 전송
🎉 추천 시스템 기능
- User-Based 추천 시스템 ("나와 비슷한 기술 스택을 보유한 유저의 프로젝트" 추천)
- Django-CronTab을 이용한 유사도 계산 부하 방지 (1분마다 Query & 유사도 계산)
- 스토리
-
- CronTab이 1분마다 나와 유사한 기술 스택 보유한 유저간의 유사도 계산
-
- 유사도 계산 파일 csv 저장
-
- 사용자 요청시 해당 파일 읽어서 추천 프로젝트 결과 출력
-
🎉 프로필 페이지(마이/유저 페이지)
- 마이(유저) 프로젝트 모아보기
- 북마크한 프로젝트 모아보기
- 유저 프로필 정보 조회
- 내 프로필 정보 조회 수정, 삭제
🎉 AWS Infra & CI-CD
- AWS EC2 내 container 기반 Publish 배포
- AWS S3 FE 버켓 2개 이용하여 각각 정적 웹 호스팅, 업로드 파일 저장소
- AWS IAM 부여하여 Infra Team 공동 관리
- AWS RDS 이용하여 DataBase 속도와 안정성 확보
- AWS ROUTER 53 도메인 등록하여 가독성, 접근성 증가
- GitActions 이용한 CI-CD 자동화 구축
🎉 Nginx / Gunicorn / Daphne
- Nginx : Proxy 역할
- Gunicorn : Django 배포용 WSGI서버 http protocol 요청 처리 (worker : 2)
- Daphne : Django 배포용 ASGI서버 WebSocket portocol 요청 처리
👉 시연 화면
🎉 첫 화면, 회원가입, 로그인 화면
🎉 메인 페이지 (게시판)
🎉 상세 페이지 (글 조회, 글 쓰기)
🎉 마이(유저) 페이지
🎉 채팅
🛡 Trouble Shooting
🛠 서비스 비대응시간 최소화 브랜치 전략
⚡ 문제 발생
- EC2 단일 서버에서 서비스 대응 중 Bug가 발견되어 수정 소요가 발생
- 재빌드 및 재배포 과정에서 서비스 중단 시간이 생기게 됨
- Bug 수정 후 재배포 간 추가 Bug 발생으로 빌드 실패 => "Bug 발생 + 오류 DEBUGGING 시간 + 재빌드 시간" 등 서비스 중단 시간이 계속 늘어나게 됨
⚡ 문제 정의
- 단일 EC2에서 서비스를 대응 및 수정 사항을 직접 반영하다보니, 개발(수정)시 서비스가 중단되야 되는 상황 발생
- CD(Continuous Deployment)과정에서 Git Main Branch => Publish Branch로 배포하는 Branch 전략에 문제가 있다고 판단
⚡ 문제 해결 방법
- Dev Branch 배포 서버 추가 (개발자용 배포 서버)
- 기존 배포 전략 : Main(개발, local)⇒ Publish (서비스, 배포O)
- 수정 후 배포 전략 : Main(개발, local) ⇒ Development (개발, 배포O) ⇒ Publish (서비스, 배포O)
- Dev Branch에서 최종 완료 확인 후 Publish 로 배포
🛠 동시성 문제 (Concurrency) 발생
⚡ 문제 발생
게시물 상세 조회시 여러명(N)이 동시에 접근하였더니, 조회수가 N이 오르지 않고, N 미만의 숫자가 오름 (조회수, 북마크 수, 댓글 수 등에 동시성 이슈 확인)
⚡ 문제 이해
PostgreSQL은 기본적으로 READ COMMITTED의 Transaction 격리 환경을 가지고 있어, 한 유저의 Transaction이 값을 수정 중이더라도, 다른 유저의 Transaction이 접근 가능하고, commit 되기 전, 순차적으로 commit에 더하는 것이 아닌, 이전 commit 값을 같이 바라보고 같은 값으로 수정하게 되는 현상 발생
⚡ 문제 해결 방법
Django에서 제공해주는 F Method 활용하여 Python 메모리 로드 없이 DB단에서 즉석 반영하게 함. 총 3건 (조회수, 북마크 수, 댓글 수) 에 적용하였고, Curl 메소드로 테스트시 정상적으로 실행되는 것 확인.
🛠 Query 최적화
⚡ DRF ORM select_related(), prefetch_related()를 이용하여 쿼리 최적화 진행
- 지연로딩을 사용할 경우 연관관계가 있는 엔티티가 필요한 경우라면, Select 쿼리를 여러번 수행해서 엔티티를 조회하게 되므로 따라서 성능에 문제가 생길 수 있다. select_related, prefetch_related를 사용하여 즉시로딩 (Eager Loading)하여 쿼리를 최적화하였습니다.
⚡ django 내장 모듈을 이용하여 transaction 경험
- 통신 도중 연결이 끊긴다거나 오류 발생 시 여러개의 insert, update 쿼리가 발생될 때 중간 과정에 끊길 경우 DB데이터에 대한 신뢰성이 깨질 수 있기 때문에 @transaction.atomic을 이용해서 SAVEPOINT를 이용하여 모든 쿼리가 성공했을 때 DB에 반영되도록 하게 만들었습니다.
블로그 정리내용(https://psb6604.tistory.com/69)