REQUEST)
회원사에서 수신만 해도 송신측으로 ACK신호가 가나요?

RESPONSE)
TCP 통신에서는 회원사가 데이터를 수신하기만 해도 자동으로 송신 측으로 ACK(확인 응답) 신호가 전송됩니다. 이는 TCP 프로토콜의 기본 동작 방식으로, 송신 측이 데이터가 성공적으로 전달되었는지 확인하는 데 사용됩니다.

어떻게 ACK가 동작하나요?

  1. 데이터 수신
    • 송신 측에서 데이터를 전송하면, 수신 측(회원사)은 이를 TCP 계층에서 먼저 처리합니다.
    • 애플리케이션에서 실제 데이터를 처리하지 않아도, TCP 계층에서 데이터를 수신한 후 자동으로 ACK를 생성합니다.
  2. ACK 전송
    • 수신 측 TCP 계층은 데이터 패킷이 손상되지 않았고 올바르게 도착했음을 송신 측에 알리기 위해 ACK 패킷을 송신합니다.
    • ACK에는 다음에 기대하는 **시퀀스 번호(Sequence Number)**가 포함됩니다.
  3. 회원사에서 처리 지연이 있어도 ACK는 즉시 발송
    • 회원사 애플리케이션에서 데이터 처리가 느리더라도, TCP 스택 자체는 데이터를 수신한 즉시 ACK를 보냅니다.
    • 하지만, 수신 버퍼가 가득 차거나 회원사 애플리케이션이 데이터를 읽지 않아 문제가 발생하면 송신 측에 영향을 줄 수 있습니다.

수신 측에서 ACK를 안 보내는 경우

ACK가 송신되지 않는 경우는 일반적으로 다음과 같은 상황에서 발생합니다:

  1. 수신 버퍼 오버플로우
    • 회원사 측에서 데이터를 읽지 않아 수신 버퍼가 가득 차면 TCP 윈도우 크기가 0으로 설정됩니다.
    • 이 경우, ACK는 송신되지만 송신 측은 데이터 전송을 일시 중단합니다.
  2. 네트워크 장애
    • ACK 패킷이 네트워크 문제로 인해 송신 측에 도달하지 못할 수 있습니다.
  3. 수신 측 시스템 장애
    • 수신 측 시스템이 과부하 상태거나 비정상적으로 동작하면 ACK가 생성되지 않거나 늦게 송신될 수 있습니다.

요약

회원사가 데이터를 수신하기만 하면 TCP 스택이 자동으로 ACK를 송신합니다. 하지만 회원사 측의 애플리케이션이 데이터를 처리하지 못해 수신 버퍼가 가득 차거나 네트워크 상태가 불안정하면 송신 측의 데이터 전송이 영향을 받을 수 있습니다. 이를 방지하려면 수신 측 시스템의 안정성과 처리 속도를 보장하는 것이 중요합니다.

REQUEST)
수신 측인 회원사에서 데이터를 처리하는 과정에서 딜레이가 발생하면(?)

RESPONSE)
TCP 통신에서 거래소가 증권 정보 데이터를 일방적으로 송신하고, 수신 측인 회원사에서 데이터를 처리하는 과정에서 딜레이가 발생하면 다음과 같은 현상이 벌어질 수 있습니다.

1. TCP 윈도우 크기 축소 (Flow Control)

  • TCP는 수신 측의 데이터 처리 속도에 따라 송신 속도를 조절합니다.
  • 회원사 쪽에서 데이터를 처리하지 못하고 수신 버퍼가 꽉 차면, 수신 측은 송신 측에 윈도우 크기를 줄이라는 신호를 보냅니다.
  • 송신 측에서는 이를 인지하고 데이터 송신 속도를 줄입니다.
  • 최악의 경우, 수신 측이 윈도우 크기 = 0 신호를 보내면 송신 측은 데이터를 전송하지 못하고 대기 상태에 빠집니다.

2. 송신 측의 데이터 큐 축적

  • 회원사에서 데이터를 처리하지 못해 ACK 패킷이 늦게 도착하면, 송신 측의 데이터 큐에 전송 대기 데이터가 점점 쌓이게 됩니다.
  • 이로 인해 송신 측의 메모리 사용량 증가 또는 송신 애플리케이션의 지연 문제가 발생할 수 있습니다.
  • 데이터 큐가 한계에 도달하면 송신 애플리케이션은 데이터를 더 이상 보내지 못하거나 연결이 끊어질 수 있습니다.

3. 연결 끊김 가능성 (Timeout)

  • TCP는 패킷 전송 후 수신 측으로부터 ACK를 받지 못하면 재전송을 시도합니다.
  • 재전송을 여러 번 시도해도 응답이 없으면, 연결이 타임아웃되어 종료될 수 있습니다.
  • 특히 네트워크가 불안정하거나 회원사 시스템이 과부하 상태라면 이런 상황이 빈번히 발생할 수 있습니다.

4. 증권 정보의 지연 전달

  • 회원사가 데이터를 실시간으로 처리하지 못하면 증권 정보가 적시에 전달되지 않을 수 있습니다.
  • 이는 주식 매매와 같은 실시간 거래에 큰 영향을 미쳐 시장의 신뢰성을 해칠 가능성이 있습니다.

해결 방안

  1. 회원사 데이터 처리 속도 최적화
    • 데이터 처리 로직을 개선하거나 병렬 처리 등을 통해 처리 속도를 높입니다.
  2. TCP 윈도우 크기 및 버퍼 관리 최적화
    • 수신 측에서 TCP 버퍼 크기를 늘리거나 송신 측에서 데이터 송신 속도를 조절합니다.
  3. UDP 프로토콜 사용 검토
    • TCP의 신뢰성 보장을 위한 제어 메커니즘이 문제라면, 신뢰성보다는 속도가 중요한 경우 UDP를 사용하는 것도 고려할 수 있습니다.
  4. 애플리케이션 레벨의 큐 처리
    • 데이터 처리 지연이 발생하더라도 송수신 사이에 임시 버퍼(큐)를 두어 데이터를 효율적으로 관리합니다.

이와 같은 현상은 네트워크 환경, 시스템 성능, 애플리케이션 설계 방식에 따라 다르게 나타날 수 있으니, 구체적인 원인 분석이 필요합니다.

C#에서 byte[] 데이터를 Redis에 전송하는 것은 가능합니다. 하지만 Redis는 문자열 기반 저장소이기 때문에, byte[] 데이터를 저장하려면 적절히 직렬화(serialize)하거나 Base64 인코딩을 적용해야 합니다. 다음은 이를 처리하는 방법입니다.

AddItemToList 메서드를 사용할 경우

만약 Redis 클라이언트 라이브러리의 AddItemToList 메서드를 사용하려는 경우, byte[] 데이터를 문자열로 변환해야 합니다. 아래는 Base64 인코딩 방식으로 이를 수행하는 예제입니다.

byte[] realData = new byte[datalen];
Array.Copy(data, 0, realData, 0, datalen);

// Convert byte[] to Base64 string
string encodedData = Convert.ToBase64String(realData);

// Add to Redis list
sendRealRedis.AddItemToList("REAL", encodedData);

Redis에서 데이터를 복원할 때

// Retrieve Base64 string from Redis
string encodedData = receiveRealRedis.GetItemFromList("REAL");

// Convert Base64 string back to byte[]
byte[] realData = Convert.FromBase64String(encodedData);

 

간단한 Redis AddItemToList 및 복원

만약 간단히 데이터를 추가하고 문자열 기반으로 저장하려면 다음과 같이 구현할 수 있습니다.

using System;
using ServiceStack.Redis;

class Program
{
    static void Main()
    {
        string redisHost = "localhost:6379"; // Redis 서버 주소
        string redisKey = "REAL";

        // Redis 클라이언트 초기화
        using (var redisClient = new RedisClient(redisHost))
        {
            // 예제 데이터 준비
            byte[] realData = new byte[] { 100, 200, 255 };

            // 1. byte[] 데이터를 문자열로 저장 (Base64 인코딩 사용)
            string encodedData = Convert.ToBase64String(realData);
            redisClient.AddItemToList(redisKey, encodedData);
            Console.WriteLine("Data added to Redis.");

            // 2. Redis에서 데이터를 가져와 복원
            string retrievedEncodedData = redisClient.GetItemFromList(redisKey, 0); // 첫 번째 아이템 가져오기
            byte[] decodedData = Convert.FromBase64String(retrievedEncodedData);
            Console.WriteLine("Retrieved byte[]: " + BitConverter.ToString(decodedData));
        }
    }
}

- BRPop을 사용시에 해결방법

  1. data 배열이 byte[][] 형식으로 반환되었을 가능성이 높습니다.
    • data[0]: Redis 키 이름 (byte 배열로 반환됨)
    • data[1]: Redis 값 (Base64 인코딩된 byte 배열)
  2. Encoding.UTF8.GetString() 및 Convert.FromBase64String() 메서드는 입력 값이 적절하지 않을 경우 오류를 발생시킵니다.
var data = _receiveRealRedis.BRPop("REAL", 10);

