레거시 소프트웨어 현대화: Erlang 및 CloudI를 사용한 MUD 프로그래밍
게시 됨: 2022-03-11레거시 현대화란 무엇입니까?
레거시 코드는 어디에나 있습니다. 그리고 코드 확산 속도가 계속 기하급수적으로 증가함에 따라 점점 더 많은 코드가 레거시 상태로 강등되고 있습니다. 많은 대규모 조직에서 레거시 시스템의 유지 관리는 정보 시스템 리소스의 90% 이상을 소비합니다.
현재 성능 및 처리 요구 사항을 충족하기 위해 레거시 코드 및 시스템을 현대화해야 할 필요성이 널리 퍼져 있습니다. 이 게시물은 Erlang 프로그래밍 언어와 Erlang 기반 CloudI SOA(서비스 지향 아키텍처)를 사용하여 레거시 코드(특히 수십 년 된 C 소스 코드 모음)를 21세기에 적용하는 사례 연구를 제공합니다. .
소스 코드 드래곤 죽이기
몇 년 전 저는 MUD(Multi-User Dungeons)로 알려진 텍스트 기반 멀티플레이어 온라인 게임의 열렬한 팬이었습니다. 그러나 그들은 항상 성능 문제로 가득 차 있었습니다. 나는 수십 년 된 C 소스 코드 더미로 돌아가 이 레거시 코드를 현대화하고 초기 온라인 게임을 한계까지 밀어붙일 수 있는 방법을 보기로 결정했습니다. 높은 수준에서 이 프로젝트는 Erlang을 사용하여 레거시 소프트웨어를 21세기 요구 사항에 맞게 조정한 훌륭한 예였습니다.
간략한 요약:
- 목표 : 오래된 50명 제한 MUD 비디오 게임을 가지고 소스 코드를 푸시하여 수천 개의 동시 연결을 지원합니다.
- 문제 : 레거시 단일 스레드 C 소스 코드.
- 솔루션 : 내결함성과 확장성을 제공하는 Erlang 기반 서비스 CloudI.
텍스트 기반 MUD란 무엇입니까?
World of Warcraft 및 EverQuest와 같은 모든 MMORPG(대규모 멀티플레이어 온라인 롤플레잉 게임)는 초기 기원이 Multi-User Dungeons(MUD)로 알려진 오래된 텍스트 기반 멀티플레이어 온라인 게임으로 거슬러 올라갈 수 있는 기능을 개발했습니다.
첫 번째 MUD는 Roy Trubshaw의 Essex MUD(또는 MUD1)로 원래 DEC PDP-10에서 MARO-10 어셈블러 언어를 사용하여 1978년에 개발되었지만 C 프로그래밍 언어의 전신인 BCPL로 변환되었습니다. 1987). (보다시피 이러한 것들은 대부분의 프로그래머보다 오래되었습니다.)
MUD는 C로 작성된 다양한 MUD 코드베이스와 함께 1980년대 후반과 1990년대 초반에 점차 인기를 얻었습니다. 예를 들어 DikuMUD 코드베이스는 파생된 MUD 소스 코드의 가장 큰 트리 중 하나로 알려져 있으며, 모두 최소 51개의 고유 변형이 있습니다. 동일한 DikuMUD 소스 코드를 기반으로 합니다. (이 기간 동안 우연히 MUD에 대한 집착으로 학교를 그만둔 대학생의 수가 많아 "다학부 파괴자"로 MUD가 알려지게 되었습니다.)
레거시 MUD의 문제
과거 C MUD 소스 코드(DikuMUD 및 그 변형 포함)는 생성 당시의 기존 제한으로 인해 성능 문제로 가득 차 있습니다.
스레딩 부족
그 당시에는 쉽게 액세스할 수 있는 스레딩 라이브러리가 없었습니다. 게다가 스레딩은 소스 코드를 유지 관리하고 수정하기 더 어렵게 만들었습니다. 결과적으로 이러한 MUD는 모두 단일 스레드였습니다.
단일 "틱"(모든 게임 이벤트의 진행을 추적하는 내부 시계의 증분) 동안 MUD 소스 코드는 연결된 모든 소켓에 대한 모든 게임 이벤트를 처리해야 합니다. 즉, 모든 코드 조각은 단일 틱의 처리 속도를 늦춥니다. 그리고 계산으로 인해 처리가 단일 틱보다 오래 지속되는 경우 MUD가 지연되어 연결된 모든 플레이어에게 영향을 줍니다.
이 지연으로 인해 게임의 몰입도가 즉시 낮아집니다. 플레이어는 자신의 명령이 처리되지 않은 채로 캐릭터가 죽어가는 모습을 무기력하게 바라보고 있습니다.
SillyMUD를 소개합니다
이 레거시 애플리케이션 현대화 실험의 목적을 위해 저는 현대 MMORPG와 이들이 공유하는 성능 문제에 영향을 미친 DikuMUD의 역사적 파생물인 SillyMUD를 선택했습니다. 1990년대에 저는 SillyMUD 코드베이스에서 파생된 MUD를 플레이했기 때문에 소스 코드가 흥미롭고 다소 친숙한 출발점이 될 것이라는 것을 알고 있었습니다.
나는 무엇을 물려받았습니까?
SillyMUD 소스 코드는 동시 플레이어가 약 50명(정확히 말하면 소스 코드 기준으로 64명)으로 제한된다는 점에서 다른 역사적 C MUD의 소스 코드와 유사합니다.
그러나 성능상의 이유로(즉, 동시 플레이어 제한을 푸시하기 위해) 소스 코드가 수정되었음을 알았습니다. 구체적으로 특별히:
- 소스 코드에 연결 IP 주소에 대한 도메인 이름 조회가 누락되었으며 도메인 이름 조회에 의해 강제된 대기 시간으로 인해 존재하지 않습니다(일반적으로 이전 MUD는 악의적인 사용자를 더 쉽게 차단할 수 있도록 도메인 이름 조회를 원합니다).
- 소스 코드는 처리 집약적인 목록 순회가 필요한 기부 항목의 긴 연결 목록 생성 가능성으로 인해 "기부" 명령이 비활성화되었습니다(약간 특이함). 이는 차례로 다른 모든 플레이어의 게임 성능을 저하시킵니다(단일 스레드, 기억하십니까?).
CloudI 소개
CloudI는 제공하는 내결함성과 확장성으로 인해 다중 언어 개발을 위한 솔루션으로 이전에 논의되었습니다.
CloudI는 Erlang, C/C++, Java, Python 및 Ruby에서 서비스 추상화(SOA(Service Oriented-Architecture) 제공)를 제공하는 동시에 CloudI 프레임워크 내에서 소프트웨어 결함을 격리합니다. 내결함성은 Erlang의 내결함성 기능과 Actor 모델의 구현에 의존하는 CloudI의 Erlang 구현을 통해 제공됩니다. 이 내결함성은 모든 소프트웨어에 버그가 포함되어 있기 때문에 CloudI의 Erlang 구현의 핵심 기능입니다.
CloudI는 또한 서비스 실행 수명과 서비스 프로세스 생성을 제어하는 애플리케이션 서버를 제공합니다(비 Erlang 프로그래밍 언어의 경우 운영 체제 프로세스 또는 Erlang에서 구현된 서비스의 경우 Erlang 프로세스). 따라서 서비스 실행이 외부 상태에 영향을 미치지 않고 발생합니다. 신뢰할 수 있음. 자세한 내용은 내 이전 게시물을 참조하십시오.

