본문으로 건너뛰기

2. 대규모 데이터 처리 입문

4강. 하테나 북마크의 데이터 규모

하테나 북마크를 예로 본 대규모 데이터

처음에는 대규모 데이터의 실제를 하테나 북마크를 예로 살펴보도록 합니다. 하테나 북마크에는 3억 5천만 레코드가 있습니다. 이 테이블에 갑자기 select * from relword와 같은 쿼리를 실행하면 응답이 반환되지 않는데, 그 이유는 3억 레코드 이상이 존재하기 때문입니다.

하테나 북마크의 데이터 규모

하테나 북마크의 데이터 규모를 대략 보면 다음과 같습니다. 2009년 8월 시점 기준으로 entry 테이블은 1,520만 엔트리, 엔트리 데이터는 3GB, bookmark 테이블은 4,500만 북마크, 북마크 데이터는 5.5GB, tag 테이블은 5,000만 태그, 태그 데이터는 4.8GB, HTML은 200GB 이상입니다.

대규모라고는 하지만 Google이나 Yahoo!가 사용하는 규모가 되면 여기서 더 나아가 테라바이트, 페타바이트가 되므로 이는 초대규모입니다. 이와 비교하면 하테나는 대규모에서 중규모 정도입니다. 그렇지만 보통 웹 애플리케이션을 만들면서 기가바이트 단위의 DB를 다루는 일은 흔하지 않으므로, 일반적인 웹 애플리케이션이라는 관점에서 보면 큰 규모입니다. 하테나 북마크는 일본에서 최대의 소셜 북마크 서비스로, 이 정도 데이터 규모의 웹 서비스로서는 사용자 수 관점에서도 큰 규모라고 할 수 있습니다. 따라서 대규모의 사례로 살펴보는 데 적합하다고 볼 수 있습니다.

대규모 데이터로의 쿼리

다음으로 대규모 데이터로의 쿼리에 대해 살펴보겠습니다. 앞에서 본 정도의 규모인 DB가 되면 쿼리를 던져 결과가 나올 때의 느낌도 달라집니다.

그림 2.2의 use index(hoge)는 일부러 인덱스를 태우지 않고 쿼리를 던지고 있는 예인데, 1️⃣ 검색하는 데 200초가 경과해도 검색 결과가 나오지 않습니다.

5강. 대규모 데이터 처리의 어려운 점

대규모 데이터는 어떤 점이 어려운가?

대규모 데이터를 다룰 때 어려운 점이라고 생각되는 첫 번째 포인트는 메모리 내에서 계산할 수 없다는 점입니다. 메모리 내에서 계산할 수 없으면 기본적으로 디스크를 계속 읽어가면서 검색하게 되어 좀처럼 발견할 수 없는 상태가 되기 때문입니다. 데이터 건수가 많으면 그만큼 입력 데이터 건수가 늘어나므로 계산량이 많아진다는 점도 당연한 이유이지만, 이 점보다도 문제가 되는 것은 디스크를 읽고 있다는 점입니다.

이전 예 정도의 규모가 되면 데이터가 너무 많아서 메모리 내에서 계산할 수 없으므로 디스크에 두고 특정 데이터를 검색하게 됩니다. 그리고 디스크는 메모리에 비해 상당히 느립니다.

메모리와 디스크의 속도차

메모리 내의 특정 번지에 있는 데이터를 찾는 데이터 탐색과 디스크의 특정 원반 내에 있는 데이터를 찾는 것은 얼마의 속도차가 날까요? 이런 수치 감각은 꽤 중요합니다. 정답은 10^5-10^6 정도의 차이, 즉 10만 배에서 100만 배입니다.

디스크는 왜 늦을까

그림 2.3 1️⃣의 메모리 그림에서 예를 들어 그림 2.3의 ❶ 부분에 1바이트 숫자 5가 들어 있고 그림 2.3의 ❷에 0이라는 숫자가 들어 있을 때, ❷ 부분을 탐색하다가 ❶ 부분을 확인하고자 하더라도 마이크로초 단위로 포인터를 이동시킬 수 있습니다.

한편 디스크는 동축 상에 원반이 쌓여 있고, 이 원반이 회전하면서 데이터를 읽어냅니다. 즉 메모리와는 달리 회전 등의 물리적인 동작을 수반하고 있습니다.

탐색속도에 영향을 주는 다양한 요인

디스크에서는 ❹ 헤드의 이동과 ❺ 원반의 회전이라는 두 가지 물리적인 이동이 필요합니다. 오늘날의 기술로도 원반의 회전속도를 빛의 속도에 가깝게 만들 수는 없습니다. 디스크에서는 ❹, ❺ 각각 밀리초 단위, 합해서 수 밀리초가 걸립니다. 메모리는 1회 탐색할 때 마이크로초면 되지만 디스크는 수 밀리초가 걸리는 것입니다.