if (data != null && data.Length > 0)
{
    // data[0]과 data[1]이 byte[] 형식이라고 가정
    string listName = Encoding.UTF8.GetString(data[0]); // 키 이름 변환
    byte[] decodedData = Convert.FromBase64String(Encoding.UTF8.GetString(data[1])); // 데이터 변환

    Console.WriteLine($"List Name: {listName}");
    Console.WriteLine($"Decoded Data: {BitConverter.ToString(decodedData)}");
}



주요 고려사항

  1. 직렬화 사용:
    • byte[] 데이터를 직렬화하여 Redis에 저장할 수 있습니다.
    • 직렬화된 데이터는 나중에 Redis에서 가져올 때 역직렬화(deserialize)하여 원래 데이터로 복원해야 합니다.
  2. Base64 인코딩 사용:
    • byte[] 데이터를 Base64로 변환하여 문자열로 저장한 후, 복원 시 Base64 디코딩을 수행할 수 있습니다.



주의사항

  1. 데이터 크기:
    • Redis는 데이터 크기에 제한이 있습니다. (일반적으로 하나의 값당 최대 512MB)
    • 데이터 크기가 큰 경우 압축을 고려하세요.
  2. 성능:
    • Base64 인코딩은 약 33%의 데이터 크기 증가를 초래합니다.
    • 데이터를 효율적으로 처리하려면 직렬화 방식이 적합합니다.
  3. 호환성:
    • 저장된 데이터는 다른 언어/플랫폼에서 접근해야 할 경우 호환성을 고려하세요. Base64는 플랫폼 독립적이지만, 직렬화는 언어/플랫폼 종속적일 수 있습니다.

이제 필요에 따라 Base64 인코딩 또는 직렬화를 선택하여 Redis에 데이터를 저장하고 복원할 수 있습니다!




Json 구조체.출력형태 코드(따로따로, 혹은 전체)

1. 나누어서 출력하는 형태
2. 전체를 출력하는 형태 - JsonConvert.SerializeObject(estate, Formatting.Indented)

public void DataToBuffer(byte[] data, int datalen)
{
    string dataText = Encoding.UTF8.GetString(data, 0, datalen);

    if ((dataText.IndexOf("ComplexNo") >= 0) && (dataText.IndexOf("CortarNo") >= 0))
    {
        estateAllInterfaceText estate = JsonConvert.DeserializeObject<estateAllInterfaceText>(dataText);

         PublicApiNM.SendToDebug8(3, "[" + estate.dataClass + "/" + estate.infoMarketClass + "/" + estate.transactionTime + "/" + estate.ComplexNo + "/" + estate.ComplexName + "/" + estate.CortarNo + "]");
         PublicApiNM.SendToDebug8(3, "[" + JsonConvert.SerializeObject(estate, Formatting.Indented) + "]");
    }
}


[2025-01-16 05:15:30]>[ES/555/20250110202308/120617/강정이매/5013011600]
[2025-01-16 05:15:30]>[{
  "dataClass": "ES",
  "infoMarketClass": "555",
  "transactionTime": "20250110202308",
  "ComplexNo": "120617",
  "ComplexName": "강정이매",
  "CortarNo": "5013011600",
  "RealEstateTypeCode": "OPST",
  "RealEstateTypeName": "오피스텔",
  "UseApproveYmd": "20180208",
  "CortarAddress": "제주도 서귀포시 강정동",
  "MinPriceByLetter": "2억 2,000",
  "MaxPriceByLetter": "2억 2,000",
  "MinLeasePriceByLetter": "NONE",
  "MaxLeasePriceByLetter": "NONE",
  "MinPrice": "22000",
  "MaxPrice": "22000",
  "MinLeasePrice": "0",
  "MaxLeasePrice": "0"
}]

코드에서 특정 외부프로세스를 종료시키려고 할떄에(이미 프로세스.아이디를 알고 있는경우에), 예를 들어서ㅡ, 자신의 프로그램에서 발생시킨 프로세스의 경우에, Process.GetProcessById().Kill() 을 이용하려면(?)


app.manifest 파일은 애플리케이션에 대한 메타데이터를 포함하는 파일로, 프로그램이 실행될 때 필요한 권한이나 설정을 지정할 수 있습니다. 예를 들어, 프로그램을 관리자 권한으로 실행하려면 app.manifest 파일에 requestedExecutionLevel을 설정할 수 있습니다.

1. Visual Studio에서 app.manifest 파일 생성 및 설정 방법

Step 1: app.manifest 파일 생성

  1. 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 버튼으로 클릭한 후, "추가" > **"새 항목"**을 선택합니다.
  2. **"애플리케이션 매니페스트 파일"**을 선택하고, 이름을 app.manifest로 지정한 후 "추가" 버튼을 클릭합니다.
  3. 이 작업으로 프로젝트에 app.manifest 파일이 생성됩니다.

Step 2: app.manifest 파일에 관리자 권한 설정 추가

app.manifest 파일을 열고, requestedExecutionLevel을 **requireAdministrator**로 설정하여 애플리케이션이 관리자 권한을 요구하도록 합니다.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
  <assemblyIdentity version="1.0.0.0" name="MyApp.app" />

  <!-- 요청된 실행 레벨 설정 -->
  <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

</assembly>
  • level="requireAdministrator": 애플리케이션을 실행하려면 관리자 권한이 필요합니다.
  • uiAccess="false": 사용자 인터페이스 접근 권한을 설정합니다. 기본적으로 false로 설정되며, 특정 상황에서만 true로 설정합니다.

Step 3: 프로젝트 빌드 및 실행

  1. 프로젝트를 다시 빌드합니다. 이때 app.manifest 파일에 설정한 권한이 자동으로 반영됩니다.
  2. 관리자 권한이 필요한 애플리케이션을 실행하면, Windows에서 사용자 계정 컨트롤(UAC) 팝업이 나타나고, 사용자가 "예"를 선택해야 실행됩니다.

2. app.manifest 파일에 추가할 수 있는 다른 설정들

app.manifest 파일에는 권한 설정 외에도 여러 중요한 설정을 할 수 있습니다. 예를 들어, 애플리케이션의 최소 Windows 버전, DPI 설정, 그리고 다중 프로세서 사용 등을 지정할 수 있습니다.

예시: 최소 Windows 버전 설정

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <!-- 최소 Windows 7 이상 -->
    <application xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <supportedOS Id="win7" />
    </application>
</compatibility>

예시: DPI 호환성 설정

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <!-- DPI 자동 크기 조정 -->
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
    </windowsSettings>
</application>

3. 관리자 권한 없이 실행하려면

만약 관리자가 아닌 권한으로 실행하고 싶다면, requestedExecutionLevel을 **asInvoker**로 설정할 수 있습니다. 이 경우 애플리케이션은 호출한 프로세스와 동일한 권한을 사용하여 실행됩니다.

<requestedExecutionLevel level="asInvoker" uiAccess="false" />

이 설정은 기본값으로 관리자가 아닌 사용자 권한으로 실행됩니다.


결론

app.manifest 파일을 사용하면 애플리케이션이 실행될 때 필요한 권한 및 설정을 정의할 수 있습니다. 관리자 권한이 필요한 애플리케이션의 경우 requestedExecutionLevel을 requireAdministrator로 설정하여 관리자 권한을 요구하도록 할 수 있습니다. 이를 통해 Process.GetProcessById().Kill() 등의 중요한 작업을 수행할 때 필요한 권한을 보장할 수 있습니다.

1. ServiceStack.dll: 1.0.0.0
2. ServiceStack.Interfaces.dll: 1.0.0.0
3. ServiceStack.ServiceInterface.dll: 1.0.0.0

Real)

\DllVersion>dotnet build
  복원할 프로젝트를 확인하는 중...
  복원할 모든 프로젝트가 최신 상태입니다.
  DllVersion -> \DllVersion\bin\Debug\net8.0\DllVersion.dll

빌드했습니다.
    경고 0개
    오류 0개

경과 시간: 00:00:01.91

\DllVersion>dotnet run
\ServiceStackRealVersion\Bin\Release\ServiceStack.dll: 1.0.0.0
\ServiceStackRealVersion\Bin\Release\ServiceStack.Interfaces.dll: 1.0.0.0
\ServiceStackRealVersion\Bin\Release\ServiceStack.ServiceInterface.dll: 1.0.0.0


Trial)

\DllVersion>dotnet build
  복원할 프로젝트를 확인하는 중...
  복원할 모든 프로젝트가 최신 상태입니다.
  DllVersion -> \DllVersion\bin\Debug\net8.0\DllVersion.dll

빌드했습니다.
    경고 0개
    오류 0개

경과 시간: 00:00:01.65

\DllVersion>dotnet run
\RedisTickServer\bin\Debug\net8.0\ServiceStack.dll: 1.0.0.0
\RedisTickServer\bin\Debug\net8.0\ServiceStack.Interfaces.dll: 6.0.0.0
\RedisTickServer\bin\Debug\net8.0\ServiceStack.ServiceInterface.dll: 1.0.0.0

위의 에러는 ServiceStack.Redis 라이브러리를 사용하여 Redis에 요청을 보내는 애플리케이션이 무료 라이선스 제한을 초과했기 때문에 발생합니다.

