TTL: 개념, 캐시 수명 및 작동 방식

저자: IT Sectr 게시일: 2026-06-13 읽는 시간: 8 분

TTL(Time To Live)은 데이터가 유효한 것으로 간주되는 최대 시간을 결정하는 매개변수입니다. TTL이 만료되면 레코드는 오래된(stale) 것으로 표시되고 삭제 또는 업데이트되어야 합니다. Mozilla Developer Network(2026)에 따르면, TTL 메커니즘은 Cache-Control: max-age 헤더를 통한 HTTP 캐싱의 기초이며 네트워크 요청을 최적화하기 위해 모든 최신 브라우저와 모바일 애플리케이션에서 사용됩니다.

주요 내용

  • TTL(Time To Live) — 레코드의 수명. 이후 데이터는 오래된 것으로 간주되어 업데이트 필요
  • 균형 — 짧은 TTL은 최신 데이터를 제공하지만 캐싱 효율성을 낮춤. 긴 TTL은 성능을 향상시키지만 오래될 위험이 있음
  • HTTP 캐싱 — Cache-Control: max-age 헤더가 서버 응답의 TTL을 초 단위로 설정
  • DNS 레코드 — TTL은 리졸버가 도메인의 IP 주소를 캐시하는 시간(60~86400초)을 결정
  • 모바일 앱 — TTL은 API 응답, 이미지 및 세션 데이터를 캐시하는 데 사용

TTL이란?

TTL(Time To Live)은 데이터가 무효한 것으로 간주되는 타임스탬프 또는 간격입니다. 캐싱의 맥락에서 TTL은 레코드가 소스에서 다시 가져와야 하기 전에 캐시에 저장될 수 있는 시간을 결정합니다. 네트워크 프로토콜에서 TTL은 패킷의 수명을 제한하여 무한 라우팅을 방지합니다.

TTL 값은 항상 밀리초, 초, 분 또는 시간 단위로 표현됩니다. 설정된 시간이 경과하면 레코드는 캐시에서 삭제되거나 오래된 것으로 표시됩니다. 오래된 레코드에 대한 다음 요청에서 시스템은 이후 업데이트(stale-while-revalidate)와 함께 오래된 데이터를 반환하거나 새 데이터를 얻을 때까지 요청을 차단할 수 있습니다.

TTL 선택은 항상 데이터 신선도와 성능 간의 균형입니다. 너무 짧은 TTL(1~5초)은 애플리케이션이 빈번한 네트워크 요청을 하도록 강제하여 캐싱의 이점을 무효화합니다. 너무 긴 TTL(시간/일)은 사용자에게 오래된 정보를 표시할 위험을 증가시킵니다. 최적의 값은 데이터 유형에 따라 다릅니다: 환율 — 초, 날씨 — 분, API 버전 — 시간.

TTL과 캐시 무효화

TTL은 수동적 무효화입니다: 일정 시간이 지나면 데이터가 자동으로 제거됩니다. 대안은 능동적 무효화로, 데이터 소스가 변경 사항을 캐시에 알리는 방식입니다(예: WebSocket 메시지 또는 푸시 알림). TTL을 통한 수동적 무효화는 구현이 간단하지만 즉각적인 신선도를 보장하지 않습니다. 능동적 무효화는 더 복잡하지만 TTL에 내재된 지연 없이 데이터를 최신 상태로 유지할 수 있습니다.

TTL 작동 방식

TTL 메커니즘은 두 가지 방식으로 구현될 수 있습니다: 절대 만료(absolute expiration)와 상대 만료(relative expiration)입니다. 절대 만료에서는 레코드가 무효화되는 특정 시간을 저장합니다. 상대 만료에서는 레코드의 생성 시간과 TTL이 간격으로 기록되며, creationTime + TTL > currentTime을 계산하여 확인합니다.

캐시에 대한 각 요청에서 시스템은 각 레코드의 TTL을 확인합니다. TTL이 만료된 경우 데이터가 삭제되거나 오래된 것으로 표시되고 요청이 소스로 전달됩니다. TTL 확인을 최적화하기 위해 예약된 정리(만료된 모든 레코드의 주기적 삭제) 또는 지연 정리(레코드에 액세스할 때만 삭제)를 사용할 수 있습니다. 지연 정리는 전체 캐시를 스캔하기 위해 백그라운드 스레드가 필요하지 않으므로 메모리 효율성이 더 높습니다.