다음으로 ❻과 같이 데이터가 뿔뿔이 흩어져 배치되어 있고 이분탐색처럼 여기저기에서 찾아야 하는 알고리즘을 사용한다고 하면, 한 바퀴 회전해서 이쪽으로 이동하고 또 한 바퀴 회전해서 저쪽으로 이동하고 다시 회전해서 이쪽으로 오는 식으로 원반을 계속 돌려야 합니다. 경우에 따라서는 헤드도 움직여야 합니다. 그래서 상당한 시간이 걸리게 됩니다. 그러나 데이터가 메모리상에 있다면 탐색할 때 물리적인 동작 없이 실제 데이터 탐색 시의 오버헤드가 거의 없으므로 빠릅니다.

OS 레벨에서의 연구

디스크는 느리지만 OS는 이를 어느 정도 커버합니다. 그림 2.3의 ❼과 같이 OS는 연속된 데이터를 같은 위치에 쌓고, 데이터를 읽을 때 1바이트씩 읽는 것이 아니라 4KB 정도를 한꺼번에 읽도록 되어 있습니다. 이렇게 해서 비슷한 데이터를 비슷한 곳에 두어 1번의 디스크 회전으로 읽는 데이터 수를 많게 합니다. 그 결과 디스크의 회전 횟수를 최소화할 수 있게 됩니다.

전송속도, 버스의 속도차

지금까지는 탐색속도 측면에서 메모리가 디스크에 비해 10^5-10^6배 이상 빠르다는 이야기였는데 사실은 이것뿐만이 아닙니다. 이제 전송속도 차이도 살펴보겠습니다.

메모리나 디스크 모두 CPU와 버스로 연결되어 있습니다. 그림 2.3의 ❽, ❾와 같이 이 버스의 속도에서도 상당한 차이가 있습니다. 찾은 데이터를 디스크에서 메모리로 보내거나 메모리에서 CPU로 보내는 등 컴퓨터 내부에서 전송하기 위한 속도입니다. 메모리와 CPU는 상당히 빠른 버스로 연결되어 있으므로 그림 2.4 ❶처럼 7.5GB/초 정도 나오지만, 디스크는 그림 2.4 ❷처럼 58MB/초 정도밖에 나오지 않습니다.

6강. 규모조정의 요소

규모조정, 확장성

웹 서비스에서는 고가의 빠른 하드웨어를 사서 성능을 높이는 스케일업 전략보다도, 저가이면서 일반적인 성능의 하드웨어를 많이 나열해서 시스템 전체 성능을 올리는 스케일아웃 전략이 주류입니다. 개별적인 이유는 다양하겠지만, 스케일아웃 전략이 더 나은 이유는 웹 서비스에 적합한 형태이고 비용이 저렴하다는 점, 그리고 시스템 구성에 유연성이 있다는 점입니다.

웹 애플리케이션과 부하의 관계

웹 애플리케이션과 부하의 관계를 그림으로 보면 그림 2.5의 3단 구조에는 프록시 ❶, AP 서버 ❷, DB ❸이 있습니다. 웹 애플리케이션에 그림 2.5의 ❶, ❷라는 요청이 오고 ❸ DB에 도달해서 I/O가 발생하고, 이 I/O가 발생해서 되돌아온 콘텐츠를 변경한 후 그림 2.5의 ❹처럼 클라이언트로 응답합니다. 기본적으로 ❷ AP 서버에는 I/O 부하가 걸리지 않고 ❸ DB 측에 I/O 부하가 걸립니다.

❷ AP 서버는 CPU 부하만 걸리므로 분산이 간단합니다. 기본적으로 데이터를 분산해서 갖고 있는 것이 아니므로 ❷', ❷''와 같이 동일한 호스트가 동일하게 작업을 처리하기만 하면 분산할 수 있습니다. 따라서 대수를 늘리기만 하면 간단히 확장해 갈 수 있습니다. 결국 새로운 서버를 추가하고자 한다면 원래 있던 서버와 완전히 동일한 구성을 갖는 서버를 추가하면 됩니다. 이를 균등하게 분산하는 것은 로드밸런서가 담당합니다.

한편 I/O 부하에는 문제가 있습니다. ❸'를 추가한다고 생각해보면 바로 알 수 있는데, DB ❸과 ❸'을 함께 놓는다고 하면 예를 들어 ❷에서 쓰기가 발생했을 때 ❸이 지닌 데이터와 ❸'의 데이터를 어떻게 동기화할 것인가라는 문제가 생깁니다. ❸의 데이터를 ❸'의 DB에 복사하면 좋겠지만, ❸의 DB에 쓰인 내용을 어떻게 ❸'에 쓸 것인가라는 상황에 놓입니다. 그렇습니다. 쓰기는 간단히 분산할 수가 없습니다.

