버그 해결을 위한 모든 질문을 던져
+1 vote
622 views
패치 서버 같은건 어떻게 구축하고 구현하는 건가요?

일단 생각해본거는

 

DB에 버전를 관리하고

최신 파일을 압축파일로 파일 시스템이 올리고

클라이언트에서 최신버전을 받아서 해당 파일을 다운받는다.

 

이건데 뭔가 찝찝한 기분이 자꾸 들어서 어떻게 구현하는게 좋은지 경험이 없어서 잘 모르겠네요.

 

어떻게 하는건지 자료나 링크나 책 등등으로 도움 좀 부탁드립니다.
asked (7 point) , 622 views

2 answers

+2 votes
대략 예를 들면 다음과 같은 과정으로 돌아갑니다.

(참고로, 전체 파일에 대해서 최신 버전 하나만 유지하는 방식입니다.)

[업로드 과정]

일단 파일들의 지문(MD5)를 추출해서 하나의 텍스트 파일로 만듭니다. 예:) MD5.txt

파일 전체를 각자 zip으로 묶고요. 예) game.exe.zip, character/Male.model.zip weapon/AK47.model.zip, ....

위의 파일들을 ftp로 패치서버에 올립니다.

패치서버에 올라간 파일은 http로 아무나 받을 수 있게 세팅을 합니다.

 

[다운로드 과정]

패치서버에서 MD5.txt를 다운로드 받아서 파싱합니다.

로컬에 이미 있는 파일의 MD5와 비교합니다.

로컬에 없는 파일(추가된 파일)이거나, MD5가 다른 파일(수정된 파일)이 있으면, 임시 폴더에 다운로드 받습니다.

임시폴더의 zip 파일을 풀어서 게임이 설치된 폴더로 복사합니다.

zip 파일은 지웁니다.

MD5 목록을 다시 비교해 보고 문제가 없으면 게임을 실행합니다.

 

[개선 방향]

로컬의 MD5을 모두 추출하는 것은 느리므로, 로컬 파일에서 추출한 MD5는 파일로 저장해서 다음 실행시 재활용할 수 있게 합니다. (예: Local_MD5.txt)

로컬에 있는 파일이 깨진 경우에 대비해서 로컬에 있는 모든 파일에 대해서 MD5를 다시 검사할 수 있는 기능이 필요합니다.

zip 파일과 MD5를 만들 때, 원본 파일이 너무 큰 경우 분할해야 될 수 있음.

알고리즘을 업그레이드해서 파일 갯수나 디렉토리 구조와 무관하게 패치 묶음 파일을 만들 수도 있음. (스팀 방식 참조)

런처 자체를 갱신해 주는 툴이 하나 더 필요할 수 있음.

zip 대신 다른 포맷(예 : 7z)등이 더 효율적일 수 있음.

업로드 시간이 오래 걸리는 경우를 대비해서 업로드 중에서 임시 폴더에 올리고,

업로드가 끝나면 폴더 이름만 바꾸는 방식을 써야함. CDN에서 이런 툴을 제공해 주는 경우도 있음.

업로드를 할 때에도 패치서버의 MD5와 새 버전의 MD5를 비교해서 필요한 파일만 올리는 방식의 툴을 개발할 수도 있습니다.

기타 등등..
 

[변경된 내역만 패치로 올리는 방식]

위의 내용은 최신 풀 버전 하나만 유지하는 방식으로 설명드린 거고요.

버전이 바뀔 때 마다 패치를 올리는 방식도 있습니다.

1.0 이 처음에 나갔다면 그 다음 패치는 1.01, 1.02, 1.03, 1.04, 1.05 이렇게 패치를 만들어서 올리는 거죠.

런처에서는 현재 로컬의 버전이 뭔지 저장해 놓고 있다가 업데이트를 받을 때 패치 서버의 최신 버전과 비교해 보고 그 중간에 나왔던 패치 파일을 다 내려 받아서 차례대로 덮어 씌우는 방식입니다.

예를 들어 유저의 로컬 버전이 1.03이고 최신이 1.05라면, 1.04를 먼저 받고, 1.05를 받는 거죠.

그런데 이 방식은 처음에는 직관적으로 보이지만, 문제가 좀 있습니다.

예를 들어 매번 패치때 마다 실행 파일이 바뀌었고 또 그게 용량이 큰 경우라면,

1.0을 갖고 있는 유저는 1.05를 받기 위해서 필요도 없는 1.01~ 1.04 까지의 실행파일을 다 받아야 합니다.

예전의 블리자드 런처가 이런식으로 작동한 적이 있었죠.

패치 하나 받고, 런처가 재시작하고, 패치하나 받아서 풀고 또 재시작하고, ...

그래서 이걸 개선하기 위해 패치가 많이 쌓이면 여러 패치를 다 합쳐 놓은 누적 패치를 추가로 올려놓는 방식도 있습니다.

예를 들어 1.0->1.05 까지 패치를 누적해서 하나의 묶음 파일로 올려 두는 거죠.

여기서 부터 뭔가 좀 복잡해집니다.

또, 로컬에 있는 파일 중 일부가 손상이 되어서 복원을 해야 되는 경우라면 문제는 더 복잡해집니다.

앞서 얘기한 최신 버전의 전체 파일이 패치서버에 다 올라가 있지 않으면, 어떤 버전부터 패치로 받아야 할 지가 막막해질 수 있습니다.

 

