Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.01.25;
Скачать: CL | DM;

Вниз

стабильный и мощный FTP - реально?   Найти похожие ветки 

 
istok   (2007-12-11 21:13) [0]

Надо пересылать файлы с клиентских модулей программы на серверный. Используем для этого ftp. Надо обеспечить бесперебойную работу системы при 3х тысячах клиентов и сотнях файлов по ~2Кб. Причём всё должно работать (не обязательно быстро, но надёжно) в случае если все клиенты приконнектятся одновременно и будут слать данные.

Это реально?

Тесты indy, ics с серверами на indy, ics, file zilla не дают 100% гарантии доставки каждого файла.

То есть операция Put иногда не проходит. И для этого достаточно 2-4х клиентов, постоянно отсылающих файлы.

ics и indy сервера вообще убиваются после определенного времени.

Может фтп для таких задач не очень годится или надо специальное что-то делать или я что-то не понимаю? (ведь фтп сервера в инете как-то работают с тысячами клиентов?)

В идеале я хочу чтоб любой файл мог быть доставлен, если сервер доступен. И ничего при этом не глючило.


 
DVM ©   (2007-12-11 22:07) [1]


> Это реально?

реально


> Тесты indy, ics с серверами на indy, ics .... не дают 100% гарантии доставки каждого файла.

Это уже не от них а от программиста зависит.


> ics и indy сервера вообще убиваются после определенного
> времени.

они тут не причем

А почему бы не взять один из множества готовых и проверенных временем фтп серверов, нпример под FreeBSD ?


 
Anatoly Podgoretsky ©   (2007-12-11 22:09) [2]

> istok  (11.12.2007 21:13:00)  [0]

Может ты просто не умеешь их готовить?
Известны примеры работы ICS  с 30000 клиентов одновременно, при том в одном потоке.


 
istok   (2007-12-11 22:22) [3]


> Это уже не от них а от программиста зависит.


я делаю банальный put. делаю его в цикле. что тут можно поправить? может низя в цикле его юзать, а давать "передохнуть"?

function TForm1.UploadFileIndy(AFileName: string): Boolean;
var
 i: Integer;
 sent: Boolean;
begin
 Result := False;
 sent := False;
 if FileExists(AFileName) then
 with IdFTP1 do
 begin

   AddLog(">....");      

   try
     Put(AFileName, ExtractFileName(AFileName));
     sent := True;
   except
     on e: exception do
       AddLog("Put exception: " + e.Message, True);
   end;

   AddLog("....<");
   if not sent then
     AddLog("not sent ", True);
 end;

 Result := sent;
end;



> Известны примеры работы ICS  с 30000 клиентов одновременно,
>  при том в одном потоке.


В этом примере кажется речь шла о месагинге а не о пересылке файлов по фтп с частыми открытиями и закрытиями соединений, не?


 
tesseract ©   (2007-12-11 22:25) [4]


> я делаю банальный put. делаю его в цикле. что тут можно
> поправить? может низя в цикле его юзать, а давать "передохнуть"?
>


Код оптимистичен, как Джордж Буш. В цикле без потоков и ассиметричной синхронизации, ты лосося не получишь. 30000 - при грамотном коде мелочь. У тебя даже обработки искоючения не присутствует.


 
DVM ©   (2007-12-11 22:28) [5]


> В этом примере кажется речь шла о месагинге а не о пересылке
> файлов по фтп с частыми открытиями и закрытиями соединений,
>  не?

разницы нет


 
istok   (2007-12-11 22:59) [6]


> Код оптимистичен, как Джордж Буш. В цикле без потоков и
> ассиметричной синхронизации, ты лосося не получишь. 30000
> - при грамотном коде мелочь. У тебя даже обработки искоючения
> не присутствует.


Можете грамотной закачки файлов пример показать?

Насчет исключений - а что конкретно имеется в виду? я ж там вроде try except юзаю..

>разницы нет
ок, а в чем разница - в том что написал tesseract  ?


 
DVM ©   (2007-12-11 23:03) [7]


> istok   (11.12.07 22:59) [6]

Я чего то не пойму, ты клиента или сервера делаешь? И кто из них у тебя не работает? В [0] речь о серверах, а в [3] вроде как код клиента?


 
istok   (2007-12-12 00:21) [8]


> DVM ©   (11.12.07 23:03) [7]


Замечение правомерное, ща объясню.

Я делаю и сервера и клиента.

Проблемы клиента:
1.Нет гарантии что Put сработает удачно (когда я его вызываю в цикле и есть еще пара клиентов) - вне зависимости от сервере (будь то мой или не мой сервер). Я понимаю что результат Put обрабатываем и всё такое, меня смущает сам факт того, что если 4 клиента не могут стабильно аплоадить файлы, то что уж говорить о тысячах.

2.ICS клиент работает медленнее чем Indy"шный. Где-то в 10 раз. Но с Indy"шным иногда возникают то exception"ы, то просто зависания, а ics клиент работает стабильно. Наверное дело в том, что я криво юзаю инди клиента.

В связи с этими вопросами я дал пример кода. Может что-то явно не так делаю.

Проблемы сервера:
3.Стабильность. С 50ю клиентами мой ICS сервер живёт от пары часов до пары недель и потом винда выдаёт неизвестную ошибку. Как и что ловить пока не ясно. Сервер довольно простой, ничего особенного, простые обработчики событий.

Сервер на инди, при желании падает хоть от одного клиента, причём то зависнет, то exception вылетил. по-разному. В сервере опять же ничего особенного, пара обработчиков событий и всё.

4.Масштабируемость. В идеале нужно чтоб сервер держал тысячи клиентов, и без проблем получал от них файлики или отдавал им оных. Чтоб это работало с достаточной скоростью, для того чтоб данные не накапливались на клиентах до бесконечности (это примерно расчитать можно).

Но то что есть сейчас - упадёт от сотни клиентов без проблем.

Резюме: я не ищу решений конкретных проблем своими силами, косяков много,  а компетенция в этой области никакая. я хочу комплексное решение, которое гарантирует мне вышеобозначенные цели с минимумом моего кода. Желательно чтоб оно было платное и с сапортом.

К примеру, меня смущает что есть удобные, мощные "ready-ro-use" средства для работы с данными, но я не вижу аналогичных вещей для обмена данными по сети.

В идеале хотелось бы использовать что-то опробованное на тысячах клиентов и готовое к употреблению :)

Итого, я буду рад, если знающие люди объяснят при каком подходе и затратах я бы мог добиться обозначенных целей. Может быть это пара строк кода, может быть иные компоненты, может быть заказная разработка, примеры, статьи или еще что-то - мне всё равно как именно решить проблемы, лишь бы решить.

Any concerns?


 
Сергей М. ©   (2007-12-12 08:20) [9]


> Нет гарантии что Put сработает удачно


Что говорит сообщение об исключении при неудачном "срабатывании" ?


 
tesseract ©   (2007-12-12 10:41) [10]


> Сервер на инди, при желании падает хоть от одного клиента,
>  причём то зависнет, то exception вылетил. по-разному.


Exception-ы они для того и созданы, чтобы их обрабатывать E:EXception  многого не скажет. Почитай справку по exception-ам indy.

"Зависнет " на какой высоте над уровнем моря ?


> потом винда выдаёт неизвестную ошибку.


Телепатор поставил стрелку на BufferOverflow. Или утечку памяти.


 
umbra ©   (2007-12-12 10:45) [11]


> Нет гарантии что Put сработает удачно

Такой гарантии нет никогда. Поэтому надо заранее предусмотреть возможность при обрыве соединения его восстановления и докачки файла.


> Но с Indy"шным иногда возникают то exception"ы, то просто
> зависания,

иногда - это когда? как часто? какие исключения?


> В связи с этими вопросами я дал пример кода. Может что-то
> явно не так делаю.

