마스터 데이터 집합은하나의 서버에 저장하기에는 너무 크다. 데이터를 여러 장비에 어떻게 분산시킬 것인지기 중요하다. 이번 장은 다음을 정리한다.
마스터 데이터 집합을 저장하는데 필요한 요구사항
분산 파일 시스템이 왜 데이터 집합을 저장하는데 적합한지
4.1 마스터 데이터 집합 저장소의 요구사항
“데이터를 한 번만 쓰고, 읽기는 큰 단위로 여러 번 수행된다” 방식에 초점을 두면, 다음과 같이 요구사항을 정리할 수 있다.
쓰기
데이터 추가의 효율성 : 유일한 쓰기 연산은 새로운 데이터를 추가하는 것뿐이다.
확장성 있는 저장소 : 데이터 집합이 커질 때 확장하기 쉬워야한다.
읽기
병렬 처리 지원 : 거대한 양의 데이터를 확장성 있는 방식으로 다룰 수 있도록 병렬 처리를 지원해야한다.
둘 다
저장 비용과 처리 비용 조율 : 필요에 따라 데이터를 저장학고 압축하는 방식을 선택하는 유연성이 있어야한다.
불변성 강제
4.2 일괄 처리 계층을 위한 저장소 솔루션 선택
4.2.1 키/값 저장소
여러 장비에 분산되는 거대하고 영속적인 hash map
값은 저장할 데이터이다. 키는 무엇일까 ? 우리가 사용하는 데이터 모델에는 데이터 자체가 대량 소비를 전제로 한다. 그래서 원래 키가 없고, 필요하지도 않다. 즉, 처음 부터 데이터 모델과 키/값 저장소의 동작 방식이 맞지 않는 것이다. 유일하게 쓸만한 방법이라면, UUID 를 생성해서 키로 사용하는 것이다.
키/값 저장소는 무작위 읽기와 쓰기를 지원하기 위해 키/값 쌍에 세밀하게 접근해야한다. 그래서, 여러 개의 키/값 쌍을 묶어서 압축하는 것도 불가능하다.
키/값 저장소는 변경 가능한 저장소에 사용하도록 만들어져서, 마스터 데이터 집합에 불변성을 강제하는 게 극히 필요한 경우라면 문제가 된다.
키/값 저장소에는 불필요한 기능이 많다. 무작위 읽기, 쓰기 그리고 이들을 가능하게 하는 모든 장치들이 이에 해당된다.
데이터 색인을 하며 우리에게는 필요 없는 서비스도 제공해서 저장소 비용이 증가하고 데이터를 읽고 쓰는 성능이 저하될 수 있다.
// Franc Class Franc times(int multiplier){ returnnew Franc(amount * multiplier); } // Dollar Class Dollar times(int multiplier){ returnnew Dollar(amount * multiplier); }
양쪽 모두 Money 를 반환하게 만들면 더 비슷해진다.
1 2 3 4 5 6 7 8 9
// Franc Class Money times(int multiplier){ returnnew Franc(amount * multiplier); } // Dollar Class Money times(int multiplier){ returnnew Dollar(amount * multiplier); }
이제, Money 의 두 하위 클래스는 많은 일을 하지 않으므로 제거하고 싶다. 한번에 이렇게 큰 단계를 밟는 것은 TDD 를 효과적으로 보여주기 적절치 않을 것 같다. 하위 클래스에 대한 직접적인 참조가 적어지면 하위 클래스를 제거하기 쉬울 것 같다.
1 2 3 4 5 6 7
@Test voidtestMultiplication(){ Dollar five = Money.dollar(5); assertEquals(new Dollar(10), five.times(2)); assertEquals(new Dollar(15), five.times(3)); }
구현 코드는 Dollar 를 생성해 반환한다.
1 2 3 4
// Money Class static Dollar dollar(int amount){ returnnew Dollar(amount); }
제목 : 영어에서 시간과 곱하기가 모드 ‘times’ 라는 점에서 착안한 말장난이다. 통화 개념을 어떻게 테스트하길 원하는가 ? 통화를 표현하기 위한 복잡한 객체를 만들 수도 있다. 그리고, 그 객체들이 필요한 만큼만 만들어지도록 하기 위해 flyweight factories 경량 팩토리를 사용할 수 있을 것이다. 하지만, 당분간 대신 문자열을 쓰자.