Server programming

04_05_Job Queue_JobQuene#2

devRiripong 2023. 5. 16.
반응형

개요: 서버 백로그 및 레지스터 설정, 작업 큐 관리, 클라이언트 연결 및 패킷 전송 최적화

  1. 서버 백로그 및 레지스터 설정: 서버의 Listener에서 백로그(서버가 새로운 요청을 거부하기 전에 대기할 수 있는 최대 연결 요청 수)와 레지스터(생성할 소켓의 수)를 설정할 수 있도록 코드를 수정합니다. 이는 동시다발적인 연결 요청이 있더라도 멀티스레드 환경에서 효율적으로 처리할 수 있도록 도와줍니다.
  2. 작업 큐 관리 방법: 서버에서는 일감을 큐에 차곡차곡 쌓고 순차적으로 실행하는 방식을 사용합니다. 각 작업은 ITask 인터페이스를 구현하는 클래스로 표현되며, 이 클래스는 Execute 메서드를 통해 작업을 실행합니다. 또한, 이 방식은 락을 사용하는 부분을 최소화하여 성능을 개선하는 데 도움이 됩니다.
  3. 작업 큐가 있어야 할 곳: 정해진 건 아니지만 신리스는 각 사물, 신이 나눠진 경우 맵마다
  4. 클라이언트 연결 및 패킷 전송 최적화: 클라이언트의 동시 연결 수를 늘리는 경우, 서버의 메모리 사용량이 증가하는 문제가 있을 수 있습니다. 이는 ThreadPool의 작업이 밀리면서 발생하는 현상일 수 있습니다. 이를 해결하기 위해 Broadcast 메서드에서 발생하는 부하를 줄이는 방안을 고려해볼 수 있습니다. 예를 들어, 패킷을 뭉쳐서 보내는 방식을 사용하면 N^2의 부하를 N까지 줄일 수 있습니다. 이는 서버의 엔진 레벨이나 컨텐츠 레벨에서 구현될 수 있습니다.

1. backlog와 register 갯수 설정할 수 있게 하기

ServerCore의 Listener에서 backlog(서버가 새로운 요청을 거부하기 전에 대기할 수 있는 최대 연결 요청 수)를 늘려줄 수 있게 Listener의 Init에 인자를 넣어 줄 수 있게 한다.

 public void Init(IPEndPoint endPoint, Func<Session> sessionFactory, int register = 10, int backlog = 100)
{
    // 문지기(가 들고있는 휴대폰)
    _listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // TCP로 할 때 설정
    _sessionFactory += sessionFactory;

    // 문지기 교육
    _listenSocket.Bind(endPoint); // 식당 주소와 후문인지 정문인지 기입을 해준 것

    // 영업 시작
    // backlog : 최대 대기수  
    _listenSocket.Listen(backlog);

    for(int i=0; i<register; i++)
    {
        SocketAsyncEventArgs args = new SocketAsyncEventArgs();
        args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
        RegistterAccept(args);
    }
}

int register와 int backlog를 추가하고, Listen에 backlog의 수를 전달하고, 생성할 socket의 갯수를 설정할 수 있게 되었다.

 

문지기가 10명이 된 셈. 그러니까 조금 동시다발적으로 연결 요청이 밀린다고 하더라도 멀티 쓰레드 환경에서 얘를 잘 분배해가지고 처리를 해 줄 거라는 기대를 할 수 있다.

 

 

2. JobQueue 수동 버전 

namespace Server
{
    interface ITask
    {
        void Execute();
    }

    class BroadcastTask : ITask
    {
        GameRoom _room; 
        ClientSession _session;
        string _chat; 

        BroadcastTask(GameRoom room, ClientSession session, string chat)
        {
            _room = room; 
            _session = session;
            _chat = chat; 
        }

        public void Execute()
        {
            _room.Broadcast(_session, _chat); 
        }
    }

		class TaskQueue
    {
        Queue<ITask> _queue = new Queue<ITask>(); 
    }
}

3. 누가 Job혹은 Task에 대한 큐를 들고 있어야 할까?

신리스의 경우는 모든 사물

맵이 나눠져 있는 경우는 나눠진 맵의 영역마다

 

4.클라이언트 연결 및 패킷 전송 최적화

패킷 모아 보내기가 들어가야 한다.

ServerCore의 Session에 이미 _sendQueue에 sendBuff를 넣어주는 코드가 있는데

public void Send(ArraySegment<byte> sendBuff)   
{
    lock (_lock)
    {
        _sendQueue.Enqueue(sendBuff);
        if (_pendingList.Count == 0)
            RegisterSend();
    }           
}

0.1초 마다 send를 하는 식으로 쌓아뒀다 Send를 한다면 N^2이 라니라 N까지 줄일 수 다.

 

패킷 모아  보내기를 엔진단에서 할지 컨텐츠 단에서 할지 다음 시간에 이어서 해본다.

반응형

'Server programming' 카테고리의 다른 글

04_07_Job Queue_JobTimer  (0) 2023.05.17
04_06_Job Queue_패킷 모아 보내기  (0) 2023.05.16
04_04_JobQueue_JobQuene#1  (0) 2023.05.07
04_03_Job Queue_Command 패턴  (0) 2023.05.05
04_02_Job Queue_채팅 테스트 #2_클라  (0) 2023.05.05

댓글