알게 된 것

[알게 된 것] 서버 <-> 클라 연결 유지 시 서버 부담에 대해

빗방울소리 2025. 4. 5. 22:59

 

 

서버와 클라의 연결 유지

 클라의 연결을 Accept하고 세션 상태를 관리하는 Stateful 방식의 서버의 경우 클라와의 연결이 완료되면 연결이 끊어질 때까지 연결이 유지된다.

 

 grpc에 대해 학습하며 클라와 연결을 유지하면서 자동으로 heartbeat를 체크하는 grpc를 보며 궁금한점이 생겼다.

 

클라가 아무런 패킷을 보내지 않고 연결만 유지하는 것만으로 서버에 큰 부담이 될까?

 

 

✅ 결론부터 말하면

❌ 부담 거의 없음.
👉 이유는 둘 다 비동기 I/O 기반 구조이기 때문에,
패킷이 오지 않는 한 스레드나 CPU를 점유하지 않기 때문

 

 

📦 실제 서버 자원 소비 요약

CPU 🟢 매우 낮음 (거의 Idle)
Thread 수 🟡 수십~수백 개로 제한 (요청 처리 Task 수에 비례)
Memory 🟡 연결 수에 비례 (약간 증가), 각 연결당 소량의 상태 정보

 

 결론적으로 연결상태만 유지하는 것은 큰 부담이 되지 않는다. 클라가 보낸 패킷을 처리하는 로직이 얼마나 비용이 큰지에 따라 서버 성능을 논하기도 하고 연결 상태 유지 자체는 큰 부담이 되지 않는다. 결정적으로 연결이 되면 연결정보를 메모리상에 저장해둘 뿐, 지속적으로 클라의 ping을 체크하는 등의 작업을 하지 않는 이상 서버측 부담은 적다.

 

 

 

 

 

Heartbaet 감지와 서버측 부담

 그럼 또 한가지 궁금한 점이 생긴다.

gprc의 경우 지속적으로 클라의 heartbeat를 관리하는데, 연결된 클라가 많아질수록 연결상태를 유지하는데에 부담이 커지지는 않을까?

 

 

이또한 결론부터 말하면 아니다. 정확히는 다음과 같은 이유 때문.

 

 

✅ gRPC의 "heartbeat" 동작방식

⚙️ TCP KeepAlive 패킷 (OS 레벨에서 감시)
📡 HTTP/2 PING frame 주기적 송수신
🔁 gRPC 연결이 끊기거나 비정상적이면 Stream() 메서드 내 catch 블럭으로 감지
🧠 서버 감시 방식 context.CancellationToken으로 연결 끊김도 감지 가능

 

 정리하면 heartbeat 감지 방식또한 비동기 I/O 기반이라 서버에서 별도의 스레드를 점유하지 않으며 OS수준의 레벨에서 관리하는 영역이기 때문에 서버 프로그램에서 자원을 소모하여 관리하는게 아니기 때문이다.

 

 

 

 

 

그럼 서버측 동시 접속자 수 관리를 왜하는가?

 앞서 언급된 내용들만 정리해보면 서버에 수천, 수만명의 클라가 달라붙는다고 해도 패킷을 보내지만 않으면 서버측 부담이 없는 것처럼 보인다.

 

 눈여겨 봐야할건 `서버 프로그램`에 부담이 안된다는 거지 `서버 프로그램이 올라가있는 머신`에 부담이 된다. 결국 수만명의 클라에대해 heartbeat를 관리하는 것을 서버 프로그램의 리소스를 사용해서 하는게 아니라면 누군가가 해야하는데, 이것이 커널 수준의 저레벨의 OS 스레드에서 하고 있음에 유의해야한다.

 

✅ 서버 애플리케이션(.NET Core gRPC 등) 자체는 heartbeat 감시로 부담을 거의 안 받지만,
👉 서버가 실행 중인 머신(OS 수준) 에는 연결 수가 많아질수록 네트워크와 커널 리소스 측면에서 부담이 생긴다.

 

 

결국 결론을 내리자면 아래와 같다. 프로그램상에서의 최적화도 중요하지만, 결국 서버 프로그램도 머신 위에서 도는것이기 때문에 저레벨 수준에서의 고민도 중요하니 앞으로도 잊지 않도록 하자.

 

 

많은 수의 클라이언트가 패킷을 보내지 않고 연결만 유지하는건 서버에 부담이 안된다. => X
많은 수의 클라이언트가 패킷을 보내지 않고 연결만 유지하는건 서버 프로그램에 부담이 안된다. => O
많은 수의 클라이언트가 패킷을 보내지 않고 연결만 유지하는건 서버 머신에 부담이 된다. => O