데이터프레임의 리밋에 대한 작은 고려 사항
스파크 애플리케이션에서 가장 간과하기 쉬운 부분이 데이터 사이즈다. 아직 대용량 데이터에 대해 익숙하지 않아서 기본적으로 사용할 수 있는 함수를 주의없이 사용한다. 애플리케이션 동작에 너무 몰두한 나머지 성능과 같은 측면을 중요시하지 않는다. 이번에 얘기하려고 하는 내용은 짧지만, 서슴없이 사용하는 리밋(limit)에 대한 내용이다.
스파크 애플리케이션을 만들다 보면은 데이터를 읽어 데이터셋(Dataset) 또는 데이터프레임(Dataframe)을 사용한다. 그리고 개수를 제한하기 위해 리밋(limit) 함수를 사용한다. 그러나 스파크 애플리케이션에서 리밋 함수가 어떻게 동작하는지 이해한다면 리밋 사용을 주의해야 한다. 다른 여러 블로그 글에서는 사용하지 말라고 권고하는 글이 많은데, 이렇게 말하는 이유는 그만큼 리밋 사용에 있어서 주의하라는 말이다.
데이터셋이나 데이터프레임에서 리밋은 크게 두 가지 단계로 나뉜다. 로컬 리밋(local Limit)과 글로벌 리밋(gloabl Limit)으로 나뉜다. 개수 n개로 제한하기 위해 리밋 함수를 호출하면 워커노드(worker node)에서 각각 n개의 데이터를 제한하는 과정을 수행한다. 이것을 로컬 리밋이라고 한다. 로컬 리밋으로 각각의 워커노드에서 n개의 데이터를 제한하고 난 후, 이 데이터를 다시 하나의 노드로 보내 다시 n개로 제한하는 과정을 거친다. 여기서 하나의 노드는 드라이버 노드로 알고 있다. 이를 글로벌 리밋이라고 한다. 다시 말하면, 워커 노드들마다 n개로 제한한 후 드라이버 노드에서 최종적으로 n개로 제한하는 과정을 거친다.
문제는 드라이버 노드에서 n개로 제한하는 부분이다. 워커노드들에서 처리한 결과가 하나의 노드로 합쳐져 처리하는 과정이 결코 빠르지 않다. 데이터가 커서 파티션도 많이 사용하고 있다면 하나의 노드로 모여지는 데이터 양도 많을 수 밖에 없다. 또 n 값이 작지 않으면 문제가 생길 수 있다. 충분히 큰 n 값으로 제한했을 때 마찬가지로 하나의 노드에서 처리하는 데이터 양이 많을 수 밖에 없다. 하나의 노드에서 많은 양의 데이터를 처리하는 것을 주의해야 한다. 문제를 이해해보면 전체 데이터가 작을 때나 n의 값이 충분히 작다면 리밋을 사용하는 것은 합리적이다. 단순히 리밋을 사용하지 말라는 말에 맹목적으로 따라가지 않아도 괜찮다.
그렇다면 리밋을 사용할 수 없는 상황에서 어떻게 하면 개수를 제한할 수 있을까. 여러 방법이 있겠지만 데이터에 대한 순서가 크게 중요하지 않다면 하나의 노드로 합치는 과정을 없앨 수 있다. 바로 각각 파티션마다 데이터를 제한하면 끝이다. 당연히 n개를 맞추기 위해 하나의 파티션은 n / 파티션의 수
값만큼 제한한다. 결과적으로 여러 파티션이 갖고 있는 데이터를 생각하면 n에 근접할 것이다. 만약 데이터 순서를 100% 정확하게 보장하지 않지만, 어느정도 보장하고 싶다면 파티션의 수를 점점 줄여나가는 것도 방법이다. 파티션의 수를 200, 100, 50, 20, 5로 줄여나가고 마지막 단계가 아닌 단계에서는 데이터를 정렬하고, 데이터를 (n / 파티션의 수) * 1.3
값 만큼 제한하는 것이다. 파티션이 줄여듬에 따라 전체 크기를 줄여나가면서 데이터 순서는 어느정도 보장하는 방법이다.