Job Queue
지난 시간에는 채팅 테스트를 위한 GameRoom을 만들고, 입장, 나가기, 전송하기 등의 기능을 구현해주었다. 또한 SessionManager를 새롭게 만들어, 이를 통해 세션을 생성해주고 관리해주도록 하였다.
⛈️ Client Session
현재 클라이언트에서는 한 명의 유저만 접속하고 있는 상황이므로, 이를 다수의 유저들이 접속하는 상황으로 가정하고 변경할 것이다.
🐦⬛ Server Session
서버쪽과 동일하게 클라이언트 세션에도 Manager를 만들어주어 직접적으로 세션을 생성하는 것이 아닌 Manager를 통해 제작하고 넘겨주는 방식을 통해 작동하도록 하자.
변경 전, 후
🐦⬛ SessionManager 제작
서버에서 작업했던 것과 동일한 방식으로, 싱글톤 형식을 이용해 매니저를 만들어준다. 이 후 Generate() 메서드를 통해 session을 list로 관리한다.
🐦⬛ Connector 변경
Connector 영역에서도 Count를 매개 변수로 추가하여 count의 숫자만큼, 다수의 Session이 연결될 수 있는 환경으로 구성해준다.
🐦⬛ 원하는 클라이언트 갯수 설정
이제 다시 Program으로 돌아와서 원하는 유저의 수 만큼 숫자를 넣어준다면, 해당 숫자만큼의 클라이언트들이 생성된다.
🐦⬛ DummyClient - ServerSesion 정리
그동안 코드 정리가 안되어있던 아래 부분을 정리해준다. PacketSession을 상속 받도록 수정하고, OnRecvPacket 또한 void 형식으로 재 수정하여준다.
🐦⬛ 패킷 전송
다시 SessionManager로 돌아와, SendForEach 메서드를 통해서 다른 Session들에게 패킷을 전송하여준다.
🐦⬛ PacketHandler 설정
패킷 별로 별도의 처리를 위해 만들어둔 PacketHandler를 아래와 같이 수정하여 준다.
🥿 Server 수정
다시 서버쪽으로 돌아가, 기존에 Server의 Main 영역이 시작할 때 처리했던 Register 부분을 생성자를 통해 자동으로 생성하도록 변경하여 줄 것이다.
변경 전, 후
🪣 PacketFormat 내용 수정
PacketManager를 변경해주었기 때문에 PacketFormat 스크립트에서 managerFormat을 수정해주어야 한다. 아래와 같이 수정한 후, GenPackets.bat 파일을 다시 실행한다.
이제 GameRoom 쪽에서 받아온 Chat 내용이 어떠한 Session의 것인지를 확인하기 위해 아래와 같이 로그를 작성해주고 실행 결과를 확인해본다.
packet.chat = $"{chat} I am {packet.playerId}";
🪣 실행 결과
로직을 실행해보면 한번에 10번씩 출력을 하고 있는 것을 볼 수 있다. 작성한 코드가 foreach문을 돌며, GameRoom 안에 있는 10명에 유저들에게 뿌려주고 있는 것을 볼 수 있다.
그러나 이러한 방식을 MMORPG에 도입하면 굉장히 느려질 수 있다. 왜냐하면 유저의 수가 증가할 수록, 패킷을 뿌리는 양이 많아질 것이기 때문이다.
🤬 부하 테스트
서버에 접속하는 클라이언트의 수를 10이 아닌 100으로 늘려서, BroadCast를 진행하는 부분에 디버깅을 잡아보자. 이 후, 스레드를 확인해보면 엄청나게 많은 스레드들이 생성된 것을 볼 수 있다.
이 스레드들은 모두 lock으로 인해 대기하고 있는 것을 볼 수 있다. 그럴 수 밖에 없는 것이 Thread.Sleep(250)을 통해, 0.25초에 한 번씩 동작하게 해놓았는데, 100명의 유저가 있다고 가정한다면 100 * 100, 즉 10.000번 동작하고 있는 상황이다. 이는 즉 1초에 40,000이 동작하고 있기 때문에 무리가 될 수 밖에 없는 상황이 되는 것이다.
이와 같이 작업이 엄청 많아 밀리게 되면 쓰레드를 관리하는 입장에서는 쓰레드를 보냈으나, 일 처리가 되지 않으니 쓰레드를 다시 보내고 있는 상황이 되는 것이다. 따라서 쓰레드가 계속해서 쌓이고 있는 것이다.
결국 문제점은 Recv를 하자마자, lock을 통해 패킷을 보내는 점이 문제가 되는 것이다. 이를 해결하기 위해서 다른 쓰레드들의 일감은 Queue에 담아두고, 하나의 쓰레드만 Queue에 쌓여있는 일감을 처리하는 것이다. 이를 Job, 혹은 Task라고 하기도 한다. 중요한 것은 패킷을 저장하고, 하나의 쓰레드에서 처리하는 것이다.
'공부 > 인프런 - Rookiss' 카테고리의 다른 글
Part 4-5-4. Job Queue : Job Queue #1 (0) | 2023.12.27 |
---|---|
Part 4-5-3. Job Queue : Command 패턴 (0) | 2023.12.26 |
Part 4-5-1. Job Queue : 채팅 테스트 #1 (1) | 2023.12.23 |
Part 4-4-11. 패킷 직렬화 : Packet Generator #6 (0) | 2023.12.22 |
Part 4-4-10. 패킷 직렬화 : Packet Generator #5 (0) | 2023.12.22 |