프로그래밍 일반 2017. 11. 15. 15:41

무 정지 서버 업데이트

2017년에 작성을 시작하여 바쁘다는 핑계로 마무리가 되지 않은 글을 마무리하지 못했는데 그래도 내용이 재미있기 때문에 3년이 흐른 지금 공개로 설정합니다.

참고로 요즘은 많은 서비스가 서버를 멈추지 않고 버전 업데이트를 진행합니다.



서비스를 정지하지 않고 서버 점검을 할 수 있어야하는 이유가 무엇일까?


고민할 필요 없다. 새벽에 출근하지 않기 위함이며 빨리 집에가기 위함이다. 개발자들에게 그것보다 중요한 이유가 필요한가?


세션형 온라인 게임에서 무 정지 서버 업데이트를 처리하기 위한 대략적인 개요는 대략 이러하다.


  • 서비스 이용 시 서버 어플리케이션이 변경되는 것을 유저가 느낄 수 없도록 해야 한다.
  • 패치 시 프로그래머 이외에 실제 작업자가 직접 패치 및 배포 작업을 할 수 있어야 한다. 즉 작업이 쉬워야 한다.
  • 작업이 쉽도록 하기 위해서는 빌드 및 배포 아키텍처가 제어 인터페이스 뒤에서 드러나지 않아야 한다.
  • 히스토리를 한눈에 알 수 있어야 한다.

위의 조건들을 만족하기 위해 빌드 자동화 및 배포 기능을 만족하는 툴 프로그램 제작 후 젠킨스를 이용해 해당 툴을 실행 시킨다.


젠킨스의 장점은 아래와 같은 빌드 설정들을 파라미터로 툴에 전달이 가능하며 빌드 전후 이벤트를 셋팅할 수 있고 사용이 쉽다.


빌드 파라미터 구성 예시빌드 파라미터 구성 예시




시스템 아키텍처시스템 아키텍처


위의 그림은 일반적인 세션형 서버 아키텍쳐이다. 최소한 본인이 경험한 다섯번의 프로젝트는 위와 크게 다르지 않으며 MMORPG 같은 경우만 게임 서버간의 관계 구조가 조금 다를 뿐... 단순화 시키면 위와 비슷하다. AWS 사용은 무 점검을 위한 필요 조건은 아니다. 


그러면 서버 패치 시 서비스를 중지 시키는 이유는 무엇일까?


1. 소스 코드에 버그가 있어 어쩔 수 없이 새로운 빌드의 서버 프로그램을 시작해야 하는 경우

2. 서버 프로그램이 데이터 로드나 환경 셋팅을 프로그램이 시작되면서 초기화될 때만 처리할 수 있는 구조인 경우

3. DB 테이블 변경을 적용하기 위해 서버 프로그램이 갱신되어야 하는 경우

4. 유저 접근을 차단하고 DB 작업이 필요한 경우



무 정지를 위해 기본적으로 크게 다섯 가지 정도 고려할 사항이 있다.


1. 최신 버전의 서버 어플리케이션에서 다양한 하위 버전의 클라이언트 수용이 가능해야한다.

 - 구버전 서버가 구동 중인 상태에서 신버전 서버 프로세스가 시작되면 높은 버전의 서버로 유저 진입이 가능해야 한다.

 - 유저가 모두 빠진 구버전 서버 프로세스는 자동으로 종료될 필요가 있다.

 - 버전별 매칭이 가능해야 한다.


2. 데이터 및 DB 패치

 - 데이터 변경 및 DB 변경에 대한 규칙 설정은 초반에 결정해야한다. 자동화하기 위해서는 규칙이 있어야 한다.

 - 데이터 로드용 구조체 생성은 자동화될 필요가 있다. 관리 대상이 늘어나면 사람은 실수 한다.

 - 서버 프로그램은 재시작하지 않고 변경된 데이터를 로드할 수 있어야 한다.

 - DB 스크립트를 이용한 패치도 자동화되어 있어야 한다.

 - DB 패치 후 구버전 서버도 문제 없이 구동이 가능해야 한다.