CloudI는 기존 텍스트 기반 MUD를 어떻게 현대화할 수 있습니까?
과거 C MUD 소스 코드는 안정성 문제를 감안할 때 CloudI 통합에 대한 흥미로운 기회를 제공합니다.
- 게임 서버 안정성은 모든 게임 메커니즘의 매력에 직접적인 영향을 미칩니다.
- 서버 안정성 버그 수정에 소프트웨어 개발에 집중하면 결과 게임의 크기와 범위가 제한됩니다.
CloudI 통합을 통해 서버 안정성 버그는 정상적으로 수정될 수 있지만 이전에 발견되지 않은 버그로 인해 내부 게임 시스템에 장애가 발생했을 때 게임 서버의 작동에 항상 영향을 미치는 것은 아니므로 영향이 제한적입니다. 이것은 레거시 코드베이스에서 내결함성을 강화하기 위해 Erlang을 사용하는 좋은 예를 제공합니다.
어떤 변화가 필요했습니까?
원래 코드베이스는 단일 스레드로 작성되었으며 전역 변수에 크게 의존합니다. 제 목표는 레거시 소스 코드 기능을 보존하면서 현재 사용을 위해 현대화하는 것이었습니다.
CloudI를 사용하여 소켓 연결 확장성을 제공하면서 소스 코드를 단일 스레드로 유지할 수 있었습니다.
필요한 변경 사항을 검토해 보겠습니다.
콘솔 출력
SillyMUD 콘솔 출력(종종 Telnet으로 연결되는 터미널 디스플레이)의 버퍼링은 이미 이루어졌지만 일부 직접 파일 설명자 사용에는 버퍼링이 필요했습니다(콘솔 출력이 CloudI 서비스 요청에 대한 응답이 될 수 있도록).
소켓 처리
원래 소스 코드의 소켓 처리는 입력, 오류 및 출력 가능성을 감지하고 보류 중인 게임 이벤트를 처리하기 전에 250밀리초의 게임 틱 동안 일시 중지하기 위해 select()
함수 호출에 의존했습니다.
CloudI SillyMUD 통합은 C CloudI API의 cloudi_poll
함수로 일시 중지하는 동안 입력에 대한 수신 서비스 요청에 의존합니다(동일한 보류 중인 게임 이벤트를 처리하기 전에 250밀리초 동안). SillyMUD 소스 코드는 C CloudI API와 통합된 후 CloudI 서비스로 CloudI 내에서 쉽게 실행되었습니다.
구독
CloudI 통합은 연결, 연결 해제 및 게임 플레이 이벤트를 처리하기 위해 세 가지 주요 서비스 이름 패턴을 구독합니다. 이러한 이름 패턴은 통합 소스 코드에서 subscribe를 호출하는 C CloudI API에서 가져옵니다. 따라서 WebSocket 연결 또는 Telnet 연결에는 연결이 설정될 때 서비스 요청을 보내기 위한 서비스 이름 대상이 있습니다.
CloudI의 WebSocket 및 Telnet 지원은 내부 cloudi_service_http_cowboy
서비스(WebSocket 지원의 경우 cloudi_service_tcp
및 Telnet 지원의 경우 cloudi_service_tcp)에서 제공합니다. 내부 CloudI 서비스는 Erlang으로 작성되었기 때문에 Erlang의 극도의 확장성을 활용할 수 있음과 동시에 CloudI API 기능을 제공하는 CloudI 서비스 추상화를 사용할 수 있습니다.
앞으로
소켓 처리를 피함으로써 소켓 오류 또는 링크 사망(사용자가 서버에서 연결이 끊긴 경우)과 같은 상황에서 발생하는 처리가 줄어듭니다. 따라서 저수준 소켓 처리를 제거하면 주요 확장성 문제가 해결되었습니다.
그러나 확장성 문제가 남아 있습니다. 예를 들어, MUD는 파일 시스템을 정적 및 동적 게임 플레이 요소(즉, 세계 영역, 개체 및 몬스터와 함께 플레이어 및 진행 상황) 모두에 대한 로컬 데이터베이스로 사용합니다. 대신 데이터베이스용 CloudI 서비스에 의존하도록 MUD의 레거시 코드를 리팩토링하면 추가 내결함성이 제공됩니다. 파일 시스템이 아닌 데이터베이스를 사용한다면 여러 SillyMUD CloudI 서비스 프로세스를 별도의 게임 서버로 동시에 사용할 수 있어 사용자를 런타임 오류로부터 격리하고 다운타임을 줄일 수 있습니다.
MUD가 얼마나 개선되었습니까?
개선의 세 가지 주요 영역이 있었습니다.
- 결함 허용. 현대화된 SillyMUD CloudI 서비스 통합을 통해 SillyMUD 소스 코드에서 소켓 오류 및 대기 시간을 격리하여 어느 정도의 내결함성을 제공합니다.
- 연결 확장성. 내부 CloudI 서비스를 사용하면 SillyMUD 동시 사용자 제한 이 64명(과거)에서 16,384명(지연 문제 없이)으로 쉽게 넘어갈 수 있습니다.
- 효율성과 성능. 단일 스레드 SillyMUD 소스 코드 대신 CloudI 내에서 연결 처리 가 수행되므로 SillyMUD 게임 플레이 소스 코드의 효율성이 자연스럽게 향상되고 더 높은 로드를 처리할 수 있습니다.
따라서 간단한 CloudI 통합을 통해 연결 수가 100배까지 확장되는 동시에 내결함성을 제공하고 동일한 레거시 게임 플레이의 효율성을 높일 수 있습니다.
더 큰 그림
Erlang은 프로덕션 시스템에 99.9999999% 가동 시간(연간 가동 중지 시간이 31.536밀리초 미만)을 제공했습니다. CloudI를 사용하여 다른 프로그래밍 언어 및 시스템에도 이와 동일한 안정성을 제공합니다.
정체된 레거시 게임 서버 소스 코드를 개선하기 위한 이 접근 방식의 실행 가능성을 증명하는 것 외에도(SillyMUD는 1993년에 마지막으로 수정되었습니다!) 이 프로젝트는 Erlang과 CloudI가 레거시 애플리케이션을 현대화하고 오류를 제공하는 데 어떻게 활용될 수 있는지 더 넓은 수준에서 보여줍니다. - 일반적으로 내성, 향상된 성능 및 고가용성. 이러한 결과는 주요 소프트웨어 점검 없이 레거시 코드를 21세기에 적용할 수 있는 유망한 잠재력을 갖고 있습니다.