ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] Redis를 활용한 성능 향상
    프로젝트/뉴스타 2024. 6. 16. 10:00

    Redis를 활용한 성능 향상 왜 궁금했을까❓

    뉴스타 서비스는 비로그인 서비스로 사용자 식별을 위한 고유 키값을 발급해 준다. 해당 키는 서비스를 이용할 때, 지속적으로 검사하는 과정이 존재하는데 MySQL에서 값을 조회하게 된다. 빈번한 디스크 I/O로 인해 DB에 부하가 갈 것이라 생각되어 In-Memory 방식인 Redis를 캐싱 서버로 활용하여 성능을 향상시키고자 한다.

     

    1. 서비스 흐름도

    1. 사용자가 서비스에 접속하면 UUID 발급 API를 서버에 전송한다.
    2. API 서버는 UUID를 생성하고 MySQL 서버에 저장한다.
    3. 생성된 UUID를 사용자에게 응답한다.
    4. 사용자 API를 사용할 때, UUID를 헤더에 담아 API 서버에 요청한다.
    5. 올바른 사용자인지 확인하기 위해 MySQL에 있는 UUID를 조회한다.
    이와 같은 서비스 흐름도로 인해 사용자가 API를 요청할 때마다 MySQL DB에 접근해야하는 문제점이 존재했다.

     

    2. Redis를 적용한 서비스 흐름도

    1. 사용자가 서비스에 접속하면 UUID 발급 API를 서버에 전송한다.
    2. API 서버는 UUID를 생성하고 MySQL 서버에 저장한다.
    3. 생성된 UUID를 사용자에게 응답한다.
    4. 사용자 API를 사용할 때, UUID를 헤더에 담아 API 서버에 요청한다.
    5. Redis에 해당 UUID가 존재하는지 조회한다.
      1. 존재할 경우, 요청을 넘긴다.
      2. 존재하지 않을 경우, MySQL에 UUID를 조회하고 Redis에 저장하고 요청을 넘긴다.
    Redis를 활용하여 MySQL의 I/O를 줄이고 캐싱 서버로 활용함으로써 성능을 향상시킬 수 있다.

     

    3. 프로젝트 적용

    public class MemberAuthenticationFilter implements Filter {
    @Override
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
          throws IOException, ServletException {
          ...
          try {
              // 회원을 선별하는 UUID 값
              String uuid = servletRequest.getHeader("X-User-Id");
              // 빈값 체크
              if (!StringUtils.hasText(uuid)) {
                throw new GlobalException(ErrorCode.KEY_NOT_FOUND);
              }
              
              // redis 접근
              Long memberId = redisTemplate.opsForValue().get(pw);
    
              // DB 접근 (redis에 UUID로 만든 key가 없으면 DB에서 찾아오기 + redis에 저장하기)
              if (memberId == null) {
                Member member = memberRepository.findByPw(pw).orElseThrow(
                    () -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND));
                memberId = member.getId();
                redisTemplate.opsForValue().set(pw, memberId);
              }
    
              servletRequest.setAttribute("memberId", memberId);
              chain.doFilter(request, response);
            } catch (GlobalException e) {
            setErrorResponse(servletResponse, e.getErrorCode());
            }
        }
    }
    • 4 ~ 5의 과정을 코드로 작성한 것이다.
    public class MemberService {
      public Member createMember(MemberRequest memberRequest) {
        // UUID 발급
        String uuid = UUID.randomUUID().toString();
        Member member = Member.createMember(uuid);
        memberRepository.save(member);
        ...
        return member;
      }
    }
    • UUID 발급 API 비즈니스 로직이다.

     

    4. 성능 지표

    MySQL을 활용하여 UUID 조회

    Redis와 MySQL을 활용하여 UUID 조회

    MySQL만을 사용할 때는 102ms의 시간으로 응답이 오는데 Redis와 같이 사용할 때는 21ms의 속도를 보이며 약 5배 향상된 결과를 나타냈다.
Designed by Tistory.