1. [펀잇] 우리팀 인프라 구조 개선 회의를 했다.
https://github.com/woowacourse/infra-architecture-4/discussions/5#discussioncomment-6985899
우리팀은 기존에 하나의 ec2에
앞단에 nginx를 두고 프론트의 정적 페이지와 백엔드의 was가 함께 돌고 있었다.
우리의 nginx가 하는 일
1. https
2. 포트포워딩
/ 로 요청이 들어오면 -> index.html (프론트의 정적페이지)
/api로 요청이 들어오면 -> http://localhost:8080;
요구사항대로 SPOF를 제거하기 위해 고민을 하다보니 NGINX가 과연 필요할까?라는 고민으로 이어졌다.
ec2 안에 있는 프론트의 정적파일들을 s3로 이동시키고, Route53으로 도메인을 달고 ACM으로 https까지 처리해준다.
ELB를 통해 각각의 WAS에 대한 로드밸런싱 진행
하게되면 NGINX를 제거해도 된다는 결론을 내렸다!
또한 WAS와 DB를 이중화하여 SPOF가 안되도록 한다!
2. 웹 브라우저의 작동 과정..? ㅋㅋㅋㅋㅋ
프론트는 다 정적 페이지로 이루어져 있는데(html, js, css..)
도대체 어떻게! 누가! 요청을 보내는지 계속 헷갈려서
사람들과 한~~~~참 얘기했다. (thanks to 우가, 망고, 솔로스타, 폴로, 글렌)
내 방식으로 이해한 결론은 다음과 같다.
1) 사용자가 브라우저 검색창에 'http://funeat.site'로 접속한다
2) funeat.site에 매핑된 ip에 요청해서 정적파일(index.html)을 받아온다.
3) 해당 페이지에서 '리뷰 작성' 버튼을 누르면!
4) js이 작동해 'http://funeat.site/api/reviews'로 요청
이때 요청 시작점(?)은 'http://funeat.site' 이고
요청 도착점(?)은 'http://funeat.site/api/reviews'이다.
즉, same origin!
3. [펀잇] 우리팀 S3 관련 이슈의 흐름을 되짚어봤다.
리뷰 작성, 레시피 작성에 이미지 업로드 기능이 필요하다.
기존에는 S3가 제공되지 않아 서버가 띄워져 있는 ec2에 저장을 해뒀었는데, 이제 S3와 CloudFront가 제공되어 이미지들을 S3로 이전하기로 했다.
기존 로직을 살려서
프론트에서 백으로 이미지 전송 -> 백에서 S3에 이미지 업로드
로 하려다가
‘굳이 백엔드로 이미지를 보내서 저장할 필요가 없다.
그냥 프론트가 바로 저장하고 백으로 파일명(또는 url)만 보내자’로 결론이 났다.
(서버로 이미지 전송하는 것 자체가 서버에 부하를 주니까)
그래서 프론트가 S3에 업로드 하기로 했다!
하지만 몇가지 방법 시도 끝에..ㅋㅋㅋ
다른 팀들처럼 그냥 백엔드가 업로드 하기로 결론이 났다.
그 과정에 대해 되짚어보자.
📍 첫번째 시도 : EC2에 Role을 부여하고 (프론트가 업로드)
외부에서 S3에 접근하는 방법에는 크게 4가지가 있다.
1. 버킷을 public으로 열기
2. S3에 접근할 수 있는 Role 부여
3. S3에 접근할 서 있는 Access Key 공유
4. 정해진 시간동안 S3에 접근할 수 있는 pre-signed url 사용
1번은 그냥 말도 안되니 아웃
3번은 우테코에서 key 공유 허용 안해줘서 탈락
그래서 2번방법으로 시도했다.
백엔드에서 업로드하는 다른 팀들도 EC2에 Role을 부여하여 S3에 접근하고 있으니,
프론트도 같은 EC2니까 Role로 접근이 되지않을까? 라는 생각. (<-바보였다 ㅜㅋㅋㅋ)
결론만 말하자면 실패했다.
이유는 자격증명이 안돼서! (Role로 접근 실패)
백엔드에서 업로드하는 경우 aws관련 라이브러리로 instance의 credential을 가져오던데,
프론트는 관련 라이브러리가 없어서 실패했다.
(생각해보면 당연하다. 프론트의 요청은 인스턴스가 아닌 웹브라우저가 하는데 정적페이지가 담긴 인스턴스의 정보를 긁어올 수 없지)
📍 두번째 시도 : pre-signed url (프론트가 업로드)
정수기 앞에서 레오랑 s3에 대해 토론하고 있었는데
지나가던 안드로이드 코치 레아께서 말씀해준 방법!
pre-signed url이란 정해진 시간동안 해당 S3에 접근할 수 있는 url이다.
플로우는
프론트에서 백으로 pre-signed url요청
백이 s3로부터 pre-signed url 발급받아서 프론트에게 반환
프론트는 pre-signed url에 이미지 업로드
이런식이다!
결론만 말하자면 얘도 실패했다 ㅎ
위의 플로우로 다 만들었는데 cors에러가 나서
s3에 cors설정을 해도되는지 토미께 여쭤봤는데!
보안상의 이유로 불허하셨다 ㅠㅅㅠ
(cors설정을 하게 된다면 우리팀 도메인인 funeat.site를 열어줄 예정이었다)
📍 세번째 시도 : 백엔드가 업로드
결국~~~
다른 팀들처럼 백엔드가 업로드 하기로 했다.
근데 또 뭔 에러가 났는데
이유를 짧게 설명하자면
버킷이 private인데 public read로 보내서 그랬던거였다.
이상 펀잇의 S3 삽질 끗~~~
4. [펀잇] 팀원들과 ReviewCount와 FavoriteCount에 대해 논의하고 반정규화로 결정했다.
Favoritecount
- 반정규화된 상태 (review, recipe가 column으로 가지고 있음)
- 사용자가 우다다 가능 (변동자주)
- 크기 한계가 있음 (사용자X리뷰). 하지만 늘기쉬움.
- 상품 상세 페이지에서 '리뷰 목록 조회'에 사용됨
ReviewCount
- 정규화된 상태 (product가 가지고 있지 않음)
- 사용자가 우다다 불가 (변동천천)
- 크기 한계 없음 (사용자X상품X??). 하지만 늘기어려움.
- 사용자가 가장 많이 접근 하는 페이지인 '상품 목록 조회'에서 사용됨
(상품 10개씩 페이징되어 나옴 -> join 10회)
결론 : FavoriteCount와 ReviewCount 모두 반정규화 하자
(+ 나중에 데이터 많아지면 스케줄러로 갱신)
https://github.com/woowacourse-teams/2023-fun-eat/pull/616
그래서 Product 엔티티에 reviewCount를 추가했다!
동시성 문제 관련해서 로건이 `AtomicInteger`를 제안했다.
기존 favoriteCount관련 동시성 문제에서는 @Lock(PESSIMISTIC_LOCK)으로 해결했는데,
reviewCount관련 동시성 문제에서는 AtomicInteger를 이야기하길래
이유가 궁금했는데!
favoriteCount같은 경우에는 reviewFavorite이라는 테이블이 연관되어 있어서 좀 더 복잡하고,
reviewCount는 별도의 연관 테이블이 없어서 AtomicInteger로 해결이 가능하다
라는 느낌으로 설명들었다.
근데 잘 몰라서 ㅎ 관련해서 좀 더 공부해봐야 할 것 같다~~