[하이브리드]

변경내역 패치만 받는 시스템과 처음에 얘기한 전체 버전을 다 올려 놓는 방식과 섞어서 운영하는 방식입니다.

버전 차이가 심하거나 문제가 있는 파일이 있으면, 처음에 얘기한 것처럼 전체 검사를 통해서 필요한 파일을 받는 방식입니다.

변경내역 패치 파일을 받는 방식은 버전 차이가 심하지 않는 경우에만 쓰고요.

여기서 조금 아이디어를 발전 시키면, 최초 버전에서 패치를 쌓아서 누적시키는 것보다는

바로 이전 버전에서 최신 버전으로 넘어오는 패치 파일 하나만 유지하거나,

최신 버전 기준으로 이전 몇개의 버전에 한해서만 최신 버전으로 바로 패치할 수 있는 시스템을 생각해 볼 수 있습니다.

예를 들어, 최신이 1.05라면, 패치 파일은 1.02->1.05, 1.03->1.05, 1.04->1.05, 이렇게 3개만 유지하는 거죠.

그런데, 이 방식의 문제는 최신 버전이 나올 때마다 저런 누적 패치를 매번 다시 만들어야 한다는 겁니다.

예를 들어 1.06이 나오면 앞서 올린 모든 누적 패치는 쓸모가 없어지고, 1.03->1.06, 1.04->1.06, 1.05->1.06 이렇게 완전히 새로운 조합의 패치가 필요하게 됩니다. 또, 이 누적 패치를 만들기 위해서는 이전 버전과 최신 버전을 비교해야 되기 때문에 이전 버전의 파일 전체 혹은 이전 버전 파일들의 MD5 목록이 필요하게 됩니다.

 

[결론]

맨 처음 제안한 방식대로 하면 일이 제일 간단하고 깔끔합니다.

버전별 차이로 패치를 만드는 방식은 신경 써야할 게 많습니다.
answered (458 point)
수정됨
클라이언트 버전 별로 다운 로드 에셋이 달라 져야 되는 경우도 있어서 md5.txt를 관리하는는 patch.txt 가 필요할수 있습니다.

 

0.84 - > 0.84/md5.txt

0.84 - > 0.84_2/md5.txt

0.85 - > 0.85/md5.txt

0.85 - > 0.86/md5.txt

0.86 - > 0.86/md5.txt

이경우 업로드 순서는 patch file -> md5 - > patch.txt 입니다.
0 votes
좋은 답변이 이미 달려있지만 추가로 저희 쪽에서 사용중인 방식도 한번 설명을 드려볼까 합니다.

우선 제시해 주신 풀 스냅샷을 매번 올리는 방식은 DB 용량면에서도 그렇고 패치용량면에서도 별로 좋지 않습니다.
더군다나 잦은 패치 사이클을 가진 게임이라면 그 부하가 극대화 됩니다.

제 경우는 스팀을 이용한 클라이언트 패치와 저희쪽에서 운영하는 AWS 가상머신에 올라가는 온라인 서버가 있는데요.
이 중에서 서버 패치에 이용하는 방식을 적어보겠습니다. 서버패치라는게 정확히는 각 서버 머신들이 받는 패치가 아니고 저희쪽의 패치 데이터를 서버들의 동기화용 데이터 센터에 올리는 과정인데 어차피 과정 자체는 유사하기 때문에 충분히 도움이 되실거라고 봅니다.

방식 자체는 패치대상이 되는 모든 파일들의 md5 hash를 이용한다는 점에서 위 답변과 매우 유사한데요.
대신 저희는 과거 버전에 대한 정보를 유지하지 않고 항시적으로 최종 상태로 업데이트 되게끔 유지하는 방식을 이용하고 있습니다.

즉 패치 서버의 풀 파일 리스트 해쉬를 다운받아서 클라가 보유한 파일 해시 정보와 비교하여 직접 어느 파일들을 받아야 하는지 알아낸 후에 해당 파일들을 내려받는 방식입니다. 물론 경우에 따라서는 클라쪽의 해시를 새로 빌드하는 과정이 필요할 겁니다. 저희는 서버 패치용으로 사용중이라 굳이 패치툴에서 이런 부분의 인터페이스는 고려하지 않고 있는데 엔드 유저용이라면 제대로 고려해 주어야겠죠.

이 방법이 우월하다거나 한건 아닌거 같고 개발할 당시에 이렇게 하는게 이런저런 귀찮은 문제들을 쉽게 피할 수 있는 방법이라고 생각했었습니다.

지금 방식의 단점이 있다면.... 아마 처음에 언급한 것처럼 버전 관리가 되지 않는다는 점이겠지요. 어떤 이유가 될 수 있을지는 모르겠지만 유저가 이전 버전의 클라이언트를 받아야 할 필요가 있다거나 하면 지금의 패치 방식으로는 제공이 불가능합니다. 최신 데이터 이외에는 모두 버려지는 방식이니까요. 해결하려면 결국 패치 서버에다 버전별 데이터를 마련해야겠지요.
answered (245 point)

버그 해결을 위해 도움을 구하고, 도움을 주세요. 우리는 그렇게 발전합니다.

throw bug 는 프로그래밍에 대한 전분야를 다룹니다. 질문,논의거리,팁,정보공유 모든 것이 가능합니다. 프로그래밍과 관련이 없는 내용은 환영받지 못합니다.

221 질문
346 answers
356 댓글
375 users