최근에 infoq에서 Qcon 2011 London에서 발표했던 동영상과 PPT 자료를 최근에 공개했다.
http://www.infoq.com/presentations/Big-Data-in-Real-Time-at-Twitter
http://qconlondon.com/dl/qcon-london-2011/slides/NickKallen_DataArchitectureAtTwitterScale.pdf
나는 자료가 최근인가 했더니. 이미 2010년부터 발표했던 자료이다. 데이터만 조그만 바뀌고.. 계속 발표하는 것 같다.
http://www.slideshare.net/nkallen/q-con-3770885
http://www.atmarkit.co.jp/news/201004/19/twitter.html
트위터는 초당 2.1 백만의 요청을 처리한다.
따라서, 초반에 3가지 이슈가 생겼는데.Tweets, Timelines, Social Graph 가 그 내용이다.
1. Tweets
트윗이라는 것은 단순히 id,author가 있고, 140자 글자, 짦은 메시지로 구성되어 있다.
초반에는 Mysql RDB를 잘 활용했다 Single table에 scale vertical 하게 하고, master/slave replication 구축하고, memcached를 이용해서 read 퍼포먼스 올리는 기본적인 웹 서비스로 구현을 했다.
하지만, 데이터는 순식간에 다 차버리고, 800G 이상의 데이터를 채울 수 없는 상태가 되었다. 2,954,291,678명의 트위 정보로 인해서 800G의 90%를 쓰고 말았다.
그래서 파티셔닝을 도입을 하려고 했다.
Dirt-Goose 방식(2010년도 문서에는 Current 구현이라고 적혀있고, 2011년도 문서에서는 그냥 Dirt-Goose 라는 단어를 사용했다. 아마도 그리 공학적으로 예쁘지는 않지만 현실적인 대안으로 썼기 때문에 이런 용어를 쓴 것이 아닌가 생각된다.) 을 사용해서 update되는 시간 정보를 바탕(월별)로 파티션을 생성해서 저장하는 방식을 채택하고 있다. 이 방식을 채택한 이유는 트위터 서비스 자체가 시간적인 정보단위로 이용되기 때문이다.
(temporary locality)
오래된 정보보다는 새로운 정보에 집중(bias)되어 있으며, 시간 순으로 데이터를 저장하는 방식이 깔끔하다.
반면, 이 것 외에 가능한 방법(T-bird)론으로 짝수, 홀수 id를 나누어서 저장하는 방식이 있을 수 있다.
이 방식은 최근 트윗 정보를 알기 위해서는 모든 파티션을 검색해야 하는 이슈가 있어 사용하지 않았다.
또한, 서로 다른 사용자들끼리 트윗을 reply, retweet 하면서 누가 멀했는지 찾기 위해서 모든 파티션을 검색해야 한다.
여기에 userid에 대해서 어떤 파티션이 저장되어 있는지 index 테이블(T-Flock)도 필요하다.
따라서, 파티션과 인덱스과 중요하다. locality(특히 temporal locality) 관점을 가져야 한다.
2. Timelines
timeline은 follow되거나 follow 받는 사람의 정보를 저장하는 것을 의미하낟. timeline은 tweet id의 시퀀스이며, 사용자 id의 의해서 가져올 수 있으며, 램에서만 사용하고 있다.
만약 한 사용자의 follower가 엄청 많아서 램에 다 못올리는 상황이 생길 수 있다. 이 때 속도 이슈가 생기고 빠른 응답을 줄 수 없게 된다.
Fanout Offline은 특정 시간 (예, 분/초 단위가 될 수 있음) 마다 요청을 큐에 쌓았다가 한번에 정보를 전달한다. 일종의 비동기 처리 개념이다.
일종의 메시지 큐처럼 mecached에 저장되고 트윗은 timeline에 전달된다. timeline에 바로 전달하는 구조가 아니기 때문에 low latency의 특징이 일어날 수 밖에 없다.
3. Social Graph
2010년에는 Search라는 단어를 사용했으나, 2011년 자료에서는 Socail Graph를 썼다.
2010년에서는 mysql db 검색이 아닌 lucene을 이용하려고 했다고 했었지만 이번에는 자료가 바뀌었다.
기존의 mysql 테이블을 변경해서 사용하고 있는 것 같다.
매번 요청이 올때마다 그 결과가 실시간으로 보여줘야 한다. 이는 lucene처럼 주기적으로 indexing하고 그 결과를 찾아주고 하는 작업을 할 수 없다. 따라서 소셜 그래프가 대안이었던 것 같다.
소셜 그래프는 집합연산을 해야 한다.
• List of who follows whom, who blocks whom, etc.
• Operations:
• Enumerate by time
• Intersection, Union, Difference
• Inclusion
• Cardinality
• Mass-deletes for spam
• Medium-velocity unbounded vectors
• Complex, predetermined queries
이 정보를 위해서 기존에 있던 정보, 단순히 누가 누구에게 follow 하는 정보만 저장했던 것을 떠나.
누군가가 누구에게 follow 되는 정보도 따로 저장하는 구조로 바뀌었다.
사용자 id별로 파티션하고, 시간 순서로 indexing 되어 있다.
이렇게 해서 소셜 그래프를 구축할 수 있었다.
똑같은 데이터를 두번 저장했기 때문에 consistency가 매우 중요한 이슈가 되었다. 성공할 때까지 계속 retry 하는 구조로 사용하고 있다.
대량 write 시에는 다른 방법을 사용하고 있다.
나름의 결론
- 모든 엔지니어링 솔루션은 그 때 뿐이다. (transient)
(스케일이 커지니까 그런 말을 하는거지.. 어느 정도 안정화되면 그런 말 안할꺼야.. ㅋㅋ)
- 잠시동안은 좋지만, 완벽한 것은 없다.
- scalabity가 마술은 아닌거 같다. scalabity는 partitioning, indexing, replication은 포함한다.
- 실시간 쿼리에 대한 모든 데이터는 반드시 메모리에 있어야 한다. 디스크는 write 용도밖에 없다. (내 생각엔 디스크는 persistent 용도이고, 나머지는 메모리상태에 있게 해서 최상의 속도를 내야 한다.)
- 어떤 문제들은 미리 처리(pre computation)하는 것으로 해결할 수 있지만, 대부분은 아니다.
- 가능한한 locality를 잘 보아야(exploit) 한다.