Facebook이 대규모 확장성 도전에서 배운 것

30
Facebook 이 이이이 이이이 이이이이 이이 이 이이이이 이이이이이이 이이이 이이 이이이이이 이이이 MS Visual C++ MVP Twitter : @jacking75

Transcript of Facebook이 대규모 확장성 도전에서 배운 것

Page 1: Facebook이 대규모 확장성 도전에서 배운 것

Facebook 이 대규모 확장성 도전에서 배운 것

마이에트 엔터테인먼트 건즈팀서버 프로그래머

최흥배MS Visual C++ MVPTwitter : @jacking75

Page 2: Facebook이 대규모 확장성 도전에서 배운 것

이 글은 http://www.publickey1.jp/blog/09/facebook8php.html 와http://www.publickey1.jp/blog/09/facebook.html 의 글을 번역 정리한 것으로

원문은 2009 년 10 월 8 일 미국의 캘리포니아 대학 센티에이고교에서 열렸던 세미나 「High Performance at Massive Scale-Lessons learned at Facebook」 의 내용을 정리한 것입니다 . 강연자는 패이스북 기술담당 부사장 Jeff Rothschild 이다 .

Page 3: Facebook이 대규모 확장성 도전에서 배운 것

3 만대의 서버에 대해서 엔지니어는 230 명

이 세미나에서는 Facebook 이 지금까지 직면한 과제를 어떻게 극복해 왔는지를 설명 한다 . Facebook 은 세계 최대급 Web 사이트의 하나로서

1 개월에 200 빌리언 (2000 억 ) 페이지 뷰로 , 300 밀리언 (3 억 ) 명의 액티브 유저가 1 일에 1 빌리언 (10 억 ) 의 채팅 , 1 일에 100 밀리언 (1 억 ) 의 검색 등을 실행하고 있다 .

게다가 이용자가 믿을 수 없을 정도로 비약적으로 증가해 왔다 . 또 금년은 회사에 있어서 중요한 이정표를 경험했다 . 4 월에 회사가 단월 흑자가 되어 현재에도 적극적인 캐쉬 플로우(cash flow) 를 유지하고 있다 .

Page 4: Facebook이 대규모 확장성 도전에서 배운 것

Facebook 의 중심은 엔지니어링이지만 2005 년에 회원이 약 200 만명이었을 때는 사내의 엔지니어는 불과 2 명 밖에 없었다 . 게다가 그 중 한 명은 창업자인 Mark Zuckerberg 이다 . 그리고 현재 사내의 엔지니어 팀은 230 명이 되었다 .

Facebook 의 액티브 유저수로 사내의 엔지니어 수를 나누면 , 대체로 110 만 액티브 유저에 대해서 1 명의 엔지니어 라는 것이 된다 . 이것은 다른 인터넷 기업과 비교하면 극단적으로 적은 엔지니어수라고 말할 수 있다 . 우리는 이것을 향후도 한층 더 향상시켜 가려고 생각한다 .

Zuckerberg( 이 ) 다 . 그리고 현재 , 사내의 엔지니어 팀은 230 사람이 되었다 .

Page 5: Facebook이 대규모 확장성 도전에서 배운 것

디스크의 물리 I/O 가 한계를 결정한다

그런데 SNS 의 소셜 그래프는 사람 뿐만이 아니라 , 기업이나 제품이나 회사나 친구의 블로그 포스트나 비디오나 사진 등 각각이 어떻게 관계하고 있는지를 나타내고 있다 . 대량의 데이터와 함께 그 사이의 릴레이션 쉽이 소셜 그래프로서 발생하고 있다 . 이렇게 복잡하게 관계한 대량의 데이터를 어떻게 보존하고 표현할지가 Facebook 에 있어서의 도전이다 .

Page 6: Facebook이 대규모 확장성 도전에서 배운 것

넷 상에는 많은 사진이 있다 . 사진을 구성하는 이미지 데이터는 크고 , 게다가 Facebook 에 보존된 사진은 소셜 그래프로 결합되고 있다 . 예를 들면 누군가가 사진을 Facebook 에 업 로드하고 태그를 붙이면 그 사람의 소셜 그래프로 결합되고 있는 사람에게는 사진이 공개되었다고 하는 통지를 Facebook 으로부터 받게 된다 .

