Medium 프론트 기술 분석

 API

Medium은 One-page Web Application으로 구성되어 있다.
HTML5 PushState (pjax 참고)를 이용하여
링크를 눌렀을 때 URL은 바뀌지만 처음부터 Request하지 않도록 했다.
추가로 불러와야할 DOM이 있는 경우엔 DOM 조각만 요청하여 넣는다.

각 페이지마다 3가지의 프론트 API가 존재한다.

  • 페이지를 처음 불러오는 경우
    ex) GET /top-100/april-2014
    Accept: text/html
브라우저는 웹페이지 요청시 기본적으로 Accept: text/html을 보내기 때문에
서버에서는 첫 요청이라는 것을 인식할 수 있다.
해당 API에서는 <html>로 시작하는 Fullpage DOM을 다 내려준다.
서버단 템플릿으로 완성된 DOM을 내려줌과 동시에,
자바스크립트 로직에서 데이터 동기화를 할 수 있도록 전역 Inline script에 JSON을 넣어주고 있다.
var GLOBALS={}에 JSON 데이터를 넣은 뒤 자바스크립트 로직에서 참조하고 있다.
medium-inline-json
  • DOM 조각의 일부만 갱신하면 되는 경우
    ex) GET /top-100/april-2014?format=fragment
    Accept: text/html

Fullpage를 불러온 뒤 링크 이동을 하는경우 타는 로직. 필요한 DOM 조각만 보내준다.

medium-fragment

  • JSON 데이터만 받고싶은 경우
    ex) GET /top-100/april-2014
    Accept: application/json
위와 마찬가지로 링크이동을 통해서 타는 로직. JSON 데이터만 보내준다.
요청시 Accept: application/json으로 AJAX Request 한다.
medium-json
이때 Response가 항상 ])}while(1);</x>로 시작하고 뒤에 JSON이 오는 형태이다.
이는 JSON Hijacking을 방지하기 위한 보안처리이다.
아래와 같은 JSON 데이터들은 데이터 성격에 따라 페이지 이동시마다 호출하여 가져온다.
https://medium.com/me/collections
https://medium.com/me/posts
https://medium.com/me/activity?minCount=100
https://medium.com/me/collections/viewed
https://medium.com/top-100/april-2014/load-more
https://medium.com/_/activity-status

CDN

자바스크립트, 이미지 파일같은 Static file들은 Amazon CloudFront를 이용하여 CDN 처리하고 있다.

통계

Google Analytics와 Google Analytics의 확장인 KISSmetrics를 이용하고 있다.
Google Analytics와 Kissmetrics는 주기적으로 통계 수집용 URL에
통계 데이터를 Query String으로 만들어서 GET Request한다.
Response는 1×1짜리 image가 나온다.
이렇게 Pseudo 이미지 파일을 GET Method로 호출하는 기법을 활용하면
Browser compatibility 문제도 없고 통계의 누락을 최소화할 수 있다.

폰트

adobe-typekit
고급 미디어 사이트답게 예쁜 Serif 폰트들을 온라인에서 사용하도록 하고 있는데,
Adobe Typekit을 이용하여 Opentype 폰트를 Web으로 제공하고 있다.
먼저 Typekit 자바스크립트 파일이 로딩되면
사용하는 폰트들의 CSS와, 폰트파일이 순차적으로 로딩된다.

브라우저 지원

IE 7으로 들어가면 아예 이미지가 깨지고, IE 10에서도 회원가입조차 안된다.
당당하게 IE지원을 버리고 크롬을 쓰라고 공지해놓고 있다.
  • Tier 1. 전체 경험 지원
    Chrome 26+, Safari 6+, Opera 15+, Firefox 19+
  • Tier 2. 글쓰기 기능을 제외하고 모두 지원
    Chrome 1+, IE 9+, Firefox 4+, Safari 3+, iOS 5+, Android 2+, Mobile Safari, Mobile Chrome
  • Tier 3. 미지원.

CSS

Base CSS / Sprite CSS / Typekit font CSS로 구분하고 있다.
Sprite CSS는 Image Sprite를 아래와 같이 CSS에 base64로 포함시켜서 넣고있다.
medium-sprite
이렇게 Data URI Scheme을 사용하는 경우 몇 가지 문제가 있다.
  • IE 6, 7 미지원
  • IE 8에서도 32k 까지만 지원
  • 이미지 Request 숫자를 줄여주지만 캐싱이 안됨.
  • Base64는 이미지 크기를 33% 증가시킴