분산 시스템에서 TTL은 자동 충돌 해결에도 사용됩니다. 예를 들어, 두 서버가 동일한 키에 대해 다른 값을 동시에 쓰는 경우, 이후 TTL이 있는 레코드가 우선순위가 더 높은 것으로 간주될 수 있습니다. Amazon DynamoDB는 테이블에서 오래된 레코드를 자동 삭제하기 위해 TTL을 사용합니다 — 이것은 수동 관리가 필요 없는 내장 기능입니다.

오래된 데이터 읽기 전략

TTL이 만료될 때 성능을 향상시키기 위해 오래된 데이터 읽기 전략이 사용됩니다. Stale-while-revalidate — 즉시 클라이언트에 오래된 데이터를 반환하고 동시에 백그라운드 업데이트를 시작합니다. Stale-if-error — 소스를 일시적으로 사용할 수 없는 경우 오래된 데이터를 반환합니다. Cache-Aside(Lazy Loading) — 캐시 미스 시 소스에서 데이터를 로드하고, 새 TTL로 캐시에 저장한 다음 클라이언트에 반환합니다. 각 전략은 데이터 일관성 요구 사항에 따라 선택됩니다.

데이터 캐싱에서의 TTL

모바일 애플리케이션에서 TTL은 캐시 관리의 핵심 메커니즘입니다. TTL이 애플리케이션 동작과 사용자 경험을 결정하는 주요 시나리오를 살펴보겠습니다.

HTTP 응답 캐싱

HTTP 프로토콜은 Cache-Control 헤더를 통해 내장된 TTL 메커니즘을 제공합니다. max-age 지시문은 TTL을 초 단위로 설정합니다: Cache-Control: public, max-age=3600은 응답을 1시간 동안 캐시할 수 있음을 의미합니다. 추가 지시문 s-maxage(공유 캐시, 예: CDN용)와 stale-while-revalidate는 더 세밀한 제어를 제공합니다. TTL이 expires 헤더와 일치하는 경우, 더 현대적인 HTTP/1.1 표준으로서 max-age가 우선순위를 갖습니다.

데이터 유형권장 TTL근거
날씨10~30분예보가 자주 업데이트되지 않음
환율15~60초높은 변동성
뉴스 피드2~5분신선도와 성능 간의 균형
사용자 프로필5~30분세션 중에 거의 변경되지 않음
상품 목록10~60분가격이 매초 변경되지 않음
정적 리소스1~24시간URL 또는 ETag를 통해 버전 관리

이미지 캐싱

이미지의 경우 콘텐츠가 거의 변경되지 않으므로 TTL이 며칠에 이를 수 있습니다. 그러나 모바일 애플리케이션은 종종 하이브리드 접근 방식을 사용합니다: 미리보기에는 짧은 TTL(30분 — 프레임 신선도), 전체 크기 이미지에는 긴 TTL(7일). HTTP 헤더 Cache-Control: immutable이 있는 이미지는 TTL이 만료될 때까지 다시 요청되어서는 안 됩니다 — 이것은 RFC 8246에서 제안된 정적 리소스 최적화입니다. 이러한 이미지는 애플리케이션의 참여 없이 OS 수준(URLCache, OkHttp Cache)에서 캐시됩니다.

네트워크 프로토콜에서의 TTL

네트워크에서 TTL은 캐싱이 아니라 패킷의 수명을 제한하는 데 사용됩니다. 각 IP 패킷에는 TTL 필드(8비트)가 포함되어 있으며, 각 라우터에 의해 1씩 감소합니다. TTL이 0에 도달하면 패킷이 폐기되고 발신자는 ICMP Time Exceeded 메시지를 받습니다. 이는 네트워크 루프 중 무한 라우팅을 방지합니다.

DNS에서의 TTL

DNS 레코드에는 리졸버(예: ISP DNS 캐시)가 권위 있는 서버에 쿼리하지 않고 레코드를 저장할 수 있는 시간을 결정하는 TTL이 있습니다. 일반적인 값: 자주 변경되는 레코드의 경우 300초(5분), 안정적인 도메인의 경우 86400초(24시간). CDN 서비스는 장애 시 빠른 트래픽 재라우팅을 위해 낮은 TTL(60~300초)을 설정하는 반면, 정적 도메인은 최대 7일의 TTL을 가질 수 있습니다. 서버 마이그레이션 시 먼저 TTL을 60초로 낮추는 것이 좋습니다(마이그레이션 48시간 전). 그러면 변경 사항이 빠르게 전파됩니다.

세션 및 토큰에서의 TTL

