Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Ограничение количества соединений с базой, на стороне клиента 
:(
    Опции темы
drkot
Дата 7.6.2014, 02:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Общие положения:
- есть N нитей (N постоянно изменяется от 0 то тысяч)
- каждая нить пишет в базу
- для данной задачи выделено 10 соединений с базой

Проблема:
- идут отказы в обслуживании от базы

Вопрос: как 1000 нитей заставить работать через 10 соединений с базой?

Работа видится примерно так:
1) есть пул из 10 соединений
2) запрос свободного соединения из пула или ожидание пока освободится
3) работа с базой
4) возврат соединения в пул

Собственно затруднение вызывает 2й пункт. 


PS: заставить работать через ОДНО соединение с базой проблем не вызывает, но это не эффективно.





--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
PointerToNil
Дата 7.6.2014, 07:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 17.6.2013

Репутация: 3
Всего: 6



WaitForMultipleObjects?
PM MAIL   Вверх
drkot
Дата 7.6.2014, 15:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



и кого ждать?


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
PointerToNil
Дата 7.6.2014, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 17.6.2013

Репутация: 3
Всего: 6



CreateEvent / SetEvent / ResetEvent


Это сообщение отредактировал(а) PointerToNil - 7.6.2014, 16:25
PM MAIL   Вверх
drkot
Дата 7.6.2014, 17:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



PointerToNil, Вы прямо таки "капитан очевидность" smile
Вы говорите "ЧЕМ", а вопрос стоит "КАК".... Велосипед склепать не проблема, только нет гарантии что он поедет...
Наверняка есть типовой алгоритм решения задачи, он и интересует.





--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
PointerToNil
Дата 7.6.2014, 17:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 17.6.2013

Репутация: 3
Всего: 6



drkot, вы из каких вариантов-то выбираете? огласите, плиз
я просто не вижу тут ни вариантов, ни каких-то проблем или непонятностей

кстати, насчет велосипедов - конечно, он возможен: массив из 10 булеанов - признаков "занято" по соединениям, попытка занять свободный нитью делается через InterlockedExchange (если вернул то же, что и положили - значит, кто-то успел раньше), а если перебор в цикле от 1 до 10 не обнаруживает свободного - небольшой sleep() и снова перебор
вот это был бы велосипед, но я предложил специальные функции, которые долго изобретали, реализовывали и тестировали программисты компании microsoft, а другие старались и описывали их в msdn и толстых книгах 

Это сообщение отредактировал(а) PointerToNil - 7.6.2014, 17:47
PM MAIL   Вверх
drkot
Дата 7.6.2014, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



PointerToNil, конкретный набор функций предполагает конкретное решение на их основе.
Ваш набор: 
Код

WaitForMultipleObjects
CreateEvent / SetEvent / ResetEvent

предполагает что?... Ставить Event на каждое соединение и ждать их? Как минимум Eventы должны быть с автосбросом и есть ограничение на 64 соединения. Из явных проблем, о которых стоит упомянуть, это именование Eventов, так как при совпадении имен можем получить не предсказуемый эффект. Из не явных затруднена обработка и отслеживание упавших соединений и изменение их общего количества.

Как по  мне, 
- либо надо использовать один Event (который срабатывает при освобождение любого соединения) и оборачивать счетчик и прочее в критическую секцию 
- либо Semaphore (но как его прикрутить к данной задаче пока не понятно), возможно он и не применим тут...

Главное чтобы не возникла проблема "узкого горлышка", а это уже конкретный алгоритм...
В том же интерпретаторе PHP есть подобная реализация, да и не только в нем...


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
PointerToNil
Дата 7.6.2014, 19:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 17.6.2013

Репутация: 3
Всего: 6



> Ставить Event на каждое соединение и ждать их?
ну как бы ничего другого даже в голову не приходит

> Как минимум Eventы должны быть с автосбросом 
какой "автосброс", зачем?

> есть ограничение на 64 соединения. 
вы же сказали, что их всего 10 - к чему тут 64??

> Из явных проблем, о которых стоит упомянуть, это именование Eventов
а зачем их именовать-то??
завели массив из 10 THandle/интегеров и сложили туда

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

> либо надо использовать один Event (который срабатывает при освобождение любого соединения)
тогда вам все равно понадобится что-то типа массива из 10 булеанов для признаков занятости каждого конкретного соединения
я предлагаю вместо них массив из 10 ивентов

> либо Semaphore
в семафоре есть счетчик, но вам-то не достаточно одного счетчика свободных или занятых соединений - вам нужны 10 отдельных признаков занятости/свободы для каждого конкретного из 10 соединений 

