모델 캐시

개요

서버 응답 캐시, 쿼리 결과 캐시 등등 상황에 따라 캐시 전략은 다양할 수 있다.
Map<Id, Model> 형태로 모델을 캐싱하는 것에 대해 집중적으로 알아보려 한다.

높은 공유성

모델 캐시는 응답 캐시, 쿼리 캐시보다 더 많이 재사용 될 수 있다. 예를 들어 인스타그램의 경우 하나의 포스트가 메인 피드, 검색 피드, 마이페이지, 릴스 등등 여러 구좌에서 쓰인다.
응답 캐시 같은 경우 메인 피드에서 A 포스트가 캐싱 되더라도, 다른 API에선 새로 A를 조회해야 한다.
반면 Map<Id, Model> 꼴로 관리하면 캐싱된 A 포스트를 어떤 구좌에서든 사용 할 수 있다.

쉬운 캐시 무효화

모델 캐시는 모델이 변경되었을 때만 캐시를 갱신하면 되기 때문에 관리가 용이하다.
특히 캐시를 갱신할 땐 version 필드를 기준으로 더 최신의 값을 쉽게 판단 할 수 있다.
따라서 옛날 값으로 캐시를 갱신하는 동시성 문제를 쉽게 잡을 수 있다.

ID 조회

사람이 인지할 수 있는 데이터는 한정적이지만 데이터는 폭발적으로 증가한다.
그러한 까닭에 우리는 사용자에게 관심 있을 모델을 선정하기 위해 노력한다.
때로는 별도의 ML 서버를 띄우거나 인덱스 테이블을 만들기도 한다.
모델을 선정하는 객체는 보통 모델의 모든 필드를 가지고 있진 않기 때문에 모델의 ID를 반환한다.
모델 캐시의 경우 이러한 경우에도 효과적으로 캐시 히트될 수 있다.

또한 ID만 쿼리하면 Index only scan하기 쉽다.
심지어는 ID만 쿼리하고 쿼리한 ID로 다시 모델을 쿼리하는게 더 빠른 경우도 있다.
다음과 같이 late row lookup을 통해 최대한 Index only scan을 오래 유지 할 수 있다.

select id from (
    select id
    from users
    where index_field1 = 'foo' and index_field2 = "bar"
    order by id
    offset 10000
) o
JOIN o.id = users.id
where users.not_index_field1 is False
limit 500