반응형
개요: 서버 백로그 및 레지스터 설정, 작업 큐 관리, 클라이언트 연결 및 패킷 전송 최적화
- 서버 백로그 및 레지스터 설정: 서버의 Listener에서 백로그(서버가 새로운 요청을 거부하기 전에 대기할 수 있는 최대 연결 요청 수)와 레지스터(생성할 소켓의 수)를 설정할 수 있도록 코드를 수정합니다. 이는 동시다발적인 연결 요청이 있더라도 멀티스레드 환경에서 효율적으로 처리할 수 있도록 도와줍니다.
- 작업 큐 관리 방법: 서버에서는 일감을 큐에 차곡차곡 쌓고 순차적으로 실행하는 방식을 사용합니다. 각 작업은 ITask 인터페이스를 구현하는 클래스로 표현되며, 이 클래스는 Execute 메서드를 통해 작업을 실행합니다. 또한, 이 방식은 락을 사용하는 부분을 최소화하여 성능을 개선하는 데 도움이 됩니다.
- 작업 큐가 있어야 할 곳: 정해진 건 아니지만 신리스는 각 사물, 신이 나눠진 경우 맵마다
- 클라이언트 연결 및 패킷 전송 최적화: 클라이언트의 동시 연결 수를 늘리는 경우, 서버의 메모리 사용량이 증가하는 문제가 있을 수 있습니다. 이는 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 |
댓글