에러 원인

  1. 무료 라이선스 제한 초과:
    • 무료 버전의 ServiceStack.Redis는 한 시간에 최대 6,000개의 Redis 요청을 처리할 수 있습니다.
    • 이 제한을 초과하면 InvalidOperationException이 발생하며, 추가 요청은 차단됩니다.
  2. 과도한 Redis 요청:
    • 애플리케이션이 짧은 시간에 너무 많은 Redis 요청을 보낸 경우입니다.
    • Redis에 연결하거나 데이터를 읽고/쓰기 위해 호출한 횟수가 누적되어 제한을 초과했을 가능성이 큽니다.
  3. ServiceStack 버전 문제:
    • 무료 버전의 ServiceStack(버전 4 이상)은 상용 라이선스가 필요합니다.
    • 버전 3은 무료로 사용 가능하지만, 제한된 기능만 제공되며 유지 관리되지 않습니다.

해결 방안

  1. 라이선스 업그레이드:
    • ServiceStack의 상용 라이선스를 구매하여 요청 제한을 제거합니다.
    • ServiceStack 라이선스 페이지를 방문해 적합한 요금제를 선택하세요.
  2. ServiceStack V3로 다운그레이드:
    • 무료로 사용 가능한 ServiceStack V3를 사용하면 요청 제한 없이 작업할 수 있습니다.
    • 다운그레이드 가이드: ServiceStack V3 GitHub
  3. Redis 요청 최적화:
    • 애플리케이션에서 Redis 요청을 줄이는 방법을 고려하세요:
      • Batching: 여러 요청을 한 번의 요청으로 묶어 처리.
      • Caching: 자주 조회하는 데이터를 Redis 외부에서 캐싱.
      • Connection pooling: Redis 연결 관리 개선.
    • 예를 들어, Redis에 데이터를 저장하기 전에 중복된 요청이 있는지 확인하세요.
  4. 대안 라이브러리 사용:
    • ServiceStack 외에 다른 Redis 클라이언트를 사용하는 것도 고려할 수 있습니다. 예를 들어:
  5. 제한 우회 (임시):
    • 요청이 집중적으로 발생하지 않도록 로직을 수정하여 요청 간 딜레이를 추가하거나, Redis 사용량을 분산시킵니다.

필자.내용)

Redis(Message Queue)를 사용하면, 데이타를 안정적으로 처리할수 있습니다.
데이타를 파싱.즉 구조체변환후에 데이타입력하는 처리과정은 생각보다 많은 소요시간이 필요합니다.

Request To CHAT.GPT) 위를 전산용어를 이용해서 표현해 주세요
필자.내용의 Request에 대한 CHAT.GPT.Response)

Redis(Message Queue)를 사용하면, 데이터의 안정적인 처리와 비동기적인 작업 분배가 가능합니다. 데이터 파싱 및 구조체 변환 후 실제 데이터 입력 과정은 많은 시스템 자원과 시간이 소요되는 복잡한 처리 단계로, 이는 종종 CPU 집약적인 작업 또는 I/O 대기 시간이 발생하는 데이터 변환 처리라고 할 수 있습니다.

따라서, 이러한 처리 시간을 효율적으로 관리하기 위해 비동기 메시지 큐를 사용하여 워크로드 분배 및 병렬 처리를 최적화할 수 있습니다. 이 방식은 처리 과정에서 발생할 수 있는 병목 현상을 완화시키고, 스케일링을 통해 시스템의 안정성을 높이는 데 기여합니다.

Recv.Redis.Server Estate.Tcp.Data.Send
Fail.Debug.Logger  

 

Windows.DLL 버젼 알아내는 프로그램 작성

>dotnet new console -o versioncheck
>notepad Program.cs

using System;
using System.Reflection;

class Program
{
    static void Main(string[] args)
    {
        // DLL 파일 경로 리스트
        string[] dllPaths = new string[]
        {
            @"C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\Newtonsoft.Json.Net20.dll",
            @"C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\ServiceStack.dll",
            @"C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\ServiceStack.Interfaces.dll",
            @"C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\ServiceStack.ServiceInterface.dll",
            @"C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\Systehttp://m.Data.SQLite.dll"
        };

        // 각 DLL 파일의 버전 출력
        foreach (var dllPath in dllPaths)
        {
            try
            {
                // 어셈블리 로드
                var assembly = Assembly.LoadFrom(dllPath);
                var version = assembly.GetName().Version;
                Console.WriteLine($"{dllPath}: {version}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error loading {dllPath}: {ex.Message}");
            }
        }
    }
}

>dotnet build
>dotnet run

C:\Users\xterm\Downloads\aa12>dotnet run
C:\Users\xterm\Downloads\aa12\aa12.csproj : warning NU1803: 'http://nuget.grapecity.com/nuget' 'HTTP' 원본을 사용하여 'restore' 작업을 실행하고 있습니다. 비 HTTPS 액세스는 이후 버전에서 제거
됩니다. 'HTTPS' 원본으로 마이그레이션하는 것이 좋습니다.
C:\Users\xterm\Downloads\aa12\aa12.csproj : warning NU1803: 'http://nuget.grapecity.com/nuget' 'HTTP' 원본을 사용하여 'restore' 작업을 실행하고 있습니다. 비 HTTPS 액세스는 이후 버전에서 제거
됩니다. 'HTTPS' 원본으로 마이그레이션하는 것이 좋습니다.
C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\Newtonsoft.Json.Net20.dll: 3.5.0.0
C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\ServiceStack.dll: 1.0.0.0
C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\ServiceStack.Interfaces.dll: 1.0.0.0
C:\Users\xterm\Downloads\tmp\ArchitectureModel\ModelChangeToRedis\RedisServiceStackReal\RedisServiceStackReal\Bin\Release\ServiceStack.ServiceInterface.dll: 1.0.0.0
  • **System.Windows.Forms.Timer**는 UI 스레드에서 실행되므로 UI와의 상호작용이 쉬운 반면, System.Timers.Timer는 그와 반대로 UI와의 상호작용을 할 때 조금 더 복잡합니다.


질문)
System.Windows.Forms.Timer ____timer = new System.Windows.Forms.Timer(); System.Timers.Timer ____timer = new System.Timers.Timer(); form 프로그램에서는 System.Timers.Timer ____timer = new System.Timers.Timer(); 는 동작하지 않는것 같은데 이유는?


답변)

System.Timers.Timer가 Windows Forms 애플리케이션에서 예상대로 동작하지 않는 이유는, 기본적으로 System.Timers.Timer가 백그라운드 스레드에서 실행되기 때문입니다. 따라서 Tick 이벤트가 UI 스레드에서 실행되지 않으므로, UI 업데이트를 하기 위해서는 별도의 스레드 동기화가 필요합니다. 반면, System.Windows.Forms.Timer는 UI 스레드에서 실행되므로 UI와 상호작용이 간편합니다.

문제의 원인:

  • **System.Timers.Timer**는 기본적으로 별도의 스레드에서 이벤트를 발생시킵니다. 이는 UI 스레드와 별개의 스레드에서 실행되므로, UI 요소를 직접적으로 업데이트하려면 스레드 동기화가 필요합니다.
  • **System.Windows.Forms.Timer**는 UI 스레드에서 실행되므로 UI와의 상호작용이 쉬운 반면, System.Timers.Timer는 그와 반대로 UI와의 상호작용을 할 때 조금 더 복잡합니다.

System.Timers.Timer 사용 시 문제 해결 방법:

System.Timers.Timer를 사용할 때 UI 스레드와의 동기화가 필요합니다. 예를 들어, Invoke 메서드를 사용하여 UI 스레드에서 작업을 수행할 수 있습니다.

예시: System.Timers.Timer 사용 시 UI 업데이트

using System;
using System.Timers;
using Systehttp://m.Windows.Forms;

public class MainForm : Form
{
    private Systehttp://m.Timers.Timer timer;  // Systehttp://m.Timers.Timer를 사용할 변수 선언

    public MainForm()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        this.timer = new Systehttp://m.Timers.Timer(); // Systehttp://m.Timers.Timer 객체 초기화
        this.SuspendLayout();

        // 타이머 설정
        this.timer.Interval = 1000;  // 1초 간격 (1000ms)
        this.timer.Elapsed += new ElapsedEventHandler(Timer_Elapsed);  // Elapsed 이벤트 핸들러 설정
        this.timer.Start();  // 타이머 시작

        // 폼 설정
        this.ClientSize = new Systehttp://m.Drawing.Size(800, 450);
        this.Name = "MainForm";
        this.Text = "Systehttp://m.Timers.Timer Example";
        this.ResumeLayout(false);
    }

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // 타이머가 Elapsed 할 때마다 호출됩니다.
        // UI 요소를 업데이트하려면 Invoke로 UI 스레드에서 실행
        if (this.InvokeRequired)
        {
            this.Invoke(new Action(() => 
            {
                // 여기서 UI 업데이트
                this.Text = "타이머 이벤트 발생";
            }));
        }
        else
        {
            // UI 업데이트가 필요한 경우 직접 수행할 수 있음
            this.Text = "타이머 이벤트 발생";
        }
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}
 

설명:

  • System.Timers.Timer는 백그라운드 스레드에서 동작하므로, Timer_Elapsed 이벤트 핸들러 내에서 UI 업데이트를 하려면 InvokeRequired를 통해 UI 스레드에서 작업이 필요한지 확인한 후 Invoke 메서드를 사용하여 UI 스레드에서 실행합니다.
  • 이렇게 하면 UI 요소가 백그라운드 스레드에서 안전하게 업데이트됩니다.