Facebook 에는 약 20 빌리언 (200 억 ) 장의 사진이 보존되고 있으며 각각 4 종류의 해상도로 보존되고 있기 때문에 전체 800 억장의 사진이 보존되고 있다고 말할 수 있다 . 이것은 사진을 전부 이으면 지구를 10 회 둘러 쌀 만한 면적이 있다 .

Page 7: Facebook이 대규모 확장성 도전에서 배운 것

기술적인 챌린지는 대량의 데이터를 보존할 뿐만 아니라 그것을 유저에게 전달 ( 표시 ) 해야 하는 점이다 . Facebook 에서는 1 초간에 60 만장의 사진을 표시하고 있으며 여기가 가장 어려운 점이다 .그러나 우리와 같은 소규모의 회사에서는 사내의 자원만으로 문제를 전부 해결할 수 없다 . 스킬이 있는 사내의 엔지니어를 대량의 사진을 표시하기 위한 연구 최종 단계 부분의 문제 해결에 투입 해야할 것인가 ? 그렇지 않으면 독특한 신기능을 개발하는데 투입 해야할 것인지 ? 선택하지 않으면 안 된다 .

대답은 분명하다 . 우수한 엔지니어는 독특한 기능의 개발에 투입하고 타사와 기술적인 과제가 오버랩 하는 부분은 솔루션을 구입하면 된다 . 거기서 우리는 간단한 방법을 선택하기로 했다 . NFS 스토리지 제품을 구입했던 것이다 .그런데 그 파일 시스템은 대량의 파일을 지원하는데 용의하지 않아서 데이터는 파일 캐쉬에 들어가지 않고 , 스토리지 용량보다 I/O 가 많음에 의해서 성능이 한계를 맞이해 버렸다 .

Page 8: Facebook이 대규모 확장성 도전에서 배운 것

계를 맞이해 버렸다 .

대량의 사진 데이터를 취급할 때 디스크의 물리 I/O 가 성능의 한계를 결정한다 . 조사해 보면 하나의 사진을 꺼내는데 10 회의 물리 I/O 를 하고 있었다 . 데이터는 복잡한 디렉토리안에 저장되어 파일 캐시 기억 장치는 대량의 사진 데이터를 위해서 거의 도움이 되지 않았었다 .거기서 우선 파일 메타데이타의 취급이나 디렉토리의 구조 , 블록 사이즈 등에 대해서 최적화를 실시하여 물리 I/O 를 24 회 정도까지 줄였다 .게다가 독자적인 Heystack 로 불리는 오버레이 파일 시스템을 구축했다 . 이것은 많은 사진 데이터를 모아 그것들을 OS 에서는 하나의 파일과 같이 가장히여 메타 데이타는 캐쉬하는 등의 구조를 가진다 . 이것으로 대부분의 경우 1 회의 물리 I/O 로 사진 데이타를 뽑기 시작할 수 있게 되었다 ( 아래 사진은 Haystack 의 개발 팀 ).

의 개발 팀 ).

Haystack 은 오픈 소스로 되어 있다 . 우리는 오픈 소스를 강하게 믿고 있다 .

Page 9: Facebook이 대규모 확장성 도전에서 배운 것

프레젠테이션 레이어는 PHP 로 프로그래밍

Facebook 의 아키텍처는 다른 사이트와 그다지 다르지 않다 . 로드 밸런스가 Web 서버의 앞에 있으며 Web 서버의 뒤에 서비스군 , 피드 , 서치 , 광고 , 그리고 캐싱이나 데이타베이스 레이어가 있다 .

그런데 . Web 서버 부분을 보자 . Web 서버에서 동작하는 프로그램은 PHP 를 사용하고 있다 .PHP 를 선택한 이유는 심플한 언어로 배우기 쉽기 때문이다 . 쓰는 것도 간단하고 , 읽는 것도 디버그도 간단 .

Page 10: Facebook이 대규모 확장성 도전에서 배운 것

한편 , 어두운 점도 있다 . 그것은 런타임 코스트다 . CPU 와 메모리의 소비가 크고 , 다른 언어와 통합하는 것도 어렵다 . 또 대규모 프로젝트에서는 모듈 구조를 잘 지원하고 있다고는 말할 수 없다 .

Page 11: Facebook이 대규모 확장성 도전에서 배운 것

그 이외에도 긴 경험으로부터 발견한 PHP 의 과제가 있다 . 새롭게 쓴 코드가 낡은 코드를 늦게 하는 것이다 . 예를 들면 PHP 로 썼던 ABC 라고 하는 기능에 DEF 라고 하는 신기능을 덧붙이면 비록 ABC 에서 DEF 를 호출하지 않았다고 해도 ABC 의 동작이 이전보다 늦어지다 . 초기화 코스트 등이 증가하기 때문이다 . PHP 에는 이러한 확장성의 과제가 있다 .

거기서 우리는 PHP 의 초기화를 완화하기 위한 확장인 Lazy loading 이나 , Cache prim-ing, 최근에는 PHP 를 C++ 로 컴파일 한다고 하는 어프로치를 채용하고 있다 .

Page 12: Facebook이 대규모 확장성 도전에서 배운 것

backend 개발용으로 프레임워크를 준비

Facebook 은 backend 에 많은 서비스가 동작하고 있다 . backend 서비스의 구축에는 PHP 는 사용하지 않고 , C++ 를 사용하는 것이 많지만 그 이외에도 복수의 언어를 이용해 개발하고 있다 .

ている。

서비스 구축을 쉽게 하기 위해서 backend 서비스용 서비스 프레임워크를 개발했다

Page 13: Facebook이 대규모 확장성 도전에서 배운 것

Thrift

Thrift 는 오픈 소스 프로젝트로서 개발하고 있는 크로스 언어 프레임워크로 RPC 환경을 제공한다 . Facebook 에서는 서비스의 태스크 마다 적절한 언어를 선택하고 라이브러리를 만들고 그것을 RPC 로 부르고 있다 . Thrift 는 라이트 웨이트한 프레임워크로 만들어져 직렬화 , connection 핸들링 등을 신경 쓰지 않고 끝나는 기본적인 템플릿을 제공해 준다 . 필요한 서버기능은 프레임워크가 제공해 준다 .

選んでライブラリを作り、それを RPC で呼んでいる。

Page 14: Facebook이 대규모 확장성 도전에서 배운 것

Scribe

Scribe 는 분산한 데이터를 중앙의 데이타베이스에 집약하는 프레임워크다 . 그 예의 하나서 UNIX 의 로그인 syslog 를 모아 관리하는 구조도 만들었다 .

각 머신의 로그를 큐잉 하면서 통합하여 거대한 하나의 시퀀셜한 로그로 변환해 준다 . 이 Scribe 도 Thrift 위에 구축되고 있다 . Scribe 로 트래픽을 처리하는데 소수의 서버로 끝나는 매우 효율적인 방법이다 . 서비스를 configuration 하거나 모니터 하는 시스템도 이러한 위에서 만들어져 있다 .

換してくれる。この Scribe も Thrift の上に構築されている。

Page 15: Facebook이 대규모 확장성 도전에서 배운 것

캐쉬가 확장성에 큰 역할을 이루고 있다

Facebook 의 주된 역할은 유저가 간단하게 ( 친구들의 ) 정보를 모으는 것이 가능할 뿐만 아니라 , 정보를 만들어 내는 것도 용이한 점에 있다 . 그 중심에 있는 것이 「뉴스 피드」라고 하는 서비스다 .