모바일 애플리케이션에서 TTL은 세션 및 액세스 토큰 관리에 사용됩니다. JWT 토큰(JSON Web Tokens)에는 exp(만료 시간) 필드가 포함되어 있으며, 이는 절대 Unix 만료 시간입니다. 만료 후에는 재인증 없이 새 액세스 토큰을 얻기 위해 리프레시 토큰이 사용됩니다. 액세스 토큰 TTL은 일반적으로 1~24시간, 리프레시 토큰 TTL은 7~30일입니다. 이는 보안(짧은 TTL은 유출 위험 감소)과 UX(긴 TTL은 재로그인 빈도 감소) 간의 균형입니다.

TTL 선택 전략

TTL 선택은 데이터 유형, 신선도 SLA 및 재요청 비용에 따라 달라지는 엔지니어링 결정입니다. 주요 전략을 살펴보겠습니다.

고정 TTL

가장 간단한 접근 방식 — 모든 레코드가 동일한 TTL을 가집니다. 예: 모든 API 응답을 5분 동안 캐시합니다. 장점: 구현의 단순성과 예측 가능한 동작. 단점: 다른 데이터 유형의 다른 변경 빈도를 고려하지 않습니다. 고정 TTL은 모든 레코드가 동일한 “신선도”를 가진 균일한 데이터(예: 하나의 거래소에서 암호화폐 환율)에 적합합니다.

적응형 TTL

TTL은 데이터 동작에 따라 동적으로 변경됩니다. 예를 들어, 레코드가 서버에서 거의 업데이트되지 않으면 TTL이 증가하고, 자주 업데이트되면 감소합니다. 구현은 HTTP 응답 헤더를 사용할 수 있습니다: Age 헤더(응답이 캐시에 있었던 초 수)와 Date 헤더를 통해 남은 수명을 계산할 수 있습니다. 적응형 TTL은 더 나은 히트율을 제공하지만 클라이언트에 추가 로직이 필요합니다.

확률적 TTL 만료

PEE(Probabilistic Early Expiration) — 지정된 범위 내에서 TTL을 무작위로 선택하는 기술입니다. 이는 많은 요청이 동시에 만료되고 모든 클라이언트가 동시에 소스에 액세스하는 “썬더링 허드”(thundering herd) 효과를 방지합니다. PEE는 특히 CDN 및 고부하 캐시에 유용합니다: 300초의 단일 TTL 대신 240~360초의 무작위 값을 사용하여 소스에 부하를 균등하게 분산합니다.

TTL 코드 예제

절대 만료를 사용하여 Kotlin에서 TTL이 있는 캐시 구현을 살펴보겠습니다. 각 레코드는 생성 시간을 저장하고 읽을 때 TTL이 만료되었는지 확인됩니다.

kotlin
class TtlCache<K, V>(
    private val defaultTtlMs: Long = 300000L
) {
    private data class Entry<V>(
        val value: V,
        val createdAt: Long = System.currentTimeMillis()
    )

    private val map = ConcurrentHashMap<K, Entry<V>>()

    fun get(key: K): V? {
        val entry = map[key] ?: return null
        if (isExpired(entry)) {
            map.remove(key)
            return null
        }
        return entry.value
    }

    fun put(key: K, value: V, ttlMs: Long = defaultTtlMs) {
        map[key] = Entry(value, createdAt = System.currentTimeMillis() + ttlMs)
    }

    private fun isExpired(entry: Entry<*>): Boolean {
        return System.currentTimeMillis() > entry.createdAt
    }

    fun cleanup() {
        map.entries.removeIf { isExpired(it.value) }
    }
}

Entry 클래스는 값과 생성 시간 + TTL(절대 만료)을 저장합니다. get 메서드는 각 액세스 시 만료를 확인합니다(지연 정리) — 만료된 레코드는 액세스를 시도할 때만 삭제됩니다. cleanup 메서드는 백그라운드 스레드에서 주기적으로 호출하여 모든 오래된 레코드를 일괄 삭제할 수 있습니다. ConcurrentHashMap은 전체 캐시를 잠그지 않고 스레드 안전성을 제공합니다.

예제: iOS에서 API 응답 캐싱을 위한 TTL

iOS에서는 TTL이 있는 캐싱을 위해 memoryCapacity 및 diskCapacity 설정과 함께 URLCache를 사용하는 것이 편리합니다. 그러나 URLCache는 다른 요청에 대해 개별 TTL을 지원하지 않습니다. TTL 지원이 있는 사용자 지정 NSCache 래퍼를 살펴보겠습니다.

swift
final class ApiResponseCache {
    private var cache = NSCache<NSString, CacheEntry>()

    func getResponse(for url: URL) -> Data? {
        guard let entry = cache.object(forKey: url.absoluteString as NSString)
            else { return nil }
        guard entry.expirationDate > Date() else {
            cache.removeObject(forKey: url.absoluteString as NSString)
            return nil
        }
        return entry.data
    }

    func storeResponse(data: Data, for url: URL, ttl: TimeInterval) {
        let entry = CacheEntry(data: data, expirationDate: Date().addingTimeInterval(ttl))
        cache.setObject(entry, forKey: url.absoluteString as NSString)
    }
}

final class CacheEntry: NSObject {
    let data: Data
    let expirationDate: Date
}

이 구현에서 NSCache는 스레드 안전 저장소로 사용됩니다. CacheEntry에는 Data와 expirationDate가 포함됩니다. get이 호출되면 시간이 만료되었는지 확인하고, 만료된 경우 레코드가 삭제되고 nil이 반환됩니다. TTL은 TimeInterval을 통해 초 단위로 설정되며 URL마다 다를 수 있습니다: API 응답의 일반적인 값은 동적 콘텐츠의 경우 120초, 정적 데이터의 경우 3600입니다.

자주 묻는 질문

TTL과 데이터 만료 날짜의 차이점은 무엇인가요?

기술적으로 TTL과 만료 날짜는 동일합니다: 데이터가 무효한 것으로 간주되는 시간 간격. 차이점은 맥락에 있습니다: TTL이라는 용어는 IT(캐싱, 네트워킹, DNS)에서 사용되는 반면, “만료 날짜”는 비즈니스 로직(프로모션 코드, 구독)에서 더 자주 사용됩니다. 구현에서 두 메커니즘은 동일합니다 — 현재 시간과 만료 시간의 비교입니다.

최적의 TTL을 선택하는 방법은?

최적의 TTL은 경험적으로 선택됩니다. 방법: 보수적인 값(30~60초)부터 시작하여 오래된 데이터에 대한 불만이 나올 때까지 점차 늘립니다. 캐시 히트율을 모니터링합니다: 70% 미만이면 TTL이 너무 짧습니다. SLA를 고려합니다: 금융 데이터의 TTL은 1초, 뉴스는 5분, 프로필은 30분이 될 수 있습니다.

HTTP에서 TTL이 만료되면 어떻게 되나요?

max-age가 만료되면 브라우저 또는 모바일 앱이 응답을 오래된 것으로 간주합니다. 동일한 URL에 대한 다음 요청에서 클라이언트는 If-None-Match(ETag) 또는 If-Modified-Since 헤더와 함께 요청을 보냅니다. 데이터가 변경되지 않은 경우 서버는 응답 본문 없이 304 Not Modified를 반환하고 TTL이 업데이트됩니다. 변경된 경우 서버는 새 데이터와 새 Cache-Control과 함께 200을 반환합니다.

TTL이 무한할 수 있나요?

기술적으로 TTL은 매우 클 수 있지만(max-age=31536000 — 1년), 정당화되는 경우는 거의 없습니다. 정적 리소스라도 변경될 수 있으며 클라이언트는 TTL이 만료될 때까지 이를 알지 못합니다. 긴 TTL과 버전 관리된 URL(style.css?v=2)을 사용하는 것이 좋습니다: 파일이 변경되면 URL이 변경되고 오래된 캐시는 자동으로 무효화됩니다.

TTL과 LRU, FIFO의 관계는?

TTL과 축출 전략(LRU, FIFO)은 다른 문제를 해결합니다. TTL은 데이터가 언제 관련성을 잃는지를 결정합니다 — 이것은 시간적 기준입니다. LRU와 FIFO는 캐시가 가득 찼을 때 어떤 데이터를 제거할지 결정합니다 — 이것은 공간적 기준입니다. 이들은 결합될 수 있습니다: TTL이 만료되었거나 캐시가 가득 찬 경우(LRU/FIFO에 의해) 레코드가 삭제됩니다. 프로덕션 시스템에서는 두 메커니즘이 함께 작동합니다.

요약

  • TTL(Time To Live) — 레코드의 수명. 이후 데이터는 오래된 것으로 간주되어 업데이트 필요
  • 절대 만료 — 레코드가 정확한 만료 시간을 저장. 상대 만료 — 생성 시간 + 간격
  • 균형 — 짧은 TTL은 캐싱 효율성을 낮추고, 긴 TTL은 오래된 데이터의 위험을 증가
  • HTTP Cache-Control — max-age가 오래된 모드 지원과 함께 서버 응답 TTL을 초 단위로 설정
  • DNS 확인 — 60~86400초의 TTL이 도메인의 IP 주소가 캐시되는 시간을 결정
  • 전략 — 고정, 적응형 및 확률적 TTL이 데이터 유형에 따라 적용됨
  • 사용 완전한 캐시 수명 주기 관리를 위해 LRU/FIFO와 함께 TTL 사용

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기