반응형

 

 

면접 준비를 하면서 오랜만에 IOCP 관련 하여 리마인드 하다가 

 

지인 팀에서는 요즘 Boost.Asio 를 사용한다고 하여 과연 어떤 차이가 있을까 궁금해서

 

한번 알아보고 작성하게 되었습니다.

 

저 같은 경우는 대학교 때, 교수님이 NC소프트 출신이셔서 그 당시 게임 서버 수업을 들으면서

 

주로 IOCP에 관하여 설명해주시고 별책으로 Boost.Asio를 알려주셨던게 기억이 납니다.

 

(아마 NC소프트는 돈이 많은 회사였기에 Windows 운영 체제를..)

 

두 개의 회사를 거치면서 두 회사 모두 C++ 게임 서버에서는 IOCP를 쓰고 있었습니다.

 

제 경험상으로 미루어 봤을 때는 그냥 C++ 게임 서버 같은 경우는 IOCP를 대부분 사용하나보다 라고 생각했었는데,

 

지인 팀 신규 프로젝트에서는 Boost.Asio를 사용한다기에 궁금해져서 한번 알아봤습니다.

 

공통점인 것보다는 차이점에 중점을 두고 알아봤습니다.

 

공통점인 부분에서는 IOCP와 Boost.Asio 를 구별하여 사용하는데, 큰 비교점이 없었다고 생각했기 때문입니다.


IOCP와 Boost.Asio의 차이점

 

  • 플랫폼 지원:
    • IOCP: Windows 운영 체제 전용
    • Boost.Asio: 플랫폼 독립적, 다양한 운영 체제에서 사용 가능.
  • 사용 편의성:
    • IOCP: 저수준 API로 사용이 복잡하고, 세부 사항을 많이 관리해야 함.
    • Boost.Asio: 고수준의 인터페이스 제공으로 사용하기 쉽고, 코드가 간결.
  • 성능:
    • IOCP: Windows에서 매우 높은 성능을 제공.
    • Boost.Asio: 플랫폼 독립적이지만, Windows에서는 IOCP를 활용할 수 있어 성능이 비슷할 수 있음. 하지만, 기본적으로는 IOCP에 비해 다소 낮은 성능을 보일 수 있음.
  • 기능 범위:
    • IOCP: 주로 네트워킹과 파일 I/O를 위한 고성능 비동기 I/O 처리.
    • Boost.Asio: 네트워킹 외에도 타이머, 신호 처리 등 다양한 비동기 I/O 기능 제공.

주된 차이점이 이렇게 있습니다. 그 중에서 봐야할 부분은 플랫폼 지원 입니다.

 

플랫폼 지원"왜? 그냥 Windows 운영 체제 쓰면 되는 거 아니야?" 라고 이야기할 수도 있습니다.

 

 

그럼요.. Windows 운영 체제를 사용하면 당연히 문제되는 부분은 없습니다.

 

다만, 서버를 올려둘 클라우드 서비스(AWS, Azure...)에서 서버를 빌릴 때, 운영체제 설정이 가능합니다.

 

요즘에는 대부분 클라우드 서비스를 사용하여 서버를 올리는데,

 

한 번 AWS EC2의 Windows 와 Linux 비용을 확인해보겠습니다.

 

(운영체제 내에서도 어떤 거냐에 따라 다르기 때문에 기본적인 Windows와 Linux 로 체크하겠습니다.)

 

 

얼핏 가격을 보셨을 때, Windows 운영체제가 Linux 운영체제보다 2배 가량 비싼걸 알 수 있습니다.

 

만약, 회사가 게임 출시를 했을 때, 무조건 대박난다 라는 보장이 있다면 Windows 운영 체제를 사용해도 부담이 없을겁니다.

 

하지만, 실패했을 경우에는 서버 비용으로 나가는 돈이 Linux에 비해 2배! 

 

어떻게 보면 현 시장에서 게임에 대한 성공 확률이 옛날에 비해 많이 낮아졌기에 리스크 감소를 위해 Boost.Asio를 사용하는 것도 좋은 방법이라고 생각합니다.

 

사용 편의성성능에 대해서는 묶어서 이야기 드리겠습니다. 

 

제가 Boost.Asio를 써본건 대학생 때, 잠깐 어떻게 쓰는지 봐온게 다이기 때문에

 

사용 편의성이 어떠하다더라 라고 함부로 판단 할 수는 없을 것 같고..

 

성능적인 면에서 IOCP 서버와 Boost.Asio를 같은 환경에서 만들어 비교해보지 않아 함부로 판단하기가 그렇습니다.

그런데, 성능적인 면에서 왜 Boost.Asio가 IOCP에 비해 Windows 운영 체제에서 성능이 떨어질 수 있는지에 궁금해서 찾아봤습니다. 


1. 추상화 오버헤드

Boost.Asio는 다양한 플랫폼에서 작동하도록 설계된 라이브러리입니다. 이로 인해 각 플랫폼의 세부사항을 추상화하여 통합된 API를 제공합니다. 이러한 추상화는 코드의 이식성과 사용의 편의성을 높이는 대신, 성능 오버헤드를 초래할 수 있습니다.

