안녕하세요
오늘은 저희 회사에서 레디스를 사용하는 방법에 대해 소개 드리겠습니다!
레디스 적용하게된 이유
저희 회사가 약 10년이 넘게 쌓아온 DB, 컨텐츠팀 && 기획팀에서 수시로 추가되는 기능들 때문에
DB구조가 엉망이 되었고 간단한 스드메 리스트를 가져오는데 부가적인 기능들을 다 포함하면 Join 테이블이 6~10개 정도가 됩니다.
(웨딩홀, 협력사등등 메인카테고리가 "브랜드"로 같음에도 테이블이 따로 있는 경우 이외 다른 이유들)
사진으로 예를 들면 "상록아트홀"에 BEST라는 아이콘을 뽑아오기 위해 테이블을 1~3개를 조인을 통해 가져올 수 있습니다.
그래서 이런 525개라는 적은 데이터를 받아오는데 1~3초가 걸렸습니다.
리스트를 불러오는데 3초라는 시간은 엄청 긴 시간이고 개선이 필수적이였습니다.
레디스를 사용하자
const getRedisData = await this.cacheService.get(`/api/v1/brand/detail/${params.entCode}`);
//레디스 데이터
if (getRedisData) {
await this.cacheService.set(
`/api/v1/brand/detail/${params.entCode}`,
getRedisData,
60 * 120,
);
return getRedisData;
} else {
//레디스 데이터가 없으면
const infoData = await this.DetailBrandService.infoData(params);
const recommendComment = await this.DetailBrandService.recommendComment(
params,
infoData?.category,
);
//이번 분들에게 추천드려요!
const userRecommend = await this.DetailBrandService.userRecommend(params);
// 리뷰
const reviewList = await this.DetailBrandService.reviewList(params);
// 쿠폰
const couponData = await this.DetailBrandService.couponData(params);
await this.cacheService.set(
`/api/v1/brand/detail/${params.entCode}`,
{
infoData,
reviewList,
recommendComment,
couponData,
userRecommend,
},
60 * 120,
);
return {
infoData,
reviewList,
recommendComment,
couponData,
userRecommend,
};
}
디테일 화면의 데이터를 불러오는 api 소스 코드이다.
레디스 데이터에 /api/v1/brand/detail/${params.entCode}라는 주소의 Key를 조회하고 데이터가 존재한다면
해당 키의 데이터를 한번 더 레디스 유효기간을 갱신해주고 클라이언트로 return 한다.
반대로 getRedisData에 데이터에가 존재하지 않는다면 MariaDB에서 데이터를 받아서 /api/v1/brand/detail/${params.entCode}라는 Key로 레디스 데이터를 저장해준뒤 해당 데이터를 클라이언트로 return한다.
정말 간단하지만 효과가 확실하다. 만약 레디스DB의 데이터를 불러오게 된다면 0.5초안에 클라이언트와의 통신이 끝난다.
하지만 sqlDB에서 데이터를 뽑아온다면 1~3초의 시간이 걸린다.
레디스 적용 시 주의사항(추가작업?)
레디스는 정적인 데이터이다. 만약 리스트중 하나를 찜 혹은 좋아요. 클릭하여 적용 시 레디스 데이터는 변함이 없을 것이다.
기존의 저희 회사의 코드는 NodeJS에서 유저별 찜 테이블을 Join하여 찜의 여부를 파악했다.
하지만 레디스를 적용한뒤에는 찜을 할때마다 레디스의 데이터를 동적으로 바꿀수가 없다.
어쩔수 없이 동적으로 찜의 여부를 파악하고 UI를 바꿔줄려면 클라이언트쪽에서 찜 로직을 처리 할 수 밖에없다.
어차피 유저별 찜 데이터는 따로 찜 테이블에서 관리하기 때문에 클라이언트에서 해당 유저의 찜리스트만 가지고 오면 가능한 부분이다.
const { data: zzims, mutate } = useUserZzimList();
export const useUserZzimList = () => {
const isLogin = haveAccessToken();
const url = '/user/getZzimList';
const getZzimList = async () => {
try {
const { data } = await fetcher(url);
return data;
} catch (err) {
console.log(err);
}
};
const { data, mutate } = useSWR(url, isLogin ? getZzimList : null);
return { data, mutate };
};
데이터별 고유번호를 위에 코드로 가져온 데이터를 비교하여 찜여부를 파악하면 된다.
data.map(item=>
<div isZzim={zzims.includes(item.no)}>찜!</div>
)
정적인 데이터를 레디스에서 불러오고 정적인 데이터 처리는 클라이언트에서 처리를 하려고 하면 더욱 성능을 높일 수 있다.
그러면 필요로 인해 DB데이터를 강제로 바꾸면?
해당 아이템을 등록한 관리자 사이트에서 급히 수정을 한다면?
레디스에 이미 저장 되어 있다면 바뀌지 않을 것이다.
하지만 분명 변경을 원해서 변경을 한 관리자가 존재 할 것이고 해당 관리자가 해당 레디스 key값만 지워주면 된다.
다른 팀에서 사용하기 쉽게 API를 따로 만들어서 처리하고 있다.
@Get('/주소')
async getDetailRefresh(@Req() req, @Param() body) {
await utf8();
const list = await this.cacheService.storeKeys(`/api/v1/brand/detail/*`);
if (list?.length > 0) {
await this.cacheService.storeDels(list);
}
const getRedisData = await this.cacheService.storeKeys();
return ['삭제되었습니다.삭제 적용되지 않을 시 기술연구소 이상민 문의.', ...getRedisData];
}
@Get('/주소/:id')
async getBrandDetailRefresh(@Req() req, @Param() body) {
await utf8();
await this.cacheService.storeDels(`/api/v1/brand/detail/${body.id}`);
const getRedisData = await this.cacheService.storeKeys();
return ['삭제되었습니다.삭제 적용되지 않을 시 기술연구소 이상민 문의.', ...getRedisData];
}
마무리
이회사에 합류하면서 레디스 작업보다 더욱 어렵고 정성이 필요한 작업을 많이 했었습니다.
(Nextjs 전환, 전체코드리팩토링등등..)
위의 작업들은 사실 앱사용 고객들과 회사 간부들에게는 성능 차이가 그리 크지 않았습니다. 노력에 비해 만족도가 떨어졌었죠.
하지만 레디스를 적용한 것은 굉장히 만족도가 높았습니다. 왜냐면 클릭시 리스트가 그냥 바로 나타나기 때문이죠.
역시 UI와 내부적인 소스코드 보다는 UX를 높이고 성능을 중요시 하는 개발이 제일 중요하다고 생각했습니다.
'개발' 카테고리의 다른 글
[velog 2022-07-06] NextJS 뒤로가기 스크롤 복원 안되는 문제 (0) | 2024.05.23 |
---|---|
[velog 2022-06-28] NextJS _middleware 사용하기 (0) | 2024.05.23 |
[velog 2022-06-21] NextJS 서버사이드 301 리다이렉트(redirect) (0) | 2024.05.23 |
[velog 2022-06-20] React 유용한 커스텀훅 useDeepEffect (0) | 2024.05.23 |
[velog 2022-06-17] 아이웨딩(회사) React(CSR) -> NextJS 전환 작업 (0) | 2024.05.23 |