평범하지 않게 파일 복사하기

외부에서 버전을 붙이는 디렉터리가 있다. 이 디렉터리를 특정 컴퓨터 A에서 B로 복사하는 일을 해보자. 버전을 붙인다는 점을 좀 더 이용하면 – 즉, 이전 버전 데이터가 있는 디렉터리가 있다면 – 좀 더 적게 복사하고, 빠르게 복사할 수 있을 거다. 만약 이 데이터가 아주 간략하게 하기엔 좀 큰 수준 – 대충 10GiB에서 30GiB 정도? – 라면 뭔가 최적화하면 좋지 않을까?

대략 다음과 같은 정도로?

  • 이전 버전 디렉터리에 똑같은 파일이 있으면 해당 컴퓨터 안에서 복사한다.
  • 비슷한 파일이 있으면, rsync 처럼 부분부분 쪼개서 없거나 다른 부분만 복사한다.
  • 아예 새 파일이면 새 파일을 복사한다.

실제로 구현을 해보니 문제가 있었다. 그리고 그 원인은 “네트워크 전송이 충분히 빠르다"라는 것. 이제 하나씩 생각해보자.

한 컴퓨터 안에서 복사

이걸 하려면 하드 디스크에서 읽기 1번, 쓰기 1번이 필요하다. 근데 네트워크를 통해 전송하면 A에서 읽기 1번, B에서 쓰기 1번이면 족하다. 그래서 두 머신 모두에서 disk I/O를 최대 속도로 할 수 있고, 이게 SSD나 RAID 안 쓰고서야 대략 100MB/s 정도. 네트워크가 1Gbps라면 대략 이 데이터를 다 실어 나를 수 있다.

하지만 다른 방법도 있다. Windows에도 hard-link1 가 있는데, 이걸 써서 여러 문제를 한 큐에 푼다. 디스크 사용량도 안 늘고, 복사 시간은 실로 0이나 다름없고…

rsync 비슷한 방법

버전 별 차이가 정말 크지 않다면 – 내가 테스트한 환경에서는 대략 절반~90%정도가 비슷하더라 – 없거나 다른 부분만 가져오는 게 아마 빠를 거다. 그래서 rsync…랑 비슷한 zsync 에서 사용한 방법을 차용해서 해봤다. 그러니까 해시 계산 / 체크섬 계산을 많이 하는 쪽이 B가 되는 rsync? 근데 90% 가까이 가도 이 방법이 느리더라.

일단 앞에서 말한 이유 – 로컬 복사가 네트워크가 충분히 빠르면 그다지 빠른 방법이 아니란 것 – 와, 이게 정말 CPU-intensive하다는 점. 파일을 1bytes 단위마다 가벼운 체크섬 하나 구하고, 이 체크섬과 맞는 게 있을 때마다 MD5 계산을 하기 때문에 정말 오래 걸린다. 대략 이 방법으로 하면 초당 10 MiB 복사하는 게 힘든 수준이었음.. 그것도 Xeon 코어 4개(=8HT) 다 써서 한 건데. Orz ((동시에 8개 스트림을 처리하게 했음)) 결국 이게 더 빠른 건 네트워크 대역폭이 100 Mbps 이하 수준인 경우에나…

결론:

하드웨어 속도 (기반 네트워크, 저장소 I/O 속도) 가 충분하면, 그냥 단순한 게 짱임.


  1. http://en.wikipedia.org/wiki/Hard_link 참고; Windows API라 한정하면, CreateHardLink() 라는 Win32 API가 있다. ↩︎