첫 바이트까지의 시간 최적화

Time to First Byte(첫 바이트까지의 시간) 측정항목에 맞게 최적화하는 방법을 알아보세요.

TTFB (Time to First Byte)콘텐츠가 포함된 첫 페인트 (FCP)콘텐츠가 포함된 최대 페인트 (LCP)와 같은 다른 의미 있는 사용자 환경 측정항목보다 먼저 오는 기본적인 웹 성능 측정항목입니다. 즉, TTFB 값이 높으면 그 뒤에 오는 측정항목에 시간이 추가됩니다.

사용자의 75번째 백분위수'양호' 기준 내에서 FCP를 경험할 수 있도록 서버가 탐색 요청에 충분히 빠르게 응답하는 것이 좋습니다. 대략적인 가이드로 대부분의 사이트는 TTFB가 0.8초 이하가 되도록 노력해야 합니다.

TTFB 값이 0.8초 이하이면 양호한 값이고, 1.8초 이상이면 좋지 않은 값이며, 그 사이의 값은 개선이 필요합니다.
TTFB 값이 0.8초 이하이면 양호한 값이고 1.8초 이상이면 좋지 않은 값입니다.

TTFB 측정 방법

TTFB를 최적화하려면 먼저 TTFB가 웹사이트 사용자에게 어떤 영향을 미치는지 확인해야 합니다. 리디렉션의 영향을 받는 TTFB를 관찰하는 기본 소스로 필드 데이터를 사용해야 합니다. 실험실 기반 도구는 최종 URL을 사용하여 측정되는 경우가 많으므로 이 추가 지연 시간이 누락됩니다.

PageSpeed InsightsChrome 사용자 환경 보고서에서 제공되는 공개 웹사이트의 필드 정보와 실험실 정보를 모두 확인할 수 있는 방법 중 하나입니다.

실제 사용자의 TTFB는 상단의 실제 사용자의 경험 확인하기 섹션에 표시됩니다.

TTFB 측정항목의 필드 데이터를 포함한 PageSpeed Insights 실제 사용자 데이터
PageSpeed Insights 필드 데이터입니다.

실험실 데이터의 경우 TTFB의 하위 집합이 서버 응답 시간 감사에 표시됩니다.

서버 응답 시간 감사
PageSpeed Insights 서버 응답 시간 감사입니다.

필드와 실험실에서 TTFB를 측정하는 방법을 자세히 알아보려면 TTFB 측정항목 페이지를 참고하세요.

필드 TTFB와 실험실 TTFB의 차이점 이해

실험실과 실제 TTFB는 여러 가지 이유로 다를 수 있으며, 다른 경우 실험실 데이터를 효과적으로 사용하여 사용자 환경을 개선하려면 그 이유를 이해하는 것이 중요합니다.

  • 실험실 TTFB가 필드 TTFB보다 훨씬 큰 경우 실험실 환경이 일반적인 사용자 환경보다 더 제한적임을 나타냅니다. 실험실 결과와 추천은 여전히 유효할 수 있지만 영향과 개선 사항이 과장될 수 있으므로 반드시 문제가 되는 것은 아닙니다.

  • 필드 TTFB가 실험실 TTFB보다 훨씬 큰 경우 서버 측 캐싱, 리디렉션, 네트워크 차이 등 실험실 실행 중에 명확하지 않은 문제가 있음을 나타냅니다. 이 경우 주요 문제 중 하나가 누락되므로 실험실 결과와 추천이 덜 유용할 수 있습니다.

    서버 측 캐싱이 실험실 TTFB에 영향을 미치는지 확인하려면 덜 일반적인 페이지를 테스트하거나 다른 URL 매개변수를 사용하여 캐시되지 않은 콘텐츠를 가져와 TTFB가 필드 TTFB와 더 일치하는지 확인하세요. 특정 URL 매개변수를 사용하여 서버 측 캐싱을 우회할 수 있는 기능도 유용할 수 있습니다. 캐시된 콘텐츠 섹션을 참고하세요.

    리디렉션 및 네트워크 차이의 경우 트래픽이 사이트로 유입되는 방식과 유입되는 위치에 대한 분석이 잠재적인 문제를 진단하는 데 유용할 수 있습니다.

Server-Timing를 사용하여 실제 환경에서 TTFB가 높은 문제 디버그

