WebServices locking/latching

34 отговора 0 прегледа
#1

WebServices locking/latching

Я да ви питам тука от къде си наливате топла вода, преди да почна сам да я откривам ...

Ситуацията е следната: имаме не мулти ами мулти на квадрат тиър аппликация.
Моята част покрива няколко от тиърите, като като основното е, че имам имплементиран WebService. Той се ползва от разни фронт енд клиенти, както и от чужди WebService. От своя страна той ползва други (трети и четвърти) WebService, докато в същото време маже по базата. А бе целият чакрък някак си работи. Естествено, това със лоад балансери, мултипъл инстанцес, хай ъвейлабилити и тралалала (макар да не съм убеден в нуждата, като гледам колко ми е голямо натоварването)

Извикванията на операциите в WebServicе-а могат да бъдат уникално идентифицирани по някакво ID. Конвенцията е, че клиентите пращат заявки с различни ID-a, а ако име заявки с едно и също ID (от един и същи клиент), те ще са в поредица. Т.е. докато не се получи респонса на заявка с дадено ID, няма дайде нова заявка със същото ID.

Е да де, ама идва. Не ме питайте защо. Нещо Клиентите на WebService имат проблем, който е извън моя контрол.

Та искам да ви питам, в подобна ситуация вие какво правите?
А) оставяте нещата такак както са - нека да се обработват паралелно, пък каквото стане накрая (това ми е текущата стратегия, че е най-лесно, обаче се опасявам че става мазало, хеле в базата - единия пише, другия трие ....)
B) пазите някъде (къде? в базата?) кой ID-та се обработват и на втора заявка със ID което вече се обработва и давате "свободно" на момента като пристигне
C) както B) пазите ID-тата, но слагате втората заявка "on hold" и като свърши първата, обработвате втората.

За всеки от вариантите A, B и C мога да изброя добри и лоши страни. Но да не правя поста на чаршаф.

Други варианти?

Търсих в нета, ама аз ли не мога да обясня какво искам, те ли не ме разбират ... нямам много голям успех. Излизат разни работи за транзакции на WebServices ама на мен не ми трябва това ...

Отговор
в отговор на BullDog #2

Re: WebServices locking/latching

А) оставяте нещата такак както са - нека да се обработват паралелно, пък каквото стане накрая (това ми е текущата стратегия, че е най-лесно, обаче се опасявам че става мазало, хеле в базата - единия пише, другия трие ....)


Базата си има изолация на транзакциите (освен ако не е nosql) и като цяло тя най-добре се оправя с това. Не виждам от какво може да се "притесняваш", освен ако нещо не е тотално омазано де.

Отговор
в отговор на Aaron #3

Re: WebServices locking/latching

Базата си е ОК - DB2.
Обаче .... не мога да си позволя да направя 1 request на WebService = 1 транзакция. Да не говорим, че това не е "nice" решение - няма значение кой request дошъл първи и кой втори, който свърши втори ще думне - заради PK violation.
Нали споменах, че аз от своя страна ползвам външни услуги. Те може да тайм-аутнат, пък и обработката си е бая сериозна. Един request отива към 20 sec. средно. Това е нормално, виж например колко време отнема на сайта на lufthansa да ти предложи полет по зададена дестинация и дати (при положение, че едва ли ползват външни услуги).
Не мога да си позволя транзакции по 20 sec. Трябва да го нацепя на по-малки, логически завършени "unit of work".
И затова може да стане мазало, първият request натъкми базата и се засили да вика външната услуга, трябва да commit-не, обаче идва втория request и за "Добър ден" избърсва всичко дето е написал първия, после почва да го пише отново (щото няма гаранция че клиента няма да си промени нещо в данните при втория request със същото ID).

Отговор
в отговор на BullDog #4

Re: WebServices locking/latching

Всички тези проблеми, които споменаваш можеш да си ги решиш by design.

И затова може да стане мазало, първият request натъкми базата и се засили да вика външната услуга, трябва да commit-не, обаче идва втория request и за "Добър ден" избърсва всичко дето е написал първия, после почва да го пише отново (щото няма гаранция че клиента няма да си промени нещо в данните при втория request със същото ID).

WebService-а ти извиква асинхронно другите външни сървиси и в callback-а решаваш кво да правиш в зависимост от резултата.

Така, както го обясняваш има нещо тотално сбъркано в дизайна на уеб услугата...По-добре помисли върху това, отколкото да мислиш други варианти.

Отговор
в отговор на BullDog #5

Re: WebServices locking/latching

Можеш да вдигнеш уеб сървиса "One instance per session" и да локваш заявките да минават една по една, но за целта трябва да сложиш state server при положение, че сървиса е във ферма.

Но пак ти казвам, че това само ще ти създаде повече главоболия.
Ако първия завърши, а втория фейлне, как ще ролбекнеш в базата? Ръчно?

ЕДИТ: Всъщност това въобще няма да работи на scale out...пак ще си имаш n на брой инстанси на сървиса (в зависимост от броя на нодовете) и нямаш никаква гаранция на кой инстансе ще пристигнат заявките (и дали ще пристигнат всички)

Редактирано от Aaron на

Отговор
в отговор на Aaron #6

Re: WebServices locking/latching

В отговор на:

Всички тези проблеми, които споменаваш можеш да си ги решиш by design.



Бе аз имах един асистент, дето казваше: Красотата ще спаси света ... е вярно само по книжките.
Нали знаеш, че в реалността, не можем да контролираме всичко, което ни заобикаля.
Имам пред вид: Клиентите на моят WS искат да го ползват синхронно, външният сървиз, дето аз ползвам е асинхронен, като дори не мога да модифицирам кода дето обработва респонса (аз си комуникирам с този външен сървиз през базата само) - нагласям базата, инциирам рекуеста и после трябва да "poll"-вам пак през базата, дали ми е дошъл респонса.

В отговор на:

WebService-а ти извиква асинхронно другите външни сървиси и в callback-а решаваш кво да правиш в зависимост от резултата.




Почти уцели 10-ката. Да знам, че изглежда weird, но това е реалността - моят sync WS трябва да wrap-ва async service. Това е постановката, аз не мога да я променя. Сам разбираш, че не мога да вися с незатворена транзакция в базата, докато чакам async сървиза.

Варианта за тотална смяна на дизайна не съществува :) Нещата работят вече, парите са изядени и изпити, клиентът дори е доволен. Но този проблем със застъпващите се рекуести ме дразни и може да ми докара главоболия по-късно.

Пък дори и да мога да го променя (дизайна) - да го променя със какво? Аз красив начин да се wrap-не async call in sync service ... не съм видял.

Отговор
в отговор на Aaron #7

Re: WebServices locking/latching

Не съм сигурен, че те разбирам 100%, но мисля че налучквам посоката ...
Верно е, че имам нещо като ферма, така че ми трябва координатор (това дето ти му викаш state server) В конкретния случай ползвам Axis2, гледам имат някакъв клъстеринг, ше трябвада вида как да го комбинирам със сегашната ситуация (имам WebSphere клъстер с много инстанси, но никой от Axis2 service-те в даден инстансе "не знае" за останалите)
Другия вариант е аз да се опитвам да пиша подобие на координатор, нешо дето хич не ми харесва като идея, щото има голяма верятност да го омажа и да стане по-лошо. Нали за това отворих темата, да не откривам пак топлата вода ....

Отговор
в отговор на BullDog #8

Re: WebServices locking/latching

То и аз не разбирам точно какво искаш да направиш, ама като си тръгнал с мацаниците - ето ти една идея:-)

1. Искаш да кажем 5 последователни рекуеста да ти формират една пълна транзакция, или
2. След като клиента е пуснал "заявка за транзакция" след 5 сек. може да пусне нова заявка за "отмяна на транзакцията"?

Ако е първото:
В момента на пристигане на рикуеста на нод1 пишеш в базата в една талибличка "рекуест1-нод1-клиентИД-threadID" и го hold-ваш . Идва нов рекуест - пишеш "рекуест3-нод2-клиентИД-threadID" и го hold-ваш и т.н. Всеки един нод/инстанс на WS през малък период от време(1сек.) проверява в базата дали са се събрали 5 последователни рикуеста (ако предположим, че 5 рекуеста ти е всъщност цяла пълна транзакция). Като се съберат и петте, нода, на който е първия рекуест пуска първия рекуест и при завършване пише в табличката "рекуест1-комплийтед". Другите нодове си проверяват в базата и почват да пускат един по един рекуестите, които hold-ват.:-).
Само трябва да решиш как (по какъв критерии) ще групираш рекуестите, че са от определена транзакция...

Това можеш да го направиш както в базата, така и на state server, се в гъз е, където и да е...
Дори в базата можеш да си направиш предварителни таблички където да няма кънстрейнти и др.глупости и да пишеш данните в суров вид. Като мине и 5-ия рекуест - почваш "същинската обработка в базата" и разнасяш данните по "истинските таблици".

Проблема е, че ако някой от нодовете "падне" - клиента трябва отново да си пусне транзакцията...

А това, че трябва да се изчака 20сек. за външния сървис, за да ти върне резултат - примиряваш се и толкова...нищо не можеш да направиш.

Ако е второто:
Пак по същия начин можеж да маркираш в базата в една табличка: "клиентИД-транзактионИД-in progress" и след като WS е извикал всичко и е готов да пише в базата проверяваш първо дали има рекуест за отказ (ако има и е свършил преди 1-вия рекуест - пишеш в табличката "клиентИД-транзактионИД-canceled") и ако има - дискардваш първия рикуест.

Отговор
в отговор на BullDog #9

Арун

се е опитал да обяснява.
Проблема ти е архитектурен (тряя ти управление на депенденсита, останалото а/синхронно е подробност) - решава се с промяна на архитектура/рефакторинг (туй са думичките дето да обелиш). Инак може да си го патчнеш като си напишеш семафоринг, в някои случаи е достатъчно.

Отговор
в отговор на Aaron #10

Re: WebServices locking/latching

Второто :) (първото е прекалено усложнена ситуация - там в общи линии отиваш на стейтфул WS)
Представи си че моят WS приема заявки за зеленчуци, а външен сървиз потвърждава дали заявката е изпълнима.
Идва заявка ID1: "искам 100 кила домати". Пиша в базата, питам сървиза "ще има ли 100 кила домати за тоя", чакам отговор, получавам отговор "ше има", записвам потвърждението в базата, връщам отговор на клиента: "Ще стане"
Идва нова заявка ID2: "искам 50 кила лук" ... същата процедура.
Никога не идват заявки "отказвам се" (cancel transaction), но може след малко да дойде пак заявка с ID1 и да каже "Бе не са домати, били 100 кила краставици" или пък "не били 100, ами били 200 кила". Понеже не ми се занимава да познавам какво е променено, се ползва "мъжката стратегия" - избърши всичко за това ID от базата и почваме на ново.

И сега, сетуацията е:
Заявка с ID 123: "искам 20 кила краставици" ... пиша в ДБ, пращам заявка навън, чакам ...
В тоз момент, същия юнак праща пак ID 123 "искам 20 кила краставици, ве!"
Нода, дето го обработва това не знае, че има текуща обработка на същото ID, дето не е завършила и ще забърши каквото има в базата. После ще си започне своята обработка. Външния сървиз не се шашка от това че ще го питам 2 пъти (приеми, че има неограничени ресурси, въпросът е по скоро имаме ли краставици изобщо или не)
Може и нищо лошо да не стане, ама нещо не ме кефи.

Докато ти го обяснявах ми хрумна очевидното решение да маркирам в базата коя обработка в приключила и коя не е. Тогава такива дето не са приключили не се изтриват, а се чака да приключат и чак тогава се трият (много умно!)

И пак остава един проблем ... моят сървиз не е перфектен, някой път думка - кофти данни, DB deadlocks (DB2 е рядък шит по отношение на деадлоците), и т.н. Та като думне (1 на 1000, ама думка) няма кой да маркира, че всъщност обработката е приключила (неуспешно). Такива ID-та могат да останат блокирани форевер. Да, да, знам, Exception Handling, и т.н. ама точно като кажеш - това никога не трябва да се случва, баш такива неща се случват :)
Както сам си споменал - ако някой ноде падне точно по време на обработка, това ID няма кой да го маркира за приключено.

Да не говорим, че маркиране през базата означава ТОЧНО да се комитва транзакцията (Иначе няма как другите да видят, че е маркирано :))

Както и да е, мерси за идеите, мерси за отделеното време ... Пий една виртуална ракия от мене :)

Отговор
в отговор на Kirosviniata #11

Re: Арун

Джими, аз споменах че в някои случай не ни е дадено да променяме архитектури, а да направим каквото се иска при съществуващи архитектури.
Аз не искам да пиша семафоринг, ако някой вече е написал нещо такова. С удоволствие бих го ползвал (стига да е фрее :))
В случая не мисля че точно семафоринг ще ми свърши работа. Семафорите имат смисъл в рамките на един JVM, аз споменах че имам клъстер. И не мисля да пиша RPC или подобни на Java :)
Ше вида дали не мога да използвам нещо от клъстеринга на framework-а (axis2)

Отговор
в отговор на BullDog #12

Те туй

и е драмата на Жабата - възпитава използвачи на чужд код, който дори не разбират - вместо да си напишат свой :)
?езултата е меко казано неуправляем.
Когато архитектурата е неадекватна и не можеш да я променяш, по-добре обяви лимитейшън отколкото да създаваш впечатление че решението работи (а то не се оправя).
ПП: проблема ти в по-голям мащаб ми е пред очите всеки ден, за съжаление. Точно както си го описал (техническата му страна).

Отговор
в отговор на Kirosviniata #13

Re: Те туй

ПП: проблема ти в по-голям мащаб ми е пред очите всеки ден, за съжаление. Точно както си го описал (техническата му страна).

Стига бе...верно ли? Ма нали си у сериозна мулти-милиардна компания...
Недопустимо е такъв елементарен проблем да ти е пред очите всеки ден:-)

И как го решихте проблема при Вас?:-) Скръм, Ъджайл, Канбан...
Всъщност забрави...то е ясно, че не сте го решили:-)

Отговор
в отговор на BullDog #14

Re: WebServices locking/latching

В отговор на:

Аз красив начин да се wrap-не async call in sync service ... не съм видял.




Ми защото не си бачкал достатъчно с Javascript според мен.
Лошо няма де, сериозните програмисти по традиция подценяват фронт-енда и неговите чалъми.

Според мен нямаш нужда от семафор, ами от "пакетьор". Накратко, някаква фунция, която отваря тикети и следи дали има незатворени. "Тикет" в случая може да е всичко - от риспонс на търд-партито, до транзакция в базата. Докато не се затвори всичко на клиента не се връща нищо, а нещото което му се връща накрая е крайния резултат. Евентуално може и някакво хистъри, за да знае какво е станало. Схемата е недодялана, но пък напълно стабилна.

Ако ти се наложи да пишеш някога GreaseMonkey скрейпър, ще видиш че без такава супервайзинг функция, всичко е хаотично и дори прави грешки. Не се налага никаква промяна по дизайна, дано ти свърши работа.

Отговор
в отговор на Aaron #15

Ъми

ш'са сетиш, тук се пише бая (като обем) - не е като при тебе да надрискаш две джарки и да забравиш съпорта после :)

Има проблеми, има решения - и кервана си върви.

Отговор
в отговор на croesus #16

Мда,

и какво става когато някой тикет си остане отворен щото е забравен от клиента?
Леко полеко ще му предложиш цяла месъджинг система и работата ще стане повече отколкото покрива сегашния му код :P

Отговор
в отговор на Kirosviniata #17

Re: Мда,

Ми кво да стане...ще използва стратегията на САП-а:-)
Зима една маймуна от пазара, дава й гръмката позиция "Джуниър аппликейшън администратор" за 800лв, прави една вътрешна уеб страничка дето да показва зависналите рекуести и слага 2 бутона "Делете" и "Рисенд" и бизнеса потръгва.
Маймуната тропа по цел ден на клавиатурата и се обяснява с клиентите:-)))

Сега, не се прави, че не ги знаеш тия неща...непрекъснато са ти пред очите-:)

Отговор
в отговор на BullDog #18

Що не пробваш да прехвърлиш проблема на клиентите

Сори ако се повтарям с някои от предишните, но не изчетох всички мнения.

Просто връщай грешка на заявката с втория ID, уж който би трябвало да бъде уникален докато се изпълнява първата заявка с това ID.

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

Отговор
в отговор на BullDog #19

Re: WebServices locking/latching

Аз бих направил както Real-Guru е написал. Screw them!

А ако все пак "отгоре" настояват да обслужа 2 еднакви ID-та, ще го направя в вариант C). То и без това сам си написал "ако име заявки с едно и също ID (от един и същи клиент), те ще са в поредица" - щом са поредица ще ги обслужа поредно.

General Protection Fault in module 0xDEEBAA. Рестартирайте държавата!

Редактирано от headhunter на

Отговор
в отговор на BullDog #20

Re: WebServices locking/latching

Аз смятам че всеки сървис трябва да е независим от клиента. Иначе няма смисъл да се използва уеб сървис. По-добре RPC. Ето ситуацията:

- Заявка 1: Искам 20 кила краставици
- Обработка
- Заявка 2: Пак искам 20 кила краставици
- Нареждаш на опашката или паралелно обработваш независима заявка за нови 20 кила крастаивици.
- Отговор на завка 2 (по-рано е приключил)
- Отговор на заявка 1 - тайм-аут грешка


Вярвам, че е лош дизайн да се използват тия ID-та, с които се следи някакъв стейт между клиент и уеб сървис. Уеб сървиса трябва да може да отговаря на въпроси образно казано според договора между него и клиента. Всеки клиент трябва да знае защо задава въпросите и в каква последователност.

Няма проблем да се използва ID, което да се връща на клиента. Но твоя уеб сървис трябва да създаде свое собствено ID за обработка. Трябват ProcessingID и ClientID.

В contract-a, сложи примерно един елемент наречен <CorrelatedData/>. Той е един и същ в request и response.

Всичко което клиента сложи под CorrelatedData, сървъра го връща без да се замисля.

<CorrelatedData>
<ClientID>12345</ClientID>
<UserName>pesho.konia</UserName>
</CorrelatedData>

По този начин ти позволяваш на клиента да си пази някакъв state, но не се занимаваш да му мениджваш клиентското ID. Ти си създаваш свое независимо ID за обработка. Най-важното е всеки играч да е независим.

Отговор