질문)
이탈리아와 한국에 Peer to Peer로 1G byte의 데이타를 보낼려면 어느정도 시간이 소요되나요?

답변)

한국 ↔ 이탈리아 간에 1기가바이트(GB) 데이터를 보내는 데 걸리는 시간은, 물리적인 거리보다 **실제 사용 가능한 네트워크 대역폭(속도)**이 훨씬 더 중요한 요소입니다.

아래는 여러 조건을 고려한 실제 전송 시간 분석입니다.


✅ 전송시간 계산의 기본 공식

복사편집
전송시간(초) = 전송할 데이터 크기 / 실질적인 전송 속도
  • 1GB = 8,000 Megabits (1 Byte = 8 bits)
  • 실질 전송 속도는 네트워크 품질, 혼잡도, TCP 설정, 거리 지연 등으로 인해 이론 속도보다 낮게 나옴

✅ 세 가지 가정 하에 분석

▶ 가정 1: 일반 인터넷 환경 (약 100Mbps)

  • 전송 속도: 100Mbps
  • 전송 시간:
  • 복사편집
    8,000Mb ÷ 100Mbps = 80초

🔹 대략 1분 20초


▶ 가정 2: 고속 회선 환경 (약 500Mbps)

  • 전송 속도: 500Mbps
  • 전송 시간:
  • 복사편집
    8,000Mb ÷ 500Mbps = 16초

🔹 대략 16초


▶ 가정 3: 아주 좋은 환경 (1Gbps 대역폭, 최적의 경로)

  • 전송 속도: 1,000Mbps = 1Gbps
  • 전송 시간:
  • 복사편집
    8,000Mb ÷ 1,000Mbps = 8초

🔹 이론적으로는 8초
(하지만 TCP 전송 지연, 패킷 재전송, 혼잡 제어로 인해 실제로는 10~30초 이상 걸릴 수 있음)


✅ 왜 실제로 더 오래 걸리는가?

1. 🌍 거리로 인한 지연 시간(Latency)

  • 앞서 언급한 대로 한국 ↔ 이탈리아 RTT: 약 250ms
  • TCP는 느린 시작(Slow Start), 혼잡 제어(Congestion Control)가 있어 처음부터 최대 속도를 내지 못함
  • RTT가 크면 윈도우 기반 전송 속도가 제약
    (이른바 Bandwidth-Delay Product의 영향을 받음)

2. 📉 패킷 손실 가능성

  • 대륙 간 전송은 보통 해저 케이블과 여러 ISP를 거침
  • 그 과정에서 손실이 발생하면, TCP는 속도를 줄이고 재전송

3. 🔐 암호화나 보안 프로토콜

  • VPN, TLS, WebRTC, NAT traversal 등은 전송 속도에 추가적인 오버헤드를 유발

✅ 요약

환경전송 속도예상 소요 시간 (1GB)
일반 인터넷 (100Mbps) 약 100Mbps 80초
고속 인터넷 (500Mbps) 약 500Mbps 16초
이상적인 환경 (1Gbps) 약 1Gbps 이론: 8초 / 현실: 10~30초
 

🔎 참고: Bandwidth-Delay Product 예시

  • RTT 250ms, Bandwidth 1Gbps일 때:
  • BDP = 1Gbps × 0.25s = 250Mb ≈ 31.25MB
  • → 한 번에 31.25MB만큼의 데이터를 "채워서" 보내야 최대 속도가 유지됨
  • TCP 윈도우 크기가 작거나 RTT가 크면 속도가 안 나옴

TCP와 IP 간략 설명

  • IP (Internet Protocol)
    네트워크에서 데이터를 목적지까지 "주소" 기반으로 전달하는 역할을 합니다.
    • IP는 데이터그램(패킷)을 네트워크를 통해 목적지 주소(IP 주소)로 라우팅합니다.
    • 하지만 IP는 단순히 패킷을 전달만 하고, 전달 보장이나 순서 보장 같은 신뢰성은 제공하지 않습니다.
  • TCP (Transmission Control Protocol)
    IP 위에서 동작하며, 신뢰성 있는 데이터 전송을 책임집니다.
    • 데이터가 순서대로 도착하는지, 중간에 손실되거나 중복되지 않는지 확인합니다.
    • 연결을 설정하고(3-way handshake), 에러 검출 및 재전송을 처리하며, 흐름 제어도 합니다.
    • 즉, IP의 단점을 보완해서 안정적인 통신을 가능하게 합니다.

왜 "TCP/IP"라고 표기할까?

  • TCP/IP는 사실 인터넷 프로토콜 스위트(Internet Protocol Suite), 즉 인터넷에서 데이터를 주고받기 위한 여러 프로토콜들의 묶음 이름이에요.
  • 이 중 가장 핵심적인 두 프로토콜이 TCP와 IP라서, 대표적으로 TCP와 IP를 "/"로 연결해 TCP/IP라고 부릅니다.
  • "/"는 "및(and)" 또는 "조합"을 의미하며, TCP와 IP가 서로 보완하며 같이 작동하기 때문에 붙이는 거죠.
  • 보통 IP만 써서 통신하는 경우도 있지만(예: UDP/IP), TCP와 IP가 같이 작동하는 경우가 가장 많아 대표적으로 TCP/IP라고 부르는 것입니다.

요약

  • IP: 데이터 전달 경로(주소 지정 및 라우팅) 담당
  • TCP: 데이터 전송 신뢰성 및 순서 보장 담당
  • TCP/IP: 인터넷 프로토콜 스위트 중 가장 중요한 두 프로토콜 조합을 의미

질문)
송신 측이 보낸 단위와 무관하게, 수신 측은 1035 byte, 789 byte, 2048 byte 등 임의의 크기로 데이터를 받을 수 있습니다. 따라서 수신 측에서는 메시지를 구분할 수 있는 명확한 기준 (예: 길이 헤더, 구분자 등) 을 반드시 사용해야 합니다.

TCP/IP 프로그램에서 헤더를 정의해서 사용하면 된다고 했는데, 심지어 헤더를 못받는 경우도 있을까요?

답변)

네, TCP/IP 통신에서 송신 측이 보낸 "헤더조차 수신하지 못하는 경우"도 충분히 발생할 수 있습니다. 이것은 TCP의 특성 때문입니다. 아래에서 그 이유를 설명드리겠습니다.


✅ TCP의 특성 요약

  • 스트림(Stream) 기반 프로토콜
  • 메시지 단위가 아니라 연속된 바이트 흐름으로 처리됨
  • recv()나 Read() 함수는 요청한 만큼만 받을 수 있다는 보장이 없음
    • 10바이트를 보냈다고 해서 한 번에 10바이트가 오지 않음
    • 3바이트, 4바이트, 3바이트 나눠서 도착할 수도 있음

❗헤더도 분할되어 수신될 수 있음

예를 들어, 다음과 같은 프로토콜을 정의했다고 가정합시다:

[헤더: 4바이트 - 메시지 길이 정보][본문: 길이만큼]

송신 측이 아래와 같이 전송했다고 해도:

// 예시) 총 4 + 1000 = 1004 bytes socket.Send(header); // 4바이트 socket.Send(body); // 1000바이트

수신 측에서는 recv() 호출 결과가 다음처럼 나뉠 수 있습니다:

호출 순서수신 바이트 수설명
첫 번째 2바이트 헤더 일부만 도착
두 번째 2바이트 헤더 나머지 수신
세 번째 512바이트 바디 일부 수신
네 번째 488바이트 바디 나머지 수신
 

즉, 헤더를 완전히 한 번에 받지 못하는 경우가 많고, 반드시 분리 처리해야 합니다.


✅ 해결 방법: 수신 버퍼에서 조립하는 구조 필요

1. 수신 루프 구현 (C# 예시)

int ReceiveFixedBytes(NetworkStream stream, byte[] buffer, int offset, int size)
{
    int totalReceived = 0;
    while (totalReceived < size)
    {
        int bytesRead = stream.Read(buffer, offset + totalReceived, size - totalReceived);
        if (bytesRead == 0)
            throw new Exception("Connection closed by remote host.");
        totalReceived += bytesRead;
    }
    return totalReceived;
}
 

2. 사용 예:

// Step 1: 헤더(예: 4바이트) 수신
byte[] headerBuffer = new byte[4];
ReceiveFixedBytes(stream, headerBuffer, 0, 4);
int bodyLength = BitConverter.ToInt32(headerBuffer, 0);

// Step 2: 바디 수신
byte[] bodyBuffer = new byte[bodyLength];
ReceiveFixedBytes(stream, bodyBuffer, 0, bodyLength);

🔒 결론

  • 헤더조차도 분할되어 수신될 수 있습니다. 이것이 TCP의 정상 동작입니다.
  • 따라서 수신 측은 '정확한 바이트 수만큼' 누적해서 읽는 방식으로 구현해야 합니다.
  • 수신 버퍼에서 헤더 → 바디 순으로 조립 방식 처리가 필수입니다.




질문)
송신프로그램이 데이타를 1000 byte 1000 byte 1000 byte 1000 byte 보내면, 수신프로그램이 1035 byte로 받을수도 있나요?

답변)

네, 수신 프로그램이 1035 byte로 받을 수도 있습니다.

이유는 다음과 같습니다:


🔧 TCP 통신의 특징 때문입니다

  • 송신 측이 1000 byte씩 나누어 send()하더라도,
    수신 측은 TCP의 스트림(Stream) 특성 때문에 그 데이터를 임의의 크기로 recv()하게 됩니다.

📌 자세히 설명하면:

  • TCP는 바이트 스트림 프로토콜입니다.
    즉, 데이터가 패킷 단위가 아니라 연속된 바이트 흐름으로 전달됩니다.
  • 송신 측이 보낸 1000 + 1000 + 1000 + 1000 = 4000 byte가
    네트워크 중간에서 합쳐지거나 잘려서 수신 측에 도달할 수 있습니다.
  • 수신 측이 recv(2048)처럼 호출하면, 운영체제가 커널 버퍼에 도착해 있는 가능한 만큼의 데이터를 한 번에 제공합니다.
    예:
    • 1035 byte가 도착해 있다면 → 1035 byte 반환
    • 950 byte만 도착해 있다면 → 950 byte 반환

✅ 결론:

  • 송신 측이 보낸 단위와 무관하게, 수신 측은 1035 byte, 789 byte, 2048 byte 등 임의의 크기로 데이터를 받을 수 있습니다.
  • 따라서 수신 측에서는 메시지를 구분할 수 있는 명확한 기준 (예: 길이 헤더, 구분자 등) 을 반드시 사용해야 합니다.

질문)
송신하는 프로그램은 한줄씩 읽어서 보내지만, 수신하는측에서는 한줄씩 받는다고 보장할수 없겠죠? 수신측의 서버상태에 따라서, 한줄, 두줄, 세줄, 네줄 혹은 그 이상의 줄을 받을수도 있겠죠?

답변)

네, 정확하게 이해하셨습니다.

TCP는 “스트림(흐름)” 기반 프로토콜이기 때문에, 송신 측이 줄 단위(Send(line + delimiter))로 보냈더라도 수신 측은 반드시 줄 단위로 받는다는 보장은 없습니다.


🔄 TCP 수신의 핵심 개념

  • TCP는 패킷을 보장된 순서로 “흐름(stream)” 형태로 전달합니다.
  • 이 흐름 속에서 수신 측은 네트워크 상태, OS 버퍼 상황, 수신 처리 타이밍 등에 따라:
    • 한 줄을 나눠서 여러 번 받을 수도 있고
    • 여러 줄이 한 번에 도착할 수도 있습니다.

📌 예시

송신 측:

text
복사편집
1st line + [0D 0A FF] 2nd line + [0D 0A FF]

수신 측 stream.Read() 호출 결과는 다음과 같이 될 수 있습니다:

  • 경우 1: 한 번 호출 → "1st line + 0D 0A FF + 2nd line + 0D 0A FF"
  • 경우 2: 두 번 호출 → "1st line + 0D", "0A FF + 2nd line + 0D 0A"
  • 경우 3: 세 번 호출 → "1st ", "line + 0D 0A FF", "2nd line + 0D 0A FF"
  • 등등...

✅ 따라서 수신 측에서는 반드시 해야 할 것

1. 바이트 버퍼 누적

  • 이전 Read에서 다 읽지 못한 데이터를 버퍼에 누적 유지해야 함

2. 패킷 구분자 기준으로 자르기

  • 0x0D 0x0A 0xFF 시퀀스를 기준으로 정확하게 잘라서 한 패킷 추출해야 함

3. 조각남 데이터 유지

  • 마지막 구분자 이후에 도달하지 못한 데이터는 다음 수신으로 이어서 누적

✅ 이 부분이 바로 List<byte> buffer + FindSeparator() 로직이 필요한 이유입니다.

앞서 작성한 HandleClient()의 이 부분이 그 역할을 하는 거죠:

while (true)
{
    int bytesRead = stream.Read(recvBuf, 0, recvBuf.Length);
    if (bytesRead == 0)
        break;

    for (int i = 0; i < bytesRead; i++)
        buffer.Add(recvBuf[i]);

    while (true)
    {
        int sepIndex = FindSeparator(buffer);
        if (sepIndex < 0)
            break;

        byte[] packet = buffer.GetRange(0, sepIndex).ToArray();
        buffer.RemoveRange(0, sepIndex + 3);  // 0x0D 0x0A 0xFF 제거

        string message = Encoding.ASCII.GetString(packet);
        Console.WriteLine($"[수신]: {message}");
    }
}

✅ 결론

맞습니다. TCP 수신 측에서는 한 줄씩 정확하게 들어온다는 보장을 할 수 없기 때문에, 반드시 **“패킷 구분자 기반 분리 및 누적 버퍼 처리”**가 필요합니다.




아래는 C#으로 작성된 파일 A0011.dat의 각 줄을 읽어, 각 줄 뒤에 0x0D 0x0A 0xFF 구분자를 붙여 TCP로 송신하는 프로그램입니다.

📌 요약

항목내용
인코딩 방식 Encoding.ASCII 사용하여 1바이트 문자로 정확하게 송신
줄 처리 방식 File.ReadLines()로 메모리 효율적으로 한 줄씩 처리
패킷 구분자 각 줄 끝에 [0x0D, 0x0A, 0xFF] 붙여 송신
예외 처리 연결 실패나 파일 문제 예외 처리 포함


📌 참고 사항

  • 파일 경로가 실행 파일과 같은 디렉토리에 있는 A0011.dat입니다.
  • 서버 IP/포트를 실제 환경에 맞게 변경하세요 (127.0.0.1:5000 은 로컬 테스트용).
  • 줄바꿈 없이 저장된 문자열도 정상적으로 송신됩니다.
  • 한 줄씩 0x0D 0x0A 0xFF를 끝에 붙여 거래소 송신 포맷을 모방합니다.

✅ 동작 개요

  • 텍스트 파일 A0011.dat을 한 줄씩 읽음
  • 각 줄을 Encoding.UTF8로 변환하여 TCP 서버로 송신
  • 각 라인의 끝에 0x0D 0x0A 0xFF 바이트를 붙여 송신
  • TCP 서버의 IP와 포트는 사용자가 설정 가능




recv_distribution.cs
0.00MB
send_distribution.cs
0.00MB

 

질문)
TCP/IP 프로그램에서, 송신하는측과 수신하는측이 반드시 존재해야 합니다. 거래소 정보분배는 echo를 받지 않고, 체결, 호가등의 데이타를 구분자를 이용해서 수신측에 송신합니다. 만일 수신측에서 서버의 문제로 서버프로그램이 죽었다면, 송신하는 프로그램은 데이타를 전달하다가 죽어버릴까요?
 

ChatGPT)
TCP/IP 프로그램에서 수신 측 서버가 죽었을 경우, 송신 측이 무조건 죽는 것은 아닙니다.
다만, 특정 조건에서는 송신 측 프로그램이
예외(Exception) 또는 오류 코드를 받고, 이에 대한 처리를 하지 않으면 죽을 수 있습니다.


✅ 기본 개념 정리

TCP는 연결 기반 프로토콜입니다. 즉,

  • 송신 측과 수신 측 간에 연결이 먼저 성립 (3-way handshake) 되어야 하고,
  • 이 연결을 통해 신뢰성 있는 데이터 전송이 이루어집니다.
  • 데이터는 send() 함수를 통해 보내고, 상대가 받지 못하면 TCP 스택이 버퍼에 쌓아둡니다.

📌 서버(수신 측)가 죽었을 때 발생 가능한 상황

상황송신 측 반응설명
1. 서버가 close() 없이 비정상 종료됨 (프로세스 강제 종료 등) 일정 시간 후 send() 호출 시 SIGPIPE / WSAECONNRESET / errno 104 (Connection reset by peer) 등의 오류 발생 커널은 일정 시간 후 상대가 죽었음을 감지하고, 연결을 끊은 것으로 처리
2. 서버가 정상 종료 (close()) send() 호출 시 바로 오류 반환 (ECONNRESET 또는 EPIPE) 연결이 종료되었기 때문에 송신 실패
3. 서버가 죽었지만 네트워크 단절이 없음 (ex: 데몬은 죽었지만 소켓은 살아 있음) 송신 측은 당장 오류 없이 send() 성공할 수도 있음 TCP의 특성상 상대의 ACK가 오지 않으면 일정 시간 후 timeout
 

📍 중요한 포인트

  • 송신 측이 send() 시 오류를 처리하지 않으면 프로그램은 예외(Exception) 또는 에러로 인해 죽을 수 있습니다.
  • 하지만 적절한 오류 처리 코드가 있으면 프로그램이 죽지 않고 재시도나 종료 처리를 할 수 있습니다.

🛠 실무적인 대응 전략

  1. send() 리턴값을 반드시 체크하고, 예외 처리하세요.
  2.  
    ssize_t ret = send(sockfd, buffer, len, 0); if (ret == -1) { perror("send"); // 여기서 재연결 로직 또는 종료 처리 }
  3. TCP KeepAlive 옵션을 사용하면, 상대가 죽었는지 일정 시간 후 감지할 수 있습니다.
  4.  
    int optval = 1; setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
  5. Non-blocking 소켓 또는 select()/poll()/epoll() 등을 사용해 오류를 감지하고 대응하면 유연한 처리가 가능합니다.

🔚 결론

  • 송신 측 프로그램은 서버가 죽었다고 해서 자동으로 죽는 것은 아닙니다.
  • send() 호출 시 오류가 발생할 수 있으며, 이 오류를 처리하지 않으면 프로그램이 죽을 수 있습니다.
  • 오류 처리를 잘 해놓는 것이 중요하며, 거래소 정보분배처럼 고신뢰가 필요한 시스템에서는 반드시 예외 및 재연결 처리 로직이 포함되어야 합니다.

필요하시다면 C, C++, C# 등에서의 구체적인 예외 처리 코드도 드릴 수 있습니다.

 

질문)
송신측에서 재시도 10번 이후에도 데이타가 send되지 않을경우에 send 프로그램을 종료시키라고 한다면, 수신측의 프로그램이 죽었을경우에, 다시 안살아 난다면, 10번 재시도후에 종료되겠군요?

ChatGPT)

✅ 요약하면:

조건:

  • 송신 측에서 send() 실패 시
  • 재시도를 10번까지 하고
  • 그래도 여전히 send()가 실패하면

행동:
송신 프로그램을 종료시키는 로직이 있다면,
수신 측 프로그램이 죽은 상태에서 복구되지 않으면
10번 재시도 후 송신 프로그램은 종료됩니다.


📌 이 경우 실제로 발생할 수 있는 에러 시나리오:

  1. 수신 측 서버가 죽어서 TCP 연결이 끊어짐
    • send() 호출 시 EPIPE, ECONNRESET, 또는 WSAECONNRESET 등의 오류 발생
    • 송신 측은 이를 감지하고 재시도
  2. 재시도 루프
  3. csharp
    복사편집
    for (int i = 0; i < 10; i++) { int result = send(socket, buffer, len, 0); if (result >= 0) break; // 성공하면 빠져나감 // 실패했을 경우 로그 출력 및 대기 Console.WriteLine($"send 실패, 재시도 {i + 1}/10"); Thread.Sleep(1000); // 1초 대기 (예시) } // 10회 모두 실패 시 종료 Console.WriteLine("10회 재시도에도 실패하여 종료합니다."); Environment.Exit(1);

🔧 추가 팁

  • 재시도 간격을 점진적으로 늘리는 Backoff 전략을 쓰면 네트워크 과부하를 방지할 수 있습니다.
  • TCP KeepAlive를 설정하면 수신 측 장애를 빨리 감지하는 데 도움이 됩니다.
  • 수신 측 장애 감지 후 자동으로 재연결 시도하는 로직을 포함하면 더 견고한 시스템이 됩니다.

 

 

질문)
계속 10번에 걸쳐서 send 했던 데이타는 혹시 수신측 프로그램이 살아난다면, 10번의 같은 데이타를 받을까요?

 

ChatGPT)

 

✅ 결론 요약

수신 측 프로그램이 중간에 죽었다가 살아난다면, 10번의 send 데이터가 모두 전달되지는 않으며, 대개는 전혀 도달하지 않습니다.

수신 측이 다시 살아나더라도 TCP 연결은 끊어진 상태이므로, 10번의 재시도는 새로운 연결 없이 모두 실패하며, 데이터는 유실됩니다.


🔍 자세한 설명

1. TCP 연결이 끊어진 상태에서 send() 호출하면?

  • 이때 send()는 실패하며, 내부적으로는 운영체제의 TCP 스택이 오류를 반환합니다 (ECONNRESET, EPIPE 등).
  • 실패한 send()는 실제로는 네트워크로 나가지 않으며, 수신 측은 어떤 것도 받지 못합니다.

2. TCP 연결이 살아 있고, 수신 측이 "잠깐 멈췄다가 다시 살아난 경우"

  • 만약 커널 수준에서 소켓이 살아 있고 수신 앱만 죽었다면, 몇 번의 send()는 TCP 버퍼에 임시로 저장될 수도 있습니다.
  • 하지만 수신 앱이 죽으면서 소켓이 닫히면, 커널은 FIN 또는 RST 패킷을 송신 측에 보내고, 그 이후의 send()는 실패합니다.

3. 재연결 없이 같은 소켓으로 10번 보냈다면?

  • 10번의 send() 중에서 실제로 TCP 스택에서 성공한 건 수신 측 앱이 죽기 전에 보낸 일부만일 수 있습니다.
  • 이후 재시도는 대부분 실패하며, 재연결이 없었다면 수신 측은 어떤 데이터도 받지 못합니다.

📦 예외적인 경우 (단기 네트워크 지연이나 커널 버퍼가 살아 있을 때)

  • 아주 짧은 시간 동안 수신 측이 죽었다가 살아났고, 기존 TCP 연결이 커널 레벨에서 유지됐다면
  • 커널 버퍼에 있는 일부 send() 데이터는 앱이 다시 살아난 후 수신될 수도 있습니다.
  • 그러나 이는 매우 예외적이고 비정형적인 경우입니다.

🔐 정리

상황수신 여부
TCP 연결이 살아 있고 수신 앱만 잠시 죽었다면 운 좋으면 일부 데이터 수신 가능
TCP 연결이 끊겼다면 수신 측은 절대 데이터를 받지 못함
재시도는 기존 연결로만 했고, 재연결이 없다면 데이터는 전송되지 않고 유실됨
같은 데이터 send() 재시도했어도 성공한 send만 도달, 실패한 것은 수신되지 않음
 

✅ 권장 방법

  1. send() 성공 여부 확인 후에만 "보냈다"고 판단
  2. 재연결 후 동일한 데이터 재전송이 필요하다면, 애플리케이션 수준의 메시지 큐 또는 전송 로그가 필요
  3. 중복 수신 방지를 위해 메시지에 ID 또는 시퀀스 번호를 붙이는 것이 좋음

질문)
1번 케이스는 오라클 데이타베이스에 오늘자 삼성전자에 대한 정보가 전부 들어있습니다. 호가, 체결, 마스터, 거래원등등, MTS나 HTS가 요청시에 TCP/IP소켓통신으로 데이타베이스를 조회해서 전송해줍니다.
2번 케이스는 호가, 체결, 마스터, 거래원등등을 모두 REDIS에 보관하고 있고, MTS나 HTS가 요청시에 조회해 가는 방식을 선택할떄에, 1번과 2번의 케이스를 볼때에 어떤게 더 빠르고 효과적일까요? 개발하는 부분에서도 생각해 주세요.

답변)
아래에 **1번 (Oracle 직접 조회 방식)**과 **2번 (Redis 캐시 방식)**을 속도, 효과, 시스템 부하, 확장성, 개발 난이도 등의 관점에서 비교해드리겠습니다.


✅ 1번: Oracle DB 직접 조회 방식 (TCP/IP 소켓 통한 DB 조회)

  • 장점
    • 실시간성 높은 데이터 보장 (DB의 최신 상태)
    • 관리 포인트가 단순 (DB만 관리하면 됨)
    • 데이터 정합성 우수
  • 단점
    • 속도 느림: MTS/HTS가 요청할 때마다 DB 쿼리가 실행되므로 I/O와 CPU 부하가 큼
    • 동시접속자 증가 시 병목 발생 (특히 체결, 호가처럼 초당 수십~수백 건 발생하는 항목)
    • 확장성 낮음: DB가 병목점이 되어 Scale-out 어려움
    • 개발 시마다 SQL 튜닝, DB 커넥션 관리 등의 이슈 동반

✅ 2번: Redis 캐시 활용 방식

  • 장점
    • 속도 매우 빠름: Redis는 메모리 기반이므로 ms 단위 응답
    • 부하 분산: DB에 부하 주지 않음 (초당 수천건 요청에도 견딜 수 있음)
    • 확장성 우수: Redis Cluster를 통한 Scale-out 가능
    • 개발 시 조회가 단순 (GET key 형태), MTS/HTS 응답도 빠름
  • 단점
    • 데이터 정합성 유지 책임 증가: Redis에 들어가는 데이터는 주기적으로 동기화하거나 실시간 반영 필요
    • 메모리 한계 고려: 데이터양이 많을 경우 메모리 증설 필요
    • 운영 시 TTL, 메모리 관리, 데이터 증발 방지 등 세심한 관리 필요

⚖️ 종합 비교

항목1번 (DB 직접 조회)2번 (Redis 캐시 조회)
속도 느림 (쿼리, 네트워크, DB 부하) 빠름 (ms 단위)
부하 DB에 집중 Redis에 분산
실시간성 매우 높음 실시간 반영 로직 필요
확장성 낮음 높음
개발 난이도 복잡 (SQL 튜닝 등) 비교적 단순 (key-value 관리)
운영 리스크 낮음 (DB가 중심) 높음 (동기화, 데이터 유실 리스크)
 

🔧 실제 적용 관점 제안

  • 혼합 방식이 가장 효과적입니다.
    • 호가, 체결, 거래원 등 빈번하게 갱신되고 요청되는 실시간성 데이터는 Redis로 처리
    • 마스터 정보 등 변경이 적고 정확성이 중요한 정보는 Oracle에서 직접 조회
    • Redis에 저장된 데이터는 별도 프로세스나 CDC 방식으로 Oracle에서 실시간 동기화

✅ 개발자가 고려할 핵심 포인트

  • Redis 키 설계를 잘 해야 함 (주식코드:데이터유형:시점 같은 구조)
  • TTL 및 Expire 정책을 세밀히 설정해야 함
  • 데이터 갱신 로직 (DB → Redis) 설계 필요 (Kafka, Trigger, CDC 등 활용)
  • Fallback 전략도 필요: Redis 장애 시 DB 조회로 전환

결론

MTS/HTS의 성능과 응답속도를 중시하고 동시접속자가 많다면2번 Redis 방식이 절대적으로 유리합니다.
단, 안정성과 정합성을 동시에 고려해야 하므로 1번은 보조용/백업용으로 남겨두는 하이브리드 구조가 실전에서는 가장 많이 채택됩니다.

질문)
최근들어서 HTS나 MTS클라이언트에서 데이타의 송수신과정을 REDIS를 활용하는 예가 많다고 합니다. 실제 TCP/IP소켓통신으로 HTS나 MTS클라이언트와 서버를 만드는것보다 효과적일까요?

