Contents Service Patterns

저자:WineSOFT 아키텍트팀

M2 파이프라인 플랫폼 구축 사례를 통해 On the fly 유스케이스를 살펴본다.

1장. 프론트엔드 서비스 패턴

이 장에서는 프론트엔드/웹페이지 구성에 유용한 패턴에 대해 설명한다. 모든 서비스가 제공하는 정보는 다르지만 구조적인 관점에서 바라보면 유사하다. 복잡한 서비스 플로우 구성이나 프론트엔드 개발없이 구조적으로 문제를 해결해보자.

반응형 상품기술서

해결하고 싶은 문제

오픈마켓에서는 판매자가 상품기술서를 <HTML> 로 업로드한다. 반응형(Responsive)을 고려하지 않고 작성된 <HTML> 은 레이아웃과 사용자 경험을 망친다. 흔히들 사용하는 배치작업을 통한 마이그레이션에는 치명적인 문제가 있다.

  • 기획이 변경되면 다시 마이그레이션해야 한다.
  • 외부에서 참조되는 리소스는 통제가 불가능하다.

솔루션/패턴 설명

전송시점에 상품기술서 <HTML> 를 반응형(Responsive)으로 수정한다.

_images/dgm006.png

부모 페이지의 CSS / JavaScript 등과 충돌되지 않도록 <iframe> 으로 삽입한다.

주석

<iframe> 에 대한 막연한 우려에 대해 접하곤 한다. 하지만 <iframe> 은 명백히 HTML5 표준이다. 유튜브, 챗봇, 리뷰, 추천등 SaaS(Software As A Service) 연동이 <iframe> 기반으로 서비스되고 있음을 상기하자.

구현

  • 상품기술서 스토리지 앞이나 외부 기술서 참조가 가능한 지점에 M2 를 배치한다. (=HTTP 통신이 가능하다.)

  • M2 상품기술서 엔드포인트를 생성한다.

    # vhosts.xml - <Vhosts><Vhost><M2><Endpoints><Endpoint>
    
    <Model>
       <Source>https://foo.com/#model</Source>
    </Model>
    <View>
       <Source>https://bar.com/#view</Source>
    </View>
    <Control>
       <Path>/item-detail</Path>
    </Control>
    
  • M2 View파일에 상품기술서에 적용할 CSS 와 필터를 적용한다.

  • 프론트엔드에서 반응형 상품기술서를 AJAX로 삽입한다.

    https://www.exmaple.com/item-detail?model=ITEM001&view=responsive
    

장점/효과

  • 상품기술서를 일일이 수정하지 않고 페이지 레이아웃/UX를 개선할 수 있다.
  • 프론트엔드 스타일 충돌없이 도입이 가능하다.
  • 지속적으로 상품기술서 정책을 보강할 수 있다.

주의점

기존 상품기술서를 삽입하는 방식과 스타일 충돌여부를 미리 살펴야 한다.

기타

마이그레이션 과정 중 깨진 상품기술서에 대한 보정도 가능하다.

_images/rsc003.png

혼합 콘텐츠 (Mixed Contents)

해결하고 싶은 문제

HTTPS 웹페이지에서 (외부에서 제공되는) HTTP 리소스를 참조할 경우 콘텐츠가 차단된다.

_images/rsc001.png
_images/rsc002.png

솔루션/패턴 설명

<HTML> 내에 존재하는 혼합 콘텐츠 문제를 클라이언트에게 전송하기 전 필터링한다.

_images/dgm005.png

외부 리소스는 M2 를 통해 단일 HTTPS 도메인으로 제공된다. 3rd Party에 의해 혼합 콘텐츠가 포함된 <iframe> 이 제공되더라도 일관되게 필터링된다.

구현

M2 에서 SSL/TLS Onloading 적용형태는 대상에 따라 4단계로 구분된다.

단계 대상
4 모든 리소스
3 2단계 포함, Scheme 이 생략된 리소스 (예. href="//foo.com/style.css" )
2 HTTP 를 사용하는 절대/상대 URL. ( http://domain/path 또는 /path )
1 2단계 에서 이미지, 동영상 등 제외
  • 스토리지 앞에 M2 를 배치한다. (=HTTP 통신이 가능하다.)

  • M2 혼합 콘텐츠를 필터링할 엔드포인트를 www.example.com 에 생성한다.

    # vhosts.xml - <Vhosts><Vhost><M2><Endpoints><Endpoint>
    
    <Model>
       <Source>https://foo.com/#model</Source>
    </Model>
    <View>
       <Source>https://bar.com/#view</Source>
    </View>
    <Control>
       <Path>/item-detail</Path>
    </Control>
    
  • M2 View파일에 nunjucks 필터를 적용한다.

    {{ model.__raw | toHttps('/item-detail/mixed') }}
    
  • M2 혼합 콘텐츠 게이트웨이용 가상호스트를 생성하고 ByClient 기능을 활성화한다.

    # vhosts.xml - <Vhosts>
    
     <Vhost Name="mixed.example.com">
        <Origin ByClient="ON" ByClientKeyword="byclient" Protocol="HTTP"/>
     </Vhost>
    
  • M2 혼합 콘텐츠 리소스는 www.example.com/item-detail/mixed/.. 로 제공된다. 해당 URL이 mixed.example.com 에서 처리될 수 있도록 URL 전처리를 규칙을 추가한다.

    <URLRewrite AccessLog="Replace">
       <Pattern><![CDATA[www.example.com/item-detail/mixed/(.*)]]></Pattern>
       <Replace><![CDATA[mixed.example/byclient/#1]]></Replace>
    </URLRewrite>
    
  • 혼합 콘텐츠가 포함된 URL을 M2 URL로 변경한다.

    https://www.exmaple.com/item-detail?model=ITEM001&view=...
    

장점/효과

  • 마이그레이션 없이 즉시 웹 사이트에 HTTPS 를 적용한다.
  • 통제할 수 없는 외부 리소스에도 일관되게 HTTPS 를 적용한다.
  • 추후 보안수준이 강화되더라도 M2 를 통해 정책개선이 가능하다.

주의점

현재(2020.06) 이미지등 단순 참조 리소스는 차단되지 않기 때문에 해당 콘텐츠는 배제하는 것이 효율적이다. 추후 보안검사 수준이 상향되는 경우 이미지에 대해서도 이 패턴의 사용이 가능하다. 이 경우 발생하게되는 데이터 트래픽 처리비용에 대해 고려해야 한다.

기타

SSL/TLS Offloading을 제공하는 CDN이 있다면 같이 활용할 수 있다.

핀치 줌 (Pinch Zoom)

해결하고 싶은 문제

모바일 해상도에 최적화되지 않은 이미지등의 가독성이 떨어진다.

솔루션/패턴 설명

전송시점에 웹페이지 영역에 M2가 제공하는 핀치줌 기능을 삽입한다.

_images/dgm028.png

구현

  • M2 의 프론트엔드 모듈 m2fe.min.js 을 웹페이지에 삽입한다.

    <!DOCTYPE html>
    <html lang="en">
    <head>
       <script src="/your-path/m2fe.min.js"></script>
    </head>
    
  • 핀치 줌을 적용하고 싶은 영역을 CSS Selector 형식으로 아래 코드의 #m2-product-area 를 대체한다.

    <head>
       <script src="/your-path/m2fe.min.js"></script>
       <script>
          window.M2OPTION = {
             contentSelector: '#m2-product-area',
             pinchzoom: {
                enable: true
             }
          };
       </script>
    </head>
    <body>
       <div id="m2-product-area">
       ...
    </body>
    

장점/효과

  • 웹페이지를 일일이 수정하지 않고 핀치줌 기능을 추가한다.
  • 프론트엔드 스타일 충돌없이 도입이 가능하다.
  • 지속적으로 인터랙티브 요소를 추가할 수 있다.

주의점

CSS Selector 로 영역을 선택할 수 있어야 한다.

기타

실시간 웹페이지 편집 기능을 이용하면 최소한의 코드 변경까지 제거가 가능하다.

웹페이지 to Web API

해결하고 싶은 문제

서비스 중인 웹페이지와 타 서비스를 연동해야 한다. Web API를 제공하고 싶지만 운영 중인 웹페이지를 수정하거나 별도의 API서비스를 구축하는 것이 부담스럽다.

솔루션/패턴 설명

M2 를 이용해 <HTML> 웹 페이지를 JSON 으로 실시간 맵핑한다.

_images/dgm018.png

Endpoint 를 이용해 RESTful하게 API를 제공한다.

구현

  • 소스 웹페이지와 통신되는 영역에 M2 를 배치한다.

  • M2 엔드포인트를 설정한다. 모델로 게시된 웹페이지를 참조한다.

    # vhosts.xml - <Vhosts><Vhost><M2><Endpoints>
    
    <Endpoint>
       <Model>
          <Source>http://www.example.com/product/#model.html</Source>
          <Mapper>http://storage.com/assets/product_mapper.json</Mapper>
       </Model>
       <View ContentType="application/json">
           <Source>http://storage.com/assets/o4o/#view.json</Source>
       </View>
       <Control>
          <Path>/o4o/events/:model/:view</Path>
       </Control>
    </Endpoint>
    
  • <HTML>M2-JSON 으로 변환할 Mapper 를 작성한다.

      {
         "branch": "#container .total_box strong, textContent, trim",
         "items": [{
            "branch": ".product_list li.item span.branch, textContent, trim",
            "dday": ".product_list li.item span.category, textContent, trim",
            "title": ".product_list li.item .tit, textContent",
            "location": ".product_list li.item p.floor, textContent",
            "period": ".product_list li.item p.date, textContent",
            "imageDataEcho": ".product_list li.item .img_thum img, attributes, data-echo, textContent",
            "imageSrc": ".product_list li.item .img_thum img, attributes, src, textContent",
            "entNo": ".product_list li.item a, attributes, value, textContent"
    }]
    
  • JSON 형식의 View 를 작성한다.

    {
       "timeStamp" : "{{ 'new Date().toISOString()' | eval }}",
       "branch" : "{{model.branch}}",
       "items" : [
       {% for item in model.items %}
       {{ "," if loop.index0 > 0 else "" }}
       {
          "branch" : "{{item.branch}}",
          "title" : "{{item.title | replace("\n", "") | replace('"', '&quot;')}}",
          "location" : "{{item.location | replace("\n", "") | replace('"', '&quot;')}}",
          "period" : "{{item.period}}",
          "imageUrl" : "{{item.imageDataEcho}}",
       }
       {% endfor %}
       ]
    }
    
  • API 를 노출한다.

    https://api.exmaple.com/product/winesoft/type1
    

장점/효과

  • 즉시 가용한 API 서비스를 제공한다.
  • 웹페이지가 수정되면 API에 즉시 반영된다.
  • 백엔드를 연동할 필요가 없다.

주의점

신규 API 서비스 구축비용의 경제성을 면밀히 따져야 한다. 만약 <HTML> 을 처리하는 과정에 복잡한 컨텍스트나 비지니스 로직이나 필요하다면 구축이 더 나은 방법일 수 있다.

기타

소스 <HTML> 이 수정되는 경우 Mapper 를 수정할 수도 있지만 엔드포인트로 제공하는 Web API의 버전을 관리하는 것도 좋은 방법이다.

http://example.com/v1/product/info.json
http://example.com/v2/product/info.json
http://example.com/product/v1/info.json
http://example.com/product/v2/info.json

웹페이지 to PDF

해결하고 싶은 문제

카드사용 내역이나 견적등 고지의무가 있는 개인데이터가 웹사이트에 이미 존재한다. 개인데이터를 기반으로 일일이 PDF를 제작/고지하기엔 비용과 시간이 낭비된다.

솔루션/패턴 설명

M2 를 이용해 개인화 페이지를 즉시 PDF 로 변환한다.

_images/dgm024.png

변환 중 표지를 삽입하거나 PDF 형식에 맞도록 페이지별 제작도 가능하다.

구현

  • 웹페이지 to Web API 와 유사한 구조를 가진다.
  • 개인정보보호를 위해 노출되는 URL을 암호화한다.
  • 해당 URL요청으로부터 웹사이트에 로그인하는 방식에 대해 정의한다.
  • M2 가 웹페이지에 로그인 후 약속된 페이지를 PDF로 실시간 편집/변환한다.

장점/효과

  • 웹페이지가 존재한다면 별도의 데이터 연동이 불필요하다.
  • 개인화가 쉽게 가능하다.

주의점

  • ID/비밀번호를 그대로 노출하는 것보다 익명성을 제공하거나, OAuth 등 제한된 접근허가 방식을 추천한다.
  • 웹페이지를 표현되는 형태 그대로 PDF 로 변환하는 편이 좋다. 숨겨진 화면이나 이벤트가 필요하다면 지나친 커스터마이징이 가미되어 복잡도를 높이게 된다.

기타

M2는 고객에 의해 접근이 허가된 페이지에만 접근할 수 있도록 사전에 통제한다.

2장. 이미지 서비스 패턴

이 장에서는 수 십억장의 이미지를 손쉽게 일괄처리하는 패턴에 대해 설명한다. 오브젝트 스토리지 등장 이후 이미지 가용량에 대한 고민은 많이 사라졌다. 집중해야 하는 지점은 어떻게 고객에게 효과적으로 이미지를 전달할 것인가? 이다.

실시간 이미지 가공

해결하고 싶은 문제

이미지는 용도에 맞추어 다양하게 가공된다. 이미지가 늘어날수록 관리가 어려워진다. 배치(batch) 프로세스로만으로는 더 이상 새로운 기획에 기민하게 대응할 수 없다.

솔루션/패턴 설명

이미지 요청시 가공 형태를 URL에 명시한다.

_images/dgm007.png

M2 를 통해 원본 이미지를 원하는 형태로 실시간 가공하여 전달한다.

구현

  • 이미지 스토리지 앞에 이미지 변환서버 용도의 M2 를 배치한다.

  • M2 이미지툴 기능을 활성화한다.

    # server.xml - <Server><VHostDefault><Options>
    # vhosts.xml - <Vhosts><Vhost><Options>
    
    <Dims Status="Active" Keyword="dims"/>
    
  • 원본 이미지 URL 뒤에 원하는 가공옵션을 붙여 호출한다.

    http://image.example.com/origin.jpg/dims/resize/500x500/optimize
    

장점/효과

  • 원본 이미지 1장만 있다면 어떠한 이미지라도 실시간으로 만들 수 있다.
  • 백엔드의 이미지 가공 시스템이 불필요해진다.

주의점

M2 최대 처리가능 이미지 용량(기본 10MB)을 넘거나 비정상 원본이라면 가공하지 않고 원본을 전송한다.

기타

이미 사용중인 URL 패턴이 있다면 커스터마이징 모듈을 통해 호환성을 확보한다.

실시간 외부 이미지 가공

해결하고 싶은 문제

실시간 이미지 가공 과 유사하나 가공하고 싶은 이미지 URL이 외부 어딘가에 존재한다.

솔루션/패턴 설명

외부이미지 힌트 를 포함한 URL 규칙을 정한다.

_images/dgm022.png

M2 는 이 힌트 를 통해 원본 이미지를 다운로드 받아 가공하여 전달한다. 힌트 는 직접적으로 원본 이미지의 URL일 수 있다.

구현

실시간 이미지 가공 과 동일한 방식이지만 협의된 URL 규칙을 처리하는 엔드포인트가 구성된다.

장점/효과

  • 어떠한 외부이미지라도 즉시 자사 서비스 스타일로 가공할 수 있다.
  • 외부 이미지 장애 또는 인증서 오류 등에도 견고한 서비스가 가능하다.

주의점

자사 백엔드가 아닌 만큼 신뢰할 수 없는 소스가 많을 수 있다.

기타

백업 파이프 패턴과 연계하면 외부 이미지를 스토리지에 백업할 수 있다.

이미지 용량 최적화

해결하고 싶은 문제

고용량 이미지 파일이 서비스되는 경우 전송비용이 상승할 뿐만 아니라 클라이언트 서비스 품질이 저하되는 문제가 발생한다.

솔루션/패턴 설명

이미지가 스토리지에 저장되면 통제가 불가능하다고 생각하는 경향이 있다. 스토리지에 저장되기 전에 이미지 최적화 프로세스를 진행하려는 시도는 실패할 확률이 높다. 서비스 고도화에 따라 스토리지로 향하는 입구가 많아지기 때문이다.

입구를 모두 통제할 수 없다면 단일 출구 정책을 사용하는 것이 효과적이다.

_images/dgm001.png

이미지서버가 이미지를 전송/배포하기 전 고용량 이미지를 최적화한다.

구현

  • 이미지 스토리지 앞에 M2 를 배치한다.

  • M2 이미지툴 기능을 활성화한다. (최대크기를 제한하지 않는다.)

    # server.xml - <Server><VHostDefault><Options>
    # vhosts.xml - <Vhosts><Vhost><Options>
    
    <Dims Status="Active" Keyword="dims" MaxSourceSize="0" />
    
  • M2 이미지 포맷을 대상으로 URL 전처리 규칙을 추가한다.

    <URLRewrite>
       <Pattern>example.com/.*\.(jpg|png).*)</Pattern>
       <Replace>example.com/#1/dims/optimize</Replace>
    </URLRewrite>
    
  • 이미지 스토리지 도메인을 M2 로 위임한다.

장점/효과

  • 기존 URL을 변경없이 사용한다.
  • 항상 균일하게 최적화된 이미지 서비스가 가능하다.
  • 별도의 관리/배치 프로세스 없이 이미지 처리가 자동화된다.
  • 이미지 최적화 정책이 변경되더라도 무중단 정책 변경이 가능하다.
  • 이미지 처리량이 많아질 경우 손쉽게 Scale-out이 가능하다.

주의점

이미지 저장시 최소한의 용량 최적화는 반드시 필요하다.

  • 이미지 크기가 너무 크면 자칫 스토리지 대역폭에 병목이 발생할 수 있다.
  • 이미지 최적화를 위한 컴퓨팅 파워가 과도하게 투입될 수 있다.

기타

  • 자주 변환되는 이미지를 캐싱해 놓으면 불필요한 중복 최적화를 방지할 수 있다.

최대 이미지 해상도 제한

해결하고 싶은 문제

지나치게 큰 이미지는 웹페이지 레이아웃을 파괴한다. 어떠한 이미지라도 가로 1200px을 넘지 않도록 제한하고 싶다.

솔루션/패턴 설명

이미지서버가 이미지를 전송/배포하기 전 해상도를 검사한다.

_images/dgm002.png

설정된 크기보다 큰 해상도라면 이미지를 축소한다.

구현

  • 이미지 스토리지 앞에 이미지 변환서버 용도의 M2 을 배치한다.

  • M2 이미지툴 원본이미지 조건판단 을 설정한다. (최대 가로 1200px)

    # server.xml - <Server><VHostDefault><Options>
    # vhosts.xml - <Vhosts><Vhost><Options>
    
    <Dims Status="Active" Keyword="dims">
       <ByOriginal Name="limit-1200">
          <Condition Width="1200">/optimize</Condition>
          <Condition>/resize/1024x768/optimize</Condition>
       </ByOriginal>
    </Dims>
    
  • M2 다음과 같이 URL을 노출한다.

    http://image.example.com/koala.jpg/dims/byoriginal/limit-1200
    

장점/효과

  • 별도의 관리/배치 프로세스 없이 이미지 처리가 자동화된다.
  • 최대 해상도 정책이 변경되더라도 실시간으로 적용할 수 있다.

주의점

<img src="..." width="1200"> 처럼 태그에 고정된 값을 설정했다면 이미지 크기가 강제로 설정된다.

기타

이미지 URL을 변경하고 싶지 않다면 URL 전처리 를 사용한다.

이미지 분할/병렬로딩

해결하고 싶은 문제

상품기술서 이미지처럼 세로가 긴 이미지는 로딩 속도가 느리다. 특히 모바일 환경처럼 가시(visible)영역이 작은 경우 다운로드가 완료되기 전까지 사용자는 상품정보를 볼 수 없다.

솔루션/패턴 설명

상품기술서는 독립된 HTML 조각(Snippet)으로 웹페이지에 삽입되는 경우가 일반적이다. m2-function-image 를 이용하면 이미지를 분할/병렬 로딩시켜 빠르게 상품기술서를 노출시킬 수 있다.

_images/dgm003.png

상품기술서 처리와 이미지 분할은 독립적으로 운영된다.

구현

  • M2 를 HTML/이미지 스토리지 앞에 배치한다. (=HTTP 통신이 가능하다.)

  • M2 상품기술서를 처리할 엔드포인트를 생성한다.

    # vhosts.xml - <Vhosts><Vhost><M2><Endpoints><Endpoint>
    
    <Model>
       <Source>https://foo.com/#model</Source>
    </Model>
    <View>
       <Source>https://bar.com/#view</Source>
    </View>
    <Control>
       <Path>/productDetail</Path>
    </Control>
    
  • M2 View파일에 m2-function-image 를 적용한다. (세로 500px을 기준으로 분할한다.)

    <html>
       <head>
          <meta name="m2-function-image"
                host="https://www.example.com/m2/image"
                split-height="500">
    
       ... (생략)...
    </html>
    
  • M2 이미지처리용 가상호스트를 생성하고 이미지툴 기능을 활성화한다.

    # vhosts.xml - <Vhosts>
    
    <Vhost Name="image.example.com">
       <Options>
          <Dims Status="Active" Keyword="dims" MaxSourceSize="0" />
       </Options>
    </Vhost>
    
  • M2 이미지처리 경로 /m2/image/image.example.com 을 찾아갈 수 있도록 URL 전처리 를 구성한다.

    # vhosts.xml
    
    <Vhosts>
       ... (생략) ...
    
       <URLRewrite AccessLog="Replace">
          <Pattern><![CDATA[^www.example.com/m2/([^/]+)/(.*)]]></Pattern>
          <Replace><![CDATA[#1.example.com/#2]]></Replace>
       </URLRewrite>
    </Vhosts>
    
  • 상품기술서 URL을 M2 URL로 변경한다.

장점/효과

  • 상품기술서 URL 변경만으로 간단히 도입이 가능하다.
  • 최신(Modern) 브라우저의 병렬로딩 메커니즘을 통해 이전보다 훨씬 빠른 체감속도 개선효과를 얻을 수 있다.

주의점

너무 짧은 TTL(Time To Live)를 설정할 경우 실시간 처리비용이 높아진다. 상품기술서는 자주 변경되지 않으니 최소 1일 이상의 TTL을 권장한다.

기타

처리량이 늘어나면 2-Tier 구조 도입을 고려한다.

스마트 배너 이미지

해결하고 싶은 문제

판매량, 재고, 할인율처럼 지속적으로 변경되는 정보가 반영된 신선한(Fresh) 배너 이미지를 제공하고 싶다. 특히 마케팅 이메일처럼 한밤 중에 발송되고 언제 열람될지 모르는 경우 낡은(Stale) 정보가 제공된다.

솔루션/패턴 설명

정보와 이미지를 동적으로 결합하여 하나의 단일한 이미지를 생성한다.

_images/dgm004.png

정보와 이미지의 결합형태는 언제든지 변경가능하다.

구현

  • M2 를 API서버와 이미지 스토리지 앞에 배치한다. (=HTTP 통신이 가능하다.)

  • M2 정보와 이미지를 결합할 엔드포인트 /mybanner 를 생성한다.

    # vhosts.xml - <Vhosts><Vhost><M2><Endpoints><Endpoint>
    
    <Model>
       <Source>https://foo.com/#model</Source>
    </Model>
    <View>
       <Source>https://bar.com/#view</Source>
    </View>
    <Control>
       <Path>/mybanner</Path>
    </Control>
    
  • M2 View 파일 을 작성하여 게시한다. 출력물은 JPG 로 한다.

    <html>
       <head>
          <meta name="m2-render-jpg" width="400" height="300">
    
       ... (생략)...
    </html>
    
  • 스마트배너 URL을 배포한다.

    /mybanner?mode=001&view=square
    

장점/효과

  • URL을 호출하는 시점의 신선한 정보가 배너 이미지에 반영된다.
  • 이미지는 호환성이 높다. 어떠한 환경이라도 개발과정 없이 즉시 배포 가능하다.

주의점

  • API 서버의 장애 또는 404 Not Found 라면 이미지를 생성할 수 없다.
  • 이메일 클라이언트를 이용한다면 제약사항 를 참고하기 바란다.

기타

API서버의 시장표준 양식은 JSON 이고 M2 도 표준 포맷을 JSON 을 사용한다. JSON 형식의 API 제공이 어렵다면 Mapper 를 활용한다.

이미지 게이트웨이

해결하고 싶은 문제

이미 배포된 이미지 URL과 복잡한 백엔드를 연결하기 위한 명목으로 다양한 시스템이 추가 투입된다. 게이트웨이, 이미지정보 DB/API, 변환시스템, URL 맵핑테이블, 상태관리 DB 등등 점차 확장/운영하기 어려워진다.

솔루션/패턴 설명

레거시 URL규칙을 M2에 이식하여 단일 이미지 게이트웨이를 구축한다.

_images/dgm023.png

HTTP/S 가 지원된다면 모든 백엔드 자원을 연결하여 단일 시스템으로 구축/운영이 가능하다.

구현

  • M2 이미지 게이트웨이의 역할로 백엔드 가장 앞단에 배치한다.
  • M2 레거시 이미지 URL규칙을 이식한다.
  • M2 콘텐츠 제작을 위해 연동이 필요한 백엔드를 순차적으로 연결한다. 예제의 Service Call Chain 은 다음과 같이 동작한다.
    1. 호출된 URL 주소의 의미를 해석한다. M2용 Hooking 함수를 작성한다.
    2. 독립된 이미지 정보서버가 존재한다면 API를 연동하여 이미지 정보(위치와 처리방식)을 얻는다.
    3. 이미지를 다운로드 받는다. 꼭 같은 백엔드에 존재할 필요는 없다.
    4. 다운로드된 이미지를 실시간 이미지 가공 한다.
  • M2 고객에게 전달되기 전 서비스 가상호스트에 캐싱한다. 이후 같은 이미지 호출인 경우 즉시 응답한다.

장점/효과

  • 배포된 URL을 수정하지 않는다.
  • 단일 M2플랫폼만으로 파편화된 이미지 정책과 백엔드를 통합한다.
  • 이미지 산출물 뿐만 아니라 모든 연결지점에 캐싱모듈 적용이 가능하다. 예를 들어 API Server 가용량이 부족할 경우 증설하지 않고 캐싱으로 부하를 낮출 수 있다.
  • 분산처리를 통한 병렬처리로 Scale-Out을 지원한다.

주의점

  • 외부 의존성에 대해서는 별도의 가상호스트로 구성해 두면 장애시 빠르게 책임규명이 가능하다.
  • 캐싱정책 및 Default 동작 등을 정해두면 예측할 수 없는 경우라도 대처가 가능하다.
  • 서비스 시나리오가 복잡한 만큼 블랙박스가 되지 않도록 구축/검수시 연결부위를 확인하는 매뉴얼을 작성해둔다.

기타

  • 레거시 URL 처리를 위해 M2는 패턴맵핑과 JavaScript 함수 연동을 제공한다.
  • 실서비스 투입시 플랫폼 전면교체보다는 점진적으로 트래픽을 이전하는 것이 바람직하다. 특히 50:50의 상황에서 자원효율성등 직접적인 비교를 통해 플랫폼 신뢰도를 확보하는 것을 추천한다.

3장. 동영상 서비스 패턴

이 장에서는 동영상을 빠르고 호환성있게 전달하는 패턴에 대해 설명한다. 동영상 서비스에서는 pattern-infra-2tier 가 기본이 될 만큼 엄청난 저장공간과 전송대역폭을 필요로 한다. 막대한 비용이 지출되는 만큼 어떻게 안정적이고 경제적인 서비스를 구성할 것인가에 초점을 맞추어야 한다.

실시간 HLS 전송

해결하고 싶은 문제

아이폰을 기준으로 시장표준 동영상 전송방식은 HLS(Http Live Streaming)이다. 이미 스토리지에 MP4포맷으로 저장된 수 많은 영상을 HLS의 미디어 포맷인 MPEG2-TS로 분할(Segmentation)하기에는 시간과 공간의 제약이 크다.

솔루션/패턴 설명

M2MP4HLS 기능을 이용해 실시간으로 MP4영상을 HLS로 가공하여 전송한다.

_images/dgm011.png

구현

  • 동영상 스토리지/서비스 앞에 M2 를 배치한다.

  • MP4HLS 기능을 활성화한다.

    # vhosts.xml - <Vhosts><Vhost><Media>
    
    <MP4HLS Status="Active" Keyword="mp4hls">
       <Index Ver="3" Alternates="off">index.m3u8</Index>
       <Sequence>0</Sequence>
       <Duration>10</Duration>
       <AlternatesName>playlist.m3u8</AlternatesName>
    </MP4HLS>
    
  • 플레이어에서 기존 동영상 URL 뒤에 /mp4hls/index.m3u8 를 붙여 호출한다.

    http://www.example.com/video.mp4/mp4hls/index.m3u8
    

장점/효과

별도의 백엔드 프로세스나 추가 저장공간의 소비 없이 즉시 HLS 서비스가 가능하다.

주의점

포맷변경/분할(Segmentation)과 트랜스코딩(transcoding)을 혼동하지 말자.

기타

사용자가 동영상 전체를 시청하는 빈도가 낮다면 Range요청 기능을 이용해 스토리지/원본서버의 대역폭 소비를 최소화한다.

실시간 구간편집

해결하고 싶은 문제

고객은 영상 전체보다 이슈 장면만 선별적으로 소비한다. 복잡한 사전작업 없이 이슈 즉시 편집된 영상을 제공하고 싶다.

솔루션/패턴 설명

Multi-Trimming 기능을 이용해 실시간으로 MP4영상을 편집한다.

_images/dgm012.png

구현

  • 동영상 스토리지/서비스 앞에 M2 를 배치한다.

  • Multi-Trimming 기능을 활성화한다.

    # server.xml - <Server><VHostDefault><Media>
    # vhosts.xml - <Vhosts><Vhost><Media>
    
    <MP4Trimming MultiParam="trimming" MaxRatio="50">ON</MP4Trimming>
    <M4ATrimming MultiParam="trimming">ON</M4ATrimming>
    
  • 플레이어에서 기존 동영상 주소 뒤에 원하는 구간을 초단위로 명시한다.

    http://example.com/video.mp4?trimming=10-70
    

장점/효과

별도의 백엔드 프로세스나 추가 저장공간의 소비 없이 즉시 편집된 동영상 서비스가 가능하다.

주의점

ngx_http_mp4_module 이나 Mod-H264-Streaming-Testing-Version2 같은 사용방식을 원한다면 Trimming 을 사용한다.

기타

실시간 HLS 전송 과 같이 사용할 수 있다.

http://example.com/video.mp4?trimming=17-20,30-40/mp4hls/index.m3u8

실시간 트랜스코딩

해결하고 싶은 문제

상품상세, 사용자리뷰 동영상의 트랜스코딩은 배치 또는 파이프라인을 통해 진행되는 경우가 많다. 업로드 되는 동영상이 많아지면 목표 시간안에 트랜스코딩이 완료되지 않아 동영상 게시가 지연될 뿐만 아니라 실패처리 비용이 지속적으로 증가한다.

솔루션/패턴 설명

M2 가 클라이언트 요청 동영상을 실시간으로 트랜스코딩한다.

_images/dgm020.png

구현

  • 동영상 스토리지/서비스 앞에 M2 를 배치한다.
  • 트랜스코딩 모듈을 활성화한다.
  • Key Frame 조건 등 상세 동영상 트랜스코딩 옵션을 설정한다.

장점/효과

  • 동영상을 미리 트랜스코딩하지 않아도 된다.
  • 별도의 백엔드 프로세스나 추가 저장공간의 소비가 없다.

주의점

  • 변환되는 동안 클라이언트가 대기하기 때문에 너무 긴 영상에는 적합하지 않다.
  • 우선순위가 높은 동영상이라면 미리 요청해 두는 것만으로 서비스 품질이 개선된다. (Pre-warming)

기타

선별적으로 비표준 동영상(wmv, mov 등)에 대해서만 표준 동영상/ mp4 로 트랜스코딩이 가능하다.

동영상 썸네일이미지 추출

해결하고 싶은 문제

동영상의 특정시점을 즉시 이미지로 추출하여 서비스하고 싶다.

솔루션/패턴 설명

M2 가 동영상으로부터 클라이언트가 요청하는 시점을 이미지로 추출하여 전송한다.

_images/dgm021.png

구현

  • 동영상 스토리지/서비스 앞에 M2 를 배치한다.

  • 동영상 썸네일 모듈을 활성화한다.

  • 클라이언트로 입력 파라미터를 연동하고 게시한다.

    https://{도메인}/{엔드포인트}/{추출시간}/{원본 URL}
    

장점/효과

  • (캐싱되어 있지 않은 동영상이라도) 어느 구간이든 즉시 이미지를 추출한다.
  • 이미지 추출에 필요한 영역만 원본서버로부터 다운로드 받는다.
  • 용량이나 길이 제한이 없다.
  • 이미 스토리지에 저장된 모든 영상에 즉시 적용이 가능하다.
  • 별도의 백엔드 프로세스나 추가 저장공간의 소비가 없다.

주의점

MP4 를 기반으로 동작하기 때문에 MP4 가 아닌 영상인 경우 실시간 트랜스코딩 을 이용해 손쉽게 MP4 로 만들 수 있다.

기타

Progressive HLS Transcoding

해결하고 싶은 문제

전형적인 동영상 배포 프로세스는 많은 단계를 거친다.

1. 업로드
2. 스토리지/원본
3. 배치프로세스
4. 트랜스코더 (1080p, 720p, 360p)
5. 스토리지/가공
6. 웹서버
7. CDN

이 과정의 대표적인 단점은 아래와 같다.

  • 스토리지 사용량 증가
  • 배치프로세스 백엔드 구축/운영비용
  • 트랜스코더 도입/운용 비용
  • 배포지연. 중요도 순이 아닌 FIFO(First Input First Out) 구조.
  • 연계서비스의 어려움

솔루션/패턴 설명

M2 를 이용해 HLS(Http Live Streaming)로 동영상이 소비되는 영역만 분할하여 트랜스코딩/전송한다.

_images/dgm019.png

영상을 미리 생성해두지 않아도 다음과 같이 소비되는 영역에 대해서만 트랜스코딩/전송/소비가 동시에 이루어진다.

_images/rsc006.png

장점/효과

단계가 다음과 같이 축소된다.

1. 업로드
2. 스토리지/원본
3. M2 (분할 트랜스코딩)
4. CDN
  • 원본이외에 스토리지를 사용하지 않는다.
  • 배치프로세스가 필요 없다.
  • 업로드 즉시 배포가 가능하다.
  • 이미지 추출을 통한 2차 가공물을 생산할 수 있다.
  • 이미지/비디오 플랫폼을 통합할 수 있다.

주의점

원본 영상이 MP4(H.264/AAC)가 아니라면 업로드 단계의 영상 트랜스코딩이 필요하다.

4장. 트래픽 최적화 패턴

이 장에서는 서비스 트래픽을 다루는 패턴에 대해 설명한다. 개별 콘텐츠나 트랜잭션에 대해서는 개발팀의 영역이지만 트래픽이라는 단어가 사용되면서 운영팀의 업무로 성격이 바뀐다. 따라서 운영의 시각으로 문제를 바라보는 것이 좋다.

써킷 브레이커(Circuit Breaker)

해결하고 싶은 문제

백엔드(웹서버, 스토리지, 데이터베이스) 장애에도 동작하는 서비스를 구축하고 싶다.

솔루션/패턴 설명

캐시서버는 원본서버의 상태를 일정시간(Time To Live)동안 저장한 뒤 대신 응답하는 메커니즘이다.

_images/dgm013.png

원본 장애발생시 캐싱된 콘텐츠의 TTL을 자동으로 늘려주어 장애를 노출시키지 않는다.

구현

  • 보호하고 싶은 서비스 앞에 M2 를 배치한다. (=HTTP 통신이 가능하다.)

  • 서비스(=가상호스트)별로 적절한 TTL을 설정한다.

    # server.xml - <Server><VHostDefault><Options>
    # vhosts.xml - <Vhosts><Vhost><Options>
    
    <TTL>
        <Res2xx Ratio="20" Max="86400">1800</Res2xx>
        <NoCache Ratio="0" Max="60" MaxAge="0">30</NoCache>
        <Res3xx>300</Res3xx>
        <Res4xx>5</Res4xx>
        <Res5xx>5</Res5xx>
    </TTL>
    
  • 장애 상황에서 원본 오동작으로 4xx , 5xx 응답이 올 수 있다. 콘텐츠가 캐시에서 사라지지 않도록 비정상 TTL연장 기능을 활성화시킨다.

    # server.xml - <Server><VHostDefault><Options>
    # vhosts.xml - <Vhosts><Vhost><Options>
    
    <TTLExtensionBy4xx>ON</TTLExtensionBy4xx>
    <TTLExtensionBy5xx>ON</TTLExtensionBy5xx>
    <UnvalidatableObjectResCode>0</UnvalidatableObjectResCode>
    

주석

M2 는 콘텐츠 갱신시점에 원본서버와 연결이 안되거나 전송지연이 발생할 경우 자동으로 TTL을 연장한다.

장점/효과

캐싱된 콘텐츠라면 장애가 클라이언트에게 노출되지 않는다.

주의점

엔터프라이즈 서비스에서는 L4/Load Balancer등을 이용해 장애서버를 배제한다. 캐시서버 운영도 동일한 방식을 사용한다.

기타

자주 변경되는 콘텐츠라면 TTL 을 0초로 설정한다. 평상시에는 대부분의 응답을 원본서버에서 처리하다 장애상황이 발생하면 캐시서버가 대신 응답한다.

압축

해결하고 싶은 문제

웹서버는 동일한 1,000건의 요청에 대해 1,000번 압축한다. 빈번하게 요청되는 웹페이지, API를 압축하여 전송하고 싶지만 지금도 높은 부하가 우려된다.

솔루션/패턴 설명

M2 는 동일한 1,000건의 요청에 대해 최초 1번만 압축하고 TTL 시간동안은 압축된 결과물을 전송한다.

_images/dgm014.png

구현

  • 서비스 앞에 M2 를 배치한다. (=HTTP 통신이 가능하다.)

  • 압축기능을 활성화한다.

    # server.xml - <Server><VHostDefault><Options>
    # vhosts.xml - <Vhosts><Vhost><Options>
    
    <Compression Method="gzip" Level="6" SourceSize="2-2048">ON</Compression>
    
  • 압축대상을 지정한다.

    # /svc/www.example.com/compression.txt
    # 구분자는 콤마( , ) 이다.
    # {URL 조건}, {Method}, {Level} 순서로 표기한다.
    
    /sample.css, no       // 압축하지 않는다.
    *.css                 // *.css 조건에 대해 기본 Method와 Level로 압축한다.
    *.htm, gzip           // *.htm 조건에 대해 gzip으로 압축한다. (기본 Level)
    *.xml, , 9            // *.xml 조건에 대해 Level 9 압축한다. (기본 Method)
    *.js, gzip, 5         // *.js 조건에 대해 gzip (Level=5)으로 압축한다.
    

장점/효과

  • 한번 요청된 콘텐츠라면 별도의 압축비용 없이 빠른 서비스 제공이 가능하다.
  • bootstrap 등 많이 쓰이는 프론트엔드 콘텐츠를 압축하면 70% 이상의 대역폭 절감효과를 얻을 수 있다.

주의점

이미지, 동영상등은 그 자체가 압축포맷이라 효과를 기대할 수 없다.

기타

원본서버에서 이미 압축된 콘텐츠라면 다시 압축하지 않는다.

5장. 인프라 구성 패턴

이 장에서는 백엔드에서 손쉽게 자원들을 연결/관리하는 패턴에 대해 설명한다. 서비스 패러다임이 모놀리틱(Monolithic)에서 마이크로서비스(Microservice)로 변화하면서 통합은 더 어려워졌다. 인프라 자원들의 유연한 결합을 통해 가용량과 확장성을 손쉽게 확보한다.

콘텐츠 체인

해결하고 싶은 문제

물리적으로 분산된 콘텐츠는 사용성이 매우 떨어진다. 스토리지 마이그레이션이나 추가 개발 없이 콘텐츠 위치투명성을 확보하고 싶다.

솔루션/패턴 설명

M2가상호스트 링크 기능을 이용해 물리적으로 분리된 엔드포인트를 연결한다.

_images/dgm008.png

구현

  • 메인 스토리지/서비스 앞에 M2 를 배치한다.

  • 개별 가상호스트를 생성하고 가상호스트 링크이미지툴 기능을 활성화한다.

    # vhosts.xml - <Vhosts>
    
    // foo.com에 없는(=404 Not Found) 콘텐츠는 bar.com에서 서비스한다.
    <Vhost Name="foo.com">
       <VhostLink Condition="404">bar.com</VhostLink>
    
       ... (생략) ...
    </Vhost>
    
    <Vhost Name="bar.com">
       ... (생략) ...
    </Vhost>
    
  • 스토리지 콘텐츠가 있다면 foo.com 에서 서비스된다.

  • 스토리지 콘텐츠가 없다면 bar.com 을 통해 외부에서 다운로드 받아 서비스한다.

장점/효과

스토리지 마이그레이션이나 코드 수정없이 콘텐츠를 유연하게 연결할 수 있다. 향후 별도의 스토리지나 외부 서비스를 연결해야 하는 경우에도 손쉽게 확장이 가능하다.

주의점

가상호스트 링크 는 아래의 경우 중단된다.

  • 대상 가상호스트가 존재하지 않는 경우 (foo.com -> ?)
  • 자기 자신을 대상 가상호스트로 지정한 경우 (foo.com -> foo.com)
  • 재귀링크(Recursive Link)가 발생한 경우 (foo.com -> bar.com -> foo.com)

기타

외부 콘텐츠를 캐싱하면 외부 종속성으로 인한 성능저하를 방지할 수 있다.

백업 파이프

해결하고 싶은 문제

마이그레이션이 시작되면 제발 장애없이 종료되길 기도하는 것 외엔 할 수 있는 것이 없다. 물론 종료되기 전까지 서비스는 불가능하다.

솔루션/패턴 설명

구성은 콘텐츠 체인 과 유사하지만 M2확장모듈 을 이용해 구현한다.

_images/dgm009.png

외부로부터의 다운로드 스트림은 3가지 파이프로 확장된다.

  • 대기 중인 클라이언트에게 응답
  • 스토리지 백업
  • 캐싱엔진 저장

구현

기본 구성은 콘텐츠 체인 과 동일하며 백업을 위해 M2 확장모듈 을 설정한다.

# vhosts.xml - <Vhosts><Vhost><M2><Endpoints><Endpoint>

<Control>
   <Module Name="aws_s3-backup">aws_access_key=...;aws_secret_key =...;bucket=...;s3_url=...;region=...;</Module>
</Control>

장점/효과

  • 마이그레이션/백업 과정없이 즉시 서비스가 가능하다.
  • 사용자가 요청하는 순서대로 콘텐츠가 백업된다.

주의점

사용자가 요청하지 않는 콘텐츠는 백업되지 않을 수 있으므로 스토리지에 없는 콘텐츠를 bar.com 으로 요청하는 보조 프로세스가 필요할 수 있다.

기타

  • 우선적으로 스토리지로 업로드하고 싶은 콘텐츠가 있다면 bar.com 을 호출하는 프로세스를 추가한다.
  • 규칙만 정해져 있다면 동적으로 외부 서비스를 연결할 수 있다.

콘텐츠 분산

해결하고 싶은 문제

모든 콘텐츠 요청이 스토리지에 집중됨에 따라 스토리지의 성능이 저하된다. 더 큰 스토리지는 근본적인 해답이 못 된다. 가용성, 성능, 경제성을 동시에 보장할 수 있는 솔루션이 필요하다.

솔루션/패턴 설명

캐시를 2계층으로 구성한다.

_images/dgm010.png
구분 Parent Layer Child Layer
캐싱대상 COLD 콘텐츠 HOT 콘텐츠
역할 콘텐츠 분산저장, 스토리지 부하 절감 콘텐츠 분산
증설시점 원본 콘텐츠 증가시점 트래픽 증가시점

구현

Child , Parent 는 개념적인 분류일 뿐 특별한 설정을 요구하는 것은 아니다.

  • Parent Layer 는 단순하게 원본서버로부터 캐싱한다.

    # vhosts.xml - <Vhosts>
    
    <Vhost Name="parent-1.example.com">
       <Origin>
          <Address>storage.example.com</Address>
       </Origin>
       <Options>
          <IfRange Purge="ON">ON</IfRange>
       </Options>
    </Vhost>
    
  • Child Layer 에서는 Parent Layer 의 주소로 콘텐츠를 분산하도록 설정한다.

    # vhosts.xml - <Vhosts>
    
    <Vhost Name="www.example.com">
       <Origin>
          <Address>parent-1.example.com</Address>
          <Address>parent-2.example.com</Address>
          <Address>parent-3.example.com</Address>
          <Address>parent-4.example.com</Address>
       </Origin>
       <OriginOptions>
          <BalanceMode>Hash</BalanceMode>
       </OriginOptions>
    </Vhost>
    

장점/효과

  • 스토리지 장애가 발생하여도 캐싱된 콘텐츠는 중단없이 서비스가 가능하다.
  • 콘텐츠 용량/개수가 급증하여도 캐시를 Scale-out하여 손쉽게 대응할 수 있다.
  • 별도의 관리 시스템이 불필요하다.

주의점

블럭캐싱과 데이터 무결성 를 참고한다.

기타 - Sibling 분산

API처럼 크기가 작거나 예측할 수 있는 수의 이미지 서비스라면 레이어 분리 없이 Sibling 분산으로 처리가 가능하다.

_images/dgm026.png

다대다(n:n) 구성으로 서로 동등하게 콘텐츠를 분산하여 저장한다.

  • RED 가 처리해야할 요청이 YELLOW 로 유입되었다. YELLOWRED 로 요청을 위임한다.
  • GREEN 이 처리해야할 요청이 BLUE 로 유입되었다. 이전에 동일 요청이 BLUE 에 발생하였고 캐싱되어 있다. BLUE 가 즉시 응답한다.
  • PURPLE 이 처리해야할 요청이 PURPLE 로 유입되었다. 즉시 처리된다.

6장. 서비스 퍼포먼스 패턴

이 장에서는 서비스 퍼포먼스를 보장하는 패턴에 대해 설명한다. 클라이언트 접속이 높아지면 서비스 부하가 증가하는 것을 당연시 생각한다. 하지만 콘텐츠 접근비율은 읽기보다 쓰기가 압도적으로 높다. 콘텐츠의 소비형태를 파악하면 백엔드 부하를 획기적으로 절감할 수 있다.

고정부하

해결하고 싶은 문제

순간적으로 접속자가 폭증할 경우 원본 장애가 빈번하다. 랭킹, 검색, 핫딜, 항공권 등 특정 시간에 오픈되는 서비스에 이런 경우가 많다.

솔루션/패턴 설명

순간적으로 발생한 동일한 요청에 대해 최초의 결과를 공유한다. TTL(Time To Live)을 0으로 설정하면 원본서버의 1트랜잭션 시간동안(1ms 내외)만 결과는 유효하다.

_images/dgm017.png

M2 는 최초의 요청만 원본서버로 보낸다. 응답은 대기 중인 모든 클라이언트에게 공유됨과 동시에 만료된다. (=유효하지 않다.) 이 과정의 반복을 통해 접속자 수와 무관하게 원본부하를 고정시킨다.

구현

  • 웹서버 앞에 M2 를 배치한다. (=HTTP 통신이 가능하다.)

  • 모든 콘텐츠를 캐싱하고 TTL을 0으로 설정한다.

    # server.xml - <Server><VHostDefault><Options>
    # vhosts.xml - <Vhosts><Vhost><Options>
    
    <TTL>
       <Res2xx Ratio="20" Max="0">0</Res2xx>
       <NoCache Ratio="0" Max="0" MaxAge="0">0</NoCache>
       <Res3xx>0</Res3xx>
       <Res4xx>0</Res4xx>
       <Res5xx>0</Res5xx>
    </TTL>
    

장점/효과

  • 백엔드 부하를 고정/예측할 수 있어 서비스 안정성이 높아진다.

주의점

  • 읽기에는 적합하나 쓰기에는 사용할 수 없다.
  • 휘발성이 높은 콘텐츠에 대해서는 Memory-Only 모드 를 권장한다.

기타

로그인한 개인 페이지라도 공유할 수 있는 영역에 대해서는 AJAX 로 분리하는 것이 효과적이다.

프록시 서버

해결하고 싶은 문제

사업장 외부에 존재하는 대용량 파일에 대한 접근이 특정 시간에 집중된다. 급격한 전송속도 저하로 업무에 차질이 발생한다.

솔루션/패턴 설명

사업장 내부에 존재하는 Local DNS 를 이용해 대용량 트래픽을 발생시키는 도메인을 M2 로 위임한다.

_images/dgm025.png

사업장 내부 클라이언트는 특정 도메인에 대하여 M2 로부터 대용량 파일을 다운로드 받는다.

주석

위 그림에서는 bar.comLocal DNS 가 리졸빙 해주는 것처럼 표현됐지만 DNS forwarding으로 동작한다. DNS 구성/운영 및 포워딩은 이 문서의 범위를 벗어난다.

구현

  • 서비스할 도메인의 가상호스트를 생성한다.

  • 모든 요청을 바이패스하도록 설정한다.

    # server.xml - <Server><VHostDefault><Options>
    # vhosts.xml - <Vhosts><Vhost><Options>
    
    <BypassPostRequest>ON</BypassPostRequest>
    <BypassGetRequest>ON</BypassGetRequest>
    
  • access.log 를 분석해 용량순으로 캐싱대상을 찾는다.

    # /svc/www.example.com/bypass.txt
    
    /bigfile.exe, cache
    /patch*.zip, cache
    

장점/효과

  • 외부 네트워크 대역폭 증설없이 빠른 전송속도를 제공한다.

주의점

  • HTTPS 통신이라면 원본서버의 인증서를 설치하거나, 비공인/Self-Siegned 인증서 환경을 구성해야 한다.
  • 개인화된 파일을 캐싱해서는 안된다.

기타

접근 빈도보다는 용량 기준으로 캐싱대상을 산정하는 것을 권장한다.

7장. 보안 패턴

이 장에서는 콘텐츠를 보호하는 패턴에 대해 설명한다. 보안(Security)의 범주는 매우 크기 때문에 다소 과하게 다루어지는 면이 있다. 용도와 목적에 알맞은 해법은 콘텐츠의 안정성과 비용을 합리적으로 다룰 수 있도록 해준다.

라이브 DRM

해결하고 싶은 문제

콘텐츠 보호를 위해 DRM(Digital Right Management)을 고려해 보았지만 비용과 운영관점에서 지나치게 무겁다. 운영이 쉽고 가볍게 도입할 수 있는 End To End 콘텐츠 암/복호화 시스템을 구축하고 싶다.

솔루션/패턴 설명

콘텐츠 전송시점에 암호화를 수행하고 콘텐츠 재생시점에 복호화를 수행한다.

_images/dgm015.png

암호화 키는 주고받지 않으며 양 주체가 약속된 알고리즘에 의해 키를 생성한다. 키의 시드(seed) 중 하나로 URL을 사용하여 모든 콘텐츠의 키를 다르게 사용한다.

구현

  • 스토리지 앞에 M2 를 배치한다. (=HTTP 통신이 가능하다.)

  • On the fly DRM 기능을 활성화한다.

    $ server.xml - <Server><VHostDefault><Options>
    $ vhosts.xml - <Vhosts><Vhost><Options>
    
    <Drm Status="Aactive" Keyword="drm" MaxSourceSize="500">
       <Algorithm>RC4</Algorithm>
       <IV> ... </IV>
       <Token> ... </Token>
       <Key Hash="none">$Token</Token>
    </Drm>
    
  • DRM 주소를 배포한다. 또는 모든 콘텐츠 주소뒤에 /drm 이 붙도록 URL 전처리 를 설정한다.

    www.example.com/music.mp3/drm
    

장점/효과

  • 콘텐츠를 암호화하여 근본적으로 안전하다.
  • 백엔드와 DRM 솔루션을 타이트하게 결합하지 않아도 같은 효과를 얻을 수 있다.
  • 모든 콘텐츠가 다른 키를 사용하며 언제든지 변경이 가능하다.

주의점

암호화 레벨설계시 타겟 모바일 디바이스의 복호화 성능을 고려해야 한다.

기타

  • 대칭키/비대칭키 모두 사용이 가능하다.
  • 성능을 고려하여 콘텐츠가 전체가 아닌 일부 영역만 선택적으로 암호화할 수 있다.

요청 인증

해결하고 싶은 문제

클라이언트 HTTP 요청을 분석하여 올바른 접근에 대해서만 콘텐츠를 서비스하고 싶다.

솔루션/패턴 설명

서비스 최전방에서 인증을 구현한다.

_images/dgm016.png

인증은 크게 인라인모듈과 인증서버로 구분된다.

  • 내부 인증모듈 - 알고리즘/스펙에 의해 요청의 유효성을 즉시 판단한다.
  • 외부 인증모듈 - 요청 전체 또는 일부 토큰을 인증서버로 보내 유효성 여부에 대해 판단 받는다.

인증이 성공했다면 정상적인 서비스 플로우로 진행도니다.

구현

  • 스토리지 앞에 M2 를 배치한다. (=HTTP 통신이 가능하다.)
  • M2 확장모듈 을 이용해 인증로직을 구현한다.

장점/효과

  • 인증과 로직, 콘텐츠를 분리하여 처리한다.
  • 기존 인증시스템을 그대로 사용한다.

주의점

인증서버가 SPOF(Single Point Of Failure)가 되지 않도록 가용량을 고려해서 설계한다.

기타

인증과 Trimming 을 결합하면 미리듣기 서비스를 손쉽게 구현할 수 있다.

접근제어 (Access Control)

해결하고 싶은 문제

특정 클라이언트의 HTTP 요청을 차단, 우회, 허가하고 싶다.

솔루션/패턴 설명

접근제어 계층을 서비스 최전방에 배치하여 사전에 접근을 통제한다.

_images/dgm027.png

IP , GeoIP , URL , HTTP-Header , Protocol 등의 조건을 조합하여 White/Black 리스트를 구성한다.

구현

장점/효과

  • 접근제어를 별도 서비스 계층으로 분리하여 운영성을 강화한다.
  • HTTP 또는 HTTPS 프로토콜을 강제할 수 있다.

주의점

모든 트래픽이 M2 를 경유하는 만큼 웹서버에 구현된 모든 가상호스트 목록이 M2 에 존재해야 한다.

Appendix A: 상품기술서 분리

E-Commerce 상품 상세페이지는 일반적으로 다음과 같이 구성된다.

_images/rsc007.png

M2 를 이용해 반응형 상품기술서이미지 분할/병렬로딩 패턴을 구현한다면 상품기술서를 메인페이지에서 분리/로딩할 것을 강력히 권장한다.

  • M2 가 페이지 전체로딩의 SPOF(Single Point Of Failure)가 되어선 안된다.
  • M2 의 도입이 단계별로 이루어질 때 전체 페이지가 영향을 받아선 안된다.
  • 가격, 재고, 결재등은 서비스의 가장 민감한 정보이기 때문에 이런 정보에 M2 가 개입하는 것은 바람직하지 않다.
  • M2 가 웹페이지 전체를 로딩하는 것은 불필요한 부하이다.

로딩속도 개선은 덤이다. 상품기술서를 웹페이지에 포함시키는 시간 동안 엔드유저의 대기시간이 줄어든다.

주석

이 전략을 가장 효과적으로 사용한 사이트 중 하나는 멜론 이다. 크롬이라면 개발자도구 -> Network -> XHR 을 열고 병렬로딩이 페이지 로딩속도를 어떻게 향상시키는지 알아보자.

AS-IS

상품기술서는 별도의 스토리지(또는 데이터베이스)에 저장되어 있다. 웹페이지가 상품기술서를 포함하고 있다면 다음과 같은 흐름으로 동작할 것이다.

_images/rsc008.png

이 구조는 중첩관계로 인해 종속성(Dependency)이 높다. 다시 말해 상품기술서 장애가 웹페이지 전체 장애로 이어진다.

위 구조에서 M2 가 도입되면 종속성이 더 상승한다.

_images/rsc009.png

Browser는 아주 운좋게 백엔드 모두가 성공하는 경우에만 웹페이지를 볼 수 있다.

TO-BE

상품기술서를 프론트엔드가 로딩하면 중첩관계가 사라져 종속성이 완화된다.

_images/rsc010.png

로딩방식은 RESTful API/JSON , <iframe> , <DIV> 코드조각 어느 것이든 무관하다.

_images/rsc011.png

이제 M2 는 상품기술서 가공에만 집중할 수 있고 웹페이지 전체에 영향은 구조적으로 차단된다.

Appendix B: 최신 상품기술서

E-Commerce 서비스의 성장에 따라 취급하는 상품(=상품기술서)도 증가한다. 상품기술서(이하 기술서)의 복잡도를 공식으로 표현하면 다음과 같다.

복잡도 = 유입경로 X  X 시간 X 리소스 개수

기술적으로 상품기술서는 웹페이지 안의 웹페이지이다.

_images/item01.png

M2 가 처리한 상품기술서 이슈 사례를 일부 소개한다.

페이지 레이아웃

페이지 레이아웃을 헤치는 대표적인 요인은 다음과 같다.

  • 사이트 개편과 오래된 상품기술서
  • 외부 상품의 대량유입
  • Shop in Shop / <iframe>
  • 마이그레이션 과정 중의 버그
  • 하드코딩된 width=1920

M2 - Document Engine 은 on the fly로 상품기술서를 적응시킨다.

고정 해상도

  • 고정 width 로 인해 가시영역을 넘어간다.

    _images/item03.png
  • 상품기술서 내의 이미지들의 가로폭이 불규칙하다.

    _images/item02.png
  • PC/타블렛/모바일 멀티 디바이스 해상도 대응이 안된다.

    _images/item04.png

반응형 상품기술서 를 적용한다.

깨진 태그

  • <HTML> 노출

    _images/item06.png
  • 인코딩 오류

    _images/item05.png

지나치게 큰 DOM 로딩

아래 상품기술서를 로딩하면 브라우저에서 메모리 문제가 발생할 수 있다.

_images/item09.png

로딩속도 개선

외부 셀러의 상품기술서를 통제할 수 없다면 서비스 품질을 담보할 수 없다.

이미지 최적화

상품기술서 하나 로딩했을 뿐인데 349MB에 1.8분이 소요된다.

_images/item10.png

실시간 외부 이미지 가공 을 통해 용량과 속도를 통제할 수 있다.

이미지 분할/병렬로딩

height 1만 pixel이 넘는 이미지가 버젓이 서비스되고 있다.

_images/item11.png

이미지 분할/병렬로딩 과 브라우저 병렬로딩을 통해 로딩속도를 개선한다.

css , js 압축

상품기술서 내의 css , js 는 자주 바뀌지 않는다. 압축된 콘텐츠를 캐싱 서비스 하면 사용자 체감속도를 향상시킬 수 있다.

트러블 슈팅

진화하는 브라우징 환경에 대비해야 한다.

혼합 콘텐츠 (Mixed Contents)

혼합 콘텐츠 문제가 발생하면 상품기술서는 노출되지 않는다.

_images/item13.png

혼합 콘텐츠 (Mixed Contents) 패턴을 적용한다.

주석

SSL/TLS 대응이 되는 도메인은 Whitelist를 통해 예외처리가 가능하다.

잘못된 인증서

HTTPS 로 로딩되지만 잘못된 인증서로 인해 이미지가 차단된다.

_images/item17.png

인증서가 교체되기 전까지 SSL/TLS Onloading을 통해 대응한다.

deprecated, obsolete 대응

플래시, 애플릿 등은 보안요소를 위협하는 요소들은 제거되어야 한다.

M2 는 상품기술서 분석을 통해 위험 요소를 제거한다.

404 Not Found

존재하지 않는 이미지라면 노출시키지 않는 편이 좋다.

_images/item08.png

최신 트렌드

언제든지 모든 상품기술서를 최신 트렌드로 즉시 적응시킬 수 있다.

더 보기

M2 는 상품기술서의 Height 를 계산하여 선택적으로 상품기술서를 접고 펼 수 있다.

_images/item14.png

Height 가 계산된 상품기술서를 캐싱하면 즉시 페이지를 완선할 수 있다.

가시영역 로딩가속

더 보기 기능에 의해 먼저 노출되는 이미지 영역만을 이미지 분할/병렬로딩 패턴으로 잘라내어 빠르게 노출시킨다.

_images/item16.png

브라우저가 모든 리소스를 다운로드 하지 않고도 빠르게 최종 페이지를 완성한다.

주석

당장 노출될 필요없는 비가시 영역은 “더 보기” 버튼이 눌리기 전까지 로딩시키지 않으면 트래픽을 절약할 수 있다.

핀치 줌

M2 에서 모바일 핀치 줌(Pinch Zoom) 기능을 추가한다.

_images/item15.png

Appendix C: 이미지 트래픽 전략

이 장에서는 이미지 트래픽을 중심으로 패턴 전략을 상세히 설명한다.

CDN(Contents Delivery Network)

CDN은 이미지, 동영상 등 자주 변경되지 않으면서, 용량이 큰 콘텐츠를 위탁/전송해주는 검증된 서비스이다. CDN 도입은 콘텐츠를 제공하는 도메인을 DNS 위임(DNS delegation)하는 것으로 이루어진다.

예를 들어 웹 서비스 주소가 www.example.com 이라면 이미지는 image.example.com 도메인으로 제공되는 형태이다. 클라이언트가 image.example.com 질의하면 CDN 사의 전송서버(일반적으로 캐시서버)가 서비스를 담당하는 구조이다.

이미지 게이트웨이

이미지 저장은 물리적인 스토리지의 한계 또는 서비스 합병, 연계등 다양한 이유를 통해 파편화될 수 있다. 하지만 백엔드가 파편화되었다는 이유로 서비스 도메인도 img01.example.com , img02.example.com 처럼 파편화되어야 할지 생각해 볼 문제이다.

  • CDN 위임의 증가
  • 백엔드 관리비용 상승
  • 브라우저 커넥션 비용 상승

이때 이미지 게이트웨이 패턴을 이용하면 보다 유연하고 확장성 있는 전략을 펼칠 수 있다.

  • 통합 이미지 도메인, 통합 이미지 전략
  • 실시간 이미지 처리 및 캐싱
  • URL 경로 패턴에 기반한 쉽고 확장가능한 백엔드 연동
_images/rsc020.png

예를 들어 이상의 패턴을 모두 통합하면 다음과 같이 전략적 이미지 URL을 제공할 수 있다.

https://image.example.com/dims/resize/100/src/nas01/ab/cd/ef/1.jpg
https://image.example.com/dims/optimize/src/s3/1234/567/89.jpg
https://image.example.com/dims/quality/50/src/http://foo.com/2.jpg

주석

M2에서는 URL 전처리를 통해 URL 경로를 각각 가상호스트로 분리/운영이 가능하다.

이미지 분할로딩과 Inbound

이미지 분할/병렬로딩 패턴을 적용할 때는 반드시 외부 트래픽 유입이 과도하게 발생하지 않는지 체크해야 한다.

_images/rsc021.png

상품기술서 내의 이미지를 분할하려면 정확한 height를 알아야 하기 때문에 상품기술서의 모든 이미지를 M2가 위치한 백엔드로 유입시켜야 한다.

이때 발생하는 대표적인 문제점은 다음과 같다.

  • 과도한 트래픽 상품기술서당 평균 10Mbps의 트래픽을 유발한다고 가정하면 100 TPS 처리를 위해서는 1Gbps가 필요하다. 흔히 www를 서비스하는 웹서버와 같은 팜의 트래픽이 많아야 100~200Mbps 수준임을 감안하면 Gbps 단위의 트래픽이 백엔드로 유입되는건 매우 부담스러운 일이다.
  • 보장할 없는 서비스 품질 원본서버가 외부에 있다는 것은 품질을 보장할 수 없다는 의미이다. 클라이언트는 일부 리소스의 로딩이 느리더라도 크게 문제되지 않는다. 하지만 상품기술서의 경우 반드시 모든 리소스가 로딩된 후에 응답이 가능한 점을 감안하면 균일한 서비스 품질을 보장할 수 없는 것은 용인할 수 없는 문제이다.

이런 연유로 대형 오픈마켓에서는 이미지 분할/병렬로딩 패턴을 그대로 적용하기 어렵다. 반면 브랜드몰의 경우 노출 상품의 대다수가 신뢰할 수 있는 내부 스토리지에 있기 때문에 이미지 분할/병렬로딩 패턴을 손쉽게 적용할 수 있다.

Insecure 이미지 트래픽 전략

혼합 콘텐츠 (Mixed Contents) 문제는 지금껏 지불하지 않았던 트래픽 비용을 강제한다. 트래픽을 세분화하여 처리하면 전송비용을 최소한으로 낮출 수 있다.

_images/rsc022.png
  1. 안전한 트래픽은 그대로 둔다. https 프로토콜을 사용하거나 http 로 명시되었지만 https 를 지원하는 URL은 굳이 Proxying하지 않는다. 정확한 판단을 위해 M2는 SVL(SSL/TLS Validation List) 를 제공한다.
  2. Proxying되는 이미지에는 명확한 Cache-Control을 부여하여 유효시간을 통제한다. 대부분의 CDN(Contents Delivery Networks)는 Cache-Control을 준수한다.
  3. Proxying되는 이미지는 용량을 최적화한다. 과도하게 큰 용량의 이미지가 클라이언트에게 제공되지 않도록 실시간 외부 이미지 가공 패턴을 적용한다. 낮아진 용량의 이미지는 전송비용의 감소뿐만 아니라 로딩속도 개선효과를 가져온다.

상품기술서 엔진과 이미지 엔진이 동시에 필요한 경우 이 둘을 별도의 팜으로 나누어 운영하는 것을 추천한다. 왜냐하면 운영관점에서 정반대의 특성을 가지는 콘텐츠를 단일 팜에 구성한다면 운영편의성이 저하될 수 있다.

구분 상품기술서 엔진 이미지 엔진
배치 웹서버 앞 CDN의 원본서버
유효시간 초~분 시간~일
트래픽 낮음/Mbps 높음/Gbps
CPU부하 높음 낮음 (단순 이미지 Proxy의 경우)

공용 스토리지 적재 전략

다음 시나리오를 생각해보자.

  • 원본서버의 안정성이 매우 떨어져서 서비스 품질을 보장할 수 없다.
  • 원본서버를 일정 시간만 사용가능하여 캐싱된 콘텐츠가 만료되면 서비스 제공이 불가능하다.
  • 콘텐츠 용량이 매우 커서 매번 외부에서 다운로드 받는 것이 부담스럽다.
  • 상품기술서 및 HTML 렌더링 후 이미지나 PDF를 제공한다.
  • 긴 동영상을 트랜스코딩 한다.

Object Storage를 공용 스토리지로 활용하면 무제한 콘텐츠 캐싱과 실시간 처리성을 극대화할 수 있다. 클라이언트와 M2 사이에 CDN이 존재한다고 가정하면 M2는 각 컴포넌트를 연결하는 허브가 된다.

_images/rsc012.png
  • CDN 무제한의 콘텐츠가 적재되어 클라이언트에게 서비스됨을 보장한다.
  • Object Storage 1차 저장소
  • Seller 원본 이미지를 제공한다.
  • Pre-warmer M2 구동 트리거. Pub/Sub Message Queue로 대체될 수 있다.
  1. Pre-warming

    _images/rsc013.png

    M2는 Pre-warmer의 호출에 의해 워크로드 처리 후 Object Stroage에 업로드 한다. Pre-warmer는 curl 과 같은 단순한 호출 프로그램일 수도 있으며, Kafa , RabbitMQ 등의 메시지큐인 경우 M2가 Subscriber 역할을 수행 한다.

  2. Storage HIT

    _images/rsc014.png

    CDN으로부터 서비스가 유입되면 M2는 Object Storage를 먼저 탐색한다. Object Storage에 적재되어 있다면, M2는 외부 다운로드나 가공없이 즉시 서비스 한다.

  3. Storage MISS

    _images/rsc015.png

    2번 시나리오를 통해 Storage MISS가 발생하는 상황으로 1번 시나리오와 동일하게 동작합니다. 다른 점은 요청자가 CDN이기 때문에 on the fly로 처리된 콘텐츠가 CDN에 적재됨과 동시에 Object Storage로 업로드된다. 이후 같은 콘텐츠는 Storage HIT 시나리오로 동작한다.

  4. 콘텐츠 변경

    _images/rsc016.png

    2가지 옵션이 가능하다.

    • 1-a는 1번 시나리오를 다시 수행한다.
    • 1-b는 2번 시나리오를 다시 수행한다.

    둘 중 하나를 수행한 뒤 CDN을 Purge 한다.

  5. CDN MISS율 모니터링

    CDN으로부터 백엔드로 유입되는 트래픽을 주의깊게 모니터링해야 한다.

    _images/rsc017.png

    위와 같은 상황은 바람직하지만 아래와 같은 상황이 발생할 경우 실시간 처리를 위한 M2의 증설 또는 Circuit Breaker 를 가동시켜 오류를 보여주는 상황이 발생하게 된다.

    _images/rsc018.png

    물론 위와 같은 경우도 Object Stroage가 HIT라면 서비스 내구성엔 문제가 없다.

M2는 이미 관계 컨포넌트를 연동하는 검증된 모듈을 제공할 뿐만 아니라, 각각의 콘텐츠 트래픽을 통합 플랫폼으로 제공할 수 있다.