뱅크셀러드 같은 예산 관리 애플리케이션 API를 개발하고 있는데, 여러 기능 중 이번 달에 설정할 예산을 추천해주는 기능을 개발하고 있었다. 사용자가 예산금액을 입력하고 서버에 보내면, 서버는 이번 달에 이미 예산을 설정한 기존 사용자들을 통계내서 각 카테고리별 예산 금액으로 추천해주는 흐름이다. 저장돼있는 예산을 카테고리별로 그룹화한 후 각 그룹의 예산 금액을 더한 값에서 총 예산 금액의 합을 나누면 평균 비율을 계산할 수 있다. 네이티브 쿼리로 작성된 로직은 다음과 같다. select SUM(amount) from budget b 먼저 모든 예산 금액의 합을 구한다. 이렇게 구한 총 금액과 사용자가 이번달에 설정할 예산금액을 가지고 각 카테고리별 예산 금액을 추천한다. 추천하는 쿼리는 다음과 같다. ..
브라우저에서 음성채팅을 구현하기 위해 웹에서 실시간 미디어 스트림을 송수신할 수 있는 WebRTC 기술을 사용했다. 먼저 어떻게 동작하는지 알기 위해 표준 방식인 P2P를 구현한 데모코드를 실행해봤다. 아래는 P2P방식의 서버 코드다. 그런데 이상하지 않은가? P2P방식의 가장 큰 특징이 중간 서버를 거치지 않고 Peer간 직접 통신을 해 지연시간이 낮다는건데, 그럼 아래의 서버 코드는 뭘까? 바로 시그널링 서버다. 시그널링 서버는 피어 간 연결을 맺기 위한 메타데이터를 교환하는 역할을 담당하고 있다. 즉, 실제로 미디어를 송수신하는 것은 피어 간 직접적으로 수행되고 해당 서버는 실시간 미디어스트림을 송수신 하기 전 피어들을 연결시키는 역할이다. const express = require("express..
nGrinder는 네이버에서 만든 오픈소스로, 성능 테스트를 쉽게할 수 있게 도와준다. nGrinder로 성능 테스트를 하기 위해선 Controller, Agent, Target Server가 각각 별도로 실행되어야 한다. Controller: 테스트 스크립트를 작성하고, Agent에 명령을 해서 테스트를 시작할 수 있도록 하는 웹서버다. 실행중인 테스트를 모니터링하거나, 테스트 결과를 시각화한 UI를 제공한다. Agent: 실질적으로 부하를 발생시키는 역할이다. Controller에서 작성된 스크립트에 따라 Target Server에 부하를 발생시킨다. TargetServer: 말 그대로 테스트를 진행할 서버를 말한다. 그럼 Controller와 Agent를 설치하고 실행해보자. 먼저 nGrinder에..
Electron앱을 패키징했다. 근데 앱 용량이 너무 크다. 원래 일렉트론으로 만든 앱 용량이 기본적으로 크다곤 하지만, 대표적인 Electron앱인 디스코드는 392MB, vscode는 549MB다. 그래서 어떻게 줄이는지 찾아보다가, 배포할 때 제외할 리소스를 극한으로 설정하거나 필요없는 라이브러리는 삭제시키면 된다는 해결방법이 대부분이었다. 하지만 필요없는 라이브러리 삭제같은 해결방법은 기존부터 해왔기에, 용량을 다이나믹하게 줄이려면 다른 방법이 필요했다. 그러다가 electron-react-boilerplate를 찾았고, 혹시라도 보일러플레이트 앱을 패키징하면 용량이 작게 나올지도 모른다는 생각에 설명에 적힌대로 빌드를 해봤다. git clone 후 git clone https://github...
문제상황 아래코드는 유저의 pk로 유저 관련 정보를 조회하는 로직이다. 간단하게 id로 유저를 찾은 뒤 DTO로 변환시킨다. 여기서 getUserPort에 집중해보자. @Override public UserResponseDto getUser(Long id) { var user = getUserPort.getUser(id); return userMapper.of(user); } getUserPort는 유저를 들고오는 getUser 메서드를 정의한 인터페이스다. public interface GetUserPort { User getUser(Long id); } getUserPort의 구현체는 다음과 같다. @Override public User getUser(Long id) { return userRepos..
문제상황 성능 개선에 관심이 생겨서 그동안 안보고 피했던 로그를 보던 중 성능을 저하시키는 쿼리가 나가고 있었다. 바로 로그인을 할 때 알람 엔티티가 조회되는 것이다. 유저와 알람은 1대1 양방향 관계고, 알람이 유저의 pk를 들고 있다. 로그인시 이메일과 비밀번호 확인을 위한 유저 조회 유저조회 쿼리를 날린 후 알람 엔티티 조회한다. 먼저 어느부분에서 알람 조회 쿼리가 날라가는지 알기 위해 어설프지만 로그를 찍어봤다. @Override public TokenResponseDto login(UserLoginRequestDto requestDto) { log.info(">>>>>>>>>1"); User user = getUserPort.getUserByEmail(requestDto.getEmail()); ..
이번 포스팅에서는 조회수가 무한 증가되는 것을 방지하는 방법들을 설명하겠다. 먼저 조회수가 무한 증가가 되는 것이 어떤 말인지 알아보자. 모든 코드는 깃허브에 있습니다. 조회수 무한 증가 조회수가 무한으로 증가된다는 뜻이 무슨 말일까? 원래라면 한 게시글은 하루에 단 하나의 조회수만 올라가야 한다. 내가 2번 봤다고 해서 2번 올라가는 것이 아닌, 사용자마다 하루에 단 한 번만 올라가야 된다. 만약 한 사용자가 한 게시글을 볼 때마다 조회수가 올라간다면 조회수라는 의미가 없어진다. 따라서 게시글을 볼 때마다 무작정 조회수가 올라가는 것을 조회수 무한 증가라고 한다. 아래 코드를 보자. public QuestionResponseDto getQuestion(Long id) { Question question..
이번 포스팅에서는 좋아요 개수 조회 성능을 개선해보도록 하겠다. 모든 내용은 테코블 블로그를 참고하였습니다. 모든 코드는 깃허브에 있습니다. 성능 개선 전 현재 상황은 질문글을 전체 조회할 때 발생하였다. 만약 질문글을 전체 조회할 때 아래와 같은 속성을 응답해야 된다는 요구사항이 왔다고 가정해보자. 질문글 PK 질문글 상태 제목 카테고리 댓글 개수 좋아요 개수 등록한 날짜 UI로 본다면 아래와 같은 모습이다. (예시 사진입니다.) 이 때, 각 질문글은 좋아요 개수를 가져오기 위해 좋아요 테이블과 조인하여 조회한다. 조인하는 이유는 단순히 좋아요만 누르는 것이 아닌 좋아요를 누르고 한번 더 누르면 삭제할 수 있어야 하기 때문이다. 각 질문글을 조회하는 쿼리는 다음과 같다. 나머지는 질문글 테이블에 있는 ..
Redis로 로그아웃 토큰 방식에서 로그아웃 하기 위해서는 토큰의 만료시간을 만료시키거나 토큰 자체를 삭제해야 한다. 하지만 토큰의 만료시간은 직접 조작할 수가 없다. 실제로 로그인을 유지시키는 에세스 토큰을 서버가 가지고 있지 않기 때문이다. 토큰 자체를 삭제하는 방법도 불가능하다. 만약 요청에서 받아온 토큰을 삭제하더라도 클라이언트 입장에서는 그대로 들고있는 것이기 때문에 토큰을 삭제하는 의미가 없다. 그래서 다른 방법을 사용한다. 사용자가 로그아웃 요청을 보낸다. 이 때 요청헤더에서 에세스 토큰을 찾아서 넘겨준다. @DeleteMapping("/logout") public void logout(HttpServletRequest request) { authService.logout(request.ge..
- Total
- Today
- Yesterday