viernes, 16 de mayo de 2008

¿Cómo saber cuánto se deduplicará?

La principal pregunta a la hora de aplicar deduplicación o convencer a alguien de que es algo que le puede venir muy bien es precisamente ¿Cual es mi potencial de deduplicacion? Es decir, si aplico la deduplicacion a tal o cual volumen: ¿Cuánto se deduplicará? ¿Cuanto espacio me ahorraré? El 10%, el 40%...

Aqui os pongo un script (en python) que realiza (o intenta realizar) una estimación de lo que nos ahorraríamos usando la deduplicación de NetApp.

Como ya expliqué en este post la deduplicación de NetApp funciona en un 99% de esta forma:
En algun lugar hay un directorio que dice que el fichero A esta almacenado en los bloques 123-345, 500-510 y 12999-14090. Por el momento esto es lo normal para todos los FS. La diferencia entre el FS deduplicado y el normal es que pueden usar el mismo bloque más de un fichero. Si edito el fichero A y añado 10KB al final y lo guardo como B en algun momento (dedupe en tiempo real o dedupe diferida) el proceso de deduplicacion reconocerá (via hashes o por comparacion de bytes) que ambos ficheros tienen los mismos datos y creará una entrada en el directorio que dice que B utiliza los bloques 123-345, 500-510, 12999-14090 y 66666-66669(Por ejemplo los bloques son de 1K), de forma que la creacion del fichero B solo ocupa 10K(del 66666 al 66669).

¿Como funciona el script?
El script mira recursivamente en el directorio que le indiquemos leyendo cada archivo. Posterirormente va troceando cada archivo en chunks de 4 kB (ese es el tamaño de bloque que usa NetApp) y calcula un md5 de cada bloque de 4kB. Se mantiene una lista de los md5 calculados y comprueba si se trata o no de datos duplicados.
Cada vez que se procesa un archivo el script nos proporciona por un lado la deduplicacion que obtendria ese fichero y por otro cómo vamos en el total del directoriro en el que estamos intentando estimar el ahorro debido a la deduplicación:

Archivo /tmp/dedup/Archivos_Backup.txt: Tamano 286927441 bytes (70051 bloques)
Estadisticas del Archivo /tmp/dedup/Archivos_Backup.txt: Bloques Usados: 3728, Bloques del Archivo: 70051, Ratio 5.3%, Ahorro 94.7%.
Estadisticas Totales Recalculadas: Numero de Archivos: 12, Bloques Usados: 7073, Bloques Totales: 73396, Ratio 9.6%, Ahorro 90.4%.


Finalmente, cuando se ha terminado de procesar todo el directorio el script nos muestra los datos importantes:
=======================================================================================================================
Estadisticas Totales Finales: Numero de Archivos: 961, Bloques Usados: 268422, Bloques Totales: 401134, Ratio 66.9%.
Ahorro Final que obtendras con la deduplicacion 33.1%.
=======================================================================================================================


En este caso obtendríamos un 33% de ahorro de espacio si usasemos deduplicacion.
El script sólo da una aproximación de los ahorros que conseguiríamos aplicando la dedupliación puesto que
se necesitaría también espacio para mantener la base de datos de hash y algunos metadatos.
Por las pruebas que he hecho es bastante fiable, incluso a veces el tiempo que tarda en hacerlo es equivalente en la cabina y con el script. A ver que os sale a vosotros...

Ejemplo de uso: python estimar_dedup.py /tmp/dedup
(Podeis poner delante time para ver el tiempo que tarda: time python estimar_dedup.py /tmp/dedup)

Con los comandos df -h y df -s antes y despues de realizar la dedupliación con NetApp(sis on, sis start -s) podreis comprobar si el script ha resultado fiable o no.

Por favor, si obteneis resultados(buenos o malos) o mejoras o problemas con el script, ¡comentadmelo! Espero que sirva aunque sea para saber a priori si te compensa usar deduplicacion o no...

Nota: Los resultados más espectaculares de la dedup de NetApp se dan en los ficheros que no pierden su alignment de 4kB anque se modifiquen. Como los vmdks de VMware y no como los ficheros de texto.


[root@server ~]# more estimar_dedup.py
#!/usr/bin/python

import os, sys, md5
from stat import *

# Lee todos los ficheros del directorio y
# estima los ahorros de la dudup de NetApp haciendo el md5
# y comprobandolo para cada bloque de 4 kB. el paramentro importnate
# es el que da el ultimo Ratio (un ratio de 70% significa que te ahorras # un 30%)

if len(sys.argv) != 2:
print "Uso: nombre.py "
sys.exit(1)

workdir = sys.argv[1]

if not os.path.isdir(workdir):
print "Problema: " + workdir + " no es un directorio"
sys.exit(1)

print "Comprobando directorio: " + workdir

numfiles = 0

storage_blocks = 0

total_blocks = 0

current_file_storage_blocks = 0

fingerprint_index = {}


for root, dirs, files in os.walk(workdir):
for f in files:
filename = root + "/" + f
print "Archivo " + filename + ": ",

if f==".snapshot":
continue

if not os.access(filename, os.R_OK):
print "No access, skip"
continue

if os.path.islink(filename):
print "Symlink, skip"
continue

mode = os.stat(filename)[ST_MODE]
if not S_ISREG(mode):
print "No regular file, skip"
continue

file_size = os.stat(filename).st_size

blocks = int( round( (file_size + 2048) / 4096.0) )

print "Tamano " + str(file_size) + " bytes (" + str(blocks) + " bloques)"

f = open (filename, "r")

current_file_storage_blocks = 0

for block_number in range(0,blocks):
blockdata = f.read(4096)
m = md5.new(blockdata)
fingerprint = m.digest()

if fingerprint_index.has_key( fingerprint ):
pass
else:
fingerprint_index[fingerprint] = True
storage_blocks = storage_blocks + 1
current_file_storage_blocks = current_file_storage_blocks + 1

total_blocks = total_blocks + 1

f.close()

print "Estadisticas del Archivo "+ str(filename) + ": Bloques Usados: "+str(current_file_storage_blocks)+ ", Bloques del Archivo: "+str(blocks)+
", Ratio "+str( round((100.0 *current_file_storage_blocks)/blocks,1) )+
"%, Ahorro "+str( round(100 - (100.0 *current_file_storage_blocks)/blocks, 1 ) )+"%."

numfiles = numfiles + 1
print "Estadisticas Totales Recalculadas: Numero de Archivos: " +str(numfiles)+", Bloques Usados: "+str(storage_blocks)+
", Bloques Totales: "+str(total_blocks)+ ", Ratio "+str( round ( (100.0 *storage_blocks)/total_blocks, 1 ) )+
"%, Ahorro "+str( round ( 100 - (100.0 *storage_blocks)/total_blocks, 1) )+"%."

print "-"
print

print
print "======================================================================================================================="
print "Estadisticas Totales Finales: Numero de Archivos: " + str(numfiles) + ", Bloques Usados: " + str(storage_blocks) +
", Bloques Totales: " + str(total_blocks) + ", Ratio " + str ( round ( (100.0 *storage_blocks)/total_blocks, 1) ) + "%."

print "Ahorro Final que obtendras con la deduplicacion " + str ( round ( 100 - (100.0 *storage_blocks)/total_blocks, 1) ) + "%."
print "======================================================================================================================="

No hay comentarios: