2018년 12월 23일 일요일

사용자가 업로드한 파일을 즉시 CDN 주소로 제공하는 방법 구상

사용자가 방금 업로드한 파일을 즉시 사용자에게 다시 보여줘야 하는 경우에 CDN을 어떤 구성으로 적용할지 궁리를 해왔다. 사용자에게 항상 CDN으로 파일을 제공한다는 전제로 구성하다 보면 사용자가 자체 서버로 업로드한 파일을 CDN으로 다시 배포하는 시간만큼 사용자에게 제공하는 시간이 지연된다는 부분에서 늘 막혔다. 사용자-자체서버-외부저장소-CDN 순서로 전송이 이루어지다보면 파일의 크기에 비례해 2~3배 만큼의 지연이 발생하는 구조가 되는 거였다.


그래서 이런 시나리오를 생각해봤다.
  1. 사용자는 자체 서버로 파일을 업로드를 한다. (트래픽 1차)
  2. 자체 서버에서는 직접 파일을 서빙할 수 있는 모든 준비를 마친다.
  3. 자체 서버는 미리 설정된 외부 저장소에 0바이트 크기로 blob을 만들고, 해당 blob에 custom header를 설정해서 Location 헤더가 앞서 준비한 자체 파일 서빙 URL을 가리키도록 한다.
  4. 자체 서버는 미리 설정된 CDN URL을 사용자에게 제공한다.
  5. 서버가 제공한 CDN URL에 사용자가 접속한다.
  6. CDN은 Location 헤더로 자체 서버의 URL로 다시 이동한다.
  7. 사용자는 CDN URL에서 redirection된 자체 서버의 URL로 실제 파일을 제공받는다.
  8. 그 사이 서버는 외부 저장소에 앞서 생성한 blob의 본문과 custom header를 실제 파일 내용으로 교체한다. (트래픽 2차)
  9. blob에 교체되면 CDN에서는 적당한 시점에 재배포된다. (트래픽 3차)
  10. 외부 저장소에 CDN 배포에 반영된 후에는 사용자의 접속으로 CDN이 직접 파일을 제공한다.
  11. 자체 서버는 백업용 혹은 CDN으로 제공할 수 없는 경우에 사용한다.

AWS로 중요 부분을 구현해보면 이렇다. 수동으로 했지만 아마 API로도 될 것이다.
  1. S3 버킷을 만들고 static website 기능을 켠다.
  2. 빈 파일을 하나 만들어서 blob으로 올리고 Website-Redirect-Location 헤더를 적당한 다른 URL로 지정한다.
  3. 해당 S3 blob에 static website URL로 접속했을 때 Location 헤더가 붙어오는 걸 확인한다. 그냥 blob 자체의 URL로 접속하면 x-amz-website-redirect-location 헤더로 나온다.
  4. CloudFront 배포를 하나 만들고 필요한 설정을 한다.
  5. CF의 Origin은 설정화면에서 제공하는 S3 항목을 그대로 선택하면 안되고, S3 static website 활성화 후에 생성된 도메인을 적어준다. (https://stackoverflow.com/a/41132075/6629746 참조)
  6. 해당 blob을 CF 배포의 URL을 통해서 접속했을 때 location 헤더가 붙어오는 걸 확인한다.

GCP나 Azure는 확인하지 않았지만 대체로 비슷한 수준의 지원을 할 것으로 예상한다.

아예 파일을 외부 저장소로 직접 업로드하는 방법도 있다.
FORM 내의 INPUT 항목에 (보통이라면 request header로 포함했을) 인증값과 저장할 blob 이름, custom header 등을 지정해서 S3에 직접 POST를 날리면 된다고 한다. 이쪽이 당연히 간편하긴 하겠는데, 제공하는 파일이 전체공개가 아니어서 외부 CDN으로 배포하지 않아야 하는 경우를 처리할 수가 없어서 깊게 검토하지 않았었다. 전체공개 파일을 아예 분리해서 다루는 방식이라면 채택할만하겠다.