> Главное чтобы не возникла проблема "узкого горлышка"
это обсуждайте с тем, кто вам ограничение в 10 соединений предписал - этого вполне может и мало оказаться
но сделать транзакции нитей с БД как можно короче - возможно, в вашей компетенции 

вообще говоря, это уже работающую систему нужно профилировать на тему того, что насколько загружено и что является горлышком (сеть, процессор или диски и на каком из серверов - БД или веб и т.д.) и что нужно расширять (или будет видно, что все работает вполсилы из-за искусственных ограничений в софте)


Это сообщение отредактировал(а) PointerToNil - 7.6.2014, 19:26
PM MAIL   Вверх
drkot
Дата 7.6.2014, 20:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Цитата(PointerToNil @  7.6.2014,  19:07 Найти цитируемый пост)
какой "автосброс", зачем?

а как Вы видите работу WaitForMultipleObjects на которой ждет 10 потоков без автосброса?

Цитата(PointerToNil @  7.6.2014,  19:07 Найти цитируемый пост)
что их всего 10 - к чему тут 64??

нужно всегда думать о будущем

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


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
PointerToNil
Дата 7.6.2014, 20:15 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата



*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 17.6.2013

Репутация: 3
Всего: 6



> а как Вы видите работу WaitForMultipleObjects на которой ждет 10 потоков без автосброса?
как я представляю себе внутреннюю реализацию WaitForMultipleObjects? это точно стоит описывать?
но, если что - таймаут в ней задается четвертым параметром - если вдруг он вам понадобится
и, если что, можете еще завести специальный 11-й ивент для "аварийной сигнализации" (типа "кончай работу, пора обедать")

> нужно всегда думать о будущем
проблем с увеличением числа соединений не вижу никаких - ну, расширили динамический массив, завели новый ивент, аналогично и с уменьшением

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


Это сообщение отредактировал(а) PointerToNil - 7.6.2014, 20:21
PM MAIL   Вверх
Sajtran
Дата 19.8.2014, 19:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 15.10.2008
Где: Мегион

Репутация: 2
Всего: 2



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

Код

unit ResPools;
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils,SyncObjs;

type

  { ResourcePool }

  generic ResourcePool<TObj>=class(TObject)
   private
    Event:TEventObject;
    Objs:array of TObj;
    FUseCount:integer;
    function GetSize: integer;inline;
    function GetWaitCount: integer;
   public
    constructor Create(ACount:integer);
    destructor Destroy;override;
    function Lock(Timeout : Cardinal=0):TObj;
    procedure Unlock(const O:TObj);
    property WaitCount:integer read GetWaitCount;
    property UseCount:integer read FUseCount;
    property Size:integer read GetSize;
  end;


implementation

{ ResourcePool }

function ResourcePool.GetWaitCount: integer;
begin
  Result:=FUseCount-Size;
  if Result<0 then Result:=0;
end;

function ResourcePool.GetSize: integer;
begin
  Result:=Length(Objs);
end;

constructor ResourcePool.Create(ACount: integer);
var i:integer;
begin
  inherited Create;
  Event:=TEventObject.Create(nil,false,false,'');
  SetLength(Objs,ACount);
  for i:=0 to ACount-1 do begin
    Objs[i]:=TObj.Create;
  end;

end;

destructor ResourcePool.Destroy;
var i:integer;
begin
  for i:=0 to Size-1 do begin
    FreeAndNil(Objs[i]);
  end;
  FreeAndNil(Event);
  inherited Destroy;
end;

function ResourcePool.Lock(Timeout: Cardinal): TObj;
var i:integer;
  b:boolean;
begin
  b:=false;
  repeat
    if InterLockedIncrement(FUseCount)>Size then begin
      b:=true;
      Event.WaitFor(Timeout);
    end;
    for i:=Size-1 downto 0 do begin
      Result:=Objs[i];
      if Result=nil then continue;
      if InterlockedCompareExchange(Pointer(Objs[i]),nil,Pointer(Result))=Pointer(Result) then exit;
    end;

    InterLockedDecrement(FUseCount);
  until (Timeout>0)and b;
  Result:=nil;
end;

procedure ResourcePool.Unlock(const O: TObj);
var i:integer;
begin
  for i:=Size-1 downto 0 do begin
    if InterlockedCompareExchange(Pointer(Objs[i]),Pointer(O),nil)=nil then break;
  end;

  if InterLockedDecrement(FUseCount)>Size then
    Event.SetEvent;
end;

end.



PM MAIL   Вверх
drkot
Дата 21.8.2014, 07:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Во первых событие должно быть с автосбросом.
Во вторых не понятно какие объекты заняты, а какие свободны.
Про странный цикл и смысл условия в нем я вообще молчу... все таки не смолчал...

Но ход мыслей правильный.


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
Sajtran
Дата 23.8.2014, 19:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 15.10.2008
Где: Мегион

Репутация: 2
Всего: 2



Цитата(drkot @ 21.8.2014,  09:50)
Во первых событие должно быть с автосбросом.
Во вторых не понятно какие объекты заняты, а какие свободны.
Про странный цикл и смысл условия в нем я вообще молчу... все таки не смолчал...

Но ход мыслей правильный.

Код

      constructor Create(EventAttributes : PSecurityAttributes;
        AManualReset,InitialState : Boolean;const Name : string);

а разве у меня не автосброс?
Код

Event:=TEventObject.Create(nil,false,false,'');

и что в цикле не нравится, просто объект забирается, а потом возвращается
    function Lock(Timeout : Cardinal=0):TObj; - забирает
    procedure Unlock(const O:TObj);                - отдаёт

Добавлено через 3 минуты и 44 секунды
Unlock правда ещё подправил немного
Код

procedure ResourcePool.Unlock(const O: TObj);
var i:integer;
begin
  for i:=Size-1 downto 0 do begin
    if InterlockedCompareExchange(Pointer(Objs[i]),Pointer(O),nil)=nil then break;
  end;

  if InterLockedDecrement(FUseCount)>=Size then
    Event.SetEvent;
end;   

PM MAIL   Вверх
PointerToNil
Дата 24.8.2014, 20:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 17.6.2013

Репутация: 3
Всего: 6



а у меня вот такой минимализм получился:
Код

type
  TPoolItemState = (isFree, isBusy);
  ItemPool = class
  private
    FFlags: array of TItemState;
  public
    constructor Create(size: integer);
    destructor Destroy; override;
    function AcquirePoolItem(try_count: integer = -1): integer;
    procedure FreePoolItem(index: integer);
  end;

implementation

function ItemPool.Create(size: integer);
begin
  SetLength(FFlags, size); // default = TPoolItemState(0) = isFree
end;

destructor ItemPool.Destroy;
begin
  SetLength(FFlags, 0);
end;

function ItemPool.AcquirePoolItem(try_count: integer = -1): integer;
var i, try_n: integer;
begin
  try_n := 0;
  repeat
    for i:=0 to SizeOf(FFlags)-1 do
      if (FFlags[i] = isFree) and (InterLockedExchange(FFlags[i], isBusy) = isFree) then 
        begin Result := i; exit end;
    sleep(10); inc(try_n); 
  until  (try_count > 0) and (try_n >= try_count); 
  Result := -1;
end;

procedure FreePoolItem(index: integer);
var i:integer;
begin
  FFlags[index] = isFree;
end;

(чёта я подумал, зачем какие-то еще ивенты, если есть массив признаков занятости и все равно цикл по нему крутить)
и "объектов пула" внутри нет - SRP!
try_count может быть менее удобным, чем Timeout - это можно переделать
PM MAIL   Вверх
drkot
Дата 24.8.2014, 22:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Цитата(Sajtran @  23.8.2014,  20:50 Найти цитируемый пост)
и что в цикле не нравится, просто объект забирается, а потом возвращается

в целом нет гарантии (на мой взгляд), получения экземпляра объекта. Возможно это ошибочное мнение, но думается код получения и возврата желательно делать в критической секции.

Сам реализовывал примерно так. В качестве пула использовался список.
Код

  if FEvent.WaitFor(TimeOut) = wrSignaled then
  begin
    FListSection.Enter;
    try
      try
        { TODO : Захват объекта }
    finally
      FListSection.Leave;
    end;
    if FCountCurrent < FCountMaximum then
      FEvent.SetEvent;
  end
  else
    Result:= nil;


Код

  FListSection.Enter;
  try
      { TODO : Возврат объекта }
  finally
    FListSection.Leave;
  end;
  FEvent.SetEvent;

возможно это избыточно... Но для меня важна стабильность при активной конкуренции потоков за ресурс.
Вообще простейший пул можно сделать на базе TThreadList.

Цитата(Sajtran @  23.8.2014,  20:50 Найти цитируемый пост)
а разве у меня не автосброс?

Извините, не заметил.

Цитата(PointerToNil @  24.8.2014,  21:41 Найти цитируемый пост)
зачем какие-то еще ивенты

ивенты для того, чтоб 100500 потоков не крутили один и тот же цикл в ожидании освободившегося объекта. Как то так.

Цитата(PointerToNil @  24.8.2014,  21:41 Найти цитируемый пост)
а у меня вот такой минимализм получился:

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


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0837 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.