누군가가 Facebook 에서 ( 발언을 포스트하거나 사진을 업 로드하거나 하며 ) 자신의 스테이터스를 업데이트 하면 그것이 리프 노드에 전해진다 . 그리고 다른 누군가가 페이지를 업데이트 하면 그 리퀘스트가 뉴스 피드를 통해서 리퀘스트를 전체에 발신하여 그가 흥미가 있는 모든 갱신 정보를 ( 리프 노드에 대해서 ) 체크 , 그것이 어그리게이션 되고 , PHP 레이어로 정리하여 Web 페이지가 만들어져 유저에게 표시된다 .여러 가지 의미로 이러한 시스템의 중심에 있는 것이 캐쉬다 . 캐쉬는 시스템의 확장성에 큰 역할을 이루고 있다 .

Page 16: Facebook이 대규모 확장성 도전에서 배운 것

Facebook 에서는 각 유저의 데이터가 연계하고 있으므로 1% 의 액티브 유저가 자신의 정보를 변경이나 추가라고 하는 조작을 하고 있어도 그 결과는 거의 모든 데이타베이스에 걸쳐서 조작되게 된다 . 여기에 소셜 애플리케이션의 확장성에 대한 과제가 있다 .그러나 데이터의 분할을 할 수 있으면 이 과제는 비교적 간단하게 해결한다 .5 년전 Facebook 이 대학생 전용의 사이트였던 때는 버클리든가 하버드라는 대학별로 데이타베이스를 가지고 있고 , 데이터를 분할하고 있었다 . 주된 교류 관계는 대학 내에서 닫고 있어 대학 사이에 걸치는 관계는 ( 그렇게 말했던 것이 발생한다 ) 이벤트 등의 부분에서 묶으면 충분했다 .그러나 지금은 그렇지 않다 . 유저 전체가 종횡으로 연결되어 있어 유저는 데이타베이스 전체에 걸쳐서 랜덤으로 분산하듯이 배치하고 있다 . 그런 만큼 확장성은 어려워지고 있다 .

Page 17: Facebook이 대규모 확장성 도전에서 배운 것

이것은 즉 자신이 페이지를 리드로 할 때 몇 백의 친구에 관한 대량의 데이타베이스 액세스가 발생한다 라고 하는 것이다 . 이것을 해결하기 위해서 매우 고속의 캐쉬를 채용하고 있다 .

캐쉬에 이용하고 있는 것이 Memcache 이다 . Memcache 는 쿼리 성능을 향상해 준다 . 한편 Memcache 의 데이터는 망가지기 쉽다고 하는 결점이 있다 .( 데이터가 망가지지 않게 하려면 ) 데이터가 데이타베이스를 갱신하면 캐쉬 데이터를 삭제한다 라고 하는 룰에 프로그래머가 모두 따를지에 걸려 있다 .

Page 18: Facebook이 대규모 확장성 도전에서 배운 것

Facebook 은 대규모 운용에 견딜 수 있도록 Memcache 도 개량해 왔다 . 64 비트 대응 , 보다 효율적인 직렬화 , multi-thread 대응 , 프로토콜의 개량 , 네트워크 스택의 개량 등등 . 현재 Facebook 에서는 Memcache 가 1 초 마다 120 밀리언 (12 억 ) 의 리퀘스트를 처리하고 있다 .

Page 19: Facebook이 대규모 확장성 도전에서 배운 것

Memcache 에서 일어나는 과제

Memche 를 운용해 나가는데 있어서의 과제의 하나는 Network Incast 라고 부르는 현상이다 .PHP 클라이언트가 리퀘스트를 내면 , 복수의 캐쉬로부터 각각 40 마이크로 세컨드 정도로 거의 동시에 정리하여 결과가 되돌아 온다 . 그러면 스위치가 버퍼 오버 런이 되고 패킷이 없어져 버린다 .

이것을 없애기 위해서 Memcache 에 TCP 윈드윙을 닮은 오프 sliding window 프로토콜을 구현하여 응답 시간을 늦추는 것으로 해결했다 .그 밖에도 과제가 있다 . 어떻게 캐쉬를 구성할 것인가 이다 .

Page 20: Facebook이 대규모 확장성 도전에서 배운 것

