안녕하세요 이번 시간에는 Redis를 사용하는 API의 성능을 개선하는 방법에 대해서 포스팅하도록 하겠습니다.
발생한 이슈에 대해 먼저 말씀드리겠습니다. Redis 접속 로직이 복잡해짐에 따라 Redis를 사용하는 7개의 API 실행 시 약 1600ms 정도의 속도를 보였습니다.
이를 개선하기 위해 Redis 클래스를 수정했습니다. 기존 방식은 Redis에 저장된 값을 조회 또는 Redis에 값을 저장할 때마다 매번 Redis에 접속하였습니다. 하지만 이 경우 불필요하게 Redis에 접속을 많이 하게 되어 오버헤드가 발생할 수 있습니다.
이를 해결하기 위해 정적 팩토리 메서드 패턴을 적용하였습니다. Redis 접속 클래스에 유저 정보 객체를 static으로 선언한 후 해당 값이 null일 경우 Redis에 접속해서 데이터를 가져오고 값을 초기화합니다. 값이 이미 초기화되었다면 해당 값을 리턴합니다. 이는 유저 정보가 자주 변하지 않는 객체이기 때문에 사용하는데 지장이 없으며 이로 인해 약 62.5% 가량 성능을 향상시켰습니다.
@Component
@RequiredArgsConstructor
public final class RedisProvider extends AbstractProvider implements BaseProvider {
private final AuthRepository authRepository;
private final RedisTemplate<String, byte[]> redisTemplate;
private static UserInfoAllDao userInfo = null;
@Override
public void afterPropertiesSet() throws Exception {
}
/**
* Redis key를 매개변수로 Redis에 저장된 값 get
* @param key
* @return
*/
private UserInfoAllDao getRedis(String key) {
byte[] bytes = redisTemplate.opsForValue().get(key);
if(bytes == null) return null;
try {
UserInfoProto.UserInfo userProto = UserInfoProto.UserInfo.parseFrom(bytes);
return UserInfoAllDao.builder()
.userID(userProto.getUserID())
.userCode(userProto.getUserCode())
.email(userProto.getEmail())
.password(userProto.getPassword())
.userName(userProto.getUserName())
.appPassword(userProto.getAppPassword())
.build();
}
catch (Exception e){
throw new WrongAccessException(WrongAccessException.of.REDIS_CONNECTION_EXCEPTION);
}
}
private void setRedis(String key){
UserInfoAllDao userInfoAllDao = authRepository.getUserInfoAll(key);
UserInfoProto.UserInfo userProto = UserInfoProto.UserInfo.newBuilder()
.setUserID(userInfoAllDao.getUserID())
.setUserCode(userInfoAllDao.getUserCode())
.setEmail(userInfoAllDao.getEmail())
.setPassword(userInfoAllDao.getPassword())
.setUserName(userInfoAllDao.getUserName())
.setAppPassword(userInfoAllDao.getAppPassword())
.build();
redisTemplate.opsForValue().set(key,userProto.toByteArray());
}
public UserInfoAllDao getUserInfo(String email){
if(userInfo == null){
UserInfoAllDao userInfoAllDao = getRedis(email);
if(userInfoAllDao == null){
userInfoAllDao = authRepository.getUserInfoAll(email);
setRedis(email);
}
if(!userInfoAllDao.getEmail().equals(email)) throw new WrongArgException(WrongArgException.of.WRONG_BODY_EXCEPTION);
userInfo = userInfoAllDao;
}
return userInfo;
}
}
추후 Redis 접속을 비동기로 처리하여 성능을 개선하는 방법에 대해서 조금 더 알아보는 작업을 진행하도록 하겠습니다. 그럼 이상으로 포스팅 마치도록 하겠습니다!