결론:

System.Timers.Timer는 기본적으로 백그라운드 스레드에서 동작하기 때문에, UI와 상호작용하려면 스레드 동기화가 필요합니다. System.Windows.Forms.Timer는 UI 스레드에서 실행되므로 Windows Forms 애플리케이션에서는 UI와 상호작용이 훨씬 더 간편합니다. UI 스레드에서 타이머 이벤트를 처리하고 싶다면 System.Windows.Forms.Timer를 사용하는 것이 더 적합합니다.

ServiceStack.Redis 요청 제한
(평가판에서는 요청 횟수가 제한되며, 제한을 초과하면 예외가 발생하거나 연결이 차단됩니다.)

상용판)

 



Exception발생하지 않음)

ServiceStack.Redis 요청 제한
(평가판에서는 요청 횟수가 제한되며, 제한을 초과하면 예외가 발생하거나 연결이 차단됩니다.)
ServiceStack.Redis 요청 제한
(평가판에서는 요청 횟수가 제한되며, 제한을 초과하면 예외가 발생하거나 연결이 차단됩니다.)


ServiceStack.Redis를 Windows 환경에서 사용할 때 DLL에 대한 요청 제한 여부는 사용하고 있는 라이선스 유형과 관련이 있습니다.

ServiceStack.Redis 요청 제한

  1. 무료 버전 (Trial Mode):
    • ServiceStack는 무료 평가판으로 사용 시 특정 제한이 있습니다. 예를 들어, 요청 수가 제한되거나 동시 연결 수에 제약이 있을 수 있습니다.
    • 평가판에서는 요청 횟수가 제한되며, 제한을 초과하면 예외가 발생하거나 연결이 차단됩니다.
  2. 상업용 라이선스:
    • ServiceStack.Redis는 상업용 라이선스를 구매하면 요청 제한 없이 사용할 수 있습니다.
    • 적절한 라이선스 키를 설정해야 제한이 해제됩니다. 라이선스 키는 AppHost.Configure 또는 애플리케이션의 초기 설정에서 적용 가능합니다.
  3. 오픈소스 대안:
    • 제한이 문제라면, ServiceStack.Redis 대신 StackExchange.Redis와 같은 오픈소스 대안을 고려할 수 있습니다. StackExchange.Redis는 .NET 환경에서 널리 사용되며 제한이 없습니다.

제한 확인 및 해결

  1. 제한 여부 확인:
    • ServiceStack.Redis를 실행 중 예외가 발생하며 "Free Quota Exceeded" 또는 "Trial Usage Limit Reached" 메시지가 나타나면 제한에 도달했음을 의미합니다.
  2. 라이선스 적용 방법:
    • 적절한 라이선스를 구매하고 아래와 같이 설정합니다:

       
      Licensing.RegisterLicense("Your License Key Here");
  3. Redis 클라이언트 교체:
    • 제한 없는 솔루션이 필요하면 StackExchange.Redis로 교체를 고려하세요.
       
      dotnet add package StackExchange.Redis

결론

ServiceStack.Redis에는 요청 제한이 있을 수 있으며, 이를 해결하려면 상업용 라이선스를 사용하거나 오픈소스 대안으로 전환하는 것이 좋습니다. 추가 설정이나 구현 과정이 필요하다면 도움을 드릴 수 있습니다!

throw는 예외를 명시적으로 던지는 데 사용됩니다. 예외를 직접 발생시키는 경우에 사용되며, try-catch 블록과는 다릅니다. try-catch는 예외를 처리하는 데 사용되고, throw는 예외를 발생시키는 데 사용됩니다.

throw의 사용 사례

  1. 특정 조건에서 예외를 명시적으로 던지기: 예를 들어, 프로그램 실행 중에 특정 조건이 만족되었을 때 예외를 발생시켜 오류를 알리고자 할 때 사용합니다.위 예제에서 age가 18 미만인 경우, IllegalArgumentException을 던져서 함수 호출자가 이를 처리하도록 합니다.
  2.  
    public void checkAge(int age) { if (age < 18) { throw new IllegalArgumentException("Age must be at least 18."); } System.out.println("Age is valid."); }
  3. 사용자 정의 예외 던지기: 특정 로직에서 정의된 예외를 던지기 위해 throw를 사용할 수 있습니다. 예를 들어, 자신의 애플리케이션에서 발생할 수 있는 예외를 정의하고 이를 던질 수 있습니다.
  4.  
    public class InsufficientFundsException extends Exception { public InsufficientFundsException(String message) { super(message); } } public void withdraw(double amount) throws InsufficientFundsException { if (amount > balance) { throw new InsufficientFundsException("Insufficient funds for withdrawal."); } balance -= amount; }
  5. 조건에 따른 예외를 의도적으로 발생시키기: 프로그램의 특정 상태나 조건에서 예외를 발생시켜, 이를 처리하도록 유도할 수 있습니다.
  6.  
    public void processOrder(Order order) { if (order == null) { throw new NullPointerException("Order cannot be null."); } // 나머지 로직 처리 }

throw와 throws의 차이점

  • throw는 예외를 던질 때 사용됩니다.
  • throws는 메서드 시그니처에 예외가 발생할 수 있음을 명시할 때 사용됩니다. 즉, throw와는 다르게 예외를 던진다는 것을 알리는 역할을 합니다.(?????)
 
public void someMethod() throws IOException { // 예외가 발생할 수 있음을 알림 throw new IOException("파일 읽기 오류"); }

따라서, throw는 예외를 실제로 던지는 데 사용되고, throws는 해당 메서드에서 예외가 발생할 수 있음을 호출자에게 알리는 역할을 합니다.

ServiceStack의 Redis 요청에 대한 무료 할당량을 초과(6000 Redis requests per hour)


Exception)

[2025-01-11 08:55:29]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(InvalidOperationException):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-11 08:55:31]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(InvalidOperationException):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-11 08:55:32]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(InvalidOperationException):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3. [2025-01-11 08:55:33]>(MultipleRedisManager)(SendQuery)(JsonConvert.SerializeObject)(InvalidOperationException):The free-quota limit on '6000 Redis requests per hour' has been reached. Please see https://servicestack.net to upgrade to a commercial license or visit https://github.com/ServiceStackV3/ServiceStackV3 to revert back to the free ServiceStack v3.

 

 



위의 에러 메시지는 ServiceStack의 Redis 요청에 대한 무료 할당량을 초과했다는 의미입니다. 구체적으로, 6000 Redis requests per hour의 무료 한도를 초과한 경우 발생합니다. 이로 인해 더 이상 Redis 쿼리를 처리할 수 없게 되어 InvalidOperationException이 발생한 것입니다.

원인:

  • 무료 할당량 초과: 서비스에서 제공하는 무료 쿼리 한도인 6000회를 한 시간 내에 초과했기 때문에, 더 이상 Redis 요청을 처리할 수 없습니다.
  • 사용 중인 ServiceStack 라이브러리: ServiceStack.dll, ServiceStack.Interfaces.dll, ServiceStack.ServiceInterface.dll을 사용 중인데, 이들은 Redis와 관련된 요청을 처리할 때 위의 제한에 걸릴 수 있습니다.

해결 방법:

  1. 유료 라이선스 업그레이드:
    • ServiceStack의 무료 한도를 초과한 경우, ServiceStack 공식 사이트에서 유료 라이선스를 구매하여 한도를 늘릴 수 있습니다. 이를 통해 더 많은 Redis 요청을 처리할 수 있습니다.
  2. 서비스 변경 또는 다운그레이드:
    • ServiceStack v3 다운그레이드하여 무료로 사용할 수 있는 이전 버전을 사용해 볼 수 있습니다. 다만, 최신 기능이나 보안 패치가 없을 수 있으니 이를 고려해야 합니다.
  3. Redis 요청 최적화:
    • Redis 요청을 최적화하여 6000회 한도 내에서 처리할 수 있도록 Redis 쿼리의 빈도나 로직을 개선하는 방법도 고려할 수 있습니다. 예를 들어, Redis 요청을 캐시로 처리하여 불필요한 호출을 줄이는 방법이 있을 수 있습니다.
  4. Redis 요청 분산:
    • 여러 서버 또는 Redis 인스턴스를 사용하여 요청을 분산시킬 수 있는 방법을 고려할 수도 있습니다. 다만, 이 방법은 설정과 인프라 변경이 필요할 수 있습니다.

결론:

위의 에러는 Redis 요청이 무료 한도를 초과했기 때문에 발생한 것입니다. 이를 해결하려면 유료 라이선스를 구입하거나, Redis 요청을 최적화하거나, 구버전으로 돌아가는 방법을 고려해야 합니다.

 
 
 

질문)
파일로 REDIS설정을 안해놓으면, reboot시에 데이타는 없어지는게 원칙인가요?

답변)

네, Redis는 기본적으로 메모리 기반 데이터 저장소이기 때문에, 파일 저장 설정이 없으면 서버 재시작(reboot) 시 데이터가 사라지는 것이 기본 동작입니다.


Redis의 기본 동작 원리

Redis는 메모리 내에서 데이터를 저장하며, 디스크에 데이터를 저장하도록 설정하지 않는 한, 시스템이 재부팅되거나 Redis 서버가 종료되면 데이터는 영구적으로 사라집니다.