추가 계층: Boost.Asio는 IOCP를 감싸는 추가 계층을 포함하고 있어, 직접 IOCP를 사용하는 경우에 비해 약간의 성능 저하가 발생할 수 있습니다.

 

2. 핸들러 관리

Boost.Asio는 핸들러 스트랜드와 같은 동기화 메커니즘을 제공하여 안전한 동시성 처리를 돕습니다. 이러한 메커니즘은 성능을 어느 정도 저하시킬 수 있습니다.

핸들러 스트랜드: 핸들러 스트랜드는 동기화 문제를 쉽게 해결하지만, 추가적인 관리 비용이 발생합니다. 이로 인해 직접 IOCP를 사용하는 것보다 핸들러 호출이 더 느려질 수 있습니다.

 

3. 추가적인 기능성

Boost.Asio는 단순히 비동기 I/O만 제공하지 않고, 타이머, 스트랜드, 시그널 처리 등 다양한 기능을 포함하고 있습니다. 이러한 기능을 제공하기 위해 내부적으로 더 많은 처리가 필요하며, 이는 성능에 영향을 미칠 수 있습니다.

다양한 기능 지원: 다양한 기능을 통합하여 제공하기 위해 Boost.Asio는 내부적으로 더 복잡한 구조를 가지며, 이로 인해 성능이 저하될 수 있습니다.

 

4. 에러 처리와 디버깅 기능

Boost.Asio는 높은 수준의 에러 처리 및 디버깅 기능을 제공합니다. 이러한 기능은 개발자가 코드를 더 쉽게 작성하고 유지보수할 수 있게 도와주지만, 성능에 약간의 영향을 미칠 수 있습니다.

에러 처리 오버헤드: 고급 에러 처리와 디버깅 기능을 제공하기 위해 추가적인 체크와 로직이 포함되며, 이로 인해 성능 저하가 발생할 수 있습니다.


위의 이유들로 성능들이 떨어질 수 있다고 하는데, 떨어질 수는 있겠지만 그렇다고 2배 이상 차이가 날까 라는 의문이 들었습니다.

 

Windows와 Linux 운영체제 서버 비용의 차이가 2배이기 때문에 이것을 기준으로 잡았을 때, 2배 가까운 성능 차이가 나지 않으면

 

Boost.Asio도 괜찮겠다 라고 생각이 들었습니다.

 

아마 여기서 개인적으로 어디선가 들어본 것 같은 `핸들러 스트랜드` 라는 부분이 눈에 띄었는데요.

 

IOCP 서버에서는 동기화 문제를 위해 Lock으로 관리를 하고 해결하는 반면,

 

Boost.Asio의 경우는 핸들러 스트랜드 라는 부분으로 별도의 락을 사용하지 않고 동시성 작업을 처리할 수 있습니다.

 

그러면 핸들러 스트랜드의 장점은 무엇이냐?! 라고 할 수 있습니다.

 

핸들러 스트랜드 장점은 동기화 비용 절감이 됩니다. 락을 사용할 때마다 동기화 비용이 발생하게 되는데, 이러한 부분이 없어지니 당연하게도 안전한 동시성 처리가 가능하면서 동기화 비용을 줄일 수 있습니다.

#include <boost/asio.hpp>
#include <iostream>
#include <thread>

void print(boost::asio::strand<boost::asio::io_context::executor_type>& strand, int i) {
    strand.post([i]() {
        std::cout << "Handler " << i << " executed in thread " 
                  << std::this_thread::get_id() << std::endl;
    });
}

int main() {
    boost::asio::io_context io_context;
    boost::asio::strand<boost::asio::io_context::executor_type> strand(io_context.get_executor());

    std::thread t1([&io_context](){ io_context.run(); });
    std::thread t2([&io_context](){ io_context.run(); });

    for (int i = 0; i < 10; ++i) {
        print(strand, i);
    }

    io_context.stop();
    t1.join();
    t2.join();

    return 0;
}

이런 식으로 `strand` 를 사용하여 핸들러를 순차적으로 실행되도록 보장합니다.

 

그러면 우리는 "도대체 C++ 게임 서버를 만들 때, IOCP를 써야한다는거야 Boost.Asio를 써라는거야?" 라고 물어보실 수도 있습니다.

 

그거에 답은 팀 프로젝트 내에서 알아서 선택하는걸로 ^_^

 

성능 상 큰차이가 없지만, 비용적인 측면에서 리스크 감소가 필요하다면 Linux 운영체제가 가능한 Boost.Asio를 쓰는거고

 

굳이 그렇게 리스크 감소할 필요가 있을까? 라는 생각이 들면 IOCP를 쓰면 됩니다.

 

어차피 선택의 몫은 주로 장급 분들께서 정하시기에 아직 주니어급인 제 입장에선 제 선택이 없습니다..

제가 선택권이 있다면 회사에 돈이 많으면 그냥 아무거나 쓸 것 같고 

 

돈이 없는 팀이면.. Boost.Asio를 고려해볼 것 같습니다.

 

물론 대다수의 라이브들은 IOCP를 사용하고 있지 않을까 라는 생각이 들긴합니다만, 신규 프로젝트라면 선택지가 생긴게 아닐까 싶습니다.

반응형

+ Recent posts