3장 - 고급 캐싱 항목

"컴퓨터 과학에는 캐시 무효화와 이름 지정이라는 두 가지 하드 항목만 있습니다."

— 필 칼튼

개요

세 부분으로 구성된 3부 - AEM에서 캐싱에 대한 시리즈입니다. 처음 두 부분이 Dispatcher의 일반 http 캐싱에 중점을 둔 위치와 제한 사항 이 부분에서는 이러한 한계를 극복하는 방법에 대한 몇 가지 아이디어를 논의한다.

일반 캐싱

이 시리즈의 챕터 1챕터 2은(는) 주로 Dispatcher에 중점을 둡니다. 기본 사항, 제한 사항 및 특정 절충안을 만들어야 하는 위치에 대해 설명했습니다.

캐싱의 복잡성과 복잡성은 Dispatcher 고유의 문제가 아닙니다. 일반적으로 캐싱은 어렵습니다.

도구 상자에 Dispatcher을 유일한 도구로 사용하는 것은 실제로 실제 제한 사항입니다.

이 장에서는 캐싱에 대한 시야를 더 넓히고 Dispatcher의 단점을 몇 가지 극복할 수 있는 방법을 개발하려고 합니다. 실버 글머리 기호는 없습니다. 프로젝트에서 절충안을 만들어야 합니다. 캐싱 및 무효화 정확성은 항상 복잡성을 가져오며, 복잡성은 오류 가능성을 가져온다는 점을 기억하십시오.

이런 부분에서 절충을 해야 할 겁니다

  • 성능 및 지연
  • 리소스 사용량 / CPU 로드 / 디스크 사용량
  • 정확성 / 통화 / 안정성 / 보안
  • 단순성 / 복잡성 / 비용 / 유지성 / 오류 발음성

이러한 차원은 다소 복잡한 시스템에서 상호 연결됩니다. 이렇게 하고 저렇게 하는 것은 간단치 않다. 시스템을 더 간단하게 만들면 더 빨라지거나 느려질 수 있습니다. 개발 비용은 낮추지만 헬프 데스크에서는 비용을 높일 수 있습니다(예: 고객이 오래된 콘텐츠를 보거나 느린 웹 사이트에 대해 불만을 제기하는 경우). 이 모든 요소들이 서로 고려되고 균형을 이룰 필요가 있다. 그러나 이제 여러분은 이미 좋은 아이디어를 가지고 있어야 한다. 실버 총알이나 하나의 "모범 사례"가 없다는 것이다 - 단지 많은 나쁜 관습들과 몇몇 좋은 관습들만이 있을 뿐이다.

체인 캐싱

개요

데이터 흐름

서버에서 클라이언트의 브라우저로 페이지를 전달하는 것은 많은 시스템과 하위 시스템을 교차합니다. 신중하게 살펴보면 소스에서 드레인 방향으로 가져와야 하는 홉이 여러 개 있으며, 각 홉은 캐싱할 수 있는 잠재적인 후보입니다.

일반적인 CMS 응용 프로그램의 데이터 흐름

일반적인 CMS 응용 프로그램의 데이터 흐름

하드 디스크에 저장되어 브라우저에 표시되어야 하는 데이터로 여정을 시작하겠습니다.

하드웨어 및 운영 체제

첫째, 하드 디스크 드라이브(HDD) 자체가 하드웨어에 내장된 캐시를 가지고 있습니다. 둘째, 하드 디스크를 마운트하는 운영 체제는 액세스 속도를 높이기 위해 자주 액세스하는 블록을 캐시하기 위해 사용 가능한 메모리를 사용합니다.

콘텐츠 저장소

다음 수준은 CRX 또는 Oak(AEM에서 사용하는 문서 데이터베이스)입니다. CRX 및 Oak은 HDD에 대한 액세스 속도가 느려지는 것을 방지하기 위해 데이터를 메모리에서도 캐시할 수 있는 세그먼트로 나눕니다.

타사 데이터

대부분의 대규모 웹 설치에는 제품 정보 시스템, 고객 관계 관리 시스템, 레거시 데이터베이스 또는 기타 임의의 웹 서비스에서 전송되는 타사 데이터도 있습니다. 이 데이터는 필요할 때마다 소스에서 가져올 필요가 없습니다. 특히 너무 자주 변경되지 않는다고 알려진 경우에는 가져올 필요가 없습니다. 따라서 CRX 데이터베이스에서 동기화되지 않은 경우 캐시될 수 있습니다.

비즈니스 레이어 - 앱/모델

일반적으로 템플릿 스크립트는 JCR API를 통해 CRX에서 제공되는 원시 콘텐츠를 렌더링하지 않습니다. 비즈니스 도메인 개체의 데이터를 병합, 계산 및/또는 변환하는 비즈니스 계층이 그 사이에 있을 수 있습니다. 추측해 보세요. 이러한 작업이 비용이 많이 든다면 캐시하는 것을 고려해야 합니다.

마크업 조각

이제 모델은 구성 요소에 대한 마크업을 렌더링하는 데 기초가 됩니다. 렌더링된 모델도 캐시하지 않는 이유는 무엇입니까?

Dispatcher, CDN 및 기타 프록시

꺼지면 렌더링된 HTML-페이지가 Dispatcher으로 이동합니다. Dispatcher의 주요 목적은 HTML 페이지 및 기타 웹 리소스(이름에도 불구하고)를 캐시하는 것이라고 이미 설명했습니다. 리소스가 브라우저에 도달하기 전에 캐시할 수 있는 역방향 프록시와 캐시에도 사용되는 CDN을 전달할 수 있습니다. 클라이언트는 프록시를 통해서만 웹 액세스 권한을 부여하는 사무실에 있을 수 있으며, 프록시는 트래픽을 저장하기 위해 캐시도 결정할 수 있습니다.

브라우저 캐시

마지막으로, 브라우저도 캐시합니다. 이것은 간과하기 쉬운 자산입니다. 하지만 캐싱 체인에서 가장 가깝고 빠른 캐시입니다. 안타깝게도 - 사용자 간에는 공유되지 않지만 한 사용자의 서로 다른 요청 간에는 공유됩니다.

캐시할 위치 및 이유

그것은 잠재적인 캐시의 긴 사슬이다. 그리고 우리는 모두 오래된 콘텐츠를 본 문제에 직면했습니다. 하지만 몇 단계가 있는지 고려해보면 대부분의 시간이 작동한다는 것은 기적입니다.

하지만 그 사슬의 어디를 캐싱하는 것이 말이 되나요? 처음에? 끝에? 어디에나? 그건… 그리고 엄청난 요인에 따라 다르죠. 동일한 웹 사이트에 있는 두 리소스도 해당 질문에 다른 답변을 원할 수 있습니다.

어떤 요인을 고려할 지 대략적으로 말씀드리자면

라이브할 시간 - 개체에 고유한 라이브 시간이 짧은 경우(트래픽 데이터의 라이브 시간이 날씨 데이터보다 짧을 수 있음) 캐시할 가치가 없을 수 있습니다.

프로덕션 비용 - CPU 주기와 I/O 측면에서 비용이 얼마나 많이 드는지가 개체를 다시 제작하고 전달하는 데 사용됩니다. 저렴하다면 캐싱이 필요하지 않을 수도 있습니다.

크기 - 큰 개체를 사용하려면 더 많은 리소스가 필요합니다. 그것은 제한 요인이 될 수 있고 이익과 균형을 이루어야 한다.

액세스 빈도 - 개체에 거의 액세스하지 않는 경우 캐싱이 효과적이지 않을 수 있습니다. 캐시에서 두 번째로 액세스하기 전에 오래된 상태가 되거나 무효화됩니다. 이러한 항목은 메모리 리소스를 차단합니다.

공유 액세스 - 둘 이상의 엔터티에서 사용하는 데이터는 체인 위에 캐시되어야 합니다. 실제로 캐싱 체인은 체인이 아니라 나무입니다. 둘 이상의 모델에서 저장소의 한 데이터를 사용할 수 있습니다. 두 개 이상의 렌더링 스크립트에서 이러한 모델을 사용하여 HTML 조각을 생성할 수 있습니다. 이러한 조각은 브라우저에서 개인 캐시가 있는 여러 사용자에게 배포되는 여러 페이지에 포함됩니다. 따라서 "공유"는 사람들 사이에서만 공유되는 것이 아니라 소프트웨어 조각 간에 공유되는 것입니다. 잠재적인 "공유" 캐시를 찾으려면 루트로 트리를 다시 추적하고 공통 상위 항목을 찾으면 됩니다. 이 위치가 캐시되어야 합니다.

지리공간 배포 - 사용자가 전 세계에 분포되어 있는 경우 분산된 캐시 네트워크를 사용하면 지연 시간을 줄이는 데 도움이 될 수 있습니다.

네트워크 대역폭 및 대기 시간 - 대기 시간 관련, 귀하의 고객은 누구이며 어떤 종류의 네트워크를 사용하고 있습니까? 아마도 당신의 고객들은 후진국 국가에서 구형 스마트폰의 3G 연결을 사용하는 모바일 고객일 것입니다? 더 작은 객체를 생성하여 브라우저 캐시에 캐시하는 것이 좋습니다.

지금까지는 이 목록들이 포괄적이지는 않지만, 지금까지는 당신이 그 아이디어를 얻었다고 우리는 생각합니다.

체인 캐싱에 대한 기본 규칙

다시 한 번 말하지만 캐싱은 어렵습니다. 프로젝트에서 문제를 방지하는 데 도움이 되는 이전 프로젝트에서 추출한 몇 가지 기본 규칙을 공유해 보겠습니다.

이중 캐싱 방지

마지막 장에 소개된 각 레이어는 캐싱 체인에서 일부 값을 제공합니다. 컴퓨팅 주기를 절약하거나 데이터를 소비자에게 더 가깝게 제공함으로써. 체인의 여러 단계에서 데이터 일부를 캐시하는 것이 잘못된 것은 아니지만 항상 다음 단계의 이점과 비용이 무엇인지 고려해야 합니다. Publish 시스템에서 전체 페이지를 캐시하는 것은 일반적으로 이점이 없습니다. 이미 Dispatcher에서 수행되기 때문입니다.

무효화 전략 혼합

다음과 같은 세 가지 기본 무효화 전략이 있습니다.

  • TTL, Time to Live: 개체가 일정 시간 후 만료됩니다(예: "지금부터 2시간 후").
  • 만료 날짜: 개체가 나중에 정의된 시간(예: "2019년 6월 10일 오후 5시")에 만료됩니다.
  • 이벤트 기반: 플랫폼에서 발생한 이벤트(예: 페이지가 변경되고 활성화될 때)에 의해 개체가 명시적으로 무효화됩니다.

이제 다양한 캐시 레이어에서 다양한 전략을 사용할 수 있지만 "독성"인 전략도 몇 가지 있습니다.

이벤트 기반 무효화

순수 이벤트 기반 무효화

순수 이벤트 기반 무효화: 내부 캐시에서 외부 레이어로 무효화

순수한 사건 기반 무효화는 이해하기 가장 쉽고, 이론적으로 옳게 생각하기 쉬우며, 가장 정확한 것이다.

간단히 말해, 캐시는 객체가 변경된 후 하나씩 무효화됩니다.

다음 한 가지 규칙만 염두에 두면 됩니다.

항상 내부에서 외부 캐시로 무효화하십시오. 먼저 외부 캐시를 무효화한 경우 내부 캐시에서 오래된 콘텐츠를 다시 캐시할 수 있습니다. 캐시가 새로 고쳐진 시점에 어떤 가정을 하지 마십시오. 반드시 확인하십시오. 가장 좋은 방법은 내부 캐시를 무효화하는 after 외부 캐시의 무효화를 트리거하는 것입니다.

자, 그게 이론입니다. 그러나 실제로 많은 문제들이 있다. 이벤트는 잠재적으로 네트워크를 통해 배포되어야 합니다. 이는 실질적으로 구현하기 가장 어려운 무효화 제도를 만든다.

자동 - 복구

이벤트 기반 무효화를 사용하는 경우 우발 대책을 세워야 합니다. 무효화 이벤트가 누락된 경우 어떻게 합니까? 간단한 전략은 일정 시간 후에 무효화하거나 제거하는 것일 수 있다. 따라서 - 해당 이벤트를 놓치고 이제 오래된 콘텐츠를 제공할 수 있습니다. 하지만 객체에는 몇 시간(일)의 암시적 TTL만 있습니다. 결국 시스템은 스스로 자동 치유됩니다.

순수 TTL 기반 무효화

동기화되지 않은 TTL 기반 무효화

동기화되지 않은 TTL 기반 무효화

그것 또한 매우 일반적인 계획이다. 캐시 레이어를 여러 개 스택할 수 있으며, 각 캐시 레이어는 특정 시간 동안 객체를 제공할 수 있습니다.

쉽게 구현할 수 있습니다. 안타깝게도, 데이터의 유효 수명을 예측하기는 어렵습니다.

내부 개체의 수명을 연장하는 외부 경로

내부 개체의 수명을 연장하는 외부 캐시

위의 그림을 생각해 보십시오. 각 캐싱 레이어에는 2분의 TTL이 도입됩니다. 자, 전체 TTL도 2분이어야 하죠? 그렇진 않아. 바깥쪽 레이어가 부실 상태가 되기 바로 전에 개체를 가져오는 경우 바깥쪽 레이어는 실제로 개체의 유효 라이브 시간을 연장합니다. 이 경우 유효 라이브 시간은 2~4분일 수 있습니다. 비즈니스 부서에 동의한 경우를 고려해 보십시오. 하루는 견딜 수 있으며 4개의 캐시 레이어가 있습니다. 각 레이어의 실제 TTL은 6시간을 초과할 수 없습니다. 캐시 누락률을 늘리는 중…

우리는 그것이 나쁜 계략이라고 말하고 있는 것이 아니다. 당신은 그것의 한계를 알아야 합니다. 그리고 그것은 시작하기에 좋은 쉬운 전략입니다. 사이트의 트래픽이 증가하는 경우에만 보다 정확한 전략을 고려할 수 있습니다.

특정 날짜를 설정하여 무효화 시간 동기화

만료 날짜 기반 무효화

내부 개체에 특정 날짜를 설정하고 외부 캐시에 전달하는 경우 예측 가능한 유효 수명이 늘어납니다.

만료 날짜 동기화

만료 날짜 동기화

그러나 모든 캐시가 날짜를 전달할 수 있는 것은 아닙니다. 외부 캐시가 만료 날짜가 다른 내부 개체 두 개를 집계하면 더 위험해질 수 있습니다.

이벤트 기반 및 TTL 기반 무효화 혼합

이벤트 기반 전략과 TTL 기반 전략 혼합

이벤트 기반 전략과 TTL 기반 전략 혼합

또한 AEM 세계의 일반적인 체계는 내부 캐시(예: 이벤트가 거의 실시간으로 처리될 수 있는 인메모리 캐시)에서 이벤트 기반 무효화와 외부에서 TTL 기반 캐시를 사용하는 것입니다. 이 경우 명시적 무효화에 액세스할 수 없습니다.

AEM 세계에서는 기본 리소스가 변경되고 이 변경 이벤트를 이벤트 기반으로도 작동하는 Dispatcher에 전파할 때 Publish 시스템의 비즈니스 오브젝트 및 HTML 조각에 대한 메모리 내 캐시가 무효화됩니다. 그 앞에는 예를 들어 TTL 기반 CDN이 있습니다.

Dispatcher 앞에 (짧은) TTL 기반 캐싱 레이어를 두면 자동 무효화 이후 일반적으로 발생하는 스파이크를 효과적으로 누그러뜨릴 수 있습니다.

TTL - 및 이벤트 기반 무효화 혼합

TTL - 및 이벤트 기반 무효화 혼합

독성: TTL - 및 이벤트 기반 무효화 혼합

이 조합은 독성이 있습니다. TTL 또는 만료 기반 캐시 후에는 및 이벤트 기반 캐시를 배치하지 마십시오. "pure-TTL" 전략에서 우리가 가졌던 침수 효과를 기억합니까? 여기에서도 같은 효과를 관찰할 수 있다. 외부 캐시의 무효화 이벤트가 이미 발생한 경우에만 다시 발생하지 않을 수 있습니다. 이렇게 하면 캐시된 객체의 수명이 무한대로 확장될 수 있습니다.

TTL 기반 및 이벤트 기반 결합: 무한대로 분산

TTL 기반 및 이벤트 기반 결합: 무한대로 분산

부분 캐싱 및 메모리 내 캐싱

렌더링 프로세스 단계에 연결하여 캐싱 레이어를 추가할 수 있습니다. 원격 데이터 전송 개체를 가져오거나 로컬 비즈니스 개체를 만드는 것에서부터 단일 구성 요소의 렌더링된 마크업을 캐시하는 것까지. 구체적인 구현은 이후 튜토리얼에 맡기겠습니다. 하지만 이러한 캐싱 레이어 중 일부를 이미 직접 구현했을 수도 있습니다. 그래서 우리가 여기서 할 수 있는 최소한의 일은 기본적인 원리들 - 과 고차들을 소개하는 것이다.

경고 단어

액세스 제어 존중

여기에 설명된 기술은 매우 강력하며 각 AEM 개발자의 도구 상자에는 must-have ​가 있습니다. 하지만 너무 흥분하지 말고, 그것들을 현명하게 사용하세요. 객체를 캐시에 저장하고 후속 요청에서 다른 사용자에게 공유함으로써 액세스 제어를 우회하는 것을 의미합니다. 일반적으로 공개 웹 사이트에서는 문제가 되지 않지만, 사용자가 액세스하기 전에 로그인해야 하는 경우에는 문제가 될 수 있습니다.

사이트 메인 메뉴의 HTML 마크업을 메모리 내 캐시에 저장하여 다양한 페이지 간에 공유할 수 있습니다. 실제로 이는 부분적으로 렌더링된 HTML을 저장하는 완벽한 예이며, 탐색을 만들려면 많은 페이지를 트래버스해야 하므로 일반적으로 비용이 많이 듭니다.

모든 페이지 간에 동일한 메뉴 구조를 공유하지 않고 모든 사용자와 공유하여 효율성을 더욱 높일 수 있습니다. 잠시 기다려 주십시오… 메뉴에 특정 사용자 그룹만 예약된 항목이 있을 수 있습니다. 이 경우 캐싱은 약간 더 복잡해질 수 있습니다.

사용자 지정 비즈니스 개체만 캐시

그것이 가장 중요한 조언이라면, 우리는 당신에게 줄 수 있습니다.

WARNING
변경 불가능, 직접 빌드한 약점이고 송신 참조가 없는 캐시만 합니다.

어떤 의미입니까?

  1. 다른 사람의 물건에 대해 의도한 라이브 사이클에 대해 알지 못합니다. 요청 개체에 대한 참조를 보고 캐시하도록 결정하는 것이 좋습니다. 이제 요청이 종료되고 서블릿 컨테이너가 다음 수신 요청에 대해 해당 개체를 재생하려고 합니다. 이 경우 사용자가 독점적으로 제어했다고 생각했던 콘텐츠를 다른 사용자가 변경하고 있습니다. 이를 무시하지 마십시오. 프로젝트에서 이와 같은 상황이 발생하는 것을 보았습니다. 고객이 자신의 데이터가 아닌 다른 고객 데이터를 보고 있었습니다.

  2. 개체가 다른 참조 체인에 의해 참조되는 한 힙에서 제거할 수 없습니다. 참조되는 캐시에서 작은 개체를 유지하는 경우 4MB의 이미지 표현이 있으면 메모리 누출에 문제가 발생할 가능성이 높다고 가정해 보겠습니다. 캐시는 약한 참조를 기반으로 해야 합니다. 하지만 - 약한 참조는 예상대로 작동하지 않습니다. 이것이 메모리 누수를 발생시키고 메모리 부족 오류로 끝나는 가장 좋은 방법입니다. 그리고 - 당신은 이물질의 보유 메모리 크기가 얼마나 되는지 알지 못합니까, 맞습니까?

  3. 특히 Sling에서는 각 오브젝트를 서로 (거의) 조정할 수 있습니다. 리소스를 캐시에 저장하는 것이 좋습니다. 다른 액세스 권한을 가진 다음 요청은 해당 리소스를 가져와 resourceResolver 또는 세션에 조정하여 액세스 권한이 없는 다른 리소스에 액세스합니다.

  4. AEM의 리소스 주위에 얇은 "래퍼"를 만들더라도 이를 캐시해서는 안 됩니다(자신의 것이고 변경할 수 없는 경우에도). 래핑된 물체는 참조(이전에는 금지한)가 되며 선명하게 보이면 기본적으로 마지막 항목에 설명된 것과 동일한 문제를 일으킵니다.

  5. 캐시하려면 기본 데이터를 고유한 Shallo 개체에 복사하여 고유한 개체를 만듭니다. 개체 트리를 캐시하는 등 참조를 통해 개체 간에 연결할 수 있습니다. 괜찮습니다. 하지만 동일한 요청에서 방금 만든 오브젝트만 캐시합니다. 다른 곳에서 요청된 오브젝트는 없습니다('your' 오브젝트의 name-space인 경우에도). 개체 복사 ​가 중요합니다. 연결된 개체의 전체 구조를 한 번에 지우고 구조에 대한 들어오는 참조와 나가는 참조를 방지해야 합니다.

  6. 예 - 오브젝트를 변경할 수 없습니다. 비공개 속성, 설정자만 제외.

그건 많은 규칙이지만, 따를 만한 가치가 있어요. 당신이 경험이 많고 매우 똑똑하고 모든 것을 통제한다 할지라도. 당신 프로젝트의 젊은 동료가 대학을 갓 졸업했어요. 그는 이 모든 위험을 알지 못한다. 함정이 없으면 피해야 할 게 없다. 간단하고 이해하기 쉽게 하세요.

도구 및 라이브러리

이 시리즈는 개념을 이해하고 사용 사례에 가장 적합한 아키텍처를 구축할 수 있는 권한을 부여하는 것입니다.

특별히 홍보할 수 있는 도구는 없습니다. 하지만 그것들을 평가하는 방법에 대한 힌트를 주시오. 예를 들어 AEM에는 버전 6.0 이후 고정 TTL과 함께 간단한 내장 캐시가 있습니다. 사용하시겠습니까? 이벤트 기반 캐시가 체인의 뒤에 오는 게시에는 없을 수도 있습니다(힌트: Dispatcher). 하지만 그것은 저자에게 적절한 선택일 수도 있다. 또한 ACS 커먼즈 Adobe에 의한 HTTP 캐시도 고려해 볼 만하다.

또는 Ehcache와 같은 완성도 높은 캐싱 프레임워크를 기반으로 자체 빌드합니다. Java 개체 및 렌더링된 마크업(String개 개체)을 캐시하는 데 사용할 수 있습니다.

일부 간단한 경우 동시 해시 맵을 사용하면 익숙해질 수 있습니다. 도구나 기술에서 제한을 빠르게 확인할 수 있습니다. 동시성은 이름 지정 및 캐싱만큼 마스터하기 어렵습니다.

참조

기본 용어

여기서는 캐싱 이론을 너무 깊이 다루지는 않겠지만, 우리는 몇 가지 유행어를 제공해야 할 의무가 있음을 느끼므로 당신은 좋은 점프 스타트를 얻을 수 있다.

캐시 제거

우리는 무효화와 제거에 대해 많이 이야기했다. 캐시 제거 ​는 다음 용어와 관련되어 있습니다. 항목이 제거되면 더 이상 사용할 수 없습니다. 그러나 항목이 오래된 것이 아니라 캐시가 꽉 찬 경우 축소가 발생합니다. 새 항목 또는 "더 중요한" 항목은 오래된 항목 또는 덜 중요한 항목을 캐시에서 밀어냅니다. 어떤 항목을 희생해야 할 지는 사례별로 결정하는 것입니다. 가장 오래된 항목이나 매우 드물게 사용되었거나 오랫동안 마지막으로 액세스된 항목을 제거할 수 있습니다.

선제적 캐싱

선제적 캐싱은 항목이 무효화되거나 오래된 것으로 간주되는 즉시 새로운 콘텐츠로 항목을 다시 만드는 것을 의미합니다. 물론, 몇 가지 리소스로만 이 작업을 수행할 수 있으며, 이러한 리소스는 자주 즉시 액세스할 수 있습니다. 그렇지 않으면 요청하지 않을 수 있는 캐시 항목을 만드는 데 리소스를 낭비하게 됩니다. 캐시 항목을 선제적으로 생성하면 캐시 무효화 후 리소스에 대한 첫 번째 요청의 지연을 줄일 수 있습니다.

캐시 워밍

캐시 워밍은 선제적 캐싱과 밀접한 관련이 있다. 라이브 시스템에는 이 용어를 사용하지 않을 것입니다. 그리고 이것은 전자보다 더 적은 시간 제약입니다. 무효화 직후 다시 캐시하지 않지만 시간이 허용되면 점진적으로 캐시를 채웁니다.

예를 들어 로드 밸런서에서 Publish/Dispatcher 레그를 빼서 업데이트합니다. 다시 통합하기 전에 가장 자주 액세스하는 페이지를 자동으로 크롤링하여 캐시에 다시 넣습니다. 캐시가 "warm"이면(적절히) 로드 밸런서에 레그를 다시 통합합니다.

또는 다리를 한 번에 다시 통합시킬 수도 있지만, 그 다리에 트래픽을 조절해서 주기적으로 캐시를 데울 수 있도록 할 수도 있습니다.

또는 시스템이 유휴 상태일 때 덜 액세스된 페이지를 캐시하여 실제 요청으로 액세스할 때 지연을 줄이는 것도 좋습니다.

캐시 오브젝트 ID, 페이로드, 무효화 종속성 및 TTL

일반적으로 캐시된 개체 또는 "항목"에는 5개의 주요 속성이 있습니다.

ID는 식별하여 개체를 정의하는 속성입니다. 페이로드를 검색하거나 캐시에서 제거합니다. 예를 들어 Dispatcher는 페이지의 URL을 키로 사용합니다. Dispatcher는 페이지 경로를 사용하지 않습니다. 이것은 다른 표현들을 구별하는 데 충분하지 않다. 다른 캐시는 다른 키를 사용할 수 있습니다. 우리는 나중에 몇 가지 예를 볼 것이다.

값 / 페이로드

그것은 그 물건의 보물 상자, 즉 당신이 회수하고자 하는 데이터입니다. Dispatcher의 경우 파일 콘텐츠입니다. 하지만 Java 개체 트리일 수도 있습니다.

TL

TTL은 이미 다루었습니다. 항목이 오래된 것으로 간주되어 더 이상 배달되지 않아야 하는 시간입니다.

종속성

이는 이벤트 기반 무효화와 관련이 있습니다. 해당 객체는 어떤 원본 데이터에 따라 달라집니까? 1부에서 우리는 이미 진실하고 정확한 의존도 추적이 너무 복잡하다고 말했다. 그러나 이 시스템에 대한 지식을 바탕으로 종속성을 보다 간단한 모델로 근사화할 수 있습니다. 부실 콘텐츠를 제거할 충분한 오브젝트를 무효화합니다… 의도치 않게 필요 이상의 항목을 제거할 수 있습니다. 하지만 우리는 "모든 것을 제거"하지 않으려고 노력합니다.

각 단일 애플리케이션에서 다른 사용자의 정체에 따라 달라지는 개체 나중에 종속성 전략을 구현하는 방법에 대한 몇 가지 예를 제공합니다.

HTML 조각 캐싱

다른 페이지에서 렌더링된 조각을 다시 사용

다른 페이지에서 렌더링된 조각을 다시 사용

HTML 조각 캐싱은 강력한 도구입니다. 이 아이디어는 구성 요소에서 생성한 HTML 마크업을 메모리 내 캐시에 저장하는 것입니다. 제가 왜 그래야 하는지 물어보셔도 됩니다. 구성 요소의 마크업을 포함하여 Dispatcher에 전체 페이지의 마크업을 캐시합니다. 우리는 동의합니다. 한 페이지당 한 번씩만 가능합니다. 페이지 간에 해당 마크업을 공유하지 않습니다.

각 페이지의 맨 위에 탐색을 렌더링한다고 상상해 보십시오. 마크업은 각 페이지에서 동일하게 표시됩니다. 하지만 Dispatcher에 없는 각 페이지에 대해 반복해서 렌더링합니다. 또한 기억하십시오. 자동 무효화 후에는 모든 페이지를 다시 렌더링해야 합니다. 따라서 기본적으로 동일한 코드를 동일한 결과로 수백 번 실행합니다.

경험상 중첩된 위쪽 탐색을 렌더링하는 것은 매우 비용이 많이 드는 작업입니다. 일반적으로 탐색 항목을 생성하기 위해 문서 트리의 적절한 부분을 탐색합니다. 탐색 제목과 URL만 필요한 경우에도 페이지를 메모리에 로드해야 합니다. 그리고 여기선 소중한 자원을 막아버리고 있습니다. 계속해서…

그러나 구성 요소는 여러 페이지 간에 공유됩니다. 그리고 무언가를 공유하는 것은 캐시를 사용하는 표시입니다. 따라서 - 탐색 구성 요소가 이미 렌더링되고 캐시되었는지 확인하고, 다시 렌더링하지 않고 캐시 값만 내보내면 됩니다.

이 계획에는 놓치기 쉬운 두 가지 멋진 점이 있습니다.

  1. Java 문자열을 캐시합니다. 문자열에 송신 참조가 없으며 변경할 수 없습니다. 따라서 위의 경고를 고려하면 매우 안전합니다.

  2. 무효화 또한 매우 쉽습니다. 웹 사이트를 변경할 때마다 이 캐시 항목을 무효화합니다. 재구축은 한 번만 수행한 다음 수백 페이지 전체에서 재사용해야 하므로 상대적으로 비용이 저렴합니다.

이는 Publish 서버에 큰 도움이 됩니다.

조각 캐시 구현

사용자 지정 태그

옛날에는 JSP를 템플릿 엔진으로 사용했으며 구성 요소 렌더링 코드를 감싸는 사용자 지정 JSP 태그를 사용하는 것이 일반적이었습니다.

<!-- Pseudo Code -->

<myapp:cache
  key=' ${info.homePagePath} + ${component.path}'
  cache='main-navigation'
  dependency='${info.homePagePath}'>

… original components code ..

</myapp:cache>

가 아닌 사용자 지정 태그는 본문을 캡처하여 캐시에 쓰거나 본문이 실행되지 않도록 하고 대신 캐시 항목의 페이로드를 출력합니다.

키는 홈 페이지에 있을 구성 요소 경로입니다. 현재 페이지에서는 페이지당 하나의 캐시 항목이 생성되므로 구성 요소의 경로를 사용하지 않습니다. 이는 해당 구성 요소를 공유하려는 의도에 위배됩니다. 또한 구성 요소 상대 경로(jcr:conten/mainnavigation)만 사용하면 서로 다른 사이트에서 서로 다른 탐색 구성 요소를 사용할 수 없으므로 해당 경로만 사용하지 않습니다.

"캐시"는 항목을 저장할 위치입니다. 일반적으로 항목을 저장할 수 있는 캐시가 두 개 이상 있습니다. 각 ID는 약간 다르게 작동할 수 있습니다. 따라서 저장된 내용을 구분하는 것이 좋습니다. 결국에는 문자열만 저장되는 경우에도 마찬가지입니다.

"종속성" 캐시 항목이 종속된 것입니다. "메인 탐색" 캐시에는 "종속성" 노드 아래에 변경 사항이 있는 경우 해당 항목을 삭제해야 한다는 규칙이 있을 수 있습니다. 따라서 캐시 구현은 변경 사항을 인식하기 위해 저장소에서 이벤트 리스너로 자신을 등록한 다음 캐시 관련 규칙을 적용하여 무효화해야 하는 사항을 찾아야 합니다.

위의 내용은 단지 예시일 뿐입니다. 캐시 트리를 선택할 수도 있습니다. 첫 번째 수준을 사용하여 사이트(또는 테넌트)와 두 번째 수준을 구분한 다음 위의 예제와 같이 홈 페이지 경로를 추가할 필요가 없는 컨텐츠 유형(예: "메인 탐색")으로 분기하는 경우.

그런데, 보다 최신 HTL 기반 구성 요소와 함께 이 접근 방식을 사용할 수도 있습니다. 그런 다음 HTL 스크립트 주위에 JSP 래퍼가 있습니다.

구성 요소 필터

하지만 순수한 HTL 접근 방식에서는 Sling 구성 요소 필터를 사용하여 조각 캐시를 구축하는 것이 좋습니다. 우리는 이것을 아직 야생에서 보지 않았지만, 그것이 우리가 그 문제에 대해 취할 접근입니다.

Sling Dynamic 포함 항목

조각 캐시는 변화하는 환경(다른 페이지)의 컨텍스트에서 일정한 사항(탐색)이 있는 경우 사용됩니다.

하지만 반대의 경우도 있을 수 있습니다. 비교적 일관된 컨텍스트(거의 변경되지 않는 페이지)와 해당 페이지에 계속 변경되는 조각(예: 라이브 티커)이 있습니다.

이 경우 Sling Dynamic Includes에 기회를 줄 수 있습니다. 기본적으로 이 필터는 구성 요소 필터이며, 동적 구성 요소를 감싸고 구성 요소를 페이지에 렌더링하지 않고 참조를 만듭니다. 이 참조는 Ajax 호출일 수 있습니다. 이렇게 하면 브라우저에 구성 요소가 포함되므로 주변 페이지가 정적으로 캐시될 수 있습니다. 또는 - 또는 - Sling Dynamic Include가 SSI 지시문(서버측 포함)을 생성할 수 있습니다. 이 지시문은 Apache 서버에서 실행됩니다. Varnish나 ESI 스크립트를 지원하는 CDN을 활용하는 경우 ESI - Edge Side Include 지시문을 사용할 수도 있습니다.

Sling Dynamic Include를 사용한 요청의 시퀀스 다이어그램

Sling Dynamic Include를 사용한 요청의 시퀀스 다이어그램

SDI 설명서에는 동적 구성 요소를 처리할 때 "*.nocache.html"로 끝나는 URL에 대한 캐싱을 비활성화해야 한다고 설명되어 있습니다.

SDI를 사용하는 다른 옵션이 표시될 수 있습니다. 포함 항목에 대해 Dispatcher 캐시를 사용하지 않도록 ​하면 Dispatcher은 마지막 장에서 설명한 것과 유사한 조각 캐시와 같은 역할을 합니다. 페이지 및 구성 요소 조각은 Dispatcher에서 동등하고 독립적으로 캐시되며 페이지가 요청될 때 Apache 서버의 SSI 스크립트에 의해 결합됩니다. 이렇게 하면 기본 탐색과 같은 공유 구성 요소를 구현할 수 있습니다(항상 동일한 구성 요소 URL을 사용하는 경우).

이론상으로는 그게 통할 거야 하지만…

이렇게 하지 않는 것이 좋습니다. 실제 동적 구성 요소에 대해 캐시를 우회하는 기능을 잃게 됩니다. SDI는 전체적으로 구성되며 "poor-mans-fragment-cache"에 대한 변경 사항은 동적 구성 요소에도 적용됩니다.

SDI 설명서를 주의 깊게 검토하는 것이 좋습니다. 몇 가지 다른 제한 사항이 있지만 SDI는 경우에 따라 유용한 도구입니다.

참조

모델 캐싱

모델 기반 캐싱: 두 개의 다른 렌더링이 있는 하나의 비즈니스 개체

모델 기반 캐싱: 두 개의 다른 렌더링이 있는 하나의 비즈니스 개체

내비게이션이 있는 케이스를 다시 살펴보자. 각 페이지에 탐색과 동일한 마크업이 필요하다고 가정합니다.

하지만 아마, 그렇지 않을 것이다. 현재 페이지 ​를 나타내는 탐색 메뉴의 항목에 대해 다른 태그를 렌더링할 수 있습니다.

Travel Destinations

<ul class="maninnav">
  <li class="currentPage">Travel Destinations
    <ul>
      <li>Finland
      <li>Canada
      <li>Norway
    </ul>
  <li>News
  <li>About us
<ul>
News

<ul class="maninnav">
  <li>Travel Destinations
  <li class="currentPage">News
    <ul>
      <li>Winter is coming>
      <li>Calm down in the wild
    </ul>
  <li>About us
<is

이 두 가지 표현은 완전히 다릅니다. 하지만 전체 탐색 트리인 비즈니스 개체 ​는 동일합니다. 여기서 비즈니스 개체 ​는 트리의 노드를 나타내는 개체 그래프입니다. 이 그래프는 메모리 내 캐시에 쉽게 저장할 수 있습니다. 그러나 이 그래프는 개체를 포함하거나 직접 만들지 않은 개체(특히 현재 JCR 노드)를 참조해서는 안 됩니다.

브라우저에서 캐싱

이미 브라우저에서 캐싱의 중요성에 손을 댔고, 많은 좋은 튜토리얼이 있습니다. 결국 - 브라우저의 경우 - Dispatcher은 HTTP 프로토콜을 따르는 웹 서버일 뿐입니다.

하지만 - 이론에도 불구하고 - 우리는 우리가 다른 어느 곳에서도 발견하지 못했고 우리가 공유하기를 원하는 약간의 지식을 수집했다.

기본적으로 브라우저 캐싱은 두 가지 다른 방식으로 활용할 수 있습니다.

  1. 브라우저에 정확한 만료 날짜를 알고 있는 캐시된 리소스가 있습니다. 이 경우 리소스를 다시 요청하지 않습니다.

  2. 브라우저에 리소스가 있지만 아직 유효한지 확실하지 않습니다. 이 경우 웹 서버(여기서는 Dispatcher)에 문의하십시오. 마지막으로 배송한 이후 수정되었으면 리소스를 주세요. 변경되지 않은 경우 서버는 "304 - 변경되지 않음"으로 응답하고 메타데이터만 전송되었습니다.

디버깅

브라우저 캐싱에 대해 Dispatcher 설정을 최적화하는 경우 브라우저와 웹 서버 간에 데스크탑 프록시 서버를 사용하는 것이 매우 유용합니다. 우리는 카를 본 랜도의 "찰스 웹 디버깅 프록시"를 선호합니다.

Charles를 사용하면 서버와 주고 받는 요청 및 응답을 읽을 수 있습니다. 또한 HTTP 프로토콜에 대해 자세히 알아볼 수 있습니다. 최신 브라우저도 일부 디버깅 기능을 제공하지만 데스크탑 프록시의 기능은 전례가 없습니다. 전송된 데이터를 조작하고 전송 속도를 조절하며 단일 요청을 재생하는 등의 작업을 수행할 수 있습니다. 그리고 사용자 인터페이스는 명확하게 정렬되어 있고 매우 포괄적입니다.

가장 기본적인 테스트는 사이에 프록시를 사용하여 웹 사이트를 일반 사용자로 사용하고 정적 요청(에 대한 /etc/…) 수가 시간이 지남에 따라 감소하고 있는지 프록시를 확인하는 것입니다. 정적 요청은 캐시에 있어야 하며 더 이상 요청되지 않아야 합니다.

캐시된 요청이 로그에 표시되지 않으므로 프록시가 더 명확한 개요를 제공할 수 있지만 일부 브라우저 내장 디버거는 여전히 "0ms" 또는 "from disk"로 이러한 요청을 표시합니다. 이는 적절하고 정확하지만 보기를 약간 흐리게 할 수 있습니다.

그런 다음 "Expires" http 헤더가 올바른 경우 등을 확인하기 위해 전송된 파일의 헤더를 드릴다운하고 확인할 수 있습니다. if-modified-since 헤더가 설정된 상태로 요청을 재생하여 서버가 304 또는 200 응답 코드에 올바르게 응답하는지 확인할 수 있습니다. 비동기 호출의 타이밍을 관찰할 수 있으며 보안 가정을 일정 정도 테스트할 수도 있습니다. 명시적으로 예상되지 않은 모든 선택기를 수락하지 않도록 지시했다는 점을 기억하십니까? 여기에서 URL 및 매개 변수를 재생하여 애플리케이션이 제대로 작동하는지 확인할 수 있습니다.

캐시를 디버깅할 때에는 한 가지 작업을 수행하지 마십시오.

브라우저에서 페이지를 다시 로드하지 마십시오!

"브라우저 다시 로드", 단순 다시 로드 ​와 강제 다시 로드("shift-reload")는 일반 페이지 요청과 다릅니다. 단순 재로드 요청은 헤더를 설정합니다

Cache-Control: max-age=0

