DCOM не выдерживает нагрузки?
От: Stone78 Россия  
Дата: 16.02.05 11:14
Оценка:
В трехуровневой системе, написанной на DELPHI 5.0, есть несколько разных серверов приложений (в виде EXE-модулей), работающих на одном физическом сервере под Windows 2000 Server и подключающихся к SQL Server 2000 через ADO, есть также несколько соединений между серверами. Сервера стартуются вручную администратором. Все COM-объекты выполняются в MTA, используют учетную запись "Текущий пользователь" (The Interactive user). К ним подключаются клиенты через DCOM, к некоторым серверам до 200 подключений.

Через некоторое время вызовы с рабочих станций начинают отваливаются с различными ошибками (Interface not supported, Сервер RPC недоступен и др.), причем не все, но ошибок пролетает много.

Также бывает другая ситуация — все вызовы к одному серверу начинают отваливаться с ошибкой "Out of memory", причем сервер не обязательно при этом "держит" много памяти (судя по Task Manager'у). После перезапуска этого сервера работает еще какое-то время..

Для исключения ошибок в реализации прикладной части написал тестовую программу, которая создает много потоков, каждый поток подключается к серверу (создает экземпляр COM-объекта), вызывает простой метод и отключается.
Некоторое время, довольно много тестов выполнялись успешно, ни одной ошибки. Затем произошла описанная ситуация, причем ошибки начали периодически возникать в разных местах. Выполнил тест с другой рабочей станции (к тому же серверу), ошибки полезли почти сразу. Такое ощущение, как-будто что-то случается с самой службой COM (или RPC?).

В связи с этим вопрос, в чем может быть проблема? Есть ли какие-либо ограничения на количество или интенсивность DCOM-соединений/вызовов? Можем ли мы неверно использовать саму технологию COM?
Re: DCOM не выдерживает нагрузки?
От: Tom Россия http://www.RSDN.ru
Дата: 16.02.05 14:29
Оценка:
S>Можем ли мы неверно использовать саму технологию COM?
Можете. Приводи код.
Народная мудрось
всем все никому ничего(с).
Re[2]: DCOM не выдерживает нагрузки?
От: Аноним  
Дата: 17.02.05 08:08
Оценка:
Здравствуйте, Tom, Вы писали:

S>>Можем ли мы неверно использовать саму технологию COM?

Tom>Можете. Приводи код.

ОК. Привожу код (здесь лежит весь проект (6887 байтов))

Сначала COM-сервер:

VTServer.dpr
program VTServer;

uses
  Forms,
  MainFormUnit in 'MainFormUnit.pas' {MainForm},
  VTServer_TLB in 'VTServer_TLB.pas',
  ServerUnit in 'ServerUnit.pas' {SBTstVolumeTest: CoClass};

{$R *.TLB}

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;
end.


MainFormUnit.pas, MainFormUnit.dfm
Главная форма приложения-сервера (пустая)

VTServer_TLB.pas, VTServer.tlb
Библиотека типов, сгенерированная средой DELPHI

ServerUnit.pas
Непосредственно сам COM-объект
unit ServerUnit;

interface

uses
  ComObj, ActiveX, VTServer_TLB, StdVcl;

type
  TSBTstVolumeTest = class(TAutoObject, ISBTstVolumeTest)
  protected
    procedure Test; safecall;
  end;

implementation

uses
  ComServ;

{ TSBTstVolumeTest }

procedure TSBTstVolumeTest.Test;
begin

end;

initialization
  TAutoObjectFactory.Create(ComServer, TSBTstVolumeTest, Class_SBTstVolumeTest,
    ciMultiInstance, tmFree);
end.


Теперь клиент

Client.dpr
program Client;

uses
  Forms,
  VTServer_TLB in '..\Server\VTServer_TLB.pas',
  MainFormUnit in 'MainFormUnit.pas' {MainForm},
  TestThreadUnit in 'TestThreadUnit.pas';

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;
end.


MainFormUnit.pas, MainFormUnit.dfm
Главная форма клиентского приложения
unit MainFormUnit;

interface

uses
  SysUtils, Classes, Graphics, Controls, Forms, StdCtrls;

type
  TMainForm = class(TForm)
    lblHost: TLabel;
    lblThreadCount: TLabel;
    txtThreadCount: TEdit;
    btnExecuteThreads: TButton;
    txtHost: TEdit;
    procedure btnExecuteThreadsClick(Sender: TObject);
  end;

var
  MainForm: TMainForm;

implementation

uses TestThreadUnit;

{$R *.DFM}

procedure TMainForm.btnExecuteThreadsClick(Sender: TObject);
var
  i: Integer;
begin
  Randomize;
  for i:= 1 to StrToInt(txtThreadCount.Text) do
    TTestThread.Create(txtHost.Text);
end;

end.


TestThreadUnit.pas
Поток, вызывающий тест
unit TestThreadUnit;

interface

uses
  Classes;

type
  TTestThread = class(TThread)
  private
    FHost: string;
  protected
    procedure Execute; override;
  public
    constructor Create(const Host: string);
  end;

implementation

uses
  Windows, SysUtils, ActiveX, Forms, ComObj,
  VTServer_TLB;

var LogCS: TRTLCriticalSection;

procedure Log(Msg: string);
const DebugLogFileName = 'errors.log';
var T: TextFile;
begin
  Msg:= Format('%s %s', [FormatDateTime('hh:nn:ss:zzz', Time), Msg]);
  EnterCriticalSection(LogCS);
  try
    AssignFile(T, DebugLogFileName);
    if FileExists(DebugLogFileName) then
      Append(T)
    else
      Rewrite(T);
    Writeln(T, Msg);
    Flush(T);
    CloseFile(T);
  finally
    LeaveCriticalSection(LogCS);
  end;
end;

{ TTestThread }

constructor TTestThread.Create(const Host: string);
begin
  FHost:= Host;
  FreeOnTerminate:= True;
  inherited Create(False);
end;

procedure TTestThread.Execute;
var
  IServer: ISBTstVolumeTest;
  i: Integer;
begin
  IServer:= nil;
  OleCheck(CoInitialize(nil));
  try
    for i:= 1 to 10000 do
      try
        if Application.Terminated then
          Exit;

        IServer:= CoSBTstVolumeTest.CreateRemote(FHost);
        IServer.Test;
        IServer:= nil;

        Sleep(30 + Random(1000));

        Log('Выполнено успешно');
      except
        on E: Exception do Log(Format('ОШИБКА: %s', [E.Message]));
      end;
  finally
    CoUninitialize;
  end;
end;

initialization
  InitializeCriticalSection(LogCS);
finalization
  DeleteCriticalSection(LogCS);
end.


Это все.
Только что еще раз специально включил два компьютера (Win2000 и WinXP), на одном запустил VTServer.exe (не забыв переключить объект SBTstVolumeTest в DCOMCNFG на "The Interactive user"). На другом запустил Client.exe, включил 10 потоков — все работает замечательно. Включил 100 потоков — сразу посыпались ошибки .
Re[2]: Пардон, не выполнил вход. Предыдущее сообщение мое.
От: Stone78 Россия  
Дата: 17.02.05 08:12
Оценка:
Пардон, не выполнил вход. Предыдущее сообщение мое.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.