본문 바로가기
🌐 유니티 (Unity)

Day 52 - 멀티플레이 서버 리소스 관리 전략

by shin0707 2024. 12. 11.
728x90
반응형

 

  • 주제

>>  서버 부하 분산(로드 밸런싱, 샤딩)

>>  캐싱(Cache) 활용

>>  네트워크 최적화

>>  서버 리소스 사용 모니터링


  • 공부내용

멀티플레이 게임에서는 서버 리소스를 효율적으로 관리하는 것이 성능 최적화와 사용자 경험 향상의 핵심이다.

특히, WebGL 환경에서는 서버 리소스가 제한적일 수 있으므로, 효과적인 관리 전략이 필요하다.

이번 글에서는 서버 리소스를 효율적으로 관리하기 위한 주요 전략과 함께,

이를 구현하기 위한 코드 예제를 상세히 살펴보겠다.

 

1. 서버 부하 분산

멀티플레이어 게임에서 동시에 많은 사용자가 접속하면 서버에 과부하가 발생할 수 있다. 이를 해결하기 위해 부하를 분산시키는 기술을 활용한다.

 

1-1. 로드 밸런싱

서버 간 트래픽을 고르게 분배하기 위해 로드 밸런서를 사용한다.

 

  • AWS ELB(Amazon Elastic Load Balancer), Nginx, HAProxy 등 다양한 로드 밸런서를 활용할 수 있다.
  • 예: 사용자 접속 요청을 지역별로 분산하여 처리.
plaintext

사용자가 북미에서 접속 -> 북미 서버로 연결  
사용자가 아시아에서 접속 -> 아시아 서버로 연결

 

 

 

1-2. 샤딩(Sharding)

데이터베이스를 여러 서버로 분산하여 저장하는 방식이다.

사용자 ID를 기준으로 데이터를 분산하거나, 게임 맵별로 서버를 나눈다.

 

코드 예제: 사용자 ID를 기준으로 데이터 분산

public class ShardManager
{
    public string GetShardServer(string userId)
    {
        int shardIndex = userId.GetHashCode() % 3; // 샤드 서버 3개 가정
        switch (shardIndex)
        {
            case 0:
                return "http://server1.example.com";
            case 1:
                return "http://server2.example.com";
            case 2:
                return "http://server3.example.com";
            default:
                return "http://server1.example.com";
        }
    }
}

2. 캐싱(Cache) 활용

자주 조회되는 데이터를 캐시에 저장하여 서버의 부하를 줄인다.

Redis, Memcached와 같은 메모리 캐시 시스템을 사용하여 데이터베이스 조회를 최소화한다.

 

2-1. 세션 데이터 캐싱

게임 중 발생하는 세션 데이터를 메모리에 저장하여 빠르게 액세스할 수 있도록 한다.

 

코드 예제: Redis를 사용한 세션 데이터 캐싱

using StackExchange.Redis;
using System;

public class RedisCacheManager
{
    private ConnectionMultiplexer redis;
    private IDatabase cache;

    public RedisCacheManager()
    {
        redis = ConnectionMultiplexer.Connect("localhost");
        cache = redis.GetDatabase();
    }

    public void SetSessionData(string sessionId, string data, TimeSpan expiration)
    {
        cache.StringSet(sessionId, data, expiration);
    }

    public string GetSessionData(string sessionId)
    {
        return cache.StringGet(sessionId);
    }
}

// 사용 예시
RedisCacheManager cacheManager = new RedisCacheManager();
cacheManager.SetSessionData("session123", "{playerScore: 100}", TimeSpan.FromMinutes(30));
string sessionData = cacheManager.GetSessionData("session123");

3. 네트워크 최적화

3-1. 데이터 압축

클라이언트와 서버 간 데이터를 압축하여 전송량을 줄인다.

  • Gzip 또는 Brotli와 같은 압축 알고리즘을 활용한다.

 

코드 예제: Gzip 압축 적용

using System.IO;
using System.IO.Compression;
using System.Text;

public class DataCompressor
{
    public byte[] Compress(string data)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(data);
        using (var memoryStream = new MemoryStream())
        {
            using (var gzip = new GZipStream(memoryStream, CompressionMode.Compress))
            {
                gzip.Write(bytes, 0, bytes.Length);
            }
            return memoryStream.ToArray();
        }
    }

    public string Decompress(byte[] compressedData)
    {
        using (var memoryStream = new MemoryStream(compressedData))
        using (var gzip = new GZipStream(memoryStream, CompressionMode.Decompress))
        using (var reader = new StreamReader(gzip, Encoding.UTF8))
        {
            return reader.ReadToEnd();
        }
    }
}

// 사용 예시
DataCompressor compressor = new DataCompressor();
byte[] compressed = compressor.Compress("{playerScore: 100}");
string decompressed = compressor.Decompress(compressed);

 

 

3-2. WebSocket을 사용한 실시간 통신

HTTP 기반의 요청-응답 방식은 비효율적일 수 있으므로, 실시간 데이터 교환에는 WebSocket을 활용한다.

  • WebSocket은 양방향 통신을 지원하므로, 서버와 클라이언트가 지속적으로 데이터를 주고받을 수 있다.

 

코드 예제: WebSocket 서버와 통신

using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class WebSocketClient
{
    private ClientWebSocket webSocket;

    public async Task Connect(string uri)
    {
        webSocket = new ClientWebSocket();
        await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);
        Console.WriteLine("Connected to WebSocket server");
    }

    public async Task SendMessage(string message)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(message);
        await webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, CancellationToken.None);
    }

    public async Task ReceiveMessage()
    {
        byte[] buffer = new byte[1024];
        var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        Console.WriteLine("Received: " + Encoding.UTF8.GetString(buffer, 0, result.Count));
    }
}

// 사용 예시
WebSocketClient client = new WebSocketClient();
await client.Connect("ws://example.com/websocket");
await client.SendMessage("{action: 'joinGame', playerId: 'player123'}");
await client.ReceiveMessage();

 

4. 서버 리소스 사용 모니터링

4-1. 메트릭 시스템 구축

  • 서버 CPU, 메모리 사용량, 네트워크 트래픽을 모니터링하여 병목현상을 파악한다.
  • AWS CloudWatch, Google Stackdriver 등을 활용할 수 있다.

 

4-2. 자동 확장(Auto-Scaling)

  • 서버 리소스 사용량이 특정 임계치를 초과하면 자동으로 서버 인스턴스를 추가하거나, 필요 없을 때는 제거한다.
728x90
반응형

loading