при исключении рекомендуется явно разрывать соединение, еще хорошо бы на сервере выставить разумный таймаут на чтение (т.е. если в течение некоторого времени от клиента нет данных, то соединение закрывать.


 
umbra ©   (2007-12-12 11:08) [12]


> Надо обеспечить бесперебойную работу системы при 3х тысячах
> клиентов

если делать на инди, то надо использовать не потоки, а волокна (fibers). три тысячи потоков в процессе - довольно круто.


 
Anatoly Podgoretsky ©   (2007-12-12 12:06) [13]

> tesseract  (12.12.2007 10:41:10)  [10]

> Exception-ы они для того и созданы, чтобы их обрабатывать E:EXception  многого не скажет. Почитай справку по exception-ам indy.

Инди с тысячами потоков не справится, просто не хватит памяти по стек (1-2 мб на поток).


 
MetalFan ©   (2007-12-12 12:38) [14]


> Известны примеры работы ICS  с 30000 клиентов одновременно,
>  при том в одном потоке.

разве ICS не использует асинхронность? тогда это уже не один поток.

может почитать про порты завершения?
http://www.gamedev.ru/community/mmorpg/articles/?id=6


 
Anatoly Podgoretsky ©   (2007-12-12 12:54) [15]

> MetalFan  (12.12.2007 12:38:14)  [14]

асинхронности не требуются потоки, кроме главного.


 
istok   (2007-12-12 13:26) [16]


> Anatoly Podgoretsky ©   (12.12.07 12:54) [15]


В какую сторону копать - асинхронный сервер на ICS ?

В TFtpServer подобных свойств\событий я не видел - от чего надо отталкиваться?


 
Anatoly Podgoretsky ©   (2007-12-12 13:39) [17]

> istok  (12.12.2007 13:26:16)  [16]

С ICS идет огромное количество примеров, на любой вкус.
Скажу, что правильно написаный сервер, просто не возможно уронить.


 
MetalFan ©   (2007-12-12 14:59) [18]


> асинхронности не требуются потоки, кроме главного.
>

явно - не требует... неявно система наверняка создает доп.потоки


 
istok   (2007-12-12 15:13) [19]

я правильно понял, что вот этот кусок демки фтп сервера ics - поточная обработка get?:

procedure TFtpServerForm.FtpServer1GetProcessing(
   Sender          : TObject;
   Client          : TFtpCtrlSocket;
   var DelayedSend : Boolean);
var
   MyServer : TFtpServer;
   MyClient : TMyClient;
begin                              InfoMemo.Lines.Add("-GetProcessing");
   MyServer := Sender as TFtpServer;
   MyClient := Client as TMyClient;
   { If client request a *.ZZZ file, then start a thread to do some      }
   { processing (here the thread just sleep 10 sec to show other clients }
   { are not blocked.                                                    }
   if UpperCase(ExtractFileExt(MyClient.FileName)) = ".ZZZ" then begin
       MyClient.FWorkerThread := TGetProcessingThread.Create(TRUE);
       MyClient.FWorkerThread.Server          := MyServer;
       MyClient.FWorkerThread.Client          := MyClient;
       MyClient.FWorkerThread.FreeOnTerminate := TRUE;
       MyClient.FWorkerThread.OnTerminate     := WorkerThreadTerminated;
       MyClient.FWorkerThread.Resume;
       { Ask server component to not start sending immediately           }
       { We will ask to start sending from WorkerThreadTerminated event  }
       DelayedSend := TRUE;
   end;
end;


и по аналогии можно сделать поточную обработку put ? Если "да", то в каком событии - "OnStorSessionConnected" ?


 
Anatoly Podgoretsky ©   (2007-12-12 15:29) [20]

> MetalFan  (12.12.2007 14:59:18)  [18]

Система тоже не создает, это стандартный WinSock работает на сообщениях, а не потоках.
Ну не получилось бы создать FTP сервер на 30000 одновременных подключений, только под стек потребуется 30 гб виртуальной памяти.


 
DVM ©   (2007-12-12 15:47) [21]


> Ну не получилось бы создать FTP сервер на 30000 одновременных
> подключений, только под стек потребуется 30 гб виртуальной
> памяти.

Кстати, а под Unix не знаете как реализуется подобное? Там ведь насколько я знаю вообще процесс сервера клонируется особым образом для каждого клиента.


 
Anatoly Podgoretsky ©   (2007-12-12 16:12) [22]

> DVM  (12.12.2007 15:47:21)  [21]

В общем это клонирование, но в Линуксе многое взяли из Виндоус


 
istok   (2007-12-12 17:18) [23]

Ситуация такая. Ниже приведен код службы сервера, которая при нагрузочном тестировании быстро падает.

Под падением понимается
-неожиданный вызов TFtpServer.OnStop
-запись "Ошибка приложения weServerDataTransfer.exe, версия 2.1.0.340, модуль ntdll.dll, версия 5.2.3790.3959, адрес 0x0002a754. Дополнительные сведения можно найти в центре справки и поддержки, в "http://go.microsoft.com/fwlink/events.asp"." в журнале ошибок

Когда ровно также тестирую аналогичную демку ics ftp server"a от автора - она не падает.

Может есть какие-то особенности при реализации ics сервера в службе?
Или данный код кривой?

procedure TweServerDataTransferService.FtpServer1Authenticate(Sender: TObject;
 Client: TFtpCtrlSocket; UserName, Password: TFtpString;
 var Authenticated: Boolean);
begin
 Authenticated := (UserName = "admin") and (PassWord = "we_pass");

 if Authenticated then
 begin
   AddLog("User authenticated: " + Client.GetPeerAddr + ", User """ + UserName);

   //Client.HomeDir := FweFolders.dirServerLogs;
   //ForceDirectories(Client.HomeDir);
 end
 else
   AddLog("User NOT authenticated: " + Client.GetPeerAddr + ", User """ + UserName);
end;

procedure TweServerDataTransferService.FtpServer1ClientConnect(Sender: TObject;
 Client: TFtpCtrlSocket; AError: Word);
begin
 AddLog("! " + Client.GetPeerAddr + " connected");

 if Error <> 0 then
 begin
   Client.Close;
   AddLog("quick close: FtpServer1ClientConnect");
 end;
end;

procedure TweServerDataTransferService.FtpServer1ClientDisconnect(Sender: TObject;
 Client: TFtpCtrlSocket; AError: Word);
begin
 AddLog("! " + Client.GetPeerAddr + " disconnected");
end;

procedure TweServerDataTransferService.FtpServer1RetrDataSent(Sender: TObject;
 Client: TFtpCtrlSocket; Data: TWSocket; AError: Word);
begin
   if Error <> 0 then
       AddLog("! " + Client.GetPeerAddr
       + ", ["+ Client.UserName + "], " +
                          " Data sent. Error #" + IntToStr(Error));

   if Error <> 0 then
   begin
     Client.Close;
     AddLog("quick close: FtpServer1RetrDataSent");
   end;
end;

procedure TweServerDataTransferService.FtpServer1RetrSessionClosed(Sender: TObject;
 Client: TFtpCtrlSocket; Data: TWSocket; AError: Word);
begin
 if (AError = 0) then
 begin
   if Client.AllSent then
     //FilesSent := FilesSent + 1
   else
     Addlog("FtpServer1RetrSessionClosed: ALL_SENT=FALSE "+Client.GetPeerAddr  + ", ["+ Client.UserName + "]");
 end
 else
   AddLog("FtpServer1RetrSessionClosed: "+ " ["+ Client.UserName + "], " +"error = " + IntToStr(AError));

   if AError <> 0 then
   begin
     Client.Close;
     AddLog("quick close: FtpServer1RetrSessionClosed");
   end;
end;

procedure TweServerDataTransferService.FtpServer1RetrSessionConnected(Sender: TObject;
 Client: TFtpCtrlSocket; Data: TWSocket; AError: Word);
begin
   if Error <> 0 then
       AddLog("! " + Client.GetPeerAddr
       + ", ["+ Client.UserName + "], " +
                          " Data session connected. Error #" + IntToStr(Error)
                          + " AllSent = " + BoolToStr(Client.AllSent, True));

   if (Error = 0) and Client.AllSent then
     Addlog("All Sent - ok");

   if Error <> 0 then
   begin
     Client.Close;
     AddLog("quick close: FtpServer1RetrSessionConnected; error = " + IntToStr(Error));
   end;
end;

procedure TweServerDataTransferService.FtpServer1Start(Sender: TObject);
begin
 AddLog("! Server started");
end;

procedure TweServerDataTransferService.FtpServer1Stop(Sender: TObject);
begin
 AddLog("! Ftp Server stopped", False);
 if not FServiceStoppedManually then
 begin
   AddLog("not FServiceStoppedManually, Restart", False);
   Sleep(5000); //
   HardRestart;
   //Restart;
 end;
end;

procedure TweServerDataTransferService.FtpServer1StorSessionClosed(Sender: TObject;
 Client: TFtpCtrlSocket; Data: TWSocket; AError: Word);
begin
 if AError = 0 then
   AddLog("File Received - ok")
 else
   AddLog("FtpServer1StorSessionClosed: error = " + IntToStr(AError));
end;

procedure TweServerDataTransferService.FtpServer1ValidateGet(Sender: TObject;
 Client: TFtpCtrlSocket; var FilePath: TFtpString; var Allowed: Boolean);
begin
 Allowed := False;

 if (Pos(fnClientOptions2, FilePath) > 0) then
 begin
   AddLog("ClientOptions requested, path = " + FweFolders.dirServerOptions + fnClientOptions2);
   FilePath := FweFolders.dirServerClientOptions + LowerCase(ExtractFileName(FilePath));
   Allowed := FileExists(FilePath);
 end;
end;

procedure TweServerDataTransferService.ServiceStart(Sender: TService; var Started: Boolean);
begin
               
   FtpServer1.Port := IntToStr(portServerClientsDT);
   FtpServer1.PasvPortRangeStart := portServerClientsDT2;
   FtpServer1.PasvPortRangeSize := portServerClientsDT2Size;
   
   FtpServer1.Start;  

end;

procedure TweServerDataTransferService.FtpServer1ValidateSize(Sender: TObject;
 Client: TFtpCtrlSocket; var FilePath: TFtpString; var Allowed: Boolean);
begin
 AddLog("FtpServer1ValidateSize - enter");
 AddLog("FilePath = " + FilePath);

 Allowed := False;

 if (Pos(fnClientOptions2, FilePath) > 0) then
 begin
   Allowed := FileExists(FweFolders.dirServerClientOptions + ExtractFileName(FilePath));
 end;
end;

procedure TweServerDataTransferService.FtpServer1ValidatePut(Sender: TObject;
 Client: TFtpCtrlSocket; var FilePath: TFtpString; var Allowed: Boolean);
begin
 Allowed := False;

 if (Pos(prefPackage, FilePath) > 0) then
 begin
   Allowed := True;
   FilePath := FweFolders.dirServerLogs + ExtractFileName(FilePath);
 end;

end;

end.


 
istok   (2007-12-12 17:19) [24]

P.S.:  AddLog я отключил, он ничего не делает.


 
MetalFan ©   (2007-12-12 17:37) [25]


> Anatoly Podgoretsky ©   (12.12.07 15:29) [20]
>
> Система тоже не создает, это стандартный WinSock работает
> на сообщениях, а не потоках.

Создает. но использует для этого специальные механизмы. как может асинхронность в ОДНОМ потоке работать???


 
istok   (2007-12-12 18:06) [26]

лол, стандартная демка от ics под нагрузкой тоже выдаёт "-AnswerToClient
> 127.0.0.1 500 PASV exception: "Access violation at address 7C92BD02 in module "ntdll.dll". Read of address 00000001".
-ClientCommand"

просто на разных машинах по-разному ловится.

нагрузка - 3 клиента.

в чем тут может быть косяк?


 
MetalFan ©   (2007-12-12 18:43) [27]

в 17 строке


 
istok   (2007-12-12 19:04) [28]


> MetalFan ©   (12.12.07 18:43) [27]
>
> в 17 строке


Могу конечно скинуть код примера фтп сервера от ics, только вряд ли в нём будут явные ошибки :)

Что тут можно придумать?


 
Anatoly Podgoretsky ©   (2007-12-12 19:12) [29]

> istok  (12.12.2007 17:18:23)  [23]

Особенность одна, все и везде должно быть обернуто в try except end, что бы любые ошибки не уронили сервер, он должен выживать в самых тяжелых условиях.


 
Anatoly Podgoretsky ©   (2007-12-12 19:13) [30]

> istok  (12.12.2007 19:04:28)  [28]

Примеры не обладают никакой живучестью, они примеры.


 
istok   (2007-12-12 19:54) [31]

Anatoly Podgoretsky ©   (12.12.07 19:12) [29][30]

а, значит я вас изначально не совсем верно понял, подумав что на сервере совсем не будет ошибок.

но такое AV из недр ics это разве нормально? оно не проходит без последствий и после этого только перезапуск процессе\службы помогает. Делать перезапуски службы каждые 10минут это ж бред.. не?

by the way:
а насчёт того что Put"ы часто не срабатывали я нашел ответ в малом диапазоне pasv портов сервера.


 
Anatoly Podgoretsky ©   (2007-12-12 19:55) [32]

> istok  (12.12.2007 19:54:31)  [31]

Это AV не из недр ics, а из NTDLL - ты туда передаешь недопустимые параметры.


 
istok   (2007-12-12 20:00) [33]


> Это AV не из недр ics, а из NTDLL - ты туда передаешь недопустимые
> параметры.


может не я, а ics? я-то тут причём? :)

