Bug #1931
closedWarden server 2.2 vrací zprávy po jedné, nezávisle na tom, jak jsou nastavené serverové či klientské limity
0%
Description
Warden server 2.2 vrací zprávy po jedné, nezávisle na tom, jak jsou nastavené serverové či klientské limity.
Pro klienty je to naštěstí na warden.cesnet.cz transparentní, dostanou jednu zprávu a jdou si pro další novým dotazem, dokud nedostanou všechno.
Uvnitř už to tak hezké není. Na letmý pohled totiž nejspíš dochází k tomu, že ve smyčce Warden.pm(375), která iteruje pomocí fetchrow() přes události $sth, se zavolá znovu prepare, a znovu na $sth. Takže se zpracuje v první iteraci první řádek/událost, zbytek se zahodí na nový select, z něj se vezme hostname a service, další řádky už nejsou (klienti jsou unikátní), takže do další iterace smyčky dojde tatáž $sth, už s úplně jiným dotazem, naštěstí ale už s vyčerpanými výsledky, a smyčka skončí.
Tohle chce velmi rychle opravit, protože tahle věc teď běží na ostrém wardenu - a ne tak, že se pro každou zprávu v potenciálně dlouhém poli, získaném jedním SQL dotazem, zavolá další SELECT! Tím házíme výkon do stoupy a urážíme SQL.
Od toho je přece JOIN, který má být použit už v SELECTu, získávajícím události, a rovnou přihodit do výsledku hostname a service z clients.
Updated by Tomáš Plesník about 10 years ago
- Status changed from New to In Progress
Dival jsem se na to a mas naprostou pravdu.
Toto bohuzel vzniklo novym propojenim tabulek pres client_id, kdy jsem do stareho kodu pripsal jen polovicate reseni pomoci dvou SELECTu a ne jedno SELECTu s INNER JOINu (predpokldam, ze udalost bez clienta nemuze existovat). Oba SELECTYy tedy zrusim a nahradim je pouze jednim za pouziti JOINu - pro kompletni data se tedy do DB pujde pouze jednou.
Updated by Tomáš Plesník about 10 years ago
Provedl jsem rychlou a docasnou opravu 5f61a122 a nyni uz server prijimajicim klientum posila udalosti po davkach, ne jednotlive. Novou verzi kodu jsem otestoval a nasledne nasadil na produkcni Warden server. Nyni uz predelavam neefektivni dva SELECTy na jeden INNER JOIN.
Updated by Pavel Kácha about 10 years ago
Ještě mě tak napadlo, možná úpravy toho kódu komplikují ty vnořené větve, a budeš muset upravovat dotaz na tuším čtyřech místech - jestli by nebylo jednodušší vygenerovat ten dotaz jednou. Nastřelil jsem z hlavy, ber jen jako návrh. Každopádně nechávám na tobě.
if(defined %client) { my $query = "SELECT e.id, c.hostname, c.service, _atakdál_ FROM events e, clients c WHERE e.type != 'test' AND e.valid = 't' AND e.client_id = c.client_id id > ?"; my @params = ($last_id); unless ($requested_type eq '_any_') { $query .= " AND type = ?"; push(@params, $requested_type); } unless ($client{'receive_own'} eq 't') { my ($domain) = $cn =~ /([^\.]+\.[^\.]+)$/; $query .= " AND c.hostname NOT LIKE ?"; push(@params, '%' . $domain); } $query .= " ORDER BY id ASC LIMIT ?;"; push(@params, $used_limit); $sth = $DBH->prepare($query); unless (defined $sth) { sendMsg("err", "Cannot prepare ROE-ANY statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $rc = $sth->execute(@params); unless (defined $rc) { sendMsg("err", "Cannot execute statement in function '$function_name': $DBH->errstr", "Internal 'execute' server error"); } }
Updated by Tomáš Plesník about 10 years ago
Na podobne reseni jsem ted dosel i ja, kdyz jsem si pod sebe poskladal vsechny ty ctyri dotazy. Postupnym generovanim SELECTu se ta sekce zjednodusi. Jen premyslim nad tim, zda-li pouzit primo INNER JOIN, nebo vyuzit SELECT s aliasy a nechat databazi at si jej sama prevede na INNER JOIN. Predpokladam ale, ze technicky to bude asi jedno.
Updated by Pavel Kácha about 10 years ago
Pravda... já bych tam dal JOIN, kvůli čitelnosti, ať je na první pohled jasnější, že se tam něco mixuje. A v rámci joinu stejně nejspíš aliasy použiješ (aby ses mohl snadněji odkázat na konkrétní jména sloupců), něco jako SELECT e.id, c.hostname FROM events AS e JOIN clients AS c ON e.client_id = c.client_id WHERE ...
Updated by Tomáš Plesník about 10 years ago
Souhlasim, ja jsem take pro explicitni JOIN. Aliasu se nezbavim, jelikoz sloupce type
, client_id
a valid
jsou v obou tabulkach. Dotaz by pak mel vypadat nasledovne:
SELECT id, hostname, service, detected, events.type, source_type, source, target_proto, target_port, attack_scale, note, priority, timeout FROM events INNER JOIN clients ON events.client_id = clients.client_id WHERE events.type != 'test' AND id > ? AND events.valid = 't' ORDER BY id ASC LIMIT ?;
Jen jeste premyslim, zda-li ty prefixy tabulky nedat, opet kvuli citelnosti, vsude.
Updated by Tomáš Plesník about 10 years ago
- Status changed from In Progress to Resolved
Hotovo, oprava je dostupna v revizi e37ecc64. Vse jsem otestoval a melo by to byt v poradku. Opraveny kod jsem nahral i na produkcni Warden server.
Pavle, velice dekuji za pomoc a odhaleni chyby.
Tom
Updated by Pavel Kácha about 10 years ago
Za málo. Koukám ale, že jsi ten můj kód použil téměř beze změny, doufám, že jsi to otestoval opravdu dobře, protože jsem ho psal jako nástřel spatra do inputboxu Homeproje.
Updated by Tomáš Plesník about 10 years ago
Pavel Kácha wrote:
Za málo. Koukám ale, že jsi ten můj kód použil téměř beze změny, doufám, že jsi to otestoval opravdu dobře, protože jsem ho psal jako nástřel spatra do inputboxu Homeproje.
Zmeny byly potrebne pouze v pojmenovani jednotlivych sloupcu, nicmene ten kod byl elegantni a funkcni, tak proc jej nepouzit. Pred nasazenim jsem jej ale samozrejme poradne otestoval a vyzkousel vsechny vetve.
Updated by Pavel Kácha about 10 years ago
- Status changed from Resolved to Closed
Oki, jen mi trochu zatrnulo, když jsem si uvědomil, jak jsem ho smolil/pastoval. Každopádně taky díky za promptní reakci a vyřešení.