캐쉬 안에서 작은 오브젝트를 많이 취급하는 서버는 많은 리퀘스트를 처리하고 대답을 하기 위해 CPU 를 많이 사용하는 한편 큰 오브젝트를 취급하는 서버는 데이터 송수신을 위해서 네트워크의 대역폭을 대량으로 사용한다 .

여기서 캐쉬에 대해서 오브젝트의 종류를 믹스 하면 CPU 와 대역폭의 자원을 어느쪽이나 풀로 사용할 수 있을 것 같다 .

Page 21: Facebook이 대규모 확장성 도전에서 배운 것

그러나 실제로는 이렇게 간단한 룰은 들어맞지 않는다 .

2 개의 ( 캐쉬 ) 풀에 2 종류의 오브젝트 TypeA 와 TypeB 를 균형 있게 믹스 해 배치했다고 한다 . 클라이언트로부터 TypeA 에 대한 리퀘스트 , TypeB 에 대한 리퀘스트를 각각의 풀에 보낸다고 하자 . 그러면 어느 쪽의 풀도 리퀘스트에 응하여 TypeA 에 대한 리퀘스트에 해당하는 TypeA 를 50 개 , TypeB 에 대한 리퀘스트에 해당하는 TypeB 를 50 개 대답해 온다고 한다(즉 2 개의 풀을 맞추면 리퀘스트에 합치한 TypeA,TypeB 의 오브젝트가 각각 100 개씩 있는 것이 된다 ).

Page 22: Facebook이 대규모 확장성 도전에서 배운 것

이번은 ( 각 풀에서의 오브젝트의 믹스를 그만두고 ) 2 개의 풀 각각을 TypeA 전용 , TypeB전용으로 한다 . 그리고 똑같이 클라이언트로부터 TypeA 에 대한 TypeB 에 대한 2 회의 리퀘스트를 각각의 풀에 던졌다고 한다 . 그러면 TypeA 전용 풀은 TypeA 에 대한 리퀘스트에만 응해 해당하는 TypeA 를 100 개 대답하고 , TypeB 전용 풀은 TypeB 에 대한 리퀘스트에만 응해 해당하는 TypeB 를 100 개 대답한다 . 이 상태로 네트워크의 밴드 폭에도 문제가 없고 , 게다가 후자의 구성이 리퀘스트에 대해서 1 개의 풀의 용량이 2배가 되고 있지 않을것이다 .

Page 23: Facebook이 대규모 확장성 도전에서 배운 것

다른 예를 보자 .2 개의 풀이 어느쪽이나 TypeA 의 오브젝트를 보존하고 있다고 한다 . 이 풀에 대해서 클라이언트가 100 회의 리퀘스트를 던지면 , 해당하는 50 개의 오브젝트를 돌려주지만 벌써 리퀘스트의 처리로 어느 쪽의 풀도 CPU 가 가득 차고 있다 .

CPU 가 가득하면 3 대째의 풀을 추가하여 TypeA 의 오브젝트를 조금 그 쪽으로 배분하면 , 각 풀이 대답하는 오브젝트 수는 1 대당 50 개에서 33 개 (혹은 34 개 ) 로 감소하지만 각 서버가 100 리퀘스트를 클라이언트로부터 받아 CPU 가 가득하게 되는 것은 변함 없다 .

Page 24: Facebook이 대규모 확장성 도전에서 배운 것

이것을 해결하려면 (추가한 서버에 오브젝트를 배분하는 것이 아니라 ) 추가한 서버에 오브젝트를 replication 한다 . 그리고 클라이언트가 리퀘스트를 분할하여 각각의 서버에 보내도록 하고 , 각 풀이 받는 리퀘스트 수를 줄이면 좋다 .

이와 같이 자원의 관리라고 하는 것은 매우 복잡하고 어떻게 데이터의 분산을 옵티마이즈 할까는 매우 어려운 문제다 . 사실 풀에 대해서 오브젝트를 어떻게 분산 배치시키면 좋은 것인지 ? 라고 하는 최적화는 사람이 수동 작업으로 하고 있다 .

Page 25: Facebook이 대규모 확장성 도전에서 배운 것

MySQL 는 사용하고 있지만 RDB 로서가 아니다

