Reinstalando el eeepc de Asus con Debian

Tenemos por aquí un netbook de asus, un eeepc 901 (si no me equivoco) que compramos hace unos años ya. Traía un sistema operativo basado en Linux… que no estaba mal, pero a la hora de ofrecer actualizaciones y otros programas, la verdad, lo teníamos complicado.

Trae dos discos SSD, creo que 4Gb y 16Gb. El primero era el sistema operativo (más rápido)  y el segundo para datos (más malo y lento). Como se quedaba corto decidimos en aquel momento instalar una Eeebuntu en la segunda unidad. Y fue una maravilla, podíamos hacer de todo y estaba muy bien.

Pero los años pasan y no en vano. La duración de la batería que eran unas 4 horas y media, han pasado a ser poco más de 30 minutos. El disco SSD de 16Gb ya trabaja a velocidades inferiores a la del caracol, unos 250Kb/s en escritura. Y era ya casi insoportable.

Tuvimos la siguiente idea: comprar una tarjeta SD rápida e instalar ahí un sistema operativo. La tarjeta al final fue una Samsung Essential de 32Gb y clase 10. Las hay de más rápidas, pero los precios se disparan y cuesta encontrarlas. Ésta vale unos 35 euros, y la recogimos ayer mismo en el APP. Sólo quedaba definir qué sistema operativo instalar.

Buscando, me encuentro con una wiki sobre instalar Debian en el netbook. Y al parecer ya no hacen falta ni paquetes especiales ni nada. Todo el hardware ya está perfectamente soportado desde hace tiempo. Así que me puse a mirar cómo se instala. Después de mucho mirar, las instrucciones son utilizar un USB Stick para arrancar el instalador. Pero a mí no me gusta empezar a formatear pen drives y tengo un lector de tarjetas.

Así que me propuse una instalación manual con un chroot. Un chroot, explicado de forma fácil, es un sistema operativo funcionando dentro de  otro, en una simple carpeta. Ni máquinas virtuales ni nada. Instalar un chroot completo y sin equivocarse requiere de muchos pasos, y hay que andar con cuidado. Me disponía a empezar cuando me topé con el paquete grml-debootstrap, que es un instalador automático de Debian que han hecho los de grml.org ( http://grml.org/grml-debootstrap/ ). Os lo recomiendo para estas cosas. Simplemente con una orden:

grml-debootstrap --target /dev/sda1 --grub /dev/sda

Y él hace todos los pasos necesarios, sin que nos preocupemos de nada. Tarda un rato, porque tiene que bajar el sistema base y demás cosas. Lo que nos deja es un sistema base funcional, es decir, sólo consola.

Probé a arrancarlo y funcionó a la perfección. Para que funcionase la wifi instalé los paquetes de non-free de firmware de ralink y a rodar. Como entorno gráfico un XFCE. De gestor de entrada, gdm. PulseAudio para sonido. Todo empezó a funcionar a las mil maravillas.

Y la verdad, funciona mucho más rápido que antes. Los videos de youtube se ven perfectamente y sin parones, las aplicaciones arrancan rapidísimo, y todo va muy fluido. Y por si fuera poco, probamos Armagetron Advanced, que es un juego que lleva 3D, y funcionaba muy bien, muy fluído y con una respuesta inmediata.

La batería está durando un poco más que antes. Debian está controlando mejor el consumo y la frecuencia de la CPU, y parece que la duración total de la batería está en una hora y media… algo que ya es más decente.

Ahora estamos muy contentos con el cambio, funciona la mar de bien! 🙂

De lo aleatorio que puede ser (o no) un número aleatorio

Hay ciertos momentos en los que necesitamos generar números aleatorios de calidad. Por ejemplo a la hora de generar un salt para un hash o otro tipo de prefijo, a la hora de generar certificados o para generar claves de cifrado simétrico.

La mayoría de la gente no sabe que hay diferentes “calidades” de aleatorios, como si se tratase de comida: calidad extra o calidad superior. No todos los aleatorios son iguales y hay que tenerlo en cuenta.

Mucha gente cree que esto es lo de menos y en realidad genera problemas de seguridad gravísimos, según qué funcionalidad está afectada. No exagero.

El primer problema es que creemos que un aleatorio es como una tirada de dado. Falso. Los aleatorios (o mejor llamados pseudo-aleatorios) son formulas matemáticas que intentan ser impredecibles. Pero según el uso y implementación, pueden aparecer patrones que pueden poner en compromiso nuestra aplicación.

Las implementaciones antiguas de aleatorios eran tan simples, que empezaban a repetir la secuencia de números al cuarto o quinto número solicitado. Actualmente esto no debería de pasar, pero depende de la implementación podrían aparecer patrones reconocibles.

¿Qué problema tenemos? que nosotros creemos que hay muchas posiblidades, por ejemplo a la hora de generar un salt, y si nos despistamos a lo mejor estamos generando sólo cuatro distintos. Y eso es un problema de seguridad.

En análisis estadístico que haga uso de aleatorios como el método de Montecarlo es importante que el aleatorio por lo menos sea uniforme y que pueda dar todos los resultados con igual probabilidad.

Pero cuando vamos a usarlo para cosas realmente serias, como por ejemplo la generación de una clave de 128bits, lo mejor es que dejemos eso en manos de los expertos. Por lo general todas las librerías de criptografía traen funciones para estos propósitos y es lo que se debe usar. Absteneos de usar rand(), sucedáneos o inventos chinos. En estos casos lo único que funciona de verdad son aleatorios criptográficamente seguros y eso no se consigue con un par de rand() ni por mucho que nos calentemos la cabeza. Es un problema mucho más complejo.

Si no tenéis acceso a nada de eso, hay bastantes métodos medianamente seguros. Lo primero es intentar solicitar los números aleatorios al sistema operativo. Por lo general suelen ser de bastante calidad. (En Linux /dev/urandom)

Si tampoco es posible, se puede intentar generar un aleatorio decente (pero computacionalmente costoso) de forma bastante simple si tenéis acceso a SHA1, SHA256 o similar. Sólo requiere de dos pasos:

Primero generamos una cadena de texto concatenando cualquier cosa que pueda parecer aleatoria o impredecible, como la hora con microsegundos, el resultado de rand(), el tiempo que tarda el sistema en realizar un fsync() o el tiempo entre pulsaciones de teclado.

Cuando nos hemos cansado de generar “basura” y queremos obtener aleatorios, basta con realizar el SHA de todo. Si tenemos SHA-512 mejor, porque generaremos más bytes de golpe. El hash resultante es aceptable como origen de datos aleatorios, siempre que la cadena de basura sea absolutamente imposible de predecir, ni teniendo acceso al mismo ordenador mientras se generan.

Si queremos obtener más bytes, basta con hacer de nuevo un hash SHA-512 al hash antiguo más una nueva cadena de datos basura (o en caso de no tenerla, reutilizamos la antigua).

Así que la moraleja es, dejémonos de experimentos raros y usemos las herramientas adecuadas.

Cosas que me fascinan de una base de datos, el MVCC

El estar en el trabajo constantemente analizando errores sobre programas que funcionan bajo postgreSQL me ha hecho aprender muchas cosas sobre ésta base de datos, para mí una de las más avanzadas del mercado. Hay un par de conceptos que me dejan asombrado. El MVCC es uno de ellos y creo que se merece un artículo hoy.

MVCC es la abreviatura de “Multiversion Concurrency Control” y es la forma en que PostgreSQL y otras muchas bases de datos manejan las transacciones. Sirve para que las diferentes conexiones concurrentes a una base de datos puedan leer y escribir al mismo tiempo sobre los mismos registros con un mínimo de bloqueos y aún así los datos que leen y escriben sean consistentes.

Supongo que se parece un poco a tener una especie de sistema de control de versiones (como GIT) para almacenar las filas y sus cambios, aunque esta analogía no es demasiado adecuada. El objetivo de MVCC es mantener simultáneamente varias versiones de una misma fila hasta que los cambios son efectivos. Para explicarlo un poco mejor empezaré por explicar el problema que soluciona y una posible solución.

Imaginemos que tenemos una base de datos a la que acceden decenas de empleados a la vez, leyendo y grabando registros. Un empleado introduce en el sistema un albarán de material gigantesco y al sistema le lleva minutos generar todos los registros así como descontar todo el material del almacén. Se da la casualidad que otro empleado, en ese mismo momento, está imprimiendo un informe de stocks cruzado con albaranes.

En una base de datos que no cumpla ACID, este informe recibirá muy probablemente, un estado intermedio de los datos que no es consistente. Es decir, como el programa ha generado un albarán incompleto, puede que aparezcan las líneas de albarán, pero el stock esté a medio descontar y unos artículos sí aparezcan descontados y otros no. Es fácil imaginar el dolor de cabeza de la persona que ve que todos los datos están mal y no saben por qué. O peor aún, usar información errónea y realizar previsiones erróneas.

La solución a esto son los bloqueos. Cuando alguien está escribiendo en una tabla, antes de empezar consigue un bloqueo general, y cuando termina lo libera. Por tanto en este proceso tanto las tablas de stock, como de albaranes y sus líneas permanecerían bloqueadas varios minutos. El informe más sencillo sobre una de las tablas tomaría esos minutos como mínimo en empezar a computarse, mientras tanto la aplicación quedaría a la espera de que se libere el bloqueo. Del mismo modo, al leer la tabla hay que conseguir un bloqueo de lectura, que impide que otra persona escriba hasta que nosotros terminemos de leer.

MVCC consigue reducir las conexiones bloqueadas a un mínimo bastante aceptable. Se basa en la idea de que si una tabla está siendo modificada mientras otra persona quiere leerla, podemos enviarle los datos antiguos, que eran consistentes. De hecho, mientras la conexión que escribe no haga COMMIT, los cambios no existen y no deben ser tomados en cuenta. MVCC genera una copia de la fila para la transacción que la modifica, y usa un Transaction-ID para identificar que esos registros alternativos pertenecen a ciertas transacciones y no deben ser vistos (aún) por el resto de la gente. Cuando se modifica una fila de una tabla, se consigue un bloqueo de escritura sobre ella, impidiendo que otra transacción modifique también el registro simultáneamente (lo cual crearía un conflicto). De este modo, pasamos de un bloqueo de tabla a bloqueo por registro, y de un bloqueo general a un bloqueo de escritura.

En el tema del aislamiento entre las transacciones existe una forma aún más perfecta de implementar MVCC y ofrecer datos aún más consistentes: Si se modifica una fila mientras otra transacción está en curso, la fila original se guarda para todas las transacciones que están aún trabajando, de modo que una vez iniciada una transacción nunca veremos actualizaciones externas, consiguiendo efectivamente que mientras estén dentro de su transacción parezca que absolutamente nadie está tocando sus datos mientras ellos están leyendo y escribiendo. Esto genera bastantes más bloqueos, pero es mucho más perfecto.

El objetivo del aislamiento de transacciones es garantizar que las operaciones ejecutadas en paralelo pudieron ser lanzadas en serie (en determinado orden) obteniendo el mismo resultado. En otras palabras, que la concurrencia no altera la consistencia de los datos.

Si a alguien le apetece leer más sobre el tema, recomiendo el artículo de la Wikipedia y la documentación en PostgreSQL:

http://en.wikipedia.org/wiki/Multiversion_concurrency_control

http://www.postgresql.org/docs/current/static/mvcc-intro.html

Control de versiones del código fuente (GIT)

Hace pocos días hablé con alguien sobre modificaciones hechas en su código y me preguntó qué eran esos ficheros *.patch que le envié. Nunca había visto un patch, ni tampoco conocía la existencia de programas de control de versiones.

En el mundo del software libre, los llamados VCS (Version Control Systems) son algo muy habitual y muy conocido por todos. Las herramientas diff y patch, también. Pero para el resto de programadores que nunca han colaborado con una comunidad por lo general esto les suena a chino.

Así trabaja una persona sin VCS:

  • ¿Qué hace si en un proyecto se da cuenta de que la pifió y tiene que quitar los cambios de la última semana?
    Busca un backup y restaura.
  • ¿Qué hace si necesita saber qué hizo su compañero en el proyecto para arreglar algo?
    Le pregunta o busca comentarios en el código.
  • ¿Y si quiere compartir sus cambios con otra persona?
    Le envía los ficheros modificados.

Aunque está bien, tiene muchas pegas. Tienes que hacer backups regulares de tu trabajo, documentar muy bien tus cambios, comentar los bloques por donde vas cambiando… y aún así hay muchos problemas.

Un VCS es una aplicación que lleva un control exacto de qué se cambia, donde, cuando y por quién. Gestiona todas las versiones que existen de un mismo proyecto y ofrece información sobre ellas.

Yo recomiendo mucho usar GIT, que es uno de los dos mejores VCS libres que existen ahora mismo (el otro es Mercurial).

Así trabaja una persona con GIT:

  • ¿Qué hace si en un proyecto se da cuenta de que la pifió y tiene que quitar los cambios de la última semana?
    “git revert” de los cambios que están mal. Puede seleccionar fácilmente qué partes sí y que partes no. El trabajo borrado permanece en GIT por si se necesita más tarde.
  • ¿Qué hace si necesita saber qué hizo su compañero en el proyecto para arreglar algo?
    “gitk” ofrece una forma gráfica de ver los cambios realizados. Permite extraer los cambios que se quieren a fichero para poderlos aplicar con patch a otro.
  • ¿Y si quiere compartir sus cambios con otra persona?
    “git format-patch” puede extraer los cambios en forma de emails con parches. “git diff” lo puede hacer de forma unificada. Además varias personas pueden compartir un mismo repositorio de git.

Además de muchas otras funcionalidades interesantísimas… como por ejemplo:

  • git gui blame $file
    Nos muestra para un fichero quién cambió qué líneas. Muy útil para saber cómo acabó cierto código allí.
  • git bisect
    Una herramienta para localizar qué cambios provocan un fallo.

Estas herramientas son útiles para llevar un seguimiento de cualquier cosa que sean ficheros de texto legibles. Por ejemplo se puede usar para realizar un seguimiento al escribir una novela.

Si os interesa GIT y queréis leer más:

http://www.cyberhades.com/2011/06/17/10-tutoriales-sobre-git-para-principiantes/

http://git-scm.com/documentation

Sobre la memoria ‘swap’ y el rendimiento del equipo

La memoria swap es otra gran desconocida y hay varios mitos y leyendas alrededor de ella. Suele ser la responsable de la lentitud de muchos equipos y para muchos, suele ser un problema más que una ventaja.

Primero de todo explico qué es la memoria swap. Es una sección del disco duro que se usa como amplicación de la memoria RAM y el sistema operativo pasa allí la memoria de los programas que prácticamente no se usa para reducir el uso de memoria real.

Cumple básicamente dos objetivos, el primero, que el ordenador no quede colgado cuando los programas solicitan más memoria que la instalada en el sistema. El segundo, intentar minimizar el uso de RAM por parte de los programas para maximizar la caché de disco duro.

Mucha gente opina que la swap es un cáncer y que el ordenador va mejor sin ella. Por ejemplo, que si nuestros programas no van a ocupar nunca el total de la RAM, es mejor no hacer una partición de swap (o fichero swap en windows). Yo puedo asegurar que es al contrario. Hay algunas opciones que controlan cómo se comporta la swap y se puede adecuar el comportamiento a cualquier tipo de uso, incluso al mismo uso de trabajar sin swap.

La swap siempre balancea entre caché de disco y uso de ram en desuso por parte de los programas. Si no hay programas que tengan memoria en desuso, no hay swap. Si no hay caché de disco, no hay swap. La excepción a esta regla es cuando se está a punto de terminar la memoria física, entonces la swap actúa como mecanismo de emergencia para evitar que se nos quede colgado el ordenador.

Lo que se puede configurar es la agresividad con la que el sistema mueve la memoria a la swap. Este control se le llama “swappiness” y es un valor que va de 0 a 100, donde con 100 prácticamente todos los programas y toda la memoria es candidata a ser movida a la swap para hacer hueco a la caché de disco y 0 indica que nunca se deben mover los programas a la swap excepto casos extremos.

El control se lee y se modifica desde /proc/sys/vm/swappiness

Su valor por defecto es 60. Para un servidor MySQL puede ser recomendable bajarlo a 15, entonces desde root, haríamos:

# echo 15 > /proc/sys/vm/swappiness

Pero esto se perdería en el siguiente reinicio. Para que quede guardado hay que editar /etc/sysctl.conf y agregar la línea:

vm.swappiness = 15

De este modo al reiniciar tomará efecto de nuevo.

La cantidad de espacio que asignamos a la memoria swap también es importante. Para la mayoría de usos, 2Gb suele estar bien. No es recomendable hacerla excesivamente grande, ya que no sirve para nada y puede hacer que el disco duro tarde más de la cuenta al grabar y escribir (al tener más espacio y pistas más separadas, aunque esto depende de la implementación de la swap).

Por lo general, un valor 40 es apropiado para entorno de escritorio. Los servidores cuyo trabajo está basado en memoria es importante bajar este valor y en los servidores de ficheros es recomendable aumentarlo.

http://systemadmin.es/2008/12/swappiness-regular-a-tendecia-a-usar-swap-del-kernel-de-linux

El camino hasta el soporte físico

¿A quién no le ha pasado que se ha ido la luz, luego ha arrancado el ordenador y lo que había guardado minutos antes ya no está? ¿Cuantos apagáis el ordenador desde el botón simplemente porque <es más rápido>?

Pero prácticamente nadie sabe por cuantos sitios pasan nuestros datos antes se ser guardados físicamente en el disco.

Mientras los datos están únicamente en memoria, corre el peligro de que los perdamos, por aquello de que la memoria es volátil. Cuando un programa guarda un fichero, pongamos por ejemplo al hacer un “copy”, el fichero no está físicamente guardado. Lo estará aproximadamente en 30 segundos, en la mayoría de sistemas operativos.

Cuando una aplicación quiere escribir datos que tiene en memoria al disco, estos datos pasan por una serie de lugares:

  1. Buffers de escritura de la librería de IO: La aplicación realiza un fwrite() o equivalente para escribir en disco. Pero las librerías de acceso a disco optimizan las escrituras en buffers internos, retrasando las llamadas a sistema para poder hacerlas en bloques más óptimos, tal vez de 4Kb. Hasta que la aplicación no hace una llamada flush() a la librería, ésta no está obligada a escribir. Si nunca lo hace, puede que no se vuelquen a que cierre el fichero, a que complete 4Kb, o a que escriba una línea (retorno de carro)…. eso ya según librería.
  2. Caché de escritura del S.O.: La aplicación realizó un flush() y la librería mandó al sistema operativo que le grabe los datos. El sistema contesta, sí, ya lo tienes grabado. Y en efecto si intentas acceder al fichero por otro proceso aparece grabado. Pero no lo está, sigue en la memoria RAM. En este caso en la caché de escritura del sistema. Ésta se vacía cada 30 segundos aproximadamente, menos si se escriben muchos datos o no cabe en memoria la caché. Para forzar el grabado hay que lanzar fsync() que es la orden que le dice al sistema que grabe todo lo que quede por grabar. Muchos editores de texto hacen un fsync() cada vez que guardamos para asegurarse que está en el disco.
  3. Caché de escritura del disco duro: El sistema manda a grabar los datos, pero si el disco tiene caché de escritura activo, entonces el disco ‘miente’ y dice que los tiene grabados cuando realmente los tiene en una memoria interna. Esta caché por lo general se procesa lo antes posible, por lo que no deberían pasar más de unos pocos segundos entre mandar el cambio y que realmente esté en disco.

Normalmente la caché de disco no está nunca habilitada y no se debe habilitar, tiene serios problemas de integridad de datos. La caché de escritura está pensada para cuando los discos tienen una batería interna de respaldo (sí, es un artilugio que se vende para servidores), se usa especialmente en combinación con controladoras RAID.

Es increíble por la cantidad de sitios que pasan nuestros datos antes de ser realmente almacenados. Y todo esto es por el bien de la velocidad de nuestro sistema porque los discos son, de largo, el componente más lento y menos fiable que tenemos.

Para los curiosos, en Linux el comando “sync” provoca un fsync de todos los discos y se ejecuta justo antes de apagar el equipo. Puede ser interesante ejecutarlo antes de un mal apagado. La frecuencia con la que el S.O. guarda los datos a disco se controla por los ficheros /proc/sys/vm/dirty_*

Python, la barrera de los diez mil

Llevo mucho tiempo programando con Python y me encanta. El suficiente tiempo como para haber probado a hacer prácticamente de todo. Pero más pronto o más tarde me topo con la dichosa barrera, que al final, he decidido darle el dichoso nombre.

Python es un lenguaje cuyas instrucciones (sin contar optimizaciones) tardan, de media, 50 veces comparadas que su equivalente en C. Sin embargo Python crea aplicaciones muy rápidas debido a que existen grandes optimizaciones y funciones que hacen el trabajo por tí, y ese trabajo es realizado con una eficiencia cercana a la de C. Además muchas de las librerías de Python usan C para ejecutar las operaciones o usan algún tipo de truco para evitar tener que ejecutar manualmente todo en Python.

Tu puedes mandar a una librería que te procese una imagen de 5000×5000, puedes decirle que renderice en OpenGL, que aplique una transformación a una matriz… pero cuando la lógica de la operación se tiene que expresar en Python, tienes que iterar en Python. Y aquí llega la barrera de los diez mil… de las diez mil instrucciones por segundo quiero decir.

Y es que este es el hecho: prácticamente cualquier trivialidad hecha en Python, por simple que sea, suele tener un coste de unos 10us (microsegundos). Cuando a eso le sumas una lógica real, nos vamos a los 30us, y eso, hablando de mínimos absolutos. Eso quiere decir que prácticamente cualquier cosa hecha con Python puede ejecutarse como máximo a 1/30us, lo que sería algo más de 30.000 operaciones por segundo. A unos 100.000 si es una implementación muy directa y sencilla, y unos 400.000 por segundo en caso de que apenas sea una instrucción y de las rápidas.

Así que, cuando tienes un código y te va lento para lo que necesitas, empiezas a buscar los responsables y a optimizar. Claro, mientras hay una operación que tarda 5ms, eso es fácil de localizar y probablemente también de arreglar. Pero conforme vas corrigiendo y mejorando, cada vez la velocidad de la función u operación más lenta se reduce… y se diluye con el resto de operaciones. Hasta que llegas a un momento donde todas tus operaciones parecen necesarias y tardan aproximadamente 0.1ms. Bienvenido a la barrera de los diez mil. Eso hacen diez mil iteraciones por segundo.

Y la barrera de los diez mil es como la barrera del sonido: parece insuperable. Cuanto más ganas le pones, más complicado te lo pone, de una forma exponencial.

Afortunadamente, muy pocas son las aplicaciones que requieren más de mil iteraciones por segundo. Pero si en algún momento pasa por tu cabeza “podría hacer esto en Python” y es algo donde la velocidad es importante…. párate. Piensa y calcula: ¿Cuantas iteraciones por segundo requiere tu programa? ¿Más de cinco mil? si es el caso ya puedes ir preparando una interfaz en C y desviar todos los bucles a C. Y cuando digo C  me refiero a C puro. Sin llamadas a python de ningún tipo.

Puedes pensar… usaré un ordenador el doble de potente, o compilaré las partes afectadas con Cython… error. Por un lado, ordenadores más potentes sólo llevan más núcleos, y entonces tendrías que escribir las partes con threads, pero no sirve de nada porque está el GIL, y a la práctica sólo usarías un núcleo. Así que tendrías que escribir esa parte con multiprocessing (varios procesos ejecutando en paralelo). Por otra parte, lo de compilar con Cython no ayuda lo que uno cree. Si sigue procesando objetos de Python durante los bucles, sigue siendo lento igualmente. Si hay alguna mejora, es pobre.

El truco aquí reside en saber qué es lo que se quiere realizar y tener los datos a punto para realizar la tarea entera sin requerir la intervención de Python en el proceso. El cáncer de los lenguajes dinámicos son las comprobaciones y las búsquedas. Cada paso que da tiene que buscar por lo que se le pregunta y comprobar cada operación que se hace hasta el punto de cambiar el comportamiento según lo que se encuentra. Esto es lento, lo queramos o no. C es rápido porque no comprueba, asume que es correcto, asume que sólo hay una forma de hacer algo. Por tanto, es más rápido pasar unas instrucciones, y comprobar la validez de éstas una vez, que ejecutar la operación manualmente y que el intérprete esté comprobando todo lo que hacemos en cada iteración.

Como conclusión, diría que no vale la pena meterse en estos tinglados. Se invierte mucho tiempo y apenas se obtienen resultados.

Discos de estado sólido (SSD) (parte I)

Supongo que a estas alturas todo el mundo ha oído hablar alguna vez de los discos SSD. A día de hoy se pueden comprar casi en cualquier sitio y a un precio que empieza a ser razonable.

Yo empecé a seguirles la pista casi cuando empezaron a desarrollarse. Cosa que fue pocos años después de que tuviéramos Pen Drives. Supongo que hace 3 o 4 años, ya ni me acuerdo. En aquella época los SSD eran de 32Gb y tenían precios desorbitados, además que las características tampoco eran nada del otro mundo. Hoy en día las cosas han cambiado bastante… como siempre pasa en el mundillo de la informática.

La gente se suele preguntar: ¿para qué un SSD, si es carísimo y por la mitad de precio tengo un disco normal de tropocientos teras?… y lo cierto es que casi nadie sabe realmente qué es un SSD y que pros y contras tiene con los discos normales. Así que supongo que lo ideal es empezar explicando un poco…

Un SSD o Solid State Disk es un dispositivo de almacenamiento físico basado en memoria NAND o similar (los chips NAND son los que se usan para los Pen Drives). Como es memoria NAND el grabado es permanente, los datos no se pierden si se va la luz o apagamos el ordenador. Hasta aquí parece igual que un disco duro tradicional.

Veamos las diferencias:

  • Como es memoria, carece de partes móviles, mecanismos, resortes, o cualquier cosa de esas que se estropean si le das un golpe. Los discos duros tradicionales tienen unos discos girando y un cabezal de lectura, los cuales pueden estropear parte de los datos si hay un golpe o pasa algo.
  • Como no tiene cabezal, al pedir un dato al azar no hay nada que tenga que llegar hasta determinado punto en el disco para poder leer los datos. El tiempo de acceso es muy inferior a los discos normales.
  • Al no tener partes móviles, el consumo es mucho menor, del orden del Vatio. (Puede oscilar entre 0,5 y 2Watts según marca y modelo)
  • Pesan mucho menos, no llevan prácticamente aluminio ni acero. Básicamente es casi todo plástico, baquelita y silicio.

Este tipo de discos obviamente no se usa para almacenar, ya que el Gigabyte de almacenamiento suele valer entre uno y dos euros. Para almacenar grandes cantidades de información siempre va mejor un disco de toda la vida. Eso que quede claro.

Uno de los usos más interesantes es para servidores de base de datos o de ficheros. Un servidor LAMP por ejemplo es un gran candidato para este tipo de discos, ya que el tiempo de acceso de un disco SSD de gama alta es prácticamente cero. Eso hace que aunque tengamos 600 usuarios accediendo a distintas webs, a distintas partes, simultáneamente… y volviendo loca la base de datos y al servidor web… al disco duro SSD le da igual. Un disco duro normal se volvería loco bajo tal tipo de carga, porque sólo para contestar una petición hay que leer y escribir muchos registros que están separados en el disco, así que cuando muchos usuarios piden cosas muy dispares a la vez, no hay forma de procesarlo. Esto con los SSD no pasa.

Para hacer el ejemplo más visual… imaginemos una prueba: tenemos unos ficheros ISO en una carpeta A y queremos copiarlos en la carpeta B. En vez de hacerlo en bloque y dejar que el SO serialice la operación, los pasamos de uno en uno, a la vez: mientras se está copiando uno mandamos ya a copiar al siguiente. Imagina que llega el punto donde tenemos veinte ventanas de copiar abiertas. Si midiéramos el rendimiento de nuestro disco en este punto, sería ridículo. Habría bajado de unos 40MB/s a unos 3MB/s probablemente (dependiendo del sheduler de IO). Esto es lo que le pasa a un disco duro cuando muchos procesos intentan leer y escribir a la vez.

Pero no son sólo útiles por el rendimiento. Su bajo consumo y su resistencia a impactos lo hacen idóneo para portátiles, netbooks y otros dispositivos móviles. Algunos fabricantes incluyen un SSD en sus notebooks en lugar de los discos tradicionales, aunque tengan que sacrificar espacio.

Así que, si dudas para tu portátil entre un disco de 2TB o un disco SSD de 120Gb… ten en cuenta que el segundo además de más rápido, no se rompe.

Sobre las bases de datos NoSQL (parte I)

Venga, sea esta la primera entrada útil del blog. Últimamente he estado bastante puesto analizando qué son y qué ofrecen las bases de datos NoSQL, además de que he ido siguiendo su desarrollo durante el último año.

Uno primero lee lo de NoSQL y piensa, ¿eso que es?, ¿sirve de algo? ¿que tiene esta gente en contra del SQL?. Bueno, pues no. No se trata realmente del lenguaje SQL, sino de las bases de datos relacionales. NoSQL es la terminología con la que se acuña a las bases de datos no-relacionales, es decir, que usan una forma distinta de almacenar los datos y en lugar de hacerlo de forma relacional lo hacen…. de un modo distinto. Cada una lo hace de una forma, unas más limitadas, otras menos. Pero vamos, NoSQL es un campo completamente experimental, donde cada uno prueba su solución con mejores o peores resultados.

Pero…. lo más importante… ¿porqué usar NoSQL? ¿qué tiene NoSQL que no tenga MySQL, PostgreSQL, Oracle, MS SQLServer…?. En pocas palabras: rapidez, disponibilidad, replicación y sharding.

Por supuesto hay cosas en las que las bases de datos SQL son mejores: aislamiento, consistencia/integridad, atomicidad, durabilidad. Sí, exacto. Acabo de nombrar ACID: Atomicity, Consistence, Isolation, Durability.

Y sí, efectivamente, las bases de datos NoSQL no son nada buenas con el ACID:

  • Ninguna de ellas implementa transacciones. Los cambios no se pueden echar atrás.
  • La consistencia de los datos suele ser eventual. A veces dos clientes no ven los mismos datos cuando deberían. Algunas NoSQL sí son consistentes.
  • Ninguna implementa aislamiento. Los cambios son vistos obligatoriamente por todo el mundo, aun cuando es una operación compleja y está a medias.
  • La mayoría tienen fsync=off, por lo que pierden datos si se va la luz y no hay una replica de los datos por la red.

¿y entonces, porqué NoSQL? Pues porque escalan mejor. Ese es el motivo, la escalabilidad.

Las NoSQL tienen por lo general un diseño que facilita que al meter el doble de hardware vayan el doble de rápido. Las bases de datos relacionales no tienen esa propiedad. Los bloqueos, las transacciones y el fsync provocan que la velocidad se quede estancada en cierto punto. Es el precio a pagar por que tus datos estén en sitio seguro y bien guardados.

Estas bases de datos NoSQL soportan una concurrencia prácticamente ilimitada. Todos los usuarios pueden leer y escribir los datos simultáneamente. Además prácticamente todas están orientadas a clustering, a tener una serie de nodos con réplicas totales o parciales de la base de datos y a interactuar como un único todo. De este modo, ¿la base de datos va lenta? pones otro equipo en el cluster. ¿La base de datos no tiene espacio libre? pones otro equipo en el cluster. ¿A veces se caen algunos servidores y te quedas sin servicio? pones más nodos en el cluster.

Todo se soluciona poniendo más equipos. Es fantástico. Muchas de ellas balancean la carga y los datos automáticamente, haciendo sencillo el poner nuevos nodos o quitar antiguos.

Bueno, hasta aquí por hoy. Espero que haya servido como introducción, ya continuaré la reflexión en otro post. 🙂

Abriendo blog nuevo

Al final me he decidido a abrir un blog. En castellano. Ya llevaban años diciéndomelo algunos (y algunas), que lo tenía que abrir y tal…. pues hala, ya está abierto. ¿Contentos? 🙂

¿De qué va este blog? Muy sencillo, de programación y desarrollo. No, no voy a poner nada de mi vida, para eso tengo el facebook… y tampoco pongo nada XD XD.

Así que nada, este blog va dedicado a hablar de lo que voy descubriendo cada día. Soy una persona muy dedicada a la investigación y desarrollo de nuevas tecnologías. Paso muchos días probando cosas y sacando conclusiones. Así que, voy a poner por aquí las novedades que voy descubriendo.

Espero que encontréis útil el blog 😉