데이터 영구화를 위한 옵션

Redis에서 데이터를 영구적으로 저장하려면 다음 중 하나를 활성화해야 합니다.

1. RDB (Redis Database Backup)

  • Redis는 특정 시점마다 메모리의 스냅샷을 디스크에 저장합니다.
  • 설정 예제 (redis.conf):
     
    save 900 1 # 15분 동안 1개 이상의 키가 변경되면 저장 save 300 10 # 5분 동안 10개 이상의 키가 변경되면 저장 save 60 10000 # 1분 동안 10,000개 이상의 키가 변경되면 저장 dbfilename dump.rdb dir /path/to/directory
  • RDB 파일(dump.rdb)은 Redis 서버 종료 후 재시작 시 데이터를 복원합니다.

2. AOF (Append-Only File)

  • 모든 쓰기 작업(SET, HSET 등)을 로그 형식으로 기록하여 데이터를 영구적으로 저장합니다.
  • 설정 예제 (redis.conf): 
  •  
    appendonly yes appendfilename "appendonly.aof"
  • AOF는 Redis 서버가 종료되더라도 데이터를 복원할 수 있습니다.

기본 설정 확인

Redis는 기본적으로 영구 저장 설정이 비활성화되어 있습니다. Redis의 기본 동작을 확인하려면 redis-cli에서 다음 명령어로 설정을 확인할 수 있습니다:

  1. RDB 설정 확인:출력이 비어 있거나 save ""로 설정되어 있으면 RDB가 비활성화된 상태입니다.
  2.  
    redis-cli CONFIG GET save
  3. AOF 설정 확인:결과가 appendonly no이면 AOF가 비활성화된 상태입니다.
  4.  
    redis-cli CONFIG GET appendonly

데이터 영구성을 원하지 않을 경우

만약 Redis를 캐시로만 사용한다면, 파일로 저장하지 않는 것이 합리적입니다. 이 경우 서버 재시작 시 데이터를 복원하지 않고 새롭게 시작하는 것이 적절합니다.


결론

Redis가 기본 설정 상태이거나 파일 저장 옵션(RDB, AOF)을 활성화하지 않은 경우:

  • Redis는 재부팅 시 데이터를 복원하지 않으며, 모든 데이터는 사라집니다.
  • 영구적으로 데이터를 저장하려면 RDB 또는 AOF 설정을 활성화해야 합니다.

Redis의 영구 저장 여부는 사용 목적에 따라 결정해야 하며, 일반적으로 캐시 용도라면 데이터 소멸이 큰 문제가 되지 않습니다.



질문)
"RDB 파일(dump.rdb)은 Redis 서버 종료 후 재시작 시 데이터를 복원합니다." 위의 말은 리부팅후에 자동으로 복원한다는 의미인가요?

답변)

네, 맞습니다! **Redis의 RDB 파일(dump.rdb)**은 서버가 재시작될 때 자동으로 로드되어 데이터를 복원합니다.


RDB 파일의 동작 방식

  1. RDB 스냅샷 저장
    Redis는 save 설정에 따라 메모리 상태를 주기적으로 스냅샷으로 저장합니다. 이 데이터는 디스크에 저장된 dump.rdb 파일에 기록됩니다.
  2. Redis 서버 종료
    Redis가 정상적으로 종료되면 마지막으로 저장된 RDB 파일(dump.rdb)이 디스크에 유지됩니다.
  3. Redis 서버 재시작
    Redis가 다시 시작되면, 설정된 데이터 디렉토리(기본값: /var/lib/redis/)에서 dump.rdb 파일을 자동으로 읽어 메모리에 로드합니다. 이 과정에서 저장된 데이터가 복원됩니다.

자동 복원 확인 방법

  • RDB가 활성화되어 있는 경우, 서버를 재시작하면 데이터가 자동으로 복원됩니다. 이를 확인하려면 다음을 테스트해보세요:

1. 데이터 저장 및 확인

 
redis-cli SET mykey "myvalue" redis-cli GET mykey # 출력: "myvalue"

2. Redis 서버 재시작

Redis 서버를 재시작합니다:

sudo systemctl restart redis

3. 데이터 확인

다시 데이터를 확인합니다:

redis-cli GET mykey # 출력: "myvalue" (복원됨)

자동 복원의 전제 조건

  • RDB 저장이 활성화되어야 함
    redis.conf에서 save 옵션이 설정되어 있어야 합니다. 예를 들어:
  •  
    save 900 1 # 15분 동안 1개 이상의 키가 변경되면 저장 save 300 10 # 5분 동안 10개 이상의 키가 변경되면 저장 save 60 10000 # 1분 동안 10,000개 이상의 키가 변경되면 저장 dbfilename dump.rdb dir /path/to/directory
  • RDB 파일(dump.rdb)이 손상되지 않아야 함
    RDB 파일이 Redis 데이터 디렉토리에 있고 손상되지 않았을 경우에만 데이터가 복원됩니다.

주의사항

  1. 비정상 종료 시 데이터 손실 가능성
    Redis가 강제로 종료되거나 비정상적으로 종료될 경우, 마지막 RDB 스냅샷 이후의 데이터는 손실될 수 있습니다.
    이런 경우 데이터 영구성을 더 강화하려면 **AOF(Append-Only File)**을 사용하는 것이 좋습니다.
  2. RDB 파일 경로 확인
    RDB 파일이 저장되는 경로는 redis.conf의 dir 설정에 따라 다릅니다. 기본값은 /var/lib/redis/입니다. 설정을 확인하려면:
  3.  
    redis-cli CONFIG GET dir redis-cli CONFIG GET dbfilename

결론

  • RDB 파일이 제대로 설정되어 있다면, Redis 서버가 재시작될 때 데이터를 자동으로 복원합니다.
  • 데이터 복원이 실패한다면 RDB 설정을 확인하고, 파일 손상 여부를 점검해야 합니다.

Redis는 데이터베이스, 캐시 및 메시지 브로커로 사용되며, 메모리에 데이터를 저장하지만 파일에 데이터를 영구적으로 저장하도록 구성할 수도 있습니다.

C#에서 Redis를 사용하려면 StackExchange.Redis 라이브러리를 활용할 수 있습니다.

Redis의 데이터 영구성은 두 가지 주요 메커니즘으로 지원됩니다:

  1. RDB 스냅샷: 특정 간격마다 데이터를 디스크에 저장.
  2. AOF(Append-Only File): 모든 쓰기 작업을 로그로 기록.

아래는 Redis 데이터를 파일로 저장하고 다시 읽어오는 과정을 C#으로 구현하는 예제입니다.


1. Redis 서버 설정

Redis의 redis.conf 파일에서 다음 설정을 확인하거나 수정하세요:

  • RDB 스냅샷 설정:
     
    save 900 1 # 900초(15분) 동안 1개 이상의 키가 변경되었을 때 스냅샷 저장 save 300 10 save 60 10000
  • AOF 활성화:
     
    appendonly yes

Redis 서버가 데이터를 디스크에 저장하도록 설정되어야 합니다.


2. C# 코드 작성

C# 코드에서는 StackExchange.Redis 라이브러리를 사용하여 Redis와 상호작용합니다.

using System;
using StackExchange.Redis;
using Systehttp://m.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // Redis 서버 연결
        var redisConnectionString = "localhost"; // Redis 서버 주소
        var redis = ConnectionMultiplexer.Connect(redisConnectionString);
        IDatabase db = redis.GetDatabase();

        // 1. 데이터 저장
        Console.WriteLine("Saving data to Redis...");
        await db.StringSetAsync("key1", "value1");
        await db.StringSetAsync("key2", "value2");
        Console.WriteLine("Data saved!");

        // 2. Redis에 저장된 데이터 확인
        Console.WriteLine("Reading data from Redis...");
        string value1 = await db.StringGetAsync("key1");
        string value2 = await db.StringGetAsync("key2");
        Console.WriteLine($"key1: {value1}");
        Console.WriteLine($"key2: {value2}");

        // 3. Redis의 데이터를 파일로 저장(RDB 또는 AOF는 Redis 서버에서 수행)
        Console.WriteLine("Triggering Redis SAVE operation...");
        var server = redis.GetServer(redisConnectionString, 6379);
        server.Save(SaveType.Foreground);
        Console.WriteLine("Data saved to disk!");

        // 4. Redis 서버를 재시작하면 데이터 복원 확인 가능
        Console.WriteLine("Restart Redis server and verify the data persistence.");

        redis.Dispose();
    }
}
 

3. 예제 실행 순서

  1. Redis 서버가 실행 중인지 확인하고, RDB/AOF 설정을 활성화합니다.
  2. 위 코드를 실행하여 데이터를 Redis에 저장하고 SAVE 명령으로 디스크에 기록합니다.
  3. Redis 서버를 재시작한 뒤 데이터를 다시 읽어와 복원되었는지 확인합니다.

4. 참고 사항

  • server.Save(SaveType.Foreground)는 Redis 서버의 데이터를 디스크에 저장하도록 강제로 트리거합니다. (RDB 방식)
  • AOF 방식은 데이터 변경 시 자동으로 기록되며, 이를 코드에서 명시적으로 호출할 필요는 없습니다.
  • 복구된 데이터를 확인하려면 Redis 서버를 종료한 후 재시작하고, 기존 데이터를 읽어옵니다.