그리고 Shift 키를 누른 상태에서 다시 로드 단추를 클릭하면 일반적으로 요청 헤더가 설정됩니다

Cache-Control: no-cache

두 헤더 모두 비슷하지만 약간 다른 효과가 있습니다. 그러나 가장 중요한 것은 URL 슬롯에서 URL을 열거나 사이트에서 링크를 사용할 때 일반적인 요청과 완전히 다르다는 것입니다. 일반 탐색에서는 Cache-Control 헤더가 설정되지 않지만 아마도 if-modified-since 헤더일 것입니다.

따라서 일반적인 탐색 동작을 디버깅하려면 정상적으로 찾아보기 ​를 수행해야 합니다. 브라우저의 다시 로드 단추를 사용하면 구성에서 캐시 구성 오류를 표시하지 않는 가장 좋은 방법입니다.

Charles Proxy를 사용하여 현재 논의 중인 내용을 확인하십시오. 예 - 열려 있는 동안 요청을 바로 재생할 수 있습니다. 브라우저에서 다시 로드할 필요가 없습니다.

성능 테스트

프록시를 사용하면 페이지의 타이밍 동작을 파악할 수 있습니다. 물론, 그것은 단연 성능 시험이 아니다. 성능 테스트에는 페이지를 동시에 요청하는 여러 클라이언트가 필요합니다.

너무 자주 보는 일반적인 실수는 성능 테스트에 매우 적은 수의 페이지만 포함되어 있으며 이러한 페이지는 Dispatcher 캐시에서만 전달된다는 것입니다.

애플리케이션을 라이브 시스템으로 프로모션하는 경우 로드는 테스트한 것과 완전히 다릅니다.

라이브 시스템에서 액세스 패턴은 테스트(홈 페이지 및 소수의 콘텐츠 페이지)에 있는 동일하게 배포된 페이지 수가 많지 않습니다. 페이지 수가 훨씬 많고 요청이 매우 불균일하게 배포됩니다. 그리고 - 물론 - 라이브 페이지는 캐시에서 100% 제공될 수 없습니다. 귀중한 리소스의 큰 부분을 자동으로 무효화하는 Publish 시스템에서 오는 무효화 요청이 있습니다.

예. 그리고 Dispatcher 캐시를 재구축할 때 Publish 시스템도 몇 개의 페이지만 요청하는지 또는 더 큰 숫자를 요청하는지에 따라 상당히 다르게 동작한다는 것을 알 수 있습니다. 모든 페이지가 유사하게 복잡하더라도 페이지 번호가 역할을 합니다. 체인 캐싱에 대해 우리가 말했던 것을 기억하는가? 항상 동일한 적은 수의 페이지를 요청하면 원시 데이터가 있는 블록이 하드 드라이브 캐시에 있거나 블록이 운영 체제에 의해 캐시될 가능성이 높습니다. 또한 저장소가 주 메모리에 해당 세그먼트를 캐시했을 가능성도 있습니다. 따라서 재렌더링은 다른 페이지가 여러 캐시에서 서로 제거되도록 했을 때보다 훨씬 빠릅니다.

캐싱은 어려우며, 캐싱에 의존하는 시스템의 테스트도 마찬가지입니다. 그렇다면, 더 정확한 실생활 시나리오를 갖기 위해 무엇을 할 수 있는가?

두 개 이상의 테스트를 수행해야 하며 솔루션 품질을 측정하는 방법으로 두 개 이상의 성능 지수를 제공해야 할 것으로 생각됩니다.

기존 웹 사이트가 있는 경우 요청 수와 요청 분배 방법을 측정합니다. 유사한 요청 분포를 사용하는 테스트를 모델링해 보십시오. 무작위성을 추가해도 손해 볼 수 없습니다. JS 및 CSS와 같은 정적 리소스를 로드하는 브라우저를 시뮬레이션할 필요가 없습니다. 이러한 리소스는 실제로 중요하지 않습니다. 결국 브라우저 또는 Dispatcher에서 캐시되며 로드에 크게 추가되지 않습니다. 하지만 참조된 이미지는 중요합니다. 이전 로그 파일에서도 분포를 찾아 유사한 요청 패턴을 모델링합니다.

이제 Dispatcher에서 캐싱하지 않는지 테스트해 보십시오. 그것은 당신의 최악의 시나리오입니다. 이 최악의 조건에서 시스템이 어느 정점에서 불안정해지는지 알아보십시오. 원하는 경우 Dispatcher/Publish 다리 몇 개를 빼면 문제를 더 악화시킬 수도 있습니다.

그런 다음 필요한 모든 캐시 설정을 "on"으로 설정하여 동일한 테스트를 수행합니다. 병렬 요청을 서서히 늘려 캐시를 데우고 이러한 최상의 사례 조건에서 시스템이 얼마나 많은 작업을 수행할 수 있는지 확인합니다.

일반적인 사례 시나리오는 Dispatcher이 활성화된 상태에서 테스트를 실행하지만, 일부 무효화가 발생하는 경우입니다. cronjob을 통해 상태 파일을 터치하거나 불규칙한 간격으로 무효화 요청을 Dispatcher으로 전송하여 이를 시뮬레이션할 수 있습니다. 가끔 자동 무효화되지 않은 리소스 중 일부를 제거하는 것도 잊지 마십시오.

무효화 요청을 늘리고 로드를 늘려 마지막 시나리오를 변경할 수 있습니다.

이는 단순한 선형 부하 테스트보다는 좀 더 복잡하지만 솔루션에 대한 신뢰도가 훨씬 더 높습니다.

너는 그 노력을 피할지도 모른다. 그러나 시스템의 한계를 확인하기 위해 더 많은 페이지 수(균등하게 배포됨)가 있는 Publish 시스템에 대해 최악의 테스트를 수행하십시오. 최상의 경우의 시나리오 수를 올바르게 해석하고 충분한 여유 공간이 있는 시스템을 프로비저닝해야 합니다.

recommendation-more-help
aeb7eb84-65b7-4bed-b296-3028319d2331