итого - что надо сделать, чтоб такой косяк пофиксить? править ics?


 
Anatoly Podgoretsky ©   (2007-12-12 20:02) [34]

> istok  (12.12.2007 20:00:33)  [33]

Провести отладку.


 
tesseract ©   (2007-12-12 22:55) [35]


> В общем это клонирование, но в Линуксе многое взяли из Виндоус


А не наоборот ?


> Кстати, а под Unix не знаете как реализуется подобное? Там
> ведь насколько я знаю вообще процесс сервера клонируется
> особым образом для каждого клиента.


Функция Fork полностью клонирует процесс, со всеми данными и состоянием. Поэтому там все попроще. Fork вообще крайне полезная функция, чего ее в винду не ввели ?


 
DVM ©   (2007-12-12 23:00) [36]


> Функция Fork полностью клонирует процесс, со всеми данными
> и состоянием

Ну вот я и спрашиваю, что же это получается для 30000 юзеров будет 30000 копий одного и того же процесса со всеми ресурсами занятыми для каждого процесса отдельно. Что то как то расточительно. Оно вообще работать то будет?


 
tesseract ©   (2007-12-13 10:22) [37]


> Ну вот я и спрашиваю, что же это получается для 30000 юзеров
> будет 30000 копий одного и того же процесса со всеми ресурсами
> занятыми для каждого процесса отдельно.


