Q&A

  • UDP 서버의 부하에 대한 조언을 부탁드려요.
안녕하세요?

아래 소스는 소켓서버의 수신 부분에 대당하는 소스인데요, INDY의 UDP를 이용하였습니다. 클라이언트에서 자신만의 교유한 ID를 전송하면 서버에서는 수신된 ID 와 현재의 날짜와시간을 텍스트화일에 저장하도록 하였습니다. 즉 새로운 ID면 'ID+날짜와시간'을 추가하고 기존의 ID면 날짜와시간만 갱신하도록 하였습니다.

이 상황에서 몇가지 묻고 싶은 것이 있습니다.

1. 여기서 ID는 보통 이메일 아이디인데요, 이정도 크기(10~15byte)면 클라이언트에서 날렸을 경우, 서버소켓에서는 여러번 나누어 받지 않고 한번에 받을 수 있을 거라고 생각이 드는데요, 저의 생각이 맞는지요?

2. 클라이언트(고객)의 동시접속자수가 5,000명이고, 그리고 각 클라이언트는 30초마다 한번씩 ID를 전송한다고 했을때 서버에서는 수신되는 순간마다 아래 프로시져가 실행될텐데요, 즉 StringList를 생성해서 텍스트 화일을 읽어들이고, 내용(ID+날짜와시간)을 추가하거나 업데이트하고.. 갱신된 텍스트화일을 저장하여 free하고.. 를 반복하게 되는데요, 서버부하 측면에서 문제가 없겠는지요? 만약 문제가 있다면 어떻게 하는 것이 옳은 것인지 조언을 주시면 고맙겠습니다.

3. 위와 같은 상황에서는 DB를 이용하는 것보다는 훨씬 성능면에서는 낫겠는지요?

경험하신 분들의 도움을 부탁드립니다.


procedure TUDPMainForm.UDPServerUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var
  DataStringStream: TStringStream;
  s: String;
  Strings: TStringList;
  i:integer;
  IDExist:Boolean;
begin

DataStringStream := TStringStream.Create('');
try
  DataStringStream.CopyFrom(AData, AData.Size);
  Strings :=TStringList.Create;

  Try
    Strings.LoadFromFile('C:\1234.txt');
    IDExist:=False;

    for i:=0 to Strings.Count-1 Do
      //txt화일에 ID가 존재한다면 '현재 날짜와시간+ID'로 업데이트함.
      if pos(DataStringStream.DataString,Strings[i]) > 0 then begin
        Strings.Text:=StringReplace(Strings.Text,Strings[i],FormatDateTime('YYYY-MM-DD hh:nn:ss',Now)+
                                             '*'+DataStringStream.DataString,[]);
        IDExist:=True;
        break;
      end;
    //txt화일에 ID가 없다면 '현재 날짜와시간+ID' 추가함.
    If IDExist=False then Strings.Add(FormatDateTime('YYYY-MM-DD hh:nn:ss', Now)+
                                      '*'+DataStringStream.DataString);
   end;
   Strings.SaveToFile('C:\1234.txt');
   Strings.Clear;
Finally
   Strings.Free;
end;

finally
   DataStringStream.Free;
end;

end;
2  COMMENTS
  • Profile
    kivalan 2005.09.15 12:18
    저렇게 동접자가 5000이나 되는경우 불가능할것 같습니다.
    저같은경우는 저렇게 read 프로시져에 최대한 빠르게 처리하도록 부하를 모두 없애구요.
    일종의 List같은걸 만들어서 미리 5000개의 리스트를 가지고 있다가
    UDPServerUDPRead에서는 빠르게 처리하고.
    Update된 내용을 다른 쓰레드같은걸 이용해서 DB에 기록합니다.  
    그런데 동접자가 5000이면 이것도 무리가 되겠네요.
    TEXT도 마찬가지구요. 5K짜리를 수도없이 갱신해야 하는데 이런식으로 하신다면 물론 쓰레드를
    분리해도 무리가 있을것 같구요. 분리한상태에서
    일정주기로 TEXT나 DB로 저장하면 부하는 많이 줄겠네요. 지정된 초에
    List에 있는 데이터를 변경사항만 저장하는거죠.


  • Profile
    이중철 2005.09.15 21:52
    결론적으로 말하면 가능합니다.. 그러나..
    질문자께서 했던방식은 기 답변자 말대로 오버헤드가 심합니다.

    일단 UDP이므로 동시접속자는 문제가 안됩니다.
    오히려 초당 몇개의 패킷을 처리하느냐만 문제죠..
    그런데 질문자의 내용을 볼때 초당 200개 미만으로 보여 집니다.
    이정도는 아무 문제가 없습니다.

    두번째로 기 답변자가 이야기 하였듯이 수신과 저장은 분리가 되어 있어야 합니다.
    저의 경우는 보통 스택 처리 하고 나머지는 메인스레드(SendMessage) 또는 다른 스레드가 처리하게
    합니다.

    세번째로 화일을 초당 200회 제어한다는 것은 매우 나쁜 방법입니다.
    질문자의 내용을 보면 30초이상이 되어야만 전체내용이 갱신된다는 것을 알 수 있습니다.
    결국 화일로 저장주기는 30초 이내이면 된다는 것이고 약 30초 주기로 잡으시면 되겠습니다.

    따라서 결국 위의데이터는 메모리에 보관하고 있어야 합니다. 빈번한 Setlength 추천드리고 싶지 않습니다.
    차라리 TLIST를 사용하세요

    추가적으로 TList 사용에 관해서도 new, dispose 반복하는 것 보다는 메모리풀을 사용하는 것을 추천하고요
    그리고 검색도 그냥 순차검색해도 되겠지만(5000건이야 눈 깜작이지만) 트리구조 추천합니다.

    이경우 초당 200건이 아니라 초당 만건 ~ 10만정도도 처리 가능합니다.
    제경우 만건까지 테스트 해봤네요..