Facebook 에서 데이터의 보존은 MySQL 서버를 사용하여 쉐어드 낫싱 아키텍처를 채용하고 있다 . 쉐어드 아키텍처를 이용하지 않는 것이 기본적인 원칙으로 가능한 한 모든 것을 독립 하게 하기로 하고 있다 .

MySQL 는 뛰어난 RDB 이지만 우리는 그것을 RDB 로서는 사용하지 않았다 . 뛰어난 데이터 보전성 (Data Integrity) 을 위해서 사용하고 있다 . 지금까지 사람의 실수 이외에 MySQL 에 있는 데이터가 망가지거나 없어지거나 했던 적은 없다 .

Page 26: Facebook이 대규모 확장성 도전에서 배운 것

데이터 센터간에서의 일관성을 확보하는 방법

Facebook 은 처음에는 산타클라라에 있는 데이터 센터에서 시작했다 . 거기에는 Web 티어 , Memcache 티어 , 데이타베이스 티어의 3 층이 포함되어 있었다 .

Page 27: Facebook이 대규모 확장성 도전에서 배운 것

그 건물이 가득 차면 샌프란시스코에 데이터 센터를 만들었다 .

거기에는 Web 티어와 Memcache 티어를 넣었지만 샌프란시스코와 산타클라라는 그만큼 멀지 않았기 때문에 데이타베이스 티어는 산타클라라를 공유하도록 했다 . 34 밀리 세컨드 정도 불필요하게 걸리지만 그 정도라면 거의 문제 없다

Page 28: Facebook이 대규모 확장성 도전에서 배운 것

그러나 각각의 데이터 센터에 있는 Memcache 티어의 일관성에 대한 과제를 해결해야 했다 . 거기서 각각의 데이터 센터에 Memcache 프록시를 도입 ( 그림의 오렌지 부분 ). 캐쉬내의 데이터가 삭제 되면 , 프록시가 그 카피 데이터를 모두 삭제하도록 했다 .

그 후 , 우리는 동해안에도 데이터 센터를 만들었다 . 처음 생각한 것은 서해안과 동해안을 연결하여 캐쉬의 일관성을 얻기 위해서 Memcache 프록시를 도입하는 것이었다 .그러나 문제는 Memcache 티어는 프록시를 통하여 정보를 얻고 , 데이타베이스 티어는 repli-cation 를 실시하고 있는 것으로 Memcache 와 데이타베이스의 데이터의 경합 상태가 발생하는 것이었다 .

Page 29: Facebook이 대규모 확장성 도전에서 배운 것

거기서 프록시를 MySQL 에 넣기로 하여 MySQL 의 데이터의 변경을 Memcache 티어에도 동시에 실시하는 기능을 추가했다 . 이것에 의해서 데이타베이스에 대한 변경은 자동적으로 리모트 데이터 센터 내의 캐쉬에도 반영되게 되었다

Page 30: Facebook이 대규모 확장성 도전에서 배운 것

세미나에서의 질문:네트워크의 보틀 넥 문제는 없었는가 ?

네트워크도 보틀 넥이 되어 있다 . 특히 데이터 센터의 인터널 네트워크는 리퀘스트에 대해서 수백 대의 서버로부터 대답이 되돌아 올 때의 스위치의 오버플로우에 접했지만 , 특히 그러한 문제가 일어나지 않아도 네트워크에는 큰 스트레스가 되어 있다 .아키텍처적으로는 더 Web 티어로 캐쉬를 활용하여 트래픽을 내리는 것은 검토 중이다 . 그러나 고속의 네트워크에 의해서 스파이크가 발생했을 때에도 대응할 수 있도록 하는 등 네트워크는 확장성에 있어서 중요한 요소다 .

세미나에서의 질문: (마이크가 꺼져 있어서 잘 모름 )Facebook 에서 가동하고 있는 서버 대수를 대답할 때 언제나 그 대수는 잘못되어 있다 . 왜냐하면 서버는 계속 증가하고 있으니까 . 현재는 3 만대 정도의 서버가 있다 .