MySQL AUDIT data

Jedan od velikih nedostataka MySQL-a za ozbiljno enterprise okruzenje je auditing. Nekakav minimalan auditing koji enterprise uglavnom zahteva je log
– ko se ulogovao
– kada se ulogovao
– odakle se ulogovao
– da li je logovanje bilo uspesno ili ne
– kada se odlogovao sa servera

Za web je ovo nepotrebno (bez potrebe bi u logu imali informaciju kada se web server zakacio/otkacio) ali za enterprise moze da bude vrlo korisno a vrlo cesto i neophodno, pogotovo kada enterprise aplikacije projektuju polupismeni developeri kojima baza radi autentifikaciju i user permissioning a ne aplikacija “posto im je tako lakse”.

Kao sto rekoh, MySQL ima jako slabu / nikakvu podrsku za auditing. Sve sto MySQL moze je da upali “general query log” i da u log fajl pise SVE (ko se okacio, kad, i stra je sve radio), ali to ima 2 mane
1. general query log trosi resurse (i do 20% usporenja ne high load aplikacijama)
2. general query log ne pamti neuspele konekcije

Kako je mysql-proxy postao vrlo popularan i koristi se vrlo cesto (sto za load balancing sto u neke druge svrhe) a i sastavni je deo MySQL Enterprise Monitor-a gde sve konekcije idu kroz MEM agent kako bi MEM mogao da pravi analizu upita, koristenje proxy-a za auditing uopste nije tako lose resenje.

Kako bi auditing radio, potrebno je instalirati mysql-proxy (ili agent), namestiti mysql da prima konekcije samo sa proxy-a (staviti ga na neki zaseban port i setovati firewall) a proxy podici na standardnom 3306 portu te ce vase aplikacije bez znanja sav traffic usmeriti kroz proxy.

Skript koji radi neki basic auditing bi izgledao:

function read_auth_result( auth )
  local state = auth.packet:byte()
  if state == proxy.MYSQLD_PACKET_OK then
      print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH OK:"
     .. proxy.connection.server.thread_id .. ":"
     .. proxy.connection.client.username .. ":"
     .. proxy.connection.client.src.name .. "->"
     .. proxy.connection.server.dst.name )
  elseif state == proxy.MYSQLD_PACKET_ERR then
      print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH FAILED: "
      .. proxy.connection.server.thread_id .. ":"
      .. proxy.connection.client.username .. ":"
      .. proxy.connection.client.src.name .. "->"
      .. proxy.connection.server.dst.name )
  else
      print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH UNKNOWN "
      .. string.format("%q", auth.packet)  .. ":"
      .. proxy.connection.client.username .. ":"
      .. proxy.connection.client.src.name .. "->"
      .. proxy.connection.server.dst.name )
  end
end
function disconnect_client()
  if proxy.connection.server.thread_id then
      print( os.date('%Y-%m-%d %H:%M:%S') .. ":DISCONNECT:"
      .. proxy.connection.server.thread_id .. ":"
      .. proxy.connection.client.username .. ":"
      .. proxy.connection.client.src.name .. "->"
      .. proxy.connection.server.dst.name )
  end
end

Ako pogledamo, skript nam loguje vreme, username, thread na mysql-u i sors/destination adrese konekcije. Vidimo kada je neko pokusao da se uloguje na mysql, da li je uspeo ili ne i kada se otkacio.

Log izgleda otprilike ovako:

2010-02-08 17:21:22:AUTH OK:31:arhimed:127.0.0.1:44440->127.0.0.1:3306
2010-02-08 17:21:33:DISCONNECT:31:arhimed:127.0.0.1:44440->127.0.0.1:3306
2010-02-08 17:21:38:AUTH FAILED: 32:arhime:127.0.0.1:44587->127.0.0.1:3306
2010-02-08 17:21:38:DISCONNECT:32:arhime:127.0.0.1:44587->127.0.0.1:3306
2010-02-08 17:21:43:AUTH FAILED: 33:arhie:127.0.0.1:44622->127.0.0.1:3306
2010-02-08 17:21:43:DISCONNECT:33:arhie:127.0.0.1:44622->127.0.0.1:3306

Ako hocemo da logujemo i osnovne podatke o upitima koje korisnik izvrsava onda mozemo prosiriti lua skript:

function read_auth_result( auth )
  local state = auth.packet:byte()
  if state == proxy.MYSQLD_PACKET_OK then
      print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH OK:"
     .. proxy.connection.server.thread_id .. ":"
     .. proxy.connection.client.username .. ":"
     .. proxy.connection.client.src.name .. "->"
     .. proxy.connection.server.dst.name )
  elseif state == proxy.MYSQLD_PACKET_ERR then
      print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH FAILED: "
      .. proxy.connection.server.thread_id .. ":"
      .. proxy.connection.client.username .. ":"
      .. proxy.connection.client.src.name .. "->"
      .. proxy.connection.server.dst.name )
  else
      print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH UNKNOWN "
      .. string.format("%q", auth.packet)  .. ":"
      .. proxy.connection.client.username .. ":"
      .. proxy.connection.client.src.name .. "->"
      .. proxy.connection.server.dst.name )
  end
