Сервіс подій в SQL-сервері, MySQL, Бази даних, статті

Гліб Уфімцев

Занурення в проблематику

Досить нерідко у розробників клієнт-серверних додатків виникає необхідність організувати
якийсь механізм, що дозволяє по події на SQL-сервері повідомити того або іншого клієнта. Ще частіше це
є рожево-блакитною мрією замовника, щоб розробник реалізував такий механізм. Наприклад, при
перевищенні лімітів відвантаження якомусь споживачеві, повинні бути негайно повідомлені менеджери,
працюють з цим споживачем. Деякі замовники систем вимагають (а мріють про це всі замовники без
винятки), щоб при зміні якихось даних, у решти користувачів системи ця інформація
автоматично оновлювалася, причому негайно. Тут не обговорюватиметься доцільність такого
вимоги (воно має багато підстав для критики), тут будуть обговорюватися тільки шляхи вирішення.
Microsoft SQL-сервер має штатний засіб для організацій повідомлень – alerts, але цей засіб має
вельми обмежене застосування, за великим рахунком не дає можливість створити на його основі
гарантовано працюючий механізм. І ось чому: Зв'язок з клієнтською програмою може бути
здійснена шляхом посилки e-mail або емуляцією посилки "net send". І те, і інше незручне для отримання
повідомлення.

Засіб e-mail незручно з причин:

a) немає гарантії доставки, пошта може втрачатися.
b) пошта може "застрягти" на проміжних вузлах.
c) потрібна обов'язково наявність протоколу TCP / IP
d) потрібна наявність smtp-сервера і настройка поштового профілю.
e) потрібна особлива настройка SQL-сервера, щоб він зміг посилати листи.
f) потрібна наявність у кожного клієнта, що чекає події, поштової скриньки.
g) у клієнтській програмі потрібно організувати поштовий клієнт.

Здійснення шляхом "net send" незручна з наступних причин:

a) немає гарантії доставки, так як це організовано через засіб mailslot, що не має такої гарантії.
b) потрібна наявність коректного дозволу імен NETBIOS в мережі.
c) потрібна наявність на клієнтові "Клієнт для мереж Микрософт".
d) задіяний стандартний mailslot, це може мати перетин з іншими програмами.

І в цілому засіб alerts незручно необхідністю реєстрації кожного клієнта як оператор і
відповідним налаштуванням. Тобто для найпростіших випадків alerts застосувати можна. Але для більшості
випадків воно не застосовується.

Відомі реалізації і концепції

Широкій громадськості відомі кілька варіантів реалізації механізму повідомлення сервером
клієнта. Це:

1. Створення об'єкта (Extended Stored Procedure або ActiveX), за допомогою якого SQL-сервер повідомляє
клієнта через сокети TCP / IP. При цьому на клієнтові організована прослушка, тобто клієнтська програма стала
сервером TCP / IP.
Недоліки цього методу:
a) Прив'язка до протоколу TCP / IP. У мережі, де використовується тільки IPX, NETBEUI або AppleTalk, такий механізм
не застосувати.
b) Ні асинхронності. Якщо ця подія генерується з тригера, будуть проблеми продуктивності.

2. Створення об'єкта (Extended Stored Procedure або ActiveX), за допомогою якого SQL-сервер повідомляє
клієнта через named pipes або mailslots. При цьому на клієнтові організована прослушка того або іншого.
Недоліки цього методу:
a) потрібна наявність коректного дозволу імен NETBIOS в мережі.
b) потрібна наявність на клієнтові "Клієнт для мереж Микрософт".
c) у разі використання mailslot немає гарантії доставки.
d) у разі використання named pipes, це не можна застосувати на клієнтських комп'ютерах з операційною
системою Windows 95/98/Me, оскільки named pipe можна створити тільки в операційній системі на архітектурі NT.
e) Немає асинхронності. Якщо ця подія генерується з тригера, будуть проблеми продуктивності.

3. Періодичний опитування SQL-сервера клієнтом (періодичне читання спеціальної таблички евент).
Це дуже простий шлях, але, тим не менш, вільний від більшості вищеперелічених недоліків.
На жаль, цей метод має свої специфічні 2 недоліки: a) отримання повідомлення може бути
затримано на величину таймауту опитування і b) при маленькому таймаут виникає істотний трафік.
Тим не менш, при невеликому кол-ве сесій, цей метод цілком придатний і незаслужено обійдений увагою.