Ну и что ? Работает же, во всех Unix. И не всё копируеться. Занятые файловые дескрипторы тебе же не надо копировать ? да и 30 тысяч юзеров одновременно навряд-ли ломануться на FTP - канал столько твой не выдержит. Даже 1 гигабит/30000 =34 килобита.


 
Slym ©   (2007-12-13 11:56) [38]

tesseract ©   (13.12.07 10:22) [37]
к тому же 30000*2 сокетов (команды+данные) т.е. близко к пределу MaxWord, а если в пассиве то ваще 30000*3 (команды+данные_серверн+данные_клиент) сокетов что уже больше MaxWord


 
umbra ©   (2007-12-13 15:51) [39]


> 30000 копий одного и того же процесса со всеми ресурсами
> занятыми для каждого процесса отдельно.

fork не занимает новых ресурсов, кроме памяти, разве что, он передает процессу копии открытых дескрипторов родительского процесса.



Страницы: 1 вся ветка

Текущий архив: 2009.01.25;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.018 c
15-1227708872
Ega23
2008-11-26 17:14
2009.01.25
У меня тут мобильник сперли давеча


15-1228361062
Slider007
2008-12-04 06:24
2009.01.25
С днем рождения ! 4 декабря 2008 четверг


1-1206543130
voe
2008-03-26 17:52
2009.01.25
Описание Ссылки в Webbrowser


1-1207311044
abhtr
2008-04-04 16:10
2009.01.25
OpenDialog.InitialDir ? :-о


2-1229075348
Алексей121
2008-12-12 12:49
2009.01.25
Как обойти дерево всех IXMLNode элементов?