Redis의 영구성 설정과 StackExchange.Redis 라이브러리를 조합하면 안정적으로 데이터를 저장하고 복원할 수 있습니다.

 
Newtonsoft.Json은 JSON 데이터를 처리하기 위한 인기 있는 C# 라이브러리입니다. 이를 사용하면 JSON 데이터를 쉽게 직렬화(Serialization) 및 역직렬화(Deserialization)할 수 있습니다.

1. 패키지 설치

 
dotnet add package Newtonsoft.Json

2. 사용 예제

아래는 Newtonsoft.Json을 사용하여 객체를 JSON 문자열로 변환(직렬화)하고, JSON 문자열을 객체로 변환(역직렬화)하는 간단한 예제입니다.

2.1 코드 예제

 
using System;
using Newtonsoft.Json;

namespace NewtonsoftJsonExample
{
    // Sample class
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string[] Hobbies { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // 1. 객체를 JSON으로 직렬화
            var person = new Person
            {
                Name = "John Doe",
                Age = 30,
                Hobbies = new[] { "Reading", "Traveling", "Gaming" }
            };

            string json = JsonConvert.SerializeObject(person, Formatting.Indented);
            Console.WriteLine("Serialized JSON:");
            Console.WriteLine(json);

            // 2. JSON 문자열을 객체로 역직렬화
            string jsonString = @"{
                ""Name"": ""Jane Smith"",
                ""Age"": 25,
                ""Hobbies"": [""Cooking"", ""Hiking""]
            }";

            var deserializedPerson = JsonConvert.DeserializeObject<Person>(jsonString);
            Console.WriteLine("\nDeserialized Object:");
            Console.WriteLine($"Name: {deserializedPerson.Name}");
            Console.WriteLine($"Age: {deserializedPerson.Age}");
            Console.WriteLine($"Hobbies: {string.Join(", ", deserializedPerson.Hobbies)}");
        }
    }
}
 

3. 예제 출력

 
Serialized JSON: { "Name": "John Doe", "Age": 30, "Hobbies": [ "Reading", "Traveling", "Gaming" ] } Deserialized Object: Name: Jane Smith Age: 25 Hobbies: Cooking, Hiking

4. 주요 메서드

  • JsonConvert.SerializeObject(object, Formatting)
    객체를 JSON 문자열로 변환합니다.
    Formatting.Indented를 사용하면 보기 좋은 포맷으로 JSON을 출력합니다.
  • JsonConvert.DeserializeObject<T>(string)
    JSON 문자열을 지정된 타입의 객체로 변환합니다.

5. 추가 사용 예제

5.1 JSON 데이터에서 특정 키값 추출

using Newtonsoft.Json.Linq;

string json = @"{ 'Name': 'Alice', 'Age': 22 }";
var jsonObject = JObject.Parse(json);

string name = jsonObject["Name"]?.ToString();
int age = (int)jsonObject["Age"];
Console.WriteLine($"Name: {name}, Age: {age}");
 

5.2 Dictionary로 JSON 처리

using System.Collections.Generic;

string jsonString = @"{ 'Key1': 'Value1', 'Key2': 'Value2' }";
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonString);

foreach (var kvp in dictionary)
{
    Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
 

Newtonsoft.Json은 유연하고 강력한 JSON 처리 라이브러리로, 다양한 JSON 형식과 작업을 지원합니다.

 

Redis의 데이터를 JSON 형식으로 저장하고, 이를 파일에 저장한 뒤 다시 읽어오는 C# 예제를 작성하겠습니다.
이 작업은 Newtonsoft.Json과 StackExchange.Redis를 조합하여 수행할 수 있습니다.


1. 패키지 설치

 
dotnet add package StackExchange.Redis
dotnet add package Newtonsoft.Json

2. 코드 예제

아래는 Redis 데이터를 JSON 형식으로 저장하고 파일에 저장한 뒤, 파일에서 다시 읽어서 Redis에 복원하는 예제입니다.

using System;
using System.IO;
using Systehttp://m.Threading.Tasks;
using StackExchange.Redis;
using Newtonsoft.Json;

namespace RedisJsonExample
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // Redis 연결
            var redisConnectionString = "localhost"; // Redis 서버 주소
            var redis = ConnectionMultiplexer.Connect(redisConnectionString);
            IDatabase db = redis.GetDatabase();

            // Redis 데이터 저장
            Console.WriteLine("Saving data to Redis...");
            await db.StringSetAsync("key1", "value1");
            await db.StringSetAsync("key2", "value2");
            await db.HashSetAsync("hash1", new HashEntry[] {
                new HashEntry("field1", "valueA"),
                new HashEntry("field2", "valueB")
            });
            Console.WriteLine("Data saved to Redis!");

            // Redis 데이터 읽기
            Console.WriteLine("Reading data from Redis...");
            var data = new
            {
                Key1 = await db.StringGetAsync("key1"),
                Key2 = await db.StringGetAsync("key2"),
                Hash1 = await db.HashGetAllAsync("hash1")
            };

            // 데이터를 JSON으로 직렬화
            string json = JsonConvert.SerializeObject(data, Formatting.Indented);
            Console.WriteLine("Serialized JSON:");
            Console.WriteLine(json);

            // JSON 파일로 저장
            string filePath = "redis_data.json";
            await File.WriteAllTextAsync(filePath, json);
            Console.WriteLine($"Data saved to file: {filePath}");

            // JSON 파일에서 데이터 읽기
            Console.WriteLine("\nReading data from file...");
            string jsonFromFile = await File.ReadAllTextAsync(filePath);
            var deserializedData = JsonConvert.DeserializeObject<dynamic>(jsonFromFile);
            Console.WriteLine("Deserialized Data:");
            Console.WriteLine(jsonFromFile);

            // Redis에 데이터 복원
            Console.WriteLine("\nRestoring data to Redis...");
            await db.StringSetAsync("key1", (string)deserializedData.Key1);
            await db.StringSetAsync("key2", (string)deserializedData.Key2);

            foreach (var hashEntry in deserializedData.Hash1)
            {
                await db.HashSetAsync("hash1", (string)hashEntry.Name, (string)hashEntry.Value);
            }

            Console.WriteLine("Data restored to Redis!");

            redis.Dispose();
        }
    }
}
 

3. 코드 설명

  1. Redis 데이터 저장
    • StringSetAsync와 HashSetAsync를 사용하여 데이터를 Redis에 저장합니다.
  2. JSON으로 직렬화
    • Redis에서 데이터를 가져온 뒤 JsonConvert.SerializeObject를 사용하여 JSON으로 직렬화합니다.
  3. 파일로 저장
    • File.WriteAllTextAsync를 사용하여 JSON 데이터를 파일에 저장합니다.
  4. 파일에서 읽기 및 복원
    • File.ReadAllTextAsync로 JSON 데이터를 읽어온 뒤, 이를 JsonConvert.DeserializeObject로 다시 역직렬화하여 객체로 변환합니다.
    • 데이터를 Redis에 복원합니다.

4. 예제 실행 결과

Redis에 저장된 데이터:

 
key1: value1 key2: value2 hash1: { field1: valueA, field2: valueB }

파일에 저장된 JSON:

 
{ "Key1": "value1", "Key2": "value2", "Hash1": [ { "Name": "field1", "Value": "valueA" }, { "Name": "field2", "Value": "valueB" } ] }

Redis로 복원된 데이터:

  • key1, key2, hash1가 원래 데이터와 동일하게 복원됩니다.

이 방식으로 Redis 데이터를 JSON 파일로 저장하고 복원할 수 있습니다. Newtonsoft.Json을 사용하여 데이터 직렬화 및 역직렬화를 처리하며, Redis 데이터 백업 및 복원 시 유용합니다.

 

Redis에서 특정 파일명을 지정하여 데이터를 저장하거나 복원하려면 Redis 서버 설정 파일(redis.conf) 또는 명령줄 옵션을 사용하여 파일명을 지정할 수 있습니다. Redis는 데이터의 영구 저장을 위해 RDB 스냅샷AOF(Append-Only File) 방식을 지원합니다.


1. Redis 설정 파일(redis.conf)에서 파일명 지정

Redis의 설정 파일을 수정하여 데이터 저장 파일명을 지정할 수 있습니다.

RDB 스냅샷 파일명 지정

RDB 방식은 특정 시점의 데이터를 디스크에 저장합니다. 설정 파일에서 dbfilename 값을 변경합니다:

 
dbfilename dump.rdb dir /path/to/directory
  • dbfilename: RDB 스냅샷 파일명 (예: mycustomfile.rdb)
  • dir: 파일이 저장될 디렉토리 경로

AOF(Append-Only File) 파일명 지정

AOF 방식은 모든 쓰기 작업을 로그 파일로 기록합니다:

 
appendfilename "appendonly.aof" dir /path/to/directory

2. 명령줄에서 파일명 지정

Redis 서버를 실행할 때 명령줄에서 파일명을 지정할 수도 있습니다:

 
redis-server --dbfilename mycustomfile.rdb --dir /path/to/directory

3. C#에서 특정 파일명을 사용한 Redis 데이터 저장 및 복원

Redis 서버 설정을 이용해 특정 파일명을 지정했다면, 서버 측에서 파일 관리가 이루어집니다. 그러나 C# 코드에서 직접 Redis 데이터를 읽어 특정 파일에 저장하거나 복원하려면 StackExchange.Redis와 Newtonsoft.Json을 사용할 수 있습니다.

C# 예제

using System;
using System.IO;
using Systehttp://m.Threading.Tasks;
using StackExchange.Redis;
using Newtonsoft.Json;

namespace RedisFileExample
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // Redis 연결
            var redisConnectionString = "localhost";
            var redis = ConnectionMultiplexer.Connect(redisConnectionString);
            IDatabase db = redis.GetDatabase();

            // Redis 데이터 저장
            await db.StringSetAsync("key1", "value1");
            await db.StringSetAsync("key2", "value2");

            // 특정 파일에 저장
            string filePath = "custom_redis_data.json";
            var data = new
            {
                Key1 = await db.StringGetAsync("key1"),
                Key2 = await db.StringGetAsync("key2")
            };
            string json = JsonConvert.SerializeObject(data, Formatting.Indented);
            await File.WriteAllTextAsync(filePath, json);
            Console.WriteLine($"Data saved to file: {filePath}");

            // 파일에서 데이터 읽어 Redis 복원
            string jsonFromFile = await File.ReadAllTextAsync(filePath);
            var deserializedData = JsonConvert.DeserializeObject<dynamic>(jsonFromFile);
            await db.StringSetAsync("key1", (string)deserializedData.Key1);
            await db.StringSetAsync("key2", (string)deserializedData.Key2);

            Console.WriteLine("Data restored to Redis!");
            redis.Dispose();
        }
    }
}
 

4. 데이터 복원 시 파일 경로 지정

Redis의 redis-cli를 사용하여 데이터를 특정 파일에서 복원할 수도 있습니다.

RDB 복원

  • Redis 서버를 종료한 뒤, 원하는 RDB 파일을 Redis 데이터 디렉토리에 복사하고 다시 시작합니다:
 
cp /path/to/mycustomfile.rdb /var/lib/redis/dump.rdb redis-server

AOF 복원

  • Redis 서버를 종료한 뒤, AOF 파일을 지정된 디렉토리에 복사하고 다시 시작합니다:
 
cp /path/to/appendonly.aof /var/lib/redis/appendonly.aof redis-server

5. 중요 참고사항

  • Redis 서버 설정에서 지정한 파일명은 자동으로 사용되며,
    코드에서 Redis 데이터를 백업하거나 복원할 때 파일명을 명시적으로 지정해야 합니다.
  • RDB와 AOF는 각각 장단점이 있으므로, 필요에 따라 둘 중 하나를 선택하거나 둘 다 활성화할 수 있습니다.

Redis 서버 설정 및 백업/복원 스크립트를 적절히 활용하면 특정 파일명을 이용한 데이터 관리가 가능합니다.

Caution) 중요한 데이타의 경우에 Redis 서버 설정 및 백업/복원 스크립트 작성해서, ReBoot시에 대비한다.


C#의 Queue<T>는 기본적으로 동적 크기를 가지며, 사용자가 삽입하는 데이터의 양에 따라 용량이 자동으로 조정됩니다.

Queue<T>의 용량과 동작에 대한 주요 사항은 다음과 같습니다:

1. 초기 용량

  • Queue<T>는 기본적으로 내부 배열을 사용하여 데이터를 저장합니다.
  • 초기 용량은 0입니다. 첫 번째 항목이 추가되면 내부적으로 기본 크기의 배열이 생성됩니다.

2. 자동 확장

  • Queue<T>에 항목을 추가할 때 현재 용량이 부족하면 내부적으로 배열의 크기가 자동으로 증가합니다.
  • 용량 증가는 일반적으로 현재 용량의 두 배로 이루어져, 효율적으로 동작하도록 설계되어 있습니다.

3. 최대 용량

  • Queue<T>의 최대 용량은 시스템의 가용 메모리에 의해 제한됩니다.
  • 64비트 애플리케이션에서는 매우 큰 크기의 큐를 만들 수 있지만, 시스템 메모리에 의존하기 때문에 메모리가 부족해질 수 있습니다.

4. 참고 사항

  • recvQueue는 Queue<byte[]> 타입이므로, 큐에 추가되는 항목은 byte[] 배열입니다.
  • 각 byte[]의 크기는 배열의 길이에 따라 다릅니다. 따라서 큐가 차지하는 전체 메모리는 큐에 들어있는 byte[]들의 개수와 각 배열의 크기에 의해 결정됩니다.

용량 확인 및 관리 방법

  1. 현재 저장된 항목의 수
  2.  
    코드 복사
    int itemCount = recvQueue.Count;
  3. csharp
  4. 전체 메모리 사용량 확인 (예: 디버깅용)
    • 각 byte[] 배열의 길이를 합산하면 대략적인 메모리 사용량을 계산할 수 있습니다:
      csharp
      코드 복사
      long totalMemoryUsage = recvQueue.Sum(item => item.Length);
  5. 명시적으로 초기 용량 설정
    • 필요 시, Queue<T> 생성 시 초기 용량을 설정할 수 있습니다:
      csharp
      코드 복사
      private Queue<byte[]> recvQueue = new Queue<byte[]>(initialCapacity);

결론

recvQueue의 용량은 동적으로 증가하며, 최대 용량은 시스템 메모리에 의해 제한됩니다. 만약 큐에 들어가는 byte[] 데이터가 매우 크거나 많다면, 메모리 사용량을 주의 깊게 모니터링하는 것이 좋습니다.

i5-3570 CPU (3.40GHz) / i5-10400 CPU (2.9GHz) 성능에 따른 모델변경

하드웨어 성능때문에 TCP패킷처리 못할경우, 아키텍쳐를 변경해서 처리가능

1번 장비에서 처리하지 못할경우에는 아키텍쳐 모델을 변경해본다.
현재 2기가에 해당되는 레디스메모리를 활용하면 큐와 같은 역할을 담당할수 있기때문에 레디스로 일단 전송후에 다른쓰래드에서 레디스에서 데이타를 꺼내서 처리하는 방법을 사용한결과 장비성능이 낮더라도 모두 처리가 가능할수 있음을 알수 있다.



1. Intel(R) Core(TM) i5-3570 CPU @ 3.40GHz


ARCHITECTURE MODEL1 : FAIL
ARCHITECTURE MODEL2 : SUCC

2. 인텔 / 코어i5-10세대 / 코멧레이크S / i5-10400 (2.9GHz) 

ARCHITECTURE MODEL1 : SUCC
ARCHITECTURE MODEL2 : SUCC

-TCT ESTATE DATA SEND
-REDIS MONITOR

-REDIS.TICK.SERVER
-DEBUGGER

메모리 정렬(alignment) 및 **패딩(padding)**과 관련이 있습니다. C 언어에서 구조체는 멤버들을 특정 규칙에 맞춰 메모리 상에 배치합니다.

1. 메모리 정렬 (Alignment)

C 언어에서는 메모리 정렬(alignment)이라는 개념이 존재합니다. 각 데이터 타입은 특정 바이트 경계에 맞춰 메모리에서 정렬됩니다. 이 정렬은 CPU의 성능과 관련이 있으며, 데이터 접근을 최적화하려는 목적이 있습니다.

  • int 타입은 보통 4바이트 경계에 정렬되어야 합니다.
  • char 타입은 1바이트 크기이므로 1바이트 경계에 정렬됩니다.

따라서, C 언어에서 struct 내부에 여러 타입의 변수가 있을 때, 각 타입이 그에 맞는 정렬을 따르게 되며, 필요할 경우 패딩을 추가하여 정렬 규칙을 맞춥니다.

2. 패딩 (Padding)

패딩은 정렬 규칙을 맞추기 위해 자동으로 추가되는 메모리 공간입니다. C 언어에서는 메모리 정렬을 맞추기 위해, 데이터 타입의 크기가 해당 타입의 정렬 기준에 맞지 않으면 추가적인 바이트가 삽입됩니다.

예시:

struct NM { int age; // 4 bytes char name; // 1 byte };
  • int는 보통 4바이트 정렬을 요구합니다. age는 4바이트 경계에 맞게 정렬됩니다.
  • char는 1바이트 크기이고, 정렬에 특별한 제한이 없습니다. 하지만 name이 끝나고 난 후, 구조체의 크기가 4바이트 배수로 정렬되어야 할 수 있습니다. 즉, 구조체의 전체 크기가 4바이트 배수가 되도록 패딩이 추가됩니다.

구체적으로 설명하면:

  • age는 4바이트를 차지하고, 그 뒤에 1바이트 크기의 name이 옵니다. 그러면 name 뒤에 3바이트가 패딩으로 추가되어야 전체 크기가 4의 배수가 되도록 맞춰집니다.

따라서, 구조체 NM는:

  • age (4 bytes)
  • name (1 byte)
  • 패딩 (3 bytes)

이렇게 총 4 + 1 + 3 = 8바이트가 됩니다. 즉, sizeof(struct aaa)는 8이 됩니다.

요약:

sizeof(struct NM)가 4가 아니라 8인 이유는 int 타입의 정렬 요구사항과 구조체의 메모리 정렬 규칙에 의해 패딩이 추가되기 때문입니다.

3. 다른 언어에서의 메모리 정렬 및 패딩

C++:

C++도 C 언어와 비슷한 방식으로 구조체 내에서 메모리 정렬을 처리합니다. 따라서 C++에서도 같은 규칙을 따라 메모리 정렬을 맞추고, 패딩을 추가하여 구조체의 크기를 결정합니다.

Java:

Java는 기본적으로 32비트64비트 아키텍처에서 다른 메모리 정렬 방식을 사용합니다. Java에서는 내부적으로 객체를 정렬하는 방식이 다르고, int는 기본적으로 4바이트로 정렬됩니다. 그러나 Java는 메모리 정렬을 크게 신경 쓰지 않으며, 내부적으로 JVM이 최적화합니다. Java의 구조체는 사실 클래스 형태로 구현되며, 이 클래스는 JVM의 메모리 관리 방식을 따릅니다. Java에서는 일반적으로 sizeof를 사용하지 않지만, Object 크기는 JVM이 관리합니다.

Python:

Python은 C와 같은 시스템 수준 언어가 아니므로 구조체의 크기를 sizeof와 같이 직접적으로 계산할 필요가 없습니다. 그러나 struct 모듈을 사용하면 바이트 단위로 데이터를 처리할 수 있으며, 이 때는 C와 유사한 방식으로 정렬과 패딩을 처리합니다. Python에서 struct 모듈을 사용하여 C 스타일의 구조체를 만들 때도 메모리 정렬이 자동으로 적용됩니다.

Go:

Go 언어는 C와 유사한 메모리 정렬 규칙을 따르지만, 구조체의 각 필드는 8바이트 정렬을 기본으로 하며, Go는 이를 자동으로 관리합니다. Go에서 unsafe.Sizeof()를 사용하여 구조체 크기를 확인할 수 있습니다.

Rust:

Rust도 C와 유사하게 메모리 정렬을 자동으로 처리합니다. #[repr(C)] 어트리뷰트를 사용하여 C와 같은 방식으로 메모리 레이아웃을 강제할 수 있으며, 기본적으로 1, 2, 4, 8 등의 크기 단위로 정렬합니다. Rust에서는 std::mem::size_of::<T>()를 사용하여 구조체 크기를 확인할 수 있습니다.

4. 정리

C에서 sizeof(struct NM)가 4가 아니라 8인 이유는 메모리 정렬패딩 때문입니다. int는 4바이트 경계에서 정렬되어야 하고, 그 뒤에 위치한 char는 1바이트만 차지하지만, 구조체 전체 크기를 4의 배수로 맞추기 위해 추가적인 3바이트가 패딩으로 삽입됩니다.

다른 언어들에서도 비슷한 방식으로 메모리 정렬과 패딩이 적용되며, 그 방식은 언어의 구현과 메모리 관리 방식에 따라 다를 수 있습니다.

Redis에서 시스템에서 사용할 수 있는 최대 메모리를 확인하려면, INFO MEMORY 명령어와 함께 maxmemory 설정을 통해 Redis가 할당할 수 있는 최대 메모리 용량을 확인할 수 있습니다.

1. maxmemory 설정 확인

Redis는 메모리 사용에 제한을 둘 수 있는 설정(maxmemory)이 있으며, 이 값을 확인하려면 CONFIG GET 명령어를 사용합니다.

redis-cli CONFIG GET maxmemory

이 명령어는 Redis 서버가 할당할 수 있는 최대 메모리의 값을 반환합니다. 예를 들어, maxmemory가 설정되지 않은 경우 0이 반환되며, 이는 제한 없이 Redis가 사용할 수 있음을 의미합니다.

예시:

redis-cli CONFIG GET maxmemory

출력 예시:

1) "maxmemory" 2) "1073741824"

위 예시에서는 maxmemory가 1073741824 (1GB)로 설정되어 있음을 나타냅니다. 만약 maxmemory가 0이라면 Redis는 메모리에 제한 없이 사용할 수 있습니다.

2. 전체 시스템 메모리 확인

Redis가 할당할 수 있는 최대 메모리는 운영 체제에서 Redis 프로세스에 할당된 메모리와도 관련이 있습니다. INFO MEMORY 명령어로 전체 시스템의 메모리 크기를 확인할 수 있습니다.

redis-cli INFO MEMORY

출력 예시:

# Memory used_memory:12345678 used_memory_human:11.77M used_memory_rss:98765432 used_memory_peak:23456789 mem_fragmentation_ratio:1.78 total_system_memory:8388608000

위 예시에서 **total_system_memory**는 시스템 전체 메모리 용량을 나타내며, 이는 Redis가 실행되고 있는 서버의 전체 RAM 용량입니다.

요약:

  • Redis가 사용할 수 있는 최대 메모리는 CONFIG GET maxmemory 명령어로 확인할 수 있습니다.
  • 전체 시스템 메모리는 INFO MEMORY 명령어에서 total_system_memory 항목으로 확인할 수 있습니다.
  • maxmemory 설정이 0인 경우 Redis는 시스템 전체 메모리의 사용에 제한이 없습니다.



My Case)

C:\Users\xterm>redis-cli CONFIG GET maxmemory
1) "maxmemory"
2) "1572864000"

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:9875616
used_memory_human:9.42M
used_memory_rss:9816928
used_memory_peak:9875616
used_memory_peak_human:9.42M
used_memory_lua:36864
mem_fragmentation_ratio:0.99
mem_allocator:jemalloc-3.6.0
 
C:\Users\xterm>redis-cli CONFIG GET maxmemory
1) "maxmemory"
2) "1572864000"
 

1 메가바이트(MB)는 1,048,576 바이트입니다. 따라서:

1572864000 bytes÷1048576=1500 MB1572864000 \, \text{bytes} \div 1048576 = 1500 \, \text{MB}

따라서, 1572864000 바이트는 **1500 메가바이트(MB)**입니다.

Redis에 할당된 전체 메모리 용량을 확인하려면 INFO MEMORY 명령어를 사용하여 메모리 관련 정보를 확인할 수 있습니다. 이 명령어는 Redis 서버의 메모리 사용 상태를 종합적으로 보여줍니다.

INFO MEMORY 명령어

redis-cli INFO MEMORY

이 명령어를 실행하면 Redis 서버의 메모리 상태에 대한 상세한 정보를 얻을 수 있습니다. 그 중에서 전체 메모리와 관련된 정보는 다음과 같습니다:

주요 항목:

  • used_memory: Redis가 현재 사용 중인 메모리의 총량 (바이트 단위)
  • used_memory_human: 사람이 읽기 쉬운 형식으로 표시된 사용 중인 메모리 (예: 10.5M, 2.3G 등)
  • used_memory_rss: Redis 프로세스가 운영 체제에서 실제로 할당받은 메모리 (Resident Set Size)
  • used_memory_peak: Redis가 사용한 최대 메모리
  • total_system_memory: Redis가 실행되고 있는 시스템의 전체 물리적 메모리 (이 값은 시스템의 RAM 크기를 나타냄)

예시:

 
C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:930832
used_memory_human:909.02K
used_memory_rss:872960
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:0.94
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:1049312
used_memory_human:1.00M
used_memory_rss:1049152
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:1.00
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:2683728
used_memory_human:2.56M
used_memory_rss:2624288
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:0.98
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:3072672
used_memory_human:2.93M
used_memory_rss:3013984
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:0.98
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:3052144
used_memory_human:2.91M
used_memory_rss:3051984
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:1.00
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:3063568
used_memory_human:2.92M
used_memory_rss:3063472
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:1.00
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:3106944
used_memory_human:2.96M
used_memory_rss:3048256
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:0.98
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:3116048
used_memory_human:2.97M
used_memory_rss:3057360
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:0.98
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:3124208
used_memory_human:2.98M
used_memory_rss:3065520
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:0.98
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:3135760
used_memory_human:2.99M
used_memory_rss:3077072
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:0.98
mem_allocator:jemalloc-3.6.0

C:\Users\xterm>redis-cli INFO MEMORY
# Memory
used_memory:4905536
used_memory_human:4.68M
used_memory_rss:4846848
used_memory_peak:7590400
used_memory_peak_human:7.24M
used_memory_lua:36864
mem_fragmentation_ratio:0.99
mem_allocator:jemalloc-3.6.0

주요 항목 설명:

  1. used_memory: Redis가 현재 실제로 사용하고 있는 메모리의 크기입니다.
  2. used_memory_rss: Redis 프로세스가 운영 체제에서 실제로 할당받은 메모리입니다. 이는 used_memory보다 많을 수 있으며, 메모리 단편화로 인해 실제 할당된 메모리 공간이 더 크면 used_memory_rss가 커집니다.
  3. total_system_memory: 시스템의 전체 물리적 메모리 크기입니다. 예를 들어, 8388608000은 약 8GB의 메모리입니다.

used_memory / used_memory_rss 둘은 서로 비례해서 늘기도 하고, 줄기도 한다.

INFO MEMORY 명령어를 사용하면 전체 Redis 메모리 상태를 자세히 알 수 있으며, 특히 시스템 전체 메모리와 Redis에서 사용 중인 메모리를 비교하여 시스템 리소스가 어떻게 사용되고 있는지 파악할 수 있습니다.

+ Recent posts