42partner-backend's Issues
1. 수정 이유
- session이 client에게 잘 전달 되지 않음.
- loadbalance사용하면서 clustered session 대신 jwt를 쓰기로함.
2. 수정 내용
1. 기존 코드 문제점
2. 리팩토링 내용
1. 기존 코드 문제점
- spring batch 기능을 추가할때 module을 분리하여 따로 빌드할 필요가 있음.
2. 리팩토링 내용
- api, core, common, batch 등으로 모듈을 불리할예정.
1. 기존 상태
- random match batch 에서 redis 트랜잭션이 적용되어 있지 않음.
- redis에 상태 변경 쿼리를 날리고 커밋하는 트랜잭션을 하나로 묶어야함.
- 마찬가지로 mysql에 날리는 commit도 하나로 묶어야함.
- mysql commit바로 이전 시점에 redis commit을 하여 둘중 하나만 commit되는 것을 최대한 방지
- 원래는 둘 모두 commit 되게 하거나 rollback되도록 해야하지만 2 Phase commit을 redis가 지원하지 않고
- event Queue등을 활용하기에는 시간이 부족하여 이렇게 임시방편으로 활용.
2. 성능 개선 지점
- 트랜잭션을 한번에 진행하기 때문에 성능이 향상됨.
- 데이터 정합성이 (redis, mysql간의) 떨어지는 경우가 발생할 수 있지만 실질적으로는 거의 발생하지 않게 됨.
3. 예상 결과
1. 기존 상태
2. 성능 개선 지점
- article 조회 시 Throughput상승
- article 조회 시 Response Time 상승.
- DB부하 줄이기 위해 분산 캐시 활용, local cache는 데이터 정합성을 맞추기 힘들고 SSEmitter in-memory 저장 및 현재 heap memory 용량상 예상치 못한 메모리 관련 에러 발생 가능성 때문에 분산캐시 활용. DB부하를 줄이기 위한 목적이 크기 때문에 분산캐시로도 충분하다고 판단.
- Write Through
- 적정한 TTL만료시간 설정(현재는 10초 예상.)
3. 예상 결과
- db 조회 부하 완화로 같은 조건 시나리오의 부하 테스트 시 DB 부하 개선. 및 RDS CPU 사용률 감소.
- Throughput상승 및 Response Time정상화(현재는 병목 지점에서 5초까지 상승.).
1. 기존 상태
- 목록을 받아오는 API의 경우 오프셋 기반으로 요청을 하게됨.(Slice라서 Count를 하지는 않음.)
- 현재 Frontend API의 스펙을 변경시킬 수는 없기때문에 Version 2 API 로서 구현할 계획.
- RDBMS의 성능 개선을 보기위해 Redis 캐싱 기능 배제하여야함.
2. 성능 개선 지점
- 테이블의 레코드가 많은 경우 OffSet기반일 때 Offset적용을 위해 스토리지 엔진으로 부터 읽어와야 하는 레코드가 많아지기 때문에 이부분을
커서 기반으로 변경할 경우 I/O감소로 성능 향상이 기대됨.
- RDS의 메모리 , I/O를 주로 보고, CPU성능 부하도 볼 계획.
3. 예상 결과
- 동일 시스템 스펙에서 전반적인 조회 TPS, 응답속도 향상이 기대됨.
- RDS의 메모리 사용량, I/O등이 감소할 것으로 예상됨, CPU사용률의 경우 감소한다는 보장은 없을듯함.
1. 기능 상세
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기존 상태
DBCP, Thread Pool 이 기본으로 설정되어있음.
2. 성능 개선 지점
DBCP가 적게 되어있어서 병목이 발생함.
Thread pool이 무한정 증가하는 것을 막을 수 있음.
3. 예상 결과
병목 제거 및 하드웨어 자원 활용.
1. 기존 코드 문제점
- scheduling 작업을 통해 랜덤매칭을 주기적(10초)으로 조회하고 매칭 조건을 맞는 대상을 맺어줌.
- polling으로 인해 불필요한 조회가 지속됨.
- 배치 서버가 따로 필요함.
- 기존에는 해당 코드를 랜덤 매칭 신청 시 수행할 경우 동시에 요청이 들어오거나 할 때 매칭이 맺어질 수 있음에도 맺어질 수 없는 경우(거의 동시에 요청이 발생한 경우)가 발생할 수 있었음.
2. 리팩토링 내용
- 해당 코드를 매칭 신청 시 이벤트큐에 produce하는 형태로 변경
- 혹시나 이벤트 consume(랜덤 매칭을 맺어주는 작업을 수행)가 실패하더라도 ack를 통해 재실행을 보장하고 매칭이 맺어질 수 있는 환경에서 무조건 맺어지도록 할 수 있음.
- event queue를 활용하여 비동기적으로 하나의 api 요청자체와 무관하게 동작시킬 수 있음.
1. 기능 상세
- User Entity설계
- 가능한 정도까지 DB설계
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기능 상세
2. 수정, 리팩토링, 버그발생 예상 지점
1. 원래 Redis를 사용한 이유
- SortedSet 자료구조로 해주기 때문에 저장 해서 매칭 기록을 관리하는 것 만으로도 매칭 로직을 간접적으로 구현할 수 있음.
- SortedSet의 key값을 매칭 조건을 조합해 만든 문자열로 만들면 매칭 채널을 분리할 수 있음
- SortedSet 내에서 score와 Value를 기준으로 정렬되어 저장됨.(Tree구조)
- 원래는 Score값을 기준으로 정렬 하지만 Score값이 같으면 value를 기준으로 정렬이 이루어지고 value값에 매칭 신청 시간 + memberId 값의 구조로 만들면 매칭 신청 시간을 기준으로 정렬됨.
- appliaction Server에서는 SortedSet들을 조회해 SortedSet내부의 요소개수가 매칭 인원을 충족하는지만 검사하면됨.
- 매칭 신청 데이터는 schema가 변동 가능성이 크고 데이터가 오래 잘 유지 될 필요는 없는 데이터라고 판단 했음.
- In memory이기 때문에 RDB에 I/O 속도 측면에서 더 빠르고 RDB로 구현 할 경우 application Server에서 신청 기록을 분류하고 정렬하는 작업을 매 batch program이 수행해야함(Redis는 저장하는 것 만으로 이작업이 처리됨).
- RDB의 부하를 줄여줄 수 있음.
- 공부 목적.
2. 개발 과정에서 생긴 여러 문제점으로 Redis포기
- 분산된 여러 DataSource를 사용하게 되면서 각각의 노드간에 데이터 정합성 불일치의 문제가 생길 수 있고 이를 관리하는 것이 매우 힘들다는 것을 알게됨.
- 대표적으로, Batch server가 Redis를 조회하여 매칭이 가능한것을 확인하였을 때 먼저, Redis에서 신청 기록을 제거하고 매칭이 맺어진 결과를 RDB의 Match table에도 저장해야함. 이 과정이 하나로 atomic 함이 보장 되지 않으면 데이터 일관성 손상될 수 있음. 매칭이 한번 이미 맺어졌지만 Redis에서 신청기록이 제거되지않아 Batch server가 실행될 때마다 무한하게 매칭이 맺어질 수 있음.
- 이를 해결하기 위해서는 2 Phase Commit을 활용하거나 메세지 큐 같은 것을 추가로 활용하여 Redis, RDB 모두 Rollback하거나 Commit해야함.
- 문제는 Redis가 2 Phase Commit을 지원하지 않고 지원하더라도 2 Phase Commit은 트랜잭션을 자신의 데이터를 처리하지 않는 시간에도 오래 지속해야하기 때문에 성능적인 낭비가 있음.
- 메세지 Queue를 추가로 도입하기에는 학습을 해야할 뿐만 아니라 배보다 배꼽이 커지고 있다는 생각이 듬.
- Redis를 활용해 매칭 batch application에서 최초 매칭 신청 현황을 보고 매칭 결과를 exec하는 구간에서 데이터 변경을 막기가 매우 힘듬.
- Batch server에서 매칭을 맺어주는 것과 매칭 취소 신청은 Serializable 하게 이루어 져야 하고 이를 Redis로 구현할 경우 transaction을 사용하여 해결 할 수 있을 것으로 생각함.
- 문제는 Spring 에서 사용하는 RedisTemplate의 경우 Transaction사용 시 조회 할 때 항상 null을 return 함. (Redis 트랜잭션을 한 단위의 네트워크 통신하는것으로 생각하기 때문에 트랜잭션 내에서 조회를 하더라도 조회가 되지않고 트랜잭션)
- 다른 방법으로 Watch를 활용해 락을 걸고 조회는 외부에서 하는 방법이 있는데 낙관적 락임에도 매칭 신청, 취소 요청과 batch 프로그램 매칭을 맺어주는 로직 사이에 충돌이 빈번하여 문제가 될 수 있음. 이를 처리하기 위한 로직을 추가로 굉장히 많이 작성해야함.
- RDB로 데이터를 작성하여 비지니스로직을 작성했을 때와 달리 코드가 매우 복잡하고 관리하기 힘들어짐.
- 매칭 저장 SortedSet의 경우 <String, String>의 형태를 가지고 있을 뿐인데 여기에 비지니스 로직을 작성했을 때 알아보기도 힘들고 객체 지향적인 코드도 아니면서 테스트하기 힘든 코드가 작성되었음.
1. 기능 상세
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기존 상태
- Redis cache 만료 시간 TTL이 5초로 되어있음.
2. 성능 개선 지점
- TTL 만료시 HotKey인 경우 Cache Stampede현상이 발생할 수 있음.
- 이를 대비하기 위해 Probabilistic Early Recomputation을 도입. -> 자주 참조되는 키는 확률적으로 만료 전에 갱신됨.
3. 예상 결과
- TTL만료 시 RDBMS로 부하가 쏟아지는 Cache Stampede 현상을 줄일 수 있을 것으로 예상됨.
4.먼저 해결해야하는 부분
- JMeter를 Local 에서 실행하고 있는데 Thread 생성 개수 제한이 있고 부하 테스트 제한이 있기 때문에 분산환경으로 올려야할 필요가 있음.
1. 수정 이유
- 로그인 실패시 api 페이지가 그대로 보이며 프론트엔드로 리다이렉션 되지 않는 문제가 있음.
2. 수정 내용
- 로그인 실패시 frontend 루트로 Redirection하고 쿼리 파라미터로 login_success=fail을 보냄.
- 랜덤 매칭 참여자가 조건 개수만큼으로 계산되는 버그 쿼리를 수정해야함.
1. 기능 상세
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기능 상세
- Redis Client 설정
- RandomMatch 신청
- RandomMatch 취소
- RandomMatch 상태 조회(api 조회 형식으로 할 지, 서버에서 배치서버가 주기적으로 응답주도록 할지, 아예 안할지) - 매칭 여부는 알수있어야함 DB에서 Match에서 Random + createdAt이전에 된걸로 조회해서 확인.
- Spring batch 매칭 or scheduling
- RandomMatch전체 조회
- transaction start
- RandomMatch 매칭 맺어질 사람 있는지 확인
- Random Match매칭 맺어지면 RandomMatch 정보 삭제
- Match table에 등록
- transaction end
- Async로 slack알림 주기.
2. 수정, 리팩토링, 버그발생 예상 지점
1. 수정 이유
2. 수정 내용
- Match 기록 단건 조회 api추가, Article조회 시 userId필드 추가
1. 기존 상태
- @Version annotation으로 인해 OptimisticLockException 발생 가능
2. 성능 개선 지점
- 낙관적 록으로 인한 충돌이 발생하면 재시도 하는 기능을 추가한다.
- AOP를 통해 핵심기능에서 벗어난 재시도 보조기능을 공통관심사로 관리할 수 있게 된다.
3. 예상 결과
1. 기존 상태
- access token만을 인증에 활용하여 만료기간을 길게 두었기 때문에 보안상 취약점이 있었음.
2. 성능 개선 지점
- access token의 만료 시간을 5분으로 두고 refresh_token의 만료 시간을 2주로 두어 보안성 강화
3. 예상 결과
- 전반적인 보안성이 강화됨.
- refresh token을 어디에 보관할 지 고민해야봐야함. 현재로서는 브라우저의 cookie에 저장하는 방식 고려중.
1. 기능 상세
2. 수정, 리팩토링, 버그발생 예상 지점
1. 수정 이유
- kafka를 통해 알림을 생성하는 것과 sse알림을 보내는 기능이 하나의 consumer이 수행함.
- 트랜잭션 내에서 kafka 이벤트를 발행하기 때문에 롤백 되어도 이벤트가 발행될 수 있음.
2. 수정 내용
- 알림을 생성하는 것과 sse알림을 보내는 것을 같은 이벤트에 대해서 다르게 처리하는 Consumer group두개로 분리 및 Kafka Consumer Config변경
- 트랜잭션 외부에서 이벤트 발행
1. 기능 상세
- sse를 활용하여 백엔드에서 프론트로 알림 제공.
- 내가 참여한 글이 확정 된 경우.
- 식사인지 공부인지, 글 제목, 확정자 수
- 자세한 매칭 내역 링크
- 랜덤매칭이 잡힌 경우.
- 매칭 인원들, 식사 인지 공부인지
- 자세한 매칭 내역 링크
- 내가 작성한 글에 누군가 참여한 경우.
- 내가 작성한 글에 누군가 참여를 취소한 경우.
2. 수정, 리팩토링, 버그발생 예상 지점
- 알림을 주는 시간과 대상 내용이 달라질 수 있음.
1. 기능 상세
- EC2단독으로 되어있는 dev서버에 dev 브랜치 push시 자동적으로 빌드 및 배포 되도록 CICD파이프라인 구성
- 실제 운영 서버는 Main 브랜치에 push시 CICD시 적용되도록 따로 설정
- ASG를 사용중이기 때문에 이 부분에서 더 학습해서 추가해야함.
- appspec.yml, github action의 deploy.yml, ec2내에 code-deploy-agent 설치 및 실행
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기능 상세
- 제목
- 항목별 선택(방 전체 목록에서 보여주기 위해서)
- 본문
2. 수정, 리팩토링, 버그발생 예상 지점
- 댓글 -> Opinion에서 다시 만들것.
- 댓글은 대댓글로 변경될 수 있음.
1. 기존 상태
2. 성능 개선 지점
3. 예상 결과
1. 기능 상세
2. 수정, 리팩토링, 버그발생 예상 지점
1. 수정 이유
- www.42partner.com 으로 프론트 도메인 고정
- Cloudfront + s3형태에 맞추어 프론트 배포
- Authorization header로 JWT 필터링
2. 수정 내용
1. 기능 상세
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기능 상세
- 처음 OAUTH로그인 실행시 회원가입 진행
- Access Token은 바로 폐기 (분실 시 authorization server 까지 계정정보가 털릴 우려가 있으며, 로그인 된 상태에서 다시 자원을 요청할 일이없음.)
- Session을 통해 로그인 시간 관리.
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기능 상세
- 주기(10초~20초)적으로 랜덤 매칭을 맺어줌.
- 모든 방 조회(Set으로 가져오기, 정렬된 set).
- 모든 방 스캔하면서 생성된지 30분이 넘은 데이터 collection에서 제거하고 따로 id값 기입.
- 각 방 조회 순서 랜덤으로 정함(여러 매칭 조건이 가능한 경우 평등하게 매칭이 되게 하기 위해서).
- 매칭인원(4명 예상)이 되면 생성 시간 기준 빠른 사람 부터(queue)4명씩 짝지음.
- 짝 지어진 경우 collection 에서 바로 제거하고 따로 id값 저장.
- 모든 매칭이 끝 난경우 매칭이 끝나거나, 만료된 사용자 redis에서 지우고 DB에서 isCanceled = true로 바꿈.
- 매칭 된 사용자 로 Match table db생성, random 신청 내역과 연결하는 것은 생각해 봐야할 것 같음.
- Activity점수 부여
- 알림(비동기)
- quertz로 이 행동을 주기적으로 실행시킴
- 배포 시 spring batch서버를 따로 띄움.- stand by로 ec2하나 더 있으면 좋을 것 같음.
2. 수정, 리팩토링, 버그발생 예상 지점
- isCanceled라는 이름보다 만료 되었다 정도의 의미가 더 나을 것 같음.
- 트랜잭션 구간을 어떻게 설정할지(중간에 예외 발생 시 어떻게 처리할지), 비동기 기능 어떻게 db랑 분리할지.
- redis의 트랜잭션에 대한 이해,
1. 기능 상세
- 프로젝트 구조 설정
- 디렉토리 구조
- swagger, BaseEntity,
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기존 상태
- 멀티 키 인덱스의 경우 컬럼 순서에 따라 인덱스 적용이 달라질 수 있다는 것을 알게됨
- 기존의 방식의 경우 쿼리문을 통해 인덱스가 잘 적용되지 않는 경우였음.
- ConditionCategory,
2. 성능 개선 지점
- 멀티 키 인덱스가 where 조건절 사용 시 인덱스 레인지 스캔을 할 수 없는 방향으로 작성되어 있었음.
- 반정규화된 테이블 이기 때문에 각각 멀티 키 인덱스를 적용해야함.
3. 예상 결과
- index full scan -> index range scan
- 옵티마이저 실행 계획을 공부해서 분석해볼 계획.
1. 기능 상세
- Logback 설정
- resource 파일 관련 설정 수정
- 테스트 서버 cicd적용
2. 수정, 리팩토링, 버그발생 예상 지점
1. 기존 코드 문제점
- Service Layer의 단위 테스트 필요
- 단위 테스트 하기에 적합하지 않은 메서드들 리팩토링
2. 리팩토링 내용
1. 기존 코드 문제점
- Article, Match, Activity에서 연관관계가 달라지는 경우에만 상속으로 Inheritance활용하는 것으로 결론.
- MatchCondition 활용 할때 외래키 둘 필요 없음.
2. 리팩토링 내용
- 공부, 밥의 경우 enum필드로,
- Match만 랜덤, 방에 따라서 나누어 주면 됨.
- Activity의 경우 점수 부여 이유를 어떻게 줄까 Match와 연관 관계 맺기 (만약 향후 댓글 등록 시에도 점수가 부여된다고 하면 이것도 추가 하면 될것.)
1. 기존 코드 문제점
- test code 에서 불필요한 객체를 생성하거나 테스트 메서드 명이 불 명확하거나 하나의 메서드에서 여러 케이스의 테스트를 진행하는등의 문제가 있음.
- 프로덕션 코드가 테스트 하기 부적합한 경우가 있음.
- Service Layer및 통합 테스트가 적절히 수행되지 않은 경우가 있음.
2. 리팩토링 내용
- test code 메서드 명과 given영역을 복잡하지 않게 리팩토링
- 프로덕션 service 코드에서 entity 생성, 수정 시 id 값만 반환하는 경우가 있는데 전체 entity를 반환하도록 수정.
- 전반적인 테스트 코드 더 다양하게 수정.