end
function disconnect_client()
  if proxy.connection.server.thread_id then
      print( os.date('%Y-%m-%d %H:%M:%S') .. ":DISCONNECT:"
      .. proxy.connection.server.thread_id .. ":"
      .. proxy.connection.client.username .. ":"
      .. proxy.connection.client.src.name .. "->"
      .. proxy.connection.server.dst.name )
  end
end
function read_query( packet )
  if string.byte(packet) == proxy.COM_QUERY then
    proxy.queries:append(1, packet, {resultset_is_needed = true} )
    return proxy.PROXY_SEND_QUERY
  end
end
function read_query_result( inj )
  local res         = assert(inj.resultset)
  local raw_len     = assert(res.raw):len()
  local packet      = assert(inj.query)
  local flags       = res.flags
  if res.affected_rows then
    ar = res.affected_rows
  else
    ar = "0"
  end
  print( os.date('%Y-%m-%d %H:%M:%S')
  .. ":QUERY:" .. proxy.connection.server.thread_id .. ":"
  .. inj.query .. ":"
  .. (inj.query_time / 1000) .. "ms" .. ":"
  .. (inj.response_time / 1000) .. "ms" .. ":"
  .. raw_len .. ":"
  .. tostring(res.flags.no_good_index_used) .. ":"
  .. tostring(res.flags.no_index_used) .. ":"
  .. res.warning_count .. ":"
  .. res.query_status .. ":"
  .. ar
  )
end

pa nam sada log izgleda malo drugacije:
2010-02-08 17:21:22:AUTH OK:31:arhimed:127.0.0.1:44440->127.0.0.1:3306
2010-02-08 17:21:22:QUERY:31:select @@version_comment limit 1:0.092ms:0.095ms:1:false:false:0:0:0
2010-02-08 17:21:23:QUERY:31:select * from mysql.user:0.281ms:0.305ms:1:false:true:0:0:0
2010-02-08 17:21:24:QUERY:31:select * from mysql.user:0.278ms:0.299ms:1:false:true:0:0:0
2010-02-08 17:21:25:QUERY:31:select * from mysql.user:0.272ms:0.293ms:1:false:true:0:0:0
2010-02-08 17:21:28:QUERY:31:select * from mysql.db:0.229ms:0.243ms:1:false:true:0:0:0
2010-02-08 17:21:33:DISCONNECT:31:arhimed:127.0.0.1:44440->127.0.0.1:3306
2010-02-08 17:21:38:AUTH FAILED: 32:arhime:127.0.0.1:44587->127.0.0.1:3306
2010-02-08 17:21:38:DISCONNECT:32:arhime:127.0.0.1:44587->127.0.0.1:3306
2010-02-08 17:21:43:AUTH FAILED: 33:arhie:127.0.0.1:44622->127.0.0.1:3306
2010-02-08 17:21:43:DISCONNECT:33:arhie:127.0.0.1:44622->127.0.0.1:3306

VN:F [1.8.1_1037]
Rating: +1 (from 1 vote)
February 8, 2010 • Tags: , , • Posted in: Razno, Support • No Comments

MySQL Sajt ne radi kako treba

Ako ste primetili da www.mysql.com ne radi / fale mu neki detalji (na primer download sekcija ili dokumentacija), to je zato sto se sajt trenutno reorganizuje.

Trazite dokumentaciju, nema je? pogledajte http://dev.mysql.com

VN:F [1.8.1_1037]
Rating: 0 (from 0 votes)
January 28, 2010 • Posted in: Razno • No Comments

Politika je gotova a sad malo da radimo

Oficijalni EC press release vezano za odobrenje ORACLE&SUN deal-a

Najzad, posle vise od pola godina prepucavanja, ORACLE & SUN dil ce da krene u implementaciju. Sta ce isti tacno doneti pokazace vreme. Ja sam za sada optimistican i mislim da je ovo veliki dan za open source zajednicu posto ORACLE ima mogucnost da od MySQL-a napravi “bezobrazno dobar RDBMS”. Oracle, koji je vec vlasnik najbitnijeg dela MySQL-a (InnoDB storage engine-a), je obecao da ce da ulozi znacajna sredstva u dalji razvoj MySQL-a.

Sta i kako dalje – videcemo.

Za sada i dalje vazi zabrana bilo kakvog komentarisanja od strane zaposlenih u SUN-u tako da cu sada da prekinem, vise kada nam skinu zabranu.

VN:F [1.8.1_1037]
Rating: +3 (from 3 votes)
January 21, 2010 • Posted in: Razno • 5 Comments

SRETNA NAM NOVA 2010

evo jos malo pa ce ova smorena 2009 da ode …sto pre ode to bolje .. kakva je bila bolje da je sto pre zaboravimo .. nit se sta iz nje dalo nauciti niti je ikome dobra donela …

SRETNA VAM NOVA 2010

da vam sve ide od ruke, da vam tabele budu normalizovane, hit ratio 99.99%, iow ispod 0.1%, da imate puno usera i da vas sistem sve to podnese, da nemate padove sistema, da imate uvek bekap pri ruci a da vam nikad ne zatreba …. da nam vile hw dizajna donesu 100G ethernet kartice, 1ms random access diskove sa 500M/s transferom, da nam posalju 1T SSD koj inisu skuplji od obicnih magnetnih…

ko je imao posao da ga zadrzi, ko nije da nadje novi

neka vam bitovi budu naklonjenji u 2010

VN:F [1.8.1_1037]
Rating: +9 (from 9 votes)
December 31, 2009 • Posted in: Razno • 4 Comments

file vs blob

Opet jedan od onih dana … ovi koji me duže poznaju znaju da već godinama ubeđujem ljude da se slike, dokumenti i sličan sadržaj koji se samo čuva i povlači ne stavlja u bazu… al nekim ljudima ne vredi pričati, moraju zveknuti glavom par puta dok sami ne skapiraju …

Evo ga jedan primer od danas .. klijent ima tabelu od nekoliko stotina gigabajta (ostale tabele su nebitne) .. ništa strašno ali .. sve je to mnogo bitno i povlači se sa mnogo app servera… i potrebno je non stop i prilično raste i … i … i … Ceo sistem je projektovan da koristi Oracle RAC i sve je to “nekako radilo” osim što je klijent bio nezadovoljan brzinom a bogami i cenom poštno Oracle RAC nije uopšte jeftina zver. Onda je “developer” (da ga ne nazovem sad pravim imenom, čita ovo možda neko mladđi od 18) odlučio da odradi “upgrade” i da to sve prebaci na, MySQL Cluster (seća li se neko onog posta o tome da mccge nije zamena za oracle rac??). Sve u svemu, naprave oni to nekako, izmene malo aplikaciju, promene mašine i dobiju jedno 30% ubrzanja u odnosu na oracle rac i naravno mnoooooooogo nižu cenu… no, kao i svaki sistem i ovaj raste i povremeno ne može, sve ni sa tih 30% ubrzanja da postigne šta se od njega očekuje i tu onda “developer”, $#%/?R$(($#(“) mu ja .. tipla naravno da mu mi sredimo problem … i naravno kome će nego ih uvale meni na grbaču … tu počinje tj. završava ova priča …

Pokupim ja lepo taj data i taj app source i logove i … da vidim ja šta se tu tako strašno dešava … i u trenutku me zabole tintara (što je mnogo zeznuto obzirom da sam vec 5 dana ukočen i da ne mogu ni da sedim a kamoli da hodam, leđa su mi već rekla doviđenja) kada sam video šta se nalazi u onih nekoliko stotina gigabajta tabele … BLOBOVI …. veeeeeeeeeeeeeeeliki blobovi … kreteni su nakucali fajlove u tabelu … razne fajlove, u proseku oko 10M veličine po fajlu … (najmanjioko 200K, najveći oko 120M) .. nebitno sta je u njima .  Sada se vratimo korak nazad i setimo se da su oni ovo sve radili na Oracle RAC-u, znači već imaju deljeni storage … proverim, naravno, imaju veliki, super nabudzeni, ekstra našiljen SAN sa mnogo splindlova, napravim ja test, izbacim ja te fajlove iz tabele, stavim ih na SAN, promenim app … (izgubim citava 2 sata da prepravim app, napisem skript da izvadi sve iz blobova u fajlove na SAN-u, prepravim tabelu i startujem test) i pustim test … i dobijem, 6882% ubrzanje .. da prevedem  to u jednostavnije mere … sada je aplikacija oko 70 PUTA BRŽA !!! Neću ni da spominjem koliko treba sada da se napravi bekap baze i fajlova (oko 10 puta brže) i slično … moroni …

Da ne ostanem nedorečen, ima tu dosta i do toga što mccge ne radi baš sa blobovima 1/1 … da je u pitanju bio običan db server (mysql server ili pgsql ili oracle ili bilo koji drugi koji normalno radi sa blobovima) razlika u brzini ne bi bila 70 puta već pre 5-6 puta, no i to je veliko ubrzanje.

VN:F [1.8.1_1037]
Rating: +7 (from 7 votes)
November 29, 2009 • Tags: , • Posted in: Support • 8 Comments