3. 서버 빌드 및 배포 방법

 - 반드시 자동화를 초반에 고려해야 한다. 나중으로 미루고 구현하는 경우는 거의 본적이 없다.

 - 히스토리 추적이 쉽고 간단해야 한다.

 - 파트 구분 없이 작업자가 직접할 수 있어야 한다. 패치는 프로그래머만 해야 하는 그런 거 없다. 모두가 하면 다 같이 편해진다.

 - 위의 항목이 가능하기 위해서는 프로세스에 점증 시스템이 반드시 필요하다.

   수많은 데이터를 관리하는 담당자에게 반복되는 패치 오류를 지적하는 것도 무책임하다. 최소한 데이터 타입, 논리적 모순, 링크 검증 등 

   빌드 단계에서 자동으로 확인해 줄 시스템은 프로그래머가 구축해야 한다. 필터링 되지 않은 문제들을 검증 시스템에 추가해나가면 데이터 

   패치 오류 문제는 정말로 많이 감소한다.


4. 서버 기능과 코드 관리

 - 큰 작업 단위로 조건부 컴파일을 이용하고 안정화되면 반드시 정리한다.

 - 기능 변경이나 서버 설정이 바뀐다고 빌드를 다시 하는 경우가 없어야 한다. 데이터 및 DB 변경으로 컨트롤할 수 있게 설계하자.

   하드코딩 좀 하지마.


5. 서버 스케일 정보

 - 서버 운용 정보 주기적 갱신 후 해당 정보를 이용하여 클라 접속을 제어한다.

 - AWS를 이용한다면 아키텍처 구상 단계에서 GameLift를 고려해본다.



그러면 최신 버전의 서버 어플리케이션에서 다양한 하위 버전을 수용하기 위해 고려할 사항으로는 무엇이 있을까? 일반적으로 데이터 드리븐방식으로 프로그램을 구현하기 때문에 데이터값이 변경되는 것은 문제가 없지만, 데이터 타입 변경이나 컬럼이 추가되는 등의 경우는 호환성 유지에 걸림돌이 될 수 있다.


[구버전 소스 코드]


    enum Color

    {

        Red,

        Yellow,

        Max

    }


    class TableHeaderFlower

    {

        string name;

        Color color;

        int count;

    }



[구버전 데이터]


 

string 

Color 

int 

 1

 Rose

Red 

10 

 2

 ...

... 

... 



위와 같이 정의된 꽃에 대한 데이터가 다음과 같이 변한다면


[신버전 소스 코드]


    enum Color

    {

        Red,

        Yellow,

        Green,

        Max

    }


    class TableHeaderFlower

    {

        string name;

        Color color;

        int count;

        string languageOfFlowers;

    }


[신버전 데이터]


 

 string

Color 

int 

string 

 1

 Rose

Red 

10 

장미 꽃 말 

 2

 녹색 꽃

Green 

녹색 꽃 말 


열거형 멤버와 데이터 컬럼이 추가되었다.

열거형 멤버만 추가될 수도 있다 여러가지 변경이 복합적으로 발생할 수도 있다.


일반적인 상황이라면 구버전 빌드는 구조가 변경된 데이터를 읽어올 때 Green이라는 열거형 멤버와 꽃말이라는 추가된 컬럼 때문에 정상적인 실행이 되지 않을 가능성이 높다.


...

내용은 앞으로 계속 추가하도록 하겠습니다...

프로그래밍 일반 2017. 11. 7. 17:07

GeoIP 자동 업데이트 빌드 프로세스에 추가하기

GeoIP가 무엇인지 알고 있다는 가정하에 매월 첫 주 목요일에 업데이트되는 해당 테이블을 자동으로 업데이트하는 방법을 알아보자.