그래서 Data URI Scheme을 이용한 Sprite는,
  • 작은 이미지만 사용
  • IE 지원을 신경안써도 될 때만 사용
  • 캐싱보다 Request를 줄이는게 더 중요할때 사용

일반적인 서비스 개발에서는,
Static file에 URL Versioning을 이용하여 수정시간을 기준으로 새로운 캐싱이 되게 하는 것이 좋다.

IE console.log 버그

F12로 콘솔창을 띄울 땐 잘되고, 안 띄울땐 에러가 나거나 실행이 안되는 문제

콘솔창을 띄우지 않으면 console 객체가 로드 되지 않기 때문이다.
이런경우 자바스크립트 에러가 나지만 인지 되지 않는 경우가 많다.
절대로 console.log를 그냥 사용하지 말라. 반드시 IE를 위해 다음 코드를 삽입하라.


// Avoid `console` errors in browsers that lack a console.
(function() {
var method;
var noop = function noop() {};
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});

while (length--) {
method = methods[length];

// Only stub undefined methods.
if (!console[method]) {
console[method] = noop;
}
}
}());

IE8 이하에서의 AJAX 문제 해결 방법

전역 AJAX 설정 변경
$.ajaxSetup({
‘cache’:false
});
$.support.cors = true;

서버사이드에서는 Content-Type과 Charset을 정확히 명시
Content-Type:text/xml
charset:utf-8 (소문자 유의)

DOCTYPE을 HTML5로 하면 안된다.

IE상에서 console을 찍어보고 네트워크 에러가 나거나 error 루틴을 타게 되면 아예 데이터를 못가져오는 것이므로 Cross-domain 문제일 확률이 크고, success 루틴을 타는 경우 일단 값은 잘 가져온 것이므로 위의 경우로 해결되는 경우가 많다.

유용한 FFmpeg 명령어

  • 모바일 인코딩
    ffmpeg -i 원본경로 -y -c:v libx264 -b:v 300k -r 30 -profile:v baseline -level:v 2.0 -c:a libvo_aacenc -b:a 64k -ac 2 -ar 44100 결과경로
  • 비디오소스+오디오소스 맵핑하여 합치는 명령
    ffmpeg -i 비디오소스경로 -i 오디오소스경로 -c copy -map 0:v -map 1:a -y 저장할경로
  • 합치면서 모바일용으로 인코딩 하는 명령
    ffmpeg -i 비디오소스경로 -i 오디오소스경로 -c copy -map 0:v -map 1:a -y -f mp4 -b:v 300k -vcodec libx264 -r 30 -async 2 -vprofile baseline -level 1.3 -acodec aac -b:a 64k -ac 2 -ar 22050 -strict experimental 저장할경로
  • 안드로이드 기기에서 스트리밍 재생을 위해서는?
    인코더로 mp4로 컨버팅 한 후 mp4box를 사용해서 hint값을 수정해주어야 한다.
    mp4box -hint 비디오파일.mp4
  • 파일 자르기
    ffmpeg -i 소스경로 -c copy -ss hh:mm:ss -t hh:mm:ss -y 저장할 경로
  • 원격지 파일 재생
    ffplay -i rtmp://주소

 

-c copy : Direct Stream Copy (원본 스트림을 수정하지 않음)
-ss : 시작 시간. 처음부터면 생략
-t : 기간. 끝까지면 생략

-i : INPUT
다수 가능, 처음 것이 0이며 이후 1씩 증가.
-map : 소스 매핑
-map 0:v는 첫번째 Input의 video source를 사용하겠다는 것. 스트림 별로 선택도 가능하다.
-y : 묻지 않고 덮어쓰기
-f : 강제로 컨테이너 설정 (보통은 필요없음)
-b : 비트레이트 설정
-b:v는 비디오, -b:a는 오디오
-vcodec : 비디오 코덱
libx264는 h264 코덱
-r : Frame Rate
-async (기존 화상 코드에 있어서 삽입했는데 잘 모르겠습니다.)
-s : 해상도
-aspect : 비율
-vprofile : 비디오 프로파일
h264는 다양한 프로파일을 제공하는데 안드로이드 2.2 이하는 baseline (모바일 용 경량 프로파일)만을 공식 지원합니다.
-level : 프로파일 레벨
안드로이드는 baseline@Level 1.3 지원, 아이폰은 무관
-acodec : 오디오 코덱
-ac : 오디오 채널
-ar 22050 : 오디오 Hz
-strict experimental : 옵션의 엄격함을 느슨하게 풀어주는 옵션.
aac 오디오 코덱은 검증 중이라 이 옵션을 사용하지 않으면 사용할 수 없다.

