Benchmarking de sistema antispam

El otro día se me ocurrió preguntar a los componentes de la FilaDeAtras sobre como evitarian que alguna IP hiciera más inserts de la cuenta en una web en PHP que estoy haciendo y dos componentes respondieron audazmente con dos algorismos diferentes. Me entró curiosidad sobre cual de los dos sería más rápido y por lo tanto me permitiría hacer una web más ligera.

  • franhp propuso guardar una IP y un timestamp con cada insert en la base de datos
  • hektor propuso guardar las IP en un archivo de texto plano

Para realizar estas pruebas he creado una base de datos con 10k, 100k y 10M de registros (las tablas contienen un campo varchar(16) en el que se almacena la IP y un timestamp de la hora que se insertaron) así como archivos de texto plano con la misma cantidad de datos. Después he creado unos scripts en PHP que generaban 50 peticiones 5 veces y calcula cuanto se ha tardado en total en hacerlas. Posteriormente he pensado en los siguientes algorismos:

  • MysqlA: Se cargan todos los resultados de la consulta en memoria y allí se busca
$num = rand(0,255);
$query = 'select num from lista where num = '.$num.' and timestamp > from_unixtime('.mktime(0, 0, 0, date('m'), date('d')-1, date('Y')).')';
$result = mysql_query($query);
$i = -1;
while($row = mysql_fetch_row($result)){
$i++;
}
  • MysqlB: Se confía en la capacidad de contar de mysql
$num = rand(0,255);
$query = 'select count(*) from lista where num = '.$num.' and timestamp > from_unixtime('.mktime(0, 0, 0, date('m'), date('d')-1, date('Y')).')';
$result = mysql_query($query);
$row = mysql_fetch_row($result);
  • MysqlC: Se usa el mismo comando de contar pero desde php
$num = rand(0,255);
$query = 'select num from lista where num = '.$num.' and timestamp > from_unixtime('.mktime(0, 0, 0, date('m'), date('d')-1, date('Y')).')';
$result = mysql_query($query);
$i = mysql_numrows($result);
  • Files: Se carga el archivo en memoria y luego se hace un foreach para buscar coincidencias
$lines = file($file);
$num = rand(0,255);
$i = 0;
foreach($lines as $line){
if($line == $num) $i++;
}

Resultados

Conclusiones

Si esperamos sólo 10k de inserts, podemos observar que lo mejor sería usar un archivo de texto plano para almacenar las IP y irlo borrando con cada noche (cron).  También vemos que el algorismo MysqlA (cargar todos los resultados en memoria para tratarlos) es el más lento en la mayoría de casos.

Si esperamos 100k de inserts, vemos que usar un archivo de texto plano ya no es una alternativa ya que le saca aproximadamente medio segundo más a cualquier alternativa de mysql y aprovecha mucho mejor el caché (fijaos en el tiempo del primer resultado y el siguiente) Tampoco la opción mysqlA es una alternativa, siempre es más lenta que el resto.

Si esperamos 10M de inserts, lo primero sería cambiar mysql por otra base de datos más profesional como por ejemplo Oracle (aquí el DBA de mi empresa estaría orgulloso de mí :P), y lo segundo es que extrañamente el uso de archivos de texto plano es muchisimo más rápido, hasta 3 veces más, que cualquiera de los algorismos que usan base de datos.

And the winner is … (tambores) … Archivos de texto plano!

Nota: Cabe decir que no se ha probado alguna de las bases de datos NoSQL, eso lo dejo para el próximo artículo 😛
Nota2: Podeis encontrar el codigo en https://github.com/franhp/BenchmarkingTestClass

*****6votes
2 Comentarios »  | Categorías:  filadeatras, internet, PHP, programación Tags: ,

2 Responses to Benchmarking de sistema antispam

  1. hektor says:

    vaya, te lo has tomado muy en serio esto, muy buena comparativa francesc :O

Leave a Reply

Your email address will not be published. Required fields are marked *