외부에서 버전을 붙이는 디렉터리가 있다. 이 디렉터리를 특정 컴퓨터 A에서 B로 복사하는 일을 해보자. 버전을 붙인다는 점을 좀 더 이용하면 – 즉, 이전 버전 데이터가 있는 디렉터리가 있다면 – 좀 더 적게 복사하고, 빠르게 복사할 수 있을 거다. 만약 이 데이터가 아주 간략하게 하기엔 좀 큰 수준 – 대충 10GiB에서 30GiB 정도? – 라면 뭔가 최적화하면 좋지 않을까?
대략 다음과 같은 정도로?
- 이전 버전 디렉터리에 똑같은 파일이 있으면 해당 컴퓨터 안에서 복사한다.
- 비슷한 파일이 있으면, rsync 처럼 부분부분 쪼개서 없거나 다른 부분만 복사한다.
- 아예 새 파일이면 새 파일을 복사한다.
실제로 구현을 해보니 문제가 있었다. 그리고 그 원인은 "네트워크 전송이 충분히 빠르다"라는 것. 이제 하나씩 생각해보자.
한 컴퓨터 안에서 복사
이걸 하려면 하드 디스크에서 읽기 1번, 쓰기 1번이 필요하다. 근데 네트워크를 통해 전송하면 A에서 읽기 1번, B에서 쓰기 1번이면 족하다. 그래서 두 머신 모두에서 disk I/O를 최대 속도로 할 수 있고, 이게 SSD나 RAID 안 쓰고서야 대략 100MB/s 정도. 네트워크가 1Gbps라면 대략 이 데이터를 다 실어 나를 수 있다.
하지만 다른 방법도 있다. Windows에도 hard-link ((http://en.wikipedia.org/wiki/Hard_link 참고; Windows API라 한정하면, CreateHardLink( ) 라는 Win32 API가 있다)) 가 있는데, 이걸 써서 여러 문제를 한 큐에 푼다. 디스크 사용량도 안 늘고, 복사 시간은 실로 0이나 다름없고…
rsync 비슷한 방법
버전 별 차이가 정말 크지 않다면 – 내가 테스트한 환경에서는 대략 절반~90%정도가 비슷하더라 – 없거나 다른 부분만 가져오는 게 아마 빠를 거다. 그래서 rsync…랑 비슷한 zsync 에서 사용한 방법을 차용해서 해봤다. 그러니까 해시 계산 / 체크섬 계산을 많이 하는 쪽이 B가 되는 rsync? 근데 90% 가까이 가도 이 방법이 느리더라.
일단 앞에서 말한 이유 – 로컬 복사가 네트워크가 충분히 빠르면 그다지 빠른 방법이 아니란 것 – 와, 이게 정말 CPU-intensive하다는 점. 파일을 1bytes 단위마다 가벼운 체크섬 하나 구하고, 이 체크섬과 맞는 게 있을 때마다 MD5 계산을 하기 때문에 정말 오래 걸린다. 대략 이 방법으로 하면 초당 10 MiB 복사하는 게 힘든 수준이었음.. 그것도 Xeon 코어 4개(=8HT) 다 써서 한 건데. Orz ((동시에 8개 스트림을 처리하게 했음)) 결국 이게 더 빠른 건 네트워크 대역폭이 100 Mbps 이하 수준인 경우에나…
결론:
하드웨어 속도 (기반 네트워크, 저장소 I/O 속도) 가 충분하면, 그냥 단순한 게 짱임.
*nix의 경우는 Hardlink는 한 파티션 내에서만 (동일 stat().st_dev) .. 유효한데, 윈도우즈도 그러하지 않을까 추정합니다. 결국 포스팅 하신 문제는 효율적인 증분 백업이나, 클라이언트 패치 구현의 문제로 귀결 되지 않나 싶네요 :)
클라이언트 패치…는 불가능한 시나리오고(일단 클라이언트(…)에서 하는 것도 아니고), 이전 k개 버전을 언제라도 접근할 수 있어야 합니다.
한 디스크 내에서만 링크 가능한 문제는, 이게 어차피 일반 유저들이 볼게 아니라 sysadmin들만 볼거라, 그다지 문제되지 않을 듯 합니다. (aging 처리도 인간이 할꺼니까요;;; )
아… 결론이 너무 맘에 듭니다 :) 하지만 역시나 네트웍이 느리다면(게임 클라이언트의 패치 같은 경우), 생각하신 방법이 꽤 유용할듯하네요~
전 결론이 너무 슬퍼요(?). 흑 내 시간…
네트워크가 느려도 클라이언트 패치처럼 “미리 알 수 있는 일”은 어차피 델타 인코딩 같은걸로 해서 rsync 비슷한건 안만들어도 되죠. 그래서 만들어 놓고도 망(…)