안녕하세요, 감자입니다
이번에 회고해볼 내용은 2주차 과제였던 cache 구현입니다.
제가 스스로 cache를 구현한 방식을 정리한 개인편과 팀의 best pratice로 작성하면서 배운점들이 정리한 팀편으로 나누어 블로깅해볼 예정입니다. 우선 제가 cache를 구현한 방식을 이야기해보도록 하겠습니다.
이번 과제도 10명의 팀원들과 과제를 진행하고, best pratice를 만들어서 제출하기 였습니다. 기업 과제여서 상세 내용은 공유할 수 없지만, 핵심 내용은 검색어 캐싱 구현하기 였습니다. 제가 캐싱을 구현한 방식과 팀원들이 캐싱을 구현한 방식이 크게 달랐습니다. 우선 제가 구현한 방식부터 이야기해보도록 하겠습니다.
캐싱을 구현하는데 정말 다양한 방식이 있었는데, 저는 브라우저의 storage 사용없이 javascrip의 Map을 이용하여 구현하였습니다.
기본적으로 best pratice 취합도 생각해야 했기에 지난 과제와 비슷한 셋팅을 하도록 결정하였습니다. 하지만, 다르게 선정한 부분도 있는데 바로 module.css와 vite를 사용하였습니다.
로컬 스토리지
세션 스토리지
캐시 스토리지
Map (javascript의 자료구조, 스토리지 x)
스토리지 사용함으로써 여러 장점들이 있었지만, 검색어의 캐싱이 새로고침이나 페이지가 열고 닫힘에 따라 유지될 필요가 없다고 판단되어 스토리지를 사용하지 않고 Map으로 구현하기로 결정했습니다.
구현 자체는 스토리지를 사용할때보다 비교적 간단했습니다. 하지만, Map로 구현하다보니 메모리 관리의 필요성을 느끼게되었습니다. 끊임없이 저장하다보면 메모리 누수현상이 발생하지 않을까라는 걱정이 들어 접근한지 오래된 데이터 삭제하는 LRU 알고리즘을 적용하였습니다.
(참고: 캐시(Cache) 알고리즘)
캐시 저장 변수 Map 선언하기
const cache = new Map<string, CachedRecommendType>();
검색어 캐시 확인하기
const fetchingSearch = async (searchKeyword: string) => {
const cachedData = cache.get(searchKeyword); // 기존 존재하는 여부 확인
// 해당 검색어의 캐시가 존재하는 경우
if (cachedData) {
const { data, expireTime } = cachedData;
//만료 시간이 지나지 않은 경우
if (isValidTime(expireTime)) {
setRecommendList(data);
// lastAccessedTime(마지막 접근 시간) 현재 시간을 할당
cache.set(searchKeyword, {
data,
expireTime,
lastAccessedTime: new Date(),
});
return;
}
cache.delete(searchKeyword);
}
신규 검색어 받아오기 (캐시에 없는 경우)
const data = await search(encodeURI(searchKeyword));
const expireTime = addSeconds(cacheExpire);
const lastAccessedTime = new Date();
cache.set(searchKeyword, { data, expireTime, lastAccessedTime });
if (checkCacheLimit()) {
removeOldestAccessedItem();
}
setRecommendList(data);
최대 개수 도달시 삭제하기 (LRU)
const checkCacheLimit = () => {
return cache.size > cacheLimit;
};
const removeOldestAccessedItem = () => {
let oldestKey = '';
let oldestAccessedTime = new Date();
//가장 오랜된 item key 찾기
for (const [key, value] of cache.entries()) {
if (value.lastAccessedTime < oldestAccessedTime) {
oldestKey = key;
oldestAccessedTime = value.lastAccessedTime;
}
}
if (oldestKey) {
cache.delete(oldestKey);
}
};
limit는 테스트를 위해 100개 설정해두었는데, 브라우저를 껐다키면 휘발되기 때문에 사용자가 검색어를 100개까지 도달하는 경우가 있을까라는 생각도 들어 LRU를 과하지 않았나 싶기도했다. 하지만, 알고리즘 문제나 책에서만 보던 LRU를 실제로 구현해보니까 재미있었다.