Server-Timing 응답 헤더는 애플리케이션 백엔드에서 높은 지연 시간에 영향을 줄 수 있는 개별 백엔드 프로세스를 측정하는 데 사용할 수 있습니다. 헤더 값의 구조는 유연하며 최소한 사용자가 정의한 핸들을 허용합니다. 선택적 값에는 기간 값 (dur 사용)과 선택적 사람이 읽을 수 있는 설명 (desc 사용)이 포함됩니다.

Serving-Timing는 다양한 애플리케이션 백엔드 프로세스를 측정하는 데 사용할 수 있지만 특별히 주의해야 하는 프로세스가 있습니다.

  • 데이터베이스 쿼리
  • 서버 측 렌더링 시간(해당하는 경우)
  • 디스크 탐색
  • 에지 서버 캐시 적중 또는 누락 (CDN을 사용하는 경우)

Server-Timing 항목의 모든 부분은 콜론으로 구분되며 여러 항목은 쉼표로 구분할 수 있습니다.

// Two metrics with descriptions and values
Server-Timing: db;desc="Database";dur=121.3, ssr;desc="Server-side Rendering";dur=212.2

헤더는 선택한 애플리케이션 백엔드 언어를 사용하여 설정할 수 있습니다. 예를 들어 PHP에서는 다음과 같이 헤더를 설정할 수 있습니다.

<?php
// Get a high-resolution timestamp before
// the database query is performed:
$dbReadStartTime = hrtime(true);

// Perform a database query and get results...
// ...

// Get a high-resolution timestamp after
// the database query is performed:
$dbReadEndTime = hrtime(true);

// Get the total time, converting nanoseconds to
// milliseconds (or whatever granularity you need):
$dbReadTotalTime = ($dbReadEndTime - $dbReadStartTime) / 1e+6;

// Set the Server-Timing header:
header('Server-Timing: db;desc="Database";dur=' . $dbReadTotalTime);
?>

이 헤더가 설정되면 실험실현장 모두에서 사용할 수 있는 정보가 표시됩니다.

이 필드에서 Server-Timing 응답 헤더가 설정된 페이지는 탐색 타이밍 API에서 serverTiming 속성을 채웁니다.

// Get the serverTiming entry for the first navigation request:
performance.getEntries('navigation')[0].serverTiming.forEach(entry => {
  // Log the server timing data:
  console.log(entry.name, entry.description, entry.duration);
});

실험실에서는 Server-Timing 응답 헤더의 데이터가 Chrome DevTools의 네트워크 탭에 있는 타이밍 패널에 시각화됩니다.

Chrome DevTools의 네트워크 탭에 표시된 Server-Timing 헤더 값 시각화 이 이미지에서 Server-Timing 헤더 값은 CDN 에지 서버에서 캐시 적중 또는 누락이 발생했는지 여부와 에지 및 원본 서버에서 리소스를 가져오는 시간을 측정합니다.
Chrome DevTools의 네트워크 탭에 있는 Server-Timing 헤더 값

Chrome DevTools의 네트워크 탭에 시각화된 Server-Timing 응답 헤더 여기서 Server-Timing는 리소스 요청이 CDN 캐시에 도달했는지, 요청이 CDN의 에지 서버에 도달한 후 원본에 도달하는 데 얼마나 걸리는지 측정하는 데 사용됩니다.

사용 가능한 데이터를 분석하여 TTFB에 문제가 있음을 확인한 후에는 문제를 해결할 수 있습니다.

TTFB 최적화 방법

TTFB 최적화에서 가장 어려운 점은 웹의 프런트엔드 스택은 항상 HTML, CSS, JavaScript이지만 백엔드 스택은 크게 다를 수 있다는 것입니다. 각각 고유한 최적화 기술이 있는 다양한 백엔드 스택과 데이터베이스 제품이 있습니다. 따라서 이 가이드에서는 스택별 안내에만 집중하는 대신 대부분의 아키텍처에 적용되는 내용에 중점을 둡니다.

플랫폼별 안내