서버 스케일링

수직적 확장과 수평적 확장 (스케일링)

수직적 확장은 개개의 서버에 더 많은 자원을 추가하는 것을 말한다. 많은 데이터를 처리하기 위해 서버에 하드 디스크를 추가하는 것이 이에 해당한다. 더 빠른 계산 성능을 위해 더 빠른 CPU나 큰 용량의 메모리를 추가하는 것 역시 마찬가지다. 즉 수직적 확장은 각 서버의 처리 능력을 향상시키는 것을 말한다.

반면 수평적 확장이란 노드를 추가하는 것을 말한다. 데이터가 많을 경우에는 일부분을 저장할 노드를 추가하는 것이다. 많은 연산을 필요로 하는 경우에는 연산을 분리하여 추가한 노드에서 작업이 이루어지도록 한다. 수평적 확장의 장점을 모두 취하기 위해서는 시스템 아키텍처의 고유한 설계 원칙들을 따라야 한다. 그렇지 않으면 기능 단위를 수정하거나 분리하는 것이 굉장히 불편한 일이 되어 버릴 수도 있다.

수평적 확장을 하는 가장 보편적인 방법은 서비스를 파티션이나 샤드 단위로 분할하는 것이다. 파티션은 기능별 논리 집합으로 분산될 수 있다. 이러한 파티션은 특정 사용자나 데이터의 지리적인 위치에 따라 만들어질 수 있고, 혹은 무료 사용자냐 유료 사용자냐와 같은 기준에 따라 만들어질 수도 있다. 이러한 형태의 장점은 증설한 것을 바탕으로 서비스나 데이터 저장소를 제공할 수 있다는 것이다.

파티셔닝과 샤딩 (데이터베이스에서의 스케일링)

샤드라는 것은 “조각”이라는 뜻이며, 쪼개진 데이터 각 집합을 의미한다.

(수평적) 파티셔닝은 테이블 내의 데이터를 컬럼(이것은 수직적 파티셔닝이라고 함)이 아니라 행을 기준으로 나누는 것이다. 보통 단일 인스턴스 (동일 서버 or 동일 데이터베이스)내에서 사용한다. 이를 통해 인덱스 사이즈를 줄이고 (Select시 성능 이점) 작업 동시성을 높일 수 있다. 보통 동일한 데이터베이스에서 테이블만 쪼개는 것이므로 논리적인 확장이라고도 한다.

쪼갤 때 사용되는 일반적인 방법으로, 범위 파티셔닝 (ID가 5000이하는 CustomersEast에, 5000이상은 CustomerWest 테이블에 저장하는 방법), 리스트 파티셔닝 (“한국”, “일본”… 은 “아시아” 테이블에, “미국”, “캐나다”… 는 “북아메리카” 테이블에), 해시 파티셔닝 (일정한 Hash 알고리즘을 사용하는 것)이 있다.

샤딩은 파티셔닝을 넘어서는 것으로, 파티션 된 테이블들을 여러 인스턴스(다른 서버 or 동일 서버 내 다른 데이터베이스)에 뿌리는 것이다. 물리적인 확장 (다른 서버)이 되거나 논리적인 확장 (동일 서버 내 다른 데이터베이스)이 될 수 있다. 여러 데이터베이스를 대상으로 작업하기 때문에 JOIN 연산 불가, 데이터 일관성 유지 문제, 복제 문제 등이 생길 수 있다.

NoSQL 중에서는 MongoDB처럼 데이터베이스 자체에서 수평적 확장을 유념하고 개발된 것들이 많이 있으나, 기존의 RDBMS는 수평적 확장 기능이 없는 경우가 많다. 하지만 RDBMS의 기능들이 더 개발자 친화적이고, 레거시 시스템 운용을 위해 필요하고, RDBMS에 더 적합한 데이터를 저장할 때가 있기 때문에 RDBMS를 사용할 수 밖에 없다. 그럴 땐 수평적 확장을 안하는게 아니라 그런 기능을 제공해주는 어플리케이션 레벨이나 미들티어를 사용하면 된다. 어플리케이션 레벨은 Hibernated Shards (JAVA), 미들티어로는 MySQL Spock Proxy와 트위터가 만든 Gizzard가 있다.