운용 중인 프로젝트의 CI를 젠킨스로 구축했다면 서버 빌드 시 아래와 같은 Powershell 스크립트를 추가하면 된다.


참고로 프로젝트에서 GeoIP.dat를 로드해서 룩업 테이블을 만들어 사용하는 경우 .dat 파일을 자동 업데이트하는 방법이다.



#서버를 빌드할 때 자동으로 GeoIP를 업데이트한다.

if ($ENV:JobCommand -eq "ServerBuild")

#매월 첫 주 목요일에 업데이트되는 파일을 다운 받는다.

$webclient = New-Object System.Net.WebClient

$sourceUrl = "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"

$destinationPath = "$ENV:WORKSPACE\Server\Lib\GeoIp2\GeoIP.dat.gz"

$webclient.DownloadFile($sourceUrl, $destinationPath)


#반디집을 이용하여 압축을 푼다.

[string[]]$array = "bx", "-aoa", "$ENV:WORKSPACE\Server\Lib\GeoIp2\GeoIP.dat.gz"

start-process C:\Bandizip\Bandizip.exe $array


#압축이 풀리기 전에 원본 파일이 삭제되는 것을 방지한다.

wait-event -sourceIdentifier "Bandizip" -timeout 10


#반디집 핸들러가 원본 파일을 물고 있는 것을 풀어준다.

$bz = get-process Bandizip

stop-process -inputobject @bz -force


#원본 파일을 삭제한다.

Remove-Item $destinationPath -Recurse


#압축이 풀린 파일을 svn에 적용한다.

svn commit $ENV:WORKSPACE\Server\Lib\GeoIp2\GeoIP.dat --non-interactive --trust-server-cert --username **** --password **** -m "Build server solution from CI server"

}


설명을 첨부하자면 JobCommand 는 빌드 파라미터이고 서버 빌드를 실행했을 때 웹에서 GeoIP.dat.gz 파일을 다운로드 받아 압축을 풀고 svn으로 서밋하는 간단한 내용이다.


gz 파일은 CI 서버에 반디집을 설치하여 반디집 커맨드 명령어로 압축을 푼다.

프로그래밍 일반 2017. 8. 24. 00:30

젠킨스 삽질 정리

'svn'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다.

 

라는 오류 발생 시 command line client tools 설치하면 된다. 설치 시 버전에 유의하자.

 

 

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(983,5): warning MSB3644: ".NETFramework,Version=v4.5" 프레임워크에 대한 참조 어셈블리를 찾을 수 없습니다. 이 문제를 해결하려면 이 프레임워크 버전에 대한 SDK 또는 타기팅 팩을 설치하거나 응용 프로그램의 대상을 SDK 또는 타기팅 팩을 설치한 프레임워크 버전으로 변경하십시오. 어셈블리는 GAC(전역 어셈블리 캐시)에서 확인되며 참조 어셈블리 대신 사용됩니다. 따라서 어셈블리의 대상이 사용자가 의도하는 프레임워크로 올바르게 지정되지 않을 수 있습니다.

 

해당 메시지가 발생하면 CI 서버의 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework 를 확인하자.

 

경로에 필요한 버전의 .netframework가 없을 것이다.

 

필요 버전의 SDK를 설치하자. 개발 환경과 일치 시키면된다.

 

 

svn: E170013: Commit failed (details follow):

svn: E170013: Unable to connect to a repository at URL 'https://xxx.xx.x.xxx/svn/project/trunk/Tool/BatchBuilder_x64'

svn: E230001: Server SSL certificate verification failed: issuer is not trusted

 

commit 명령어 사용 시 위와 같은 오류가 발생한다면 아래와 같이 처리한다.

 

svn commit [PATH..] --non-interactive --trust-server-cert-failures="unknown-ca,cn-mismatch,expired,not-yet-valid,other" --username ARG --password ARG -m "CI server build commit" 

 

ARG는 svn 계정 정보를 입력하면 된다. 세부 항목은 svn help 를 이용하자.