DB 확장성 확보의 어려움

이상과 같이 DB 확장성을 확보하는 것은 상당히 어렵습니다. 그리고 앞서 설명한 바와 같이 디스크가 느리다는 문제도 여기에 영향을 미칩니다. AP 서버는 디스크를 거의 사용하지 않으므로 디스크에 관해서는 별로 생각하지 않아도 되지만, DB에서는 디스크를 많이 사용하므로 디스크 I/O를 많이 발생시키는 구성으로 되어 있으면 속도차 문제가 생깁니다. 게다가 데이터가 커지면 커질수록 메모리에서 처리하지 못하고 디스크상에서 처리할 수밖에 없는 요건이 늘어납니다.

즉 대규모 환경에서는 I/O 부하를 부담하고 있는 서버는 애초에 분산시키기 어려운데다가 디스크 I/O가 많이 발생하면 서버가 금세 느려지는 본질적인 문제가 있습니다. 서비스를 운영해보면 서비스가 무거우니 서버를 늘리는 게 어떠냐는 제안을 하는 경우도 있는데, 사실 서버를 늘려서 해결할 수 있다면 간단한 것입니다.

7강. 대규모 데이터를 다루기 위한 기초지식

대규모 데이터를 다루는 세 가지 급소

대규모 시스템을 고민하게 만드는 대규모 데이터를 다루는 요령 첫 번째는 어떻게 하면 메모리에서 처리를 마칠 수 있을까라는 점입니다. 메모리에서 처리를 마쳐야 하는 이유는 앞서 설명한 대로 디스크 seek 횟수가 확장성과 성능에 크게 영향을 주기 때문입니다. 디스크 seek 횟수를 최소화한다는 의미로 메모리를 활용하고자 합니다.

두 번째 요령은 데이터량 증가에 강한 알고리즘을 사용하는 것입니다. 1,000만 건의 레코드가 있을 때 단순히 선형탐색으로 하면 1,000만 번 계산을 수행해야 하지만, Log Order인 알고리즘을 적용하면 수십 번 만에 마칠 수 있다는 기본적인 예가 있습니다.

세 번째 요령은 데이터 압축이나 검색기술과 같은 테크닉이 활용될 수 있는 국면이 있다는 점입니다. 단적으로 말하면 압축해서 데이터량을 줄일 수 있다면 읽어내는 seek 횟수도 적어지므로 디스크 읽는 횟수를 최소화할 수 있습니다. 또한 메모리에 캐싱하기 쉬워집니다.

또한 검색이 중요한 이유는 확장성 면에서 DB에만 맡겨서 해결할 수 없을 때 특정 용도에 특화된 검색엔진 등을 만들어서 해당 검색 시스템을 웹 애플리케이션에서 이용하는 형태로 전환한다면 속도를 제대로 확보할 수 있기 때문입니다. 이런 이유로 압축과 검색이 중요합니다.

대규모 데이터를 다루기 전 3대 전제지식

우선 첫 번째는 OS 캐시입니다. 두 번째는 분산을 고려해서 RDBMS를 운용할 때는 어떻게 해야 하는가라는 점입니다. 세 번째는 대규모 환경에서 알고리즘과 데이터 구조를 사용한다는 것은 어떤 것인가라는 점입니다. 이 세 가지는 이어지는 장에서 더 상세하게 살펴보게 됩니다.

Wrap Up

하테나 북마크 사례는 대규모 데이터 처리에서 핵심 문제가 단순한 레코드 수 증가가 아니라, 메모리에 올릴 수 없는 데이터와 그로 인해 발생하는 디스크 I/O라는 점을 보여줍니다. 또한 웹 서비스의 확장성은 AP 서버처럼 쉽게 늘릴 수 있는 계층과, DB처럼 쓰기 동기화 때문에 쉽게 늘릴 수 없는 계층이 다르다는 사실을 함께 이해해야 합니다.

Summary

대규모 데이터 환경에서는 select * 같은 단순한 쿼리도 즉시 응답하지 않을 수 있으며, 그 배경에는 방대한 레코드 수와 디스크 접근 비용이 있습니다. 메모리와 디스크는 탐색속도와 전송속도 모두 큰 차이를 보이므로, 메모리 내에서 처리를 마치는 전략이 성능과 확장성의 핵심이 됩니다. 웹 애플리케이션에서는 AP 서버는 비교적 쉽게 스케일아웃할 수 있지만, DB는 쓰기와 동기화 문제 때문에 확장이 어렵습니다. 그래서 대규모 데이터를 다룰 때는 메모리 활용, 데이터량 증가에 강한 알고리즘, 압축과 검색기술을 함께 고려해야 합니다. 또한 OS 캐시, 분산 환경의 RDBMS 운용, 알고리즘과 데이터 구조에 대한 이해가 이후 논의를 위한 전제지식이 됩니다.

Reference