답변)

요즘 HTS (Home Trading System), MTS (Mobile Trading System)에서 Redis를 활용한 송수신 처리가 많아진 배경과, 그것이 기존의 TCP/IP 소켓 통신 구조보다 왜 더 효과적일 수 있는지를 설명드리겠습니다.


✅ 요약 결론

단순한 요청/응답 구조만 있는 경우엔 TCP/IP 소켓 통신이 빠를 수 있지만,
HTS/MTS처럼 다수의 실시간 데이터, 멀티 프로세스, 비동기처리, 병렬성이 중요한 시스템에서는
Redis를 중간 브로커로 활용하는 방식이 구조적으로 훨씬 효과적입니다.


✅ 비교: 전통적인 TCP/IP vs Redis 기반 메시지 브로커 방식

항목전통 TCP/IP 직접통신Redis 활용 구조
통신 구조 클라이언트 ↔ 서버 직접 연결 클라이언트 ↔ Redis ↔ 서버
연결 수 각 클라이언트마다 연결 필요 Redis와만 연결 유지
병렬성 직접 구현 필요 (epoll, 스레드 등) Redis가 Pub/Sub, Stream 지원
확장성 서버 부하 증가 시 수평 확장 어려움 Redis Cluster로 손쉬운 분산처리
데이터 공유 프로세스 간 공유 어려움 (IPC 필요) Redis가 공유 메모리 역할
복잡성 낮음 (단일 시스템이면) 구조는 조금 복잡하지만 확장성 우수
장애 대응 직접 로직 작성 필요 Redis Sentinel, AOF 등 내장 기능 있음
 

✅ HTS/MTS에서 Redis가 활용되는 실제 이유

  1. 🔁 Pub/Sub 또는 Stream으로 실시간 시세 브로드캐스팅
    • 서버가 1번 계산하면, Redis가 다수 클라이언트에게 푸시
    • 예: "삼성전자 현재가 83,400원"을 Redis가 10만 명에게 전송
  2. 🧵 멀티 프로세스 간 데이터 공유
    • 주문 처리기, 체결 처리기, 시세 처리기 등 여러 프로세스가 Redis를 통해 데이터를 교환
    • LPOP, XREAD, BRPOP 등으로 안정적 큐 역할
  3. ⚙️ 비동기 처리와 부하 분산
    • 클라이언트가 요청한 주문을 Redis에 넣으면, 백엔드 프로세스가 꺼내 처리
    • 이때 서버는 즉시 응답 가능 → 빠른 체감 속도 제공
  4. 📈 통계, 로그, 알람 등 다양한 활용
    • Redis는 단순 캐시를 넘어서, 지표 수집/모니터링에도 활용

✅ Redis가 성능도 뛰어난 이유

  • C로 만들어진 단일 스레드 event loop 구조 (굉장히 빠름)
  • 키 기반 접근은 대부분 O(1)
  • 평균 레이턴시: < 1ms, 초당 수십만 건 처리 가능
  • CPU 및 I/O 병목에 강하고, 데이터 구조 다양함 (list, set, stream 등)

✅ 실제 도입 사례

  • 국내 금융사: 키움증권, NH투자증권 등에서 Redis 기반 실시간 푸시 처리 적용
  • 해외: Robinhood, Binance 등도 Redis 기반 마이크로서비스 연동

✅ 결론 요약

상황추천 방식
단일 시스템, 트래픽 적고 구조 단순함 TCP/IP 직접 통신
수많은 클라이언트, 시세/주문/체결 등 비동기 시스템 Redis 활용 구조 강력 추천
 

✅ 부가 설명

Redis를 사용한다고 해서 TCP를 쓰지 않는 건 아닙니다.
보통 구조는 이렇게 됩니다:

markdown
복사편집
HTS/MTS ↔ (TCP) ↔ 프론트 서버 ↔ (Redis로 데이터 전송) ↔ 백엔드 처리기 ↕ 실시간 시세 시스템

즉, TCP는 입출구용, Redis는 내부 데이터 전달 및 공유용으로 조화롭게 사용됩니다.

+ Recent posts