분리 된 다수의 인스턴스들에 걸쳐서 조각을 뿌리는 것은 단순한 수평적 파티셔닝보다 많은 것들을 요구하게 된다. 만약 데이터베이스가 정보 조회를 위해서 여러 개의 인스턴스에 쿼리를 넣어야만 한다면, 다중화로 기대했던 성능 향상은 도루묵이 될 수 있다. 그러므로 샤딩 된 조각에 한번에 접근할 수 있도록 샤딩 기능이 개발 되어야 한다. 이런 특징은 왜 샤딩이 shared nothing architecture와 연관되어 있는지 설명한다. 한번 샤딩되면 각 샤드들은 완전히 독립된다. 샤드 간에는 연결을 유지해야 하는 필요가 없다.

References

MSSQL 서버 트윅

Windows 설정

  • 하이퍼스레딩 활성화
  • 제어판->전원옵션->전원계획선택에서 고성능으로 변경
    프로세서 성능을 최대치까지 끌어올림
  • 컴퓨터->속성->고급시스템설정->성능->설정->성능옵션->고급->프로세서 사용계획을 ‘백그라운드 서비스‘로 변경
    SQL Server 서비스에 프로세서 우선권을 준다.
  • 동일 메뉴에서 메모리 사용계획을 ‘프로그램‘으로 변경. 해당 항목 없으면 regedit에서 HKLM\SYSTEM\CurrentControlSet\Control\SessionManager\Memory Management\LargeSystemCache에서 LargeSystemCache를 0으로 수동 변경
    SQL Server는 자체 Cache를 가지고 있으므로 시스템 캐시를 줄여서 생긴 메모리를 SQL Server 프로세스가 가져가도록 해야한다.
  • 제어판->관리도구->로컬보안->로컬정책->사용자권한할당->메모리의 페이지 잠그기 ->속성에 SQL Server가 가동중인 사용자 계정 추가
    SQL Server에서 메모리를 Disk로 Swap하는 것을 억제. 윈도우 아키텍쳐상 메모리가 놀아도 Page 쓰기를 계속 한다.
  • 가상메모리 : DB Data가 저장되지 않는 Disk에 처음크기/최대크기를 동일하게 메모리의 1.5배 크기로 잡는다.
    DB Data가 저장되지 않는 Disk에 기록하게 하여 IO를 분산하고, Page 크기 조정으로 인한 IO를 막는다.
  • 장치관리자 -> 네트워크 어댑터 -> 각 랜카드별 속성 -> 전원관리 -> ‘전원을 절약하기 위해 컴퓨터가 이 장치를 끌 수 있음‘을 체크 풀기
    안정성을 위해서 전원 절약 해제
  • 바이러스 백신 프로그램에서 탐지하지 않을 확장자에 mdf, ldf 추가
    IO 경합 방지

DB 설정

  • 데이터베이스 속성->파일
    데이터 : 기본크기 50MB, 자동증가 50MB 단위 무제한 증가
    로그 : 기본크기 50MB, 자동증가 50MB 단위 무제한 증가로 변경.
  • 데이터베이스 속성->옵션->복구모델-> 단순으로 변경
    트랜잭션 단위 복구가 필요한 경우에는 전체로 두되, 최종 커밋 백업만 필요한 경우 단순으로 두면 된다.
    전체 복구모델 사용시 로그 파일의 크기가 데이터 파일의 크기보다 커지는 일이 비일비재하므로 기능상 불필요하다면 빼는 것이 절대적으로 유리하다.
  • 신규 데이터베이스의 기본값 변경하기
    시스템 데이터베이스 -> model 의 속성 변경
    model이 신규 데이터베이스의 템플릿이다.
  • TEMPDB (시스템 데이터베이스)
    TEMPDB의 용도는 임시테이블, 변수, 저장 프로시저, 정렬수행, 조인 등의 연산에서 임시 테이블로 사용된다.
    데이터/로그 : 기본크기 2048MB, 자동증가 1024MB
    데이터 파일은 코어수의 1/2만큼 만든다. 위치는 데이터파일이 들어있지 않은 디스크로 바꾼다.
    TEMPDB에 대한 설정을 하고나면 SQL Server를 재시작해야 설정이 적용된다.
Reference
SQL Server 운영과 튜닝 – SQLTAG 저