Пропонований варіант рішення

Вашій увазі пропонується варіант вирішення проблеми, вільний від вищеперелічених (всіх
перерахованих вище!) проблем, але разом з тим досить простий. Ідея така: на сервер поміщається
якийсь двійковий об'єкт, який sql-сервер може викликати (а це може бути тільки Extended Stored
Procedure або ActiveX-об'єкт), що має два невзаємопов'язаних методу.
Перший метод створює за допомогою функції Win32API CreateEvent об'єкт ядра Win32, іменований "event" з
унікальним найменуванням, переданим параметром. Далі викликається функція Win32API WaitForSingleObject,
наткнувшись на яку, потік зупиняється і стоїть в очікуванні, поки цей об'єкт ядра не засигналив.
Звертаю вашу увагу, на той факт, що таких об'єктів ядра може бути створено скільки завгодно.
Це обмежено тільки кол-вом хендл в системі.
Другий метод викликає об'єкт ядра event по імені, заданим параметром, за допомогою функції
Win32API SetEvent і виставляє йому властивість "signaled". Як тільки це відбудеться, потік з першим методом
пробуджується і повертає керування викликав процесу. Другий метод, не чекає результату, а
повертає управління своєму викликав процесу відразу ж після виставляння властивості "signaled". Таким
чином досягається асинхронність.
Тепер залишається тільки зробити процедури T-SQL,
керівники цим об'єктом і потрібна функціональність "у нас у кишені". Клієнтська програма в
окремому потоці запускає процедуру, що зберігається очікування події, передаючи параметром унікальний
ознака-адресу. Це може бути і ім'я користувача, і ім'я комп'ютера, і будь-який рядок. Головне, щоб це
була унікальний ідентифікатор в межах клієнт-серверної системи. Процедура поверне
результат лише в разі, якщо для цього адресата буде згенеровано подія. При отриманні події,
процедура перезапускається. При закритті програми потік очікування події просто прибивається через
TerminateThread.
На перший погляд ця методу володіє "жахливим" недоліком – існує постійний
коннект з sql-сервером, який більшу частину часу нічого не робить. Але це тільки перше враження.
Насправді, задіюються ресурси тут тільки на підтримку коннекта – це щось декілька кілобайт
на сесію. І все! Більше ніяких відчутних ресурсів не витрачатися, особливо на тлі переваг, які
описані нижче. Про додаткові ліцензії можна теж не турбуватися, якщо вибрана модель
ліцензування "Per server". У цьому випадку з однієї машини може бути скільки завгодно коннектів до
sql-серверу, це все одно буде займати рівно одну клієнтську ліцензію.

Готове рішення

Рішення складається з ActiveX-об'єкта у вигляді файлу AlgoEvt.dll і двох збережених процедур spWaitForEvent і
spRaiseEvent. Перед використанням цей файл треба помістити на сервер і зареєструвати ActiveX-об'єкт з
допомогою системної утиліти regsvr32.exe. Далі вся робота проводитиметься через збережені процедури.
У готовому рішенні реалізована трохи більша функціональність, ніж в описаній концепції. Крім
самого факту події, можна передати також довільну інформацію у вигляді рядка в розмірі до 250
символів. Кожна процедура має два параметри. Перша – це унікальний ідентифікатор-адреса, про який
говорилося вище, а другий параметр – додаткова передається інформація. spWaitForEvent треба викликати
з клієнта з окремого потоку (пріоритет потоку можна вибрати найнижчий). При отриманні події,
процедуру треба перезапустити. Тайм-аут виконання запиту треба задати нескінченний.

Рішення тут: SQLEventsService.zip

Переваги рішення

1. Незалежність від мережевого протоколу і настройок мережі. Був би коннект до sql-серверу.
2. Асинхронність. Ініціатор події не чекає, коли клієнт отримає подію. Можна ініціювати події
в тригері, повернення відбувається вмить.
3. Відсутність затримки доставки.
4. Гарантія доставки.
5. Відсутність практичних обмежень на кількість клієнтів, які очікують події.
6. Не витрачаються ресурси, за винятком незначних ресурсів на підтримку з'єднань.
7. Відсутність "лівого" мережевого трафіку.
8. Не потрібно додаткових сервісів і програм.
9. Не потрібно додаткових налаштувань sql-сервера.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*