웹사이트에 사용하는 플랫폼은 TTFB에 큰 영향을 미칠 수 있습니다. 예를 들어 WordPress 성능은 플러그인의 수와 품질 또는 사용된 테마에 영향을 받습니다. 플랫폼이 맞춤설정된 경우 다른 플랫폼도 마찬가지로 영향을 받습니다. 이 게시물의 일반적인 성능 조언을 보완하기 위해 플랫폼 문서를 참고하여 공급업체별 조언을 확인하세요. 서버 응답 시간 단축을 위한 Lighthouse 감사에는 제한된 스택별 안내도 포함되어 있습니다.

호스팅, 호스팅, 호스팅

다른 최적화 접근 방식을 고려하기 전에 호스팅을 먼저 고려해야 합니다. 여기에서 제공할 수 있는 구체적인 안내는 많지 않지만 일반적인 규칙은 웹사이트 호스트가 전송되는 트래픽을 처리할 수 있는지 확인하는 것입니다.

일반적으로 공유 호스팅이 더 느립니다. 주로 정적 파일을 제공하는 소규모 개인 웹사이트를 운영하는 경우 이 정도면 충분하며, 아래에 나오는 최적화 기법을 사용하면 TTFB를 최대한 줄일 수 있습니다.

하지만 개인화, 데이터베이스 쿼리, 기타 집약적인 서버 측 작업이 포함된 대규모 애플리케이션을 많은 사용자와 함께 실행하는 경우 호스팅 선택이 필드에서 TTFB를 낮추는 데 중요해집니다.

호스팅 업체를 선택할 때는 다음 사항을 유의하세요.

  • 애플리케이션 인스턴스에 할당된 메모리 양은 얼마인가요? 애플리케이션의 메모리가 부족하면 스래싱이 발생하고 페이지를 최대한 빨리 제공하기 어려워집니다.
  • 호스팅 제공업체에서 백엔드 스택을 최신 상태로 유지하나요? 애플리케이션 백엔드 언어, HTTP 구현, 데이터베이스 소프트웨어의 새 버전이 출시되면 해당 소프트웨어의 성능이 시간이 지남에 따라 개선됩니다. 이러한 중요한 유지보수를 우선시하는 호스팅 제공업체와 파트너십을 맺는 것이 중요합니다.
  • 매우 구체적인 애플리케이션 요구사항이 있고 서버 구성 파일에 대한 최하위 수준 액세스가 필요한 경우 자체 애플리케이션 인스턴스의 백엔드를 맞춤설정하는 것이 타당한지 문의하세요.

이러한 사항을 처리해 주는 호스팅 제공업체가 많이 있지만 전용 호스팅 제공업체에서도 TTFB 값이 길어지기 시작하면 최상의 사용자 환경을 제공할 수 있도록 현재 호스팅 제공업체의 기능을 재평가해야 할 수 있습니다.

콘텐츠 전송 네트워크 (CDN) 사용

CDN 사용은 많이 다뤄진 주제이지만 그럴 만한 이유가 있습니다. 애플리케이션 백엔드를 매우 잘 최적화했더라도 원본 서버에서 멀리 떨어진 사용자는 여전히 필드에서 TTFB가 높을 수 있습니다.

CDN은 사용자에게 물리적으로 더 가까운 서버에 리소스를 캐시하는 분산 서버 네트워크를 사용하여 오리진 서버와의 사용자 근접성 문제를 해결합니다. 이러한 서버를 에지 서버라고 합니다.

CDN 제공업체는 에지 서버 외에도 다음과 같은 이점을 제공할 수 있습니다.

  • CDN 제공업체는 일반적으로 매우 빠른 DNS 확인 시간을 제공합니다.
  • CDN은 HTTP/2 또는 HTTP/3과 같은 최신 프로토콜을 사용하여 에지 서버에서 콘텐츠를 제공할 가능성이 높습니다.
  • 특히 HTTP/3는 UDP 프로토콜을 사용하여 HTTP/2가 사용하는 TCP에 있는 대기 행렬 막힘 문제를 해결합니다.
  • CDN은 TLS 협상 시간과 관련된 지연 시간을 줄이는 최신 버전의 TLS도 제공할 수 있습니다. 특히 TLS 1.3은 TLS 협상을 최대한 짧게 유지하도록 설계되었습니다.
  • 일부 CDN 제공업체는 서비스 워커 API와 유사한 API를 사용하여 요청을 가로채거나, 에지 캐시에서 응답을 프로그래매틱 방식으로 관리하거나, 응답을 완전히 다시 작성하는 '에지 워커'라는 기능을 제공합니다.
  • CDN 제공업체는 압축을 최적화하는 데 매우 능숙합니다. 압축은 직접 올바르게 수행하기가 까다로우며, 즉석에서 압축해야 하는 동적으로 생성된 마크업이 있는 경우 응답 시간이 느려질 수 있습니다.
  • CDN 제공업체는 정적 리소스에 대해 압축된 응답을 자동으로 캐시하므로 압축 비율과 응답 시간의 최적 조합을 얻을 수 있습니다.

CDN을 도입하는 데는 사소한 것부터 상당한 것까지 다양한 노력이 필요하지만, 웹사이트에서 아직 CDN을 사용하고 있지 않다면 TTFB를 최적화하기 위해 CDN을 도입하는 것이 우선순위가 높아야 합니다.

가능한 경우 캐시된 콘텐츠 사용

콘텐츠가 적절한 Cache-Control HTTP 헤더로 구성되어 있으면 CDN을 통해 방문자에게 물리적으로 더 가까운 에지 서버에 콘텐츠를 캐시할 수 있습니다. 이는 맞춤 콘텐츠에는 적합하지 않지만 원본으로 다시 이동해야 하면 CDN의 가치가 크게 떨어질 수 있습니다.

콘텐츠를 자주 업데이트하는 사이트의 경우 캐싱 시간이 짧더라도 트래픽이 많은 사이트의 성능이 눈에 띄게 향상될 수 있습니다. 해당 시간 동안 첫 번째 방문자만 원본 서버로의 전체 지연 시간을 경험하고 다른 모든 방문자는 에지 서버의 캐시된 리소스를 재사용할 수 있기 때문입니다. 일부 CDN에서는 사이트 출시 시 캐시 무효화를 허용하여 긴 캐시 시간과 필요할 때 즉시 업데이트라는 두 가지 장점을 모두 누릴 수 있습니다.

캐싱이 올바르게 구성된 경우에도 분석 측정을 위해 고유한 쿼리 문자열 매개변수를 사용하면 무시될 수 있습니다. 이러한 콘텐츠는 동일하더라도 CDN에 다른 콘텐츠로 표시될 수 있으므로 캐시된 버전이 사용되지 않습니다.

오래되었거나 방문 빈도가 낮은 콘텐츠는 캐시되지 않을 수도 있으며, 이로 인해 일부 페이지의 TTFB 값이 다른 페이지보다 높을 수 있습니다. 캐싱 시간을 늘리면 이 영향을 줄일 수 있지만 캐싱 시간이 늘어날수록 오래된 콘텐츠가 제공될 가능성이 커집니다.

캐시된 콘텐츠의 영향은 CDN을 사용하는 사용자에게만 미치지 않습니다. 캐시된 콘텐츠를 재사용할 수 없는 경우 서버 인프라에서 비용이 많이 드는 데이터베이스 조회를 통해 콘텐츠를 생성해야 할 수 있습니다. 더 자주 액세스하는 데이터나 사전 캐시된 페이지의 성능이 더 나은 경우가 많습니다.

페이지를 여러 차례 리디렉션하지 않기

TTFB가 높은 일반적인 원인 중 하나는 리디렉션입니다. 리디렉션은 문서에 대한 탐색 요청이 리소스가 다른 위치에 있음을 브라우저에 알리는 응답을 수신할 때 발생합니다. 리디렉션 하나는 탐색 요청에 원치 않는 지연 시간을 추가할 수 있지만, 리디렉션이 다른 리디렉션을 유발하는 다른 리소스를 가리키는 경우 상황이 더 악화될 수 있습니다. 이는 광고 또는 뉴스레터에서 많은 방문자가 유입되는 사이트에 특히 영향을 미칠 수 있습니다. 이러한 사이트는 측정 목적으로 분석 서비스를 통해 리디렉션되는 경우가 많기 때문입니다. 직접 제어할 수 있는 리디렉션을 없애면 TTFB를 개선할 수 있습니다.

리디렉션에는 두 가지 유형이 있습니다.

  • 동일 출처 리디렉션: 리디렉션이 웹사이트에서만 발생합니다.
  • 교차 출처 리디렉션: 웹사이트에 도착하기 전에 소셜 미디어 URL 단축 서비스와 같은 다른 출처에서 리디렉션이 처음 발생합니다.

동일 출처 리디렉션을 제거하는 데 집중하는 것이 좋습니다. 직접 제어할 수 있기 때문입니다. 여기에는 웹사이트의 링크를 확인하여 302 또는 301 응답 코드가 발생하는지 확인하는 작업이 포함됩니다. https:// 스키마가 포함되지 않아 브라우저가 기본적으로 http://로 설정되어 리디렉션되거나 URL에 후행 슬래시가 적절하게 포함되거나 제외되지 않아 발생하는 경우가 많습니다.

크로스 오리진 리디렉션은 제어할 수 없는 경우가 많으므로 더 까다롭지만, 링크를 공유할 때 여러 링크 단축기를 사용하는 등 가능한 경우 여러 리디렉션을 피하세요. 광고주 또는 뉴스레터에 제공되는 URL이 올바른 최종 URL인지 확인하여 해당 서비스에서 사용하는 URL에 다른 리디렉션을 추가하지 않도록 합니다.

리디렉션 시간의 또 다른 중요한 원인은 HTTP-HTTPS 리디렉션입니다. 이 문제를 해결하는 한 가지 방법은 Strict-Transport-Security 헤더 (HSTS)를 사용하는 것입니다. 이렇게 하면 출처를 처음 방문할 때 HTTPS가 적용되고 이후 방문 시 브라우저가 HTTPS 스킴을 통해 출처에 즉시 액세스하도록 지시합니다.

HSTS 정책을 적절하게 설정한 후 사이트를 HSTS 미리 로드 목록에 추가하여 출처를 처음 방문할 때 속도를 높일 수 있습니다.

브라우저에 마크업 스트리밍

브라우저는 마크업이 스트리밍될 때 효율적으로 처리하도록 최적화되어 있습니다. 즉, 서버에서 도착하는 대로 마크업이 청크로 처리됩니다. 이는 대규모 마크업 페이로드와 관련하여 매우 중요합니다. 파싱이 시작되기 전에 전체 응답이 도착할 때까지 기다리는 대신 브라우저가 마크업 청크를 점진적으로 파싱할 수 있기 때문입니다.

브라우저는 스트리밍 마크업을 처리하는 데 탁월하지만, 초기 마크업 비트가 최대한 빨리 전송되도록 스트림이 계속 흐르도록 최선을 다하는 것이 중요합니다. 백엔드에서 지연이 발생하면 문제가 됩니다. 백엔드 스택은 매우 많으므로 이 가이드에서 모든 스택과 각 스택에서 발생할 수 있는 문제를 다루는 것은 범위를 벗어납니다.

예를 들어 React와 서버에서 주문형으로 마크업을 렌더링할 수 있는 기타 프레임워크는 서버 측 렌더링에 동기식 접근 방식을 사용했습니다. 하지만 최신 버전의 React에서는 렌더링되는 대로 마크업 스트리밍을 위한 서버 메서드를 구현했습니다. 즉, React 서버 API 메서드가 전체 응답을 렌더링할 때까지 기다리지 않아도 됩니다.

마크업이 브라우저로 빠르게 스트리밍되도록 하는 또 다른 방법은 빌드 중에 HTML 파일을 생성하는 정적 렌더링을 사용하는 것입니다. 전체 파일을 즉시 사용할 수 있으므로 웹 서버가 즉시 파일을 전송할 수 있으며 HTTP의 고유한 특성으로 인해 마크업이 스트리밍됩니다. 이 접근 방식은 사용자 환경의 일부로 동적 응답이 필요한 페이지와 같이 모든 웹사이트의 모든 페이지에 적합하지는 않지만, 특정 사용자에 맞게 마크업을 맞춤설정할 필요가 없는 페이지에는 유용할 수 있습니다.

서비스 워커 사용

서비스 워커 API는 문서와 로드되는 리소스의 TTFB에 큰 영향을 미칠 수 있습니다. 서비스 워커가 브라우저와 서버 간의 프록시 역할을 하기 때문입니다. 하지만 웹사이트의 TTFB에 미치는 영향은 서비스 워커를 설정하는 방법과 해당 설정이 애플리케이션 요구사항과 일치하는지에 따라 달라집니다.

  • 애셋에 stale-while-revalidate 전략을 사용합니다. 애셋이 서비스 워커 캐시에 있는 경우(문서 또는 문서에 필요한 리소스) stale-while-revalidate 전략은 먼저 캐시에서 해당 리소스를 제공한 다음 백그라운드에서 해당 애셋을 다운로드하고 향후 상호작용을 위해 캐시에서 제공합니다.
    • 자주 변경되지 않는 문서 리소스가 있는 경우 stale-while-revalidate 전략을 사용하면 페이지의 TTFB가 거의 즉시 표시될 수 있습니다. 하지만 웹사이트에서 사용자 인증 여부에 따라 변경되는 마크업과 같은 동적으로 생성된 마크업을 전송하는 경우에는 잘 작동하지 않습니다. 이러한 경우 항상 네트워크를 먼저 호출하여 문서가 최대한 최신 상태가 되도록 해야 합니다.
    • 문서에서 자주 변경되지만 오래된 리소스를 가져와도 사용자 환경에 큰 영향을 미치지 않는 중요하지 않은 리소스(예: 중요하지 않은 일부 이미지 또는 기타 리소스)를 로드하는 경우 stale-while-revalidate 전략을 사용하여 이러한 리소스의 TTFB를 크게 줄일 수 있습니다.
  • 클라이언트 측 렌더링 애플리케이션에는 앱 셸 모델을 사용하세요. 이 모델은 페이지의 '셸'이 서비스 워커 캐시에서 즉시 제공되고 페이지의 동적 콘텐츠가 페이지 수명 주기에서 나중에 채워지고 렌더링되는 SPA에 가장 적합합니다.

렌더링에 중요한 리소스에 103 Early Hints 사용

애플리케이션 백엔드가 얼마나 잘 최적화되어 있더라도 서버가 응답을 준비하기 위해 해야 하는 작업이 많을 수 있습니다. 여기에는 탐색 응답이 최대한 빨리 도착하는 것을 지연시키는 비용이 많이 드는 (하지만 필요한) 데이터베이스 작업이 포함됩니다. 이로 인해 후속 렌더링 차단 리소스(예: CSS 또는 경우에 따라 클라이언트에서 마크업을 렌더링하는 JavaScript)가 지연될 수 있습니다.

103 Early Hints 헤더는 백엔드에서 마크업을 준비하는 동안 서버가 브라우저에 보낼 수 있는 초기 응답 코드입니다. 이 헤더는 마크업이 준비되는 동안 페이지가 다운로드를 시작해야 하는 렌더링에 중요한 리소스가 있음을 브라우저에 힌트하는 데 사용할 수 있습니다. 지원되는 브라우저의 경우 문서 렌더링 (CSS)이 더 빨라지고 페이지 로드가 더 빨라질 수 있습니다.

103 Early Hints의 한 가지 단점은 캐싱과 마찬가지로 사이트의 '실제' TTFB를 마스킹할 수 있다는 것입니다. 서버 인프라가 느린 경우 (전력이 부족하거나 코드를 최적화해야 하는 경우) TTFB가 빠르게 표시되므로 103 Early Hints를 사용하면 이 문제가 덜 명확해질 수 있습니다. 103 Early Hints를 사용하는 사이트는 PerformanceNavigationTiming APIServer-Timing 또는 finalResponseHeadersStart를 통해 실제 서버 시간을 측정하는 것이 좋습니다.

결론

백엔드 애플리케이션 스택의 조합이 너무 많기 때문에 웹사이트의 TTFB를 낮추기 위해 할 수 있는 모든 것을 하나의 도움말로 설명할 수는 없습니다. 하지만 서버 측에서 조금 더 빠르게 작업을 진행하기 위해 살펴볼 수 있는 몇 가지 옵션이 있습니다.

모든 측정항목을 최적화하는 것과 마찬가지로 접근 방식은 거의 비슷합니다. 필드에서 TTFB를 측정하고, 실험실 도구를 사용하여 원인을 자세히 살펴본 다음, 가능한 경우 최적화를 적용합니다. 여기에 나온 모든 기법이 상황에 적합하지는 않지만 일부는 적합할 수 있습니다. 언제나 그렇듯이 필드 데이터를 면밀히 모니터링하고 필요에 따라 조정하여 최대한 빠른 사용자 환경을 제공해야 합니다.

히어로 이미지: 테일러 빅(출처: Unsplash)