[TODOMON] EP.7 부하 테스트 계획
·
Project
📝테스트 계획테스트에 들어가기 전에 테스트 계획부터 설정해야 한다.부하 테스트는 시스템의 응답 성능과 한계치를 파악하기 위한 테스트이다.서비스가 어느 트래픽까지 처리할 수 있는지(어느 정도의 부하를 견디는지) → 어떻게 대응할지 알 수 있음병목이 발생하는 부분이 어디인지 → 어떻게 개선할지 알 수 있음주의성능 테스트는 실제 사용자가 접속하는 환경에서 진행해야 한다. 내부 네트워크에서 부하를 발생시킬 경우 응답시간에 차이가 발생할 수 있다.테스트 DB에 들어 있는 데이터 양이 실제 운영 DB와 동일하여야 한다. 통상 전체 성능의 70프로 이상이 DB에서 좌우된다. 데이터 양이 다르면 쿼리 실행 계획이 달라질 수 있으므로 성능이 다르게 나타날 수 있다.외부 요인의 경우 시스템과 분리된 별도의 서버를 구성해..
[TODOMON] Ep.6 Spring Batch 도입기 (+ 멀티스레드를 통한 성능 개선까지)
·
Project
스프링 배치 도입 이유전체 데이터가 트랜잭션 범위이다 보니 관리가 어려움에러 발생 시 전체 롤백..데이터가 많아질 수록 더 효율적인 방법들이 필요함. @Schedule 안에서 모든 작업을 처리하는 방식은 너무 무대뽀임.병렬 처리분할 처리=> Chunk Oriented 프로세싱을 지향하는 스프링 배치는 좋은 선택지가 될 것이라고 생각됨. 청크 기반으로 트랜잭션 단위를 분할하고, 멀티 스레드 기법을 통해 더 나은 성능 및 효율로 데이터를 처리할 수 있음.배치 설계일간 투두 성취 누적 포인트 반영 배치 설계정의: 매일 모든 유저들의 전날 투두 성취를 저장하고, 포인트를 집계하여 반영한다.배치 주기: 매일 새벽 1시 (트래픽이 적은 시기)2개의 Step으로 구성: Member 상태 업데이트 step -> Tod..
[TODOMON] EP.5 견고한(?)결제 시스템 구축기.. with 포트원
·
Project
저번 시간에는 아이템의 효과를 어떻게 적용할 것인지에 대한 포스팅을 해보았다면, 이번에는 아이템을 구매하는 로직에 대한 내용을 포스팅하려고 한다. 투두몬 서비스에는 ⭐️포인트로 구매할 수 있는 아이템과 실결제를 통해 구매할 수 있는 아이템이라는 2가지 종류의 아이템이 있다. 처음에는 이들 각각을 따로 보지 않고, 동일한 '구매' 로직으로 보고 같은 절차를 따라야 한다고 생각했다. 처음 생각한 시나리오는 다음과 같다.포트원에 대한 내용은 과감히 생략하겠다. 공식문서나 다양한 블로그에서 이미 충분히 자세하게 다루고 있다.예상 시나리오아이템 타입에 맞게 사전검증을 수행한다.아이템 유효성을 확인한다 ex) 아이템이 존재하는지, 유저가 구매 가능한 상태인지검증을 수행한다.StarPoint의 경우현재 소유하고 있는..
[TODOMON] EP.4 아이템 기능 구현
·
Project
투두몬 서비스에는 크게 두 가지 방식의 아이템이 있다.구매 후 즉시 유저의 상태를 변화시키는 아이템 (IMMEDIATE_EFFECT)ex) 펫 뽑기, 펫 하우스 확장(+1), 당근(펫 먹이), 유료 플랜 구독권인벤토리에 저장되었다가 사용 가능한 소모형 아이템 (CONSUMABLE) -> 유저가 원하는 때에 사용해야 함ex) 칭호 변경권, 펫 이름 변경권각 아이템마다 호출 시기가 다르므로 아이템의 효과 자체를 Item 엔터티가 갖고 있으면서 이를 원할 때 호출할 수 있도록 해야한다.item.getItemEffect().applyEffect()과 같은 코드를 원할 때 호출할 수 있어야 할 것이다. 이를 실현시키기 위해서는 일단 모든 아이템이 ItemEffect라는 타입의 필드를 갖고 있어야 관리하기 용이할 ..
[TODOMON] EP.3 펫 정보 저장 방식에 대한 고민
·
Project
펫 정보 저장 방식 고민펫(Pet) 정보를 Enum을 통해 메모리에서 관리할지, 데이터베이스에 정보를 모두 넣어 꺼내쓰는 방식으로 관리할지가 고민이었다.각 방식의 장단점을 비교해보자.Enum을 사용하는 경우장점Enum을 사용하면 코드에서 상수처럼 사용할 수 있어서 간단하고 직관적이다. -> 개발 및 테스트하기 편하다데이터베이스 조회 없이 메모리에서 바로 접근하므로 성능이 매우 빠르다 -> 항상 데이터가 캐싱되어 있는 느낌컴파일 타임에 잘못된 값을 방지할 수 있다단점새로운 펫을 추가하거나 기존 펫의 정보를 변경할 때마다 배포가 필요하다대량의 데이터를 담기에는 무리가 있다데이터베이스를 사용하는 경우장점새로운 펫 추가, 정보 수정, 삭제 등을 데이터베이스 쿼리로 쉽게 처리할 수 있다 -> 배포가 필요하지 않다..
[TODOMON] EP.2 투두 달성 보상 기능
·
Project
투두 달성 보상 기능에 대한 고민..우려되는 상황투두를 달성하면 지급되는 보상은 다음과 같다유저 일관성 게이지 증가 (레벨업 시 ⭐️ 포인트 지급)⭐️ 포인트 지급이를 투두 달성 시마다 즉시 제공하면 유저 입장에서는 매우 편할 것이다. 하지만, 투두를 완료하여 지급받은 포인트를 사용한 후 완료를 다시 철회하는 경우.. 마이너스 포인트 상황이 생기게 된다. 포인트 부채 방식을 도입하여 마이너스 상태가 된 포인트를 추가 투두 달성으로 유저가 채우도록 하는 것도 하나의 방법일 것이다. 하지만, 이러한 점을 악용하여 부채를 계속해서 누적하며 포인트를 사용하려는 유저가 생길 수 있을 것이라고 생각했다. 이를 막기 위해 부채의 상한을 설정하고, 유저에게 알림을 줄 수도 있을 것이며 부채를 상환하지 않는 유저에게 디..
[TODOMON] EP.1 투두 비즈니스 로직에 대한 고민
·
Project
투두의 startAt과 endAt을 어떻게 처리해야 할지가 너무 어렵다.. 반복되지 않는 하루짜리 단일 투두의 로직은 매우 간결하지만, 기간이 하루가 아닌.. 예를 들면, '8월 3일 ~ 8월 5일까지 오후 4시에 수행해야 하는 투두'와 같은 것을 어떻게 처리해야 할지가 고민이었다.처음 생각해본 방식은 다음 2가지였다.반복 투두 생성 방식하나의 투두의 startAt을 8월3일16시, endAt을 8월5일16시로 설정하여, 하나의 투두로 관리한다.장점설계가 매우 쉽고, 명확하다.단점이러면 '반복'이라는 느낌이 들지 않는다.따지고 보면 3일동안 수행을 하는 것인데, 하나의 투두는 3일을 하나의 객체로 관리하기에 이 3일 동안의 처리 과정을 트레이싱하기 어렵다.마찬가지로 하나의 객체로 관리되기에 하루하루의 관..
[MY-WAS] 나만의 WAS 만들기 프로젝트 (완) - HTTP 헤더 캐시
·
Project
이번 시간은 마지막으로 ETag 검증 헤더와 If-None-Match 조건부 요청을 사용하여 HTTP 헤더 캐시를 적용해보자. 관련된 내용은 '[Network]HTTP 헤더와 캐시'에서 다루었으니 참고하자.ETag & if-none-match검증 헤더 = ETag, 조건부 요청 = If-None-Match캐시용 데이터에 임의의 고유한 버전 이름을 달아두고, 데이터가 변경되면 이 이름을 변경함(Hash 다시 생성)단순히 ETag만 서버에 보내서 같으면 유지, 다르면 다시 받기서버에서 데이터가 변경될 때마다 ETag가 갱신되며, 이를 이용해 브라우저는 서버에 데이터가 변경되었는지 직접 확인웹 브라우저는 이전에 받아온 응답에 포함된 ETag 값을 If-None-Match 헤더로 사용하여 서버에 요청서버에서 데..
[MY-WAS] 나만의 WAS 만들기 프로젝트 (3) - Session & Cookie & JSON
·
Project
이번 시간에는 단순히 HTML만 내려주는 기능뿐이었던 프로젝트에 실제로 로그인 및 회원가입, 유저 정보 조회, 로그아웃 기능을 추가해보자. 이를 위해서는 WAS 서버에서 쿠키와 세션을 다룰 수 있어야 할 것이다. 더 나아가, HTML Form을 통한 통신뿐만 아니라 JSON을 통한 통신 방식도 지원하도록 개선해보자.역순으로 개발을 진행하면서 필요한 부분을 순차적으로 개발해나가자!UserController로그인 및 회원가입 기능, 유저 정보 조회 기능, 로그아웃 기능을 추가하자public class UserController { ... @RequestMapping("/login-action") public void loginAction(HttpRequest request, HttpRespo..
[MY-WAS] 나만의 WAS 만들기 프로젝트 (2) - 커맨드 패턴, 리플렉션, 애노테이션
·
Project
이전 시간에는 WAS의 아주 기본적인 기능들을 만들어보았다. 기능을 추가하기 전에, HttpRequestHandler의 다음 부분을 보자.private void process() { ... HttpResponse response = null; String requestURI = request.getRequestURI(); if (requestURI.equals("/login")) { response = new HttpResponse(HttpStatus.OK, requestURI, "/login.html"); } else if (requestURI.equals("/register")) { response = new HttpResponse(HttpStatu..