Archivo

Archive for the ‘desarrollo’ Category

Ciencias de la computación e ingeniería, y [algunas de] sus diferencias

octubre 7, 2014 17 comentarios

Hay un tema que se estudia en todas las carreras de informática, el de “sincronización, concurrencia y exclusión mutua entre procesos”. Surgió en la década de 1950 cuando empezaron a desarrollarse los primeros sistemas con multiprogramación. Aunque surgió como problemática de sistemas operativos se ha convertido en un tema de general y fundamental en informática. Todas las carreras de informática incluyen su estudio tanto en las asignaturas de sistemas operativos como en otras específicas de programación concurrente.

El tema de concurrencia (y su hermano más complejo “programación distribuida”) es un típico tema de “ciencias de la computación”, donde se estudian los algoritmos y se prueban formalmente que funcionan: se demuestra que aseguran exclusión mutua, que no produce inanición (starvation), ni interbloqueos (deadlocks). No es simple enseñar estos temas y sus soluciones obligan a pensar de otro manera, un programa ya no es una serie secuencial de instrucciones, sino que se mete por medio una intercalación “no controlada” y no determinística de otras instrucciones de procesos independientes.

El tema de exclusión mutua es un tema relativamente sencillo de demostrar, por ejemplo este código que suma una variable desde cero hasta 99.999.999 (cien millones menos uno), pero no lo hace de una forma tradicional, sino que son dos hilos (threads) los que la incrementan individualmente. Podéis compilarlo y probarlo (no olvidéis de compilarlo con la opción -pthread), veréis que produce unos errores enormes. El problema es que dos procesos diferentes acceden al mismo recurso compartido (la variable count) y se “pierden” operaciones debido a las interrupciones e intercalaciones.

Este caso es muy estudiado y todas las asignaturas comienzan con algo similar, es la exclusión mutua entre [solo] dos procesos. Así se estudian los “cuatro intentos” para solucionarlo, luego el algoritmo de Dekker y finalmente el de Peterson (aquí los tenéis a todos).

Así se puede demostrar formalmente que funciona correctamente, que asegura exclusión mutua y tal y cual. Pero si lo implementas (aquí lo tenéis listo para compilar y ejecutar con el ejemplo anterior) y lo pruebas en cualquier ordenador moderno verás que… falla como escopeta de feria.

¿Qué pasó? ¿Falla la teoría? ¿Fallan las demostraciones? ¿Los teóricos de las ciencias de la computación no sirven para nada?

Ninguna de ellas, este es un típico ejemplo donde la teoría se distanció de la “realidad”, o mejor dicho, donde la evolución tecnológica de los microprocesadores modernos hace que las técnicas de concurrencia que dábamos por buenas (y que lo son formalmente y con todos los modelos de computación y/o de lenguajes “tradicionales”) ya no funcionen. Es la diferencia entre hacer “sólo ciencia” y la “ingeniería” (es decir, resolver problemas que te impone la realidad, no tan perfecta como la teoría).

Tampoco es para los ingenieros se feliciten y miren por encima del hombro a los teóricos, porque la mayoría de “ingenieros” tampoco saben explicar o resolver este problema, muchas veces ni siquiera son capaces de identificarlo (no, si estás leyendo este blog no eres de la “media”, eres bastante friki y al menos lo habrás oído, o sabrás buscar rápidamente en la Wikipedia o Stackoverflow ;) ).

Si no tienes idea de qué está pasando, ya lo explicaré en un comentario (si nadie lo hace antes), pero mientras tanto puedes ir probando este otro código que sí funciona y sólo difiere en una línea con el anterior.

Sólo quería recordar que aún en ciencias tan “formales” como la informática la teoría no siempre funciona en la práctica, que el tema de concurrencia tiene sus complejidades no siempre a la vista, que un buen ingeniero debe saber reconocer esos problemas y poder solucionarlo, y que esto exige que conozcamos bastante de detalles del hardware y microprocesadores actuales.

No es nada simple, lleva su tiempo, y tendemos a pensar que lo sabemos todo. O que la “ingeniería informática” consiste en saber liderar sprints de Scrums con postits de colores fosforitos.

PS: Por estas cosas, entre muchas, la informática es apasionante.

Tendencias (“trends”) históricas del uso de palabras con Sphinx

febrero 13, 2014 4 comentarios

Hace unos días quise saber desde cuándo se empezó a hablar de desahucios y suicidios en la prensa en España. Fui a Google Trends y el gráfico mostraba una evolución demasiada plana, que no se correspondía con tantas noticias que leímos en la prensa española. Me pregunté si, y cómo, podía obtener esas estadísticas en Menéame. Se me ocurrió que debería haber un truco relativamente sencillo usando los índices de de búsqueda de Sphinx (lo usamos para el buscador de Menéame). Así fue que en pocas horas pude implementar un sistema similar a Google Trends en Menéame.

Esto es lo que salió con las tendencias de esas dos palabras por su frecuencia de aparición por meses:

Evolución de suicidios y deshaucios

Leer más…

No basta con ser ingeniero (y II), un ejemplo práctico

noviembre 30, 2013 7 comentarios

Hace unos días ya comenté el problema de que eliminaron una función importante en KitKat con la excusa de que no estaba documentada y por lo tanto “no oficial”, pero es una limitación seria para millones de usuarios y casi una traición para miles de desarrolladores. Hoy veo el siguiente comentario en el hilo del bug:

You broke file-uploading and released 4.4 without a ready replacement or workaround? O_o

So even if app devs manage to hack around it, they’ll have to maintain the hack forever to support phones stuck on 4.4 even after 4.5+ introduces a proper replacement function?

I need a Kitkat bar.

Es una observación clave.

Una pésima decisión de los ingenieros tendrá consecuencias negativas a largo plazo para desarrolladores, usuarios, y hasta toda la plataforma. No lo meditaron, todavía no se han percatado que las decisiones de ingenieros tienen efectos muy reales sobre las personas. Por eso, para ser un ingeniero hay que ser más que un ingeniero.

De nuevo queda en evidencia que los programadores vamos muy justitos en el tema, incluso para el nivel de programadores del sistema Android. Me genera una mezcla de decepción y cabreo, y me hace admirar cada vez más las “visión social” a largo plazo de Linus Torvalds: literalmente se enfurece cuando alguien le propone cambiar la interfaz (ABI) del kernel Linux que genera incompatibilidades con aplicaciones existentes, aunque tengan más de 10 años. Eso es ser más que un ingeniero.

PS: La única opción para remediar el problema es que parcheen las librerías de Android Kitkat para re-implementar la función openFileChooser() que eliminaron. Otra cosa es que asuman el error y lo hagan. Lo dudo, ojalá esté equivocado.

Android KitKat… ¿pretenden matar el HTML5 en Android?

noviembre 27, 2013 13 comentarios

La pregunta no es tan sensacionalista como parece. Hace unos días me avisaron de problemas para subir fotos a Menéame con Android KitKat. Era muy raro que diese problemas, está todo programado respetando estándares de HTML5 y Javascript. Descubrí que ese caso se debía a problemas de la gestión de memoria de Android y cómo la trataba Chrome (al ejecutar otro programa para seleccionar la imagen, si necesita memoria se la quita al Chrome, por lo que hay un “cambio de configuración”, al volver a Chrome, éste recarga la página completa, en vez de “reconstruir” lo que tenía). Pero descubrí otro error aún peor y que sucede siempre: es imposible subir una fotografía. Lo probé con el Nexus 4 y con el 7, en ambos el mismo problema, da un error “fatal” al seleccionar cualquier foto.

Lo probé con el Firefox sobre los mismos dispositivos, y no hubo problemas (además de sorprenderme la velocidad de Firefox, ¡cómo ha mejorado!). Se puede observar el fallo (“Error abrir archivo seleccionado” [sic]) en el siguiente vídeo que hice en el Nexus 4:

Visto lo visto, y que no parecía simple de solucionar, además que quería solucionar lo de compartir más fácilmente a Menéame desde un móvil, me decidí a desarrollar una pequeña app:

app Menéame de pruebas

Esta app sólo crea una actividad, basada en WebView, que empotra el renderer HTML. Hasta la versión 4.3 de Android, este renderer era el del “webkit” básico, a partir de 4.4 (KitKat) ya se usa el Chromium (el proyecto libre del Chrome). Todo iba bien, y funcionaba muy rápido… hasta que probé la subida de ficheros: imposible, no funciona en KitKat, y es imposible arreglarla (al menos en teoría y con la información que hay hasta ahora).

Las WebView tienen una pequeña interfaz con unas pocas clases de Java para controlar cosas básicas, y también para que el programa haga algunas de las cosas que no hace la vista por sí misma, por ejemplo, seleccionar ficheros para el <input type=”file”> de HTML. Resulta que no había un API para ello, pero dado que es imprescindible para casi cualquier aplicación HTML5, la gente analizó el código fuente del navegador estándar de Android y encontró la función que se llama cuando se selecciona el campo de subir fichero. La implementé tal cuál, adaptadas a las diferentes versiones de Android:

WbeChromeClient

Pero no funcionaba en KitKat, sólo en las versiones anterior, sin problemas. En KitKat ni se llaman esas funciones, no hace nada cuando se selecciona el campo.

Así fue que busqué, y veo que eliminaron esa interfaz, sin ninguna alternativa. Sólo dicen “no estaba documentada como oficial, y ya pensaremos una alternativa para futuras versiones de Android”. En los comentarios queda claro cómo afecta a tantas aplicaciones, sobre todos a las de PhoneGap, que están basadas completamente en HTML5: con KitKat es imposible subir ficheros de apps programadas en HTML5.

Sumado a eso, el propio Chrome de Google también falla para subir imágenes.

Es decir, miles de apps que dejarán de funcionar en Android KitKat, por decisiones [estúpidas] de eliminar la única interfaz posible para poder subir ficheros desde el “navegador empotrado” para apps, y por fallos increíbles en el navegador por defecto, Chrome.

La pregunta es: ¿están perjudicando así a aplicaciones en HTML5 por simple estupidez? ¿O es una estrategia para que se usen apps completamente nativas? No hay otra explicación, en cualquier caso, vaya ceguera y/o ineptitud enorme de los ingenieros que toman decisiones de desarrollo en Android. Para miles de :facepalm:.

PS: Mientras tanto, si tenéis Android KitKat y queréis subir fotos en Menéame o cualquier otro sitio, tenéis que usar Firefox u Opera Mini. Si habéis desarrollado una app que usa WebViews, estáis jodidos, porque no hay otra alternativa, al menos hasta que salga el GeckoView for Android, pero le falta todavía mucho tiempo :(

Nota: cómo hacer esos vídeos de la pantalla.

Para ser ingeniero no basta con ser ingeniero (y los programadores vamos justitos)

octubre 29, 2013 50 comentarios

Hace una hora iba conduciendo, llevaba mi teléfono en el bolsillo delantero derecho del pantalón, de golpe empieza a vibrar y sonar. Una vez, dos, tres, cuatro… parecía que llevaba se había desatado una batalla campal entre mis pantalones (y no eran mis tripas ni el Viagra). Me empiezo a asustar, debe ocurrir algo grave para que alguien conocido me esté escribiendo de esa manera, pensé que podía ser problemas de familia o Menéame (que ni aún así insisten tanto).

Detuve el coche en cuanto pude, saqué el teléfono, era el Hangouts (el reemplazo de Google Talk para Android) de Google. Me habían metido en un texto-vídeo hangout con muchas personas (no sé cuántas, pero eran muchas),  todos escribiendo a la vez. Después del susto que me pegué, ¡qué cabreo! Primero con el irresponsable (no sé quién fue, salí inmediatamente) que abrió una vídeo conferencia de muchas personas. Pero luego lo pensé mejor.

¿Cómo es posible que un programa me meta automáticamente en un sala de vídeo conferencia? No lo podía creer. Nunca había configurado nada así. Voy a mirar la configuración del Hangouts -que recuerdo que es un reemplazo del Gtalk de Android- y veo que Google, y sus programadores, decidieron que me iba aceptar automáticamente conversaciones de toda la gente que tengo en mis círculos de Google+, y ¡también a la que no!. También incluye a las que tengo en “My Stream” (gente a la que sólo sigo sus publicaciones en G+).

Alucinante.

Nunca quise eso (en GTalk sólo me podían escribir a los que tenía autorizado), me meten en una sala con mucha gente y a la que ni conozco por el apodo en internet, y en su momento tampoco agregué a gente en mis círculos -o en “My Stream”- para que me puedan abrir automáticamente vídeo conferencias. No sé quién es el genio al que se le ocurrió eso, pero obviamente lo han tenido que implementar programadores. Un burrada que difícilmente se deje pasar tan fácilmente en otras ingenierías.

Estamos rodeados de programas informáticos, no podemos hacer nada sin ellos, y con los móviles estamos “abiertos” al mundo las 24 horas.  Cualquier cosa que haga un ingeniero/programador tiene efectos reales sobre la gente. Te puede molestar y asustar cuando vas en coche, o despertarte cuando estás durmiendo, o molestarte en medio de una reunión o clase. Hasta hace poco teníamos razonablemente bien controlado, hay un botón u opción rápida para que las llamadas no suenen. Pero es bastante más complicado hacer que todas las aplicaciones no molesten (tampoco tiene sentido estar deshabilitando continuamente la capacidad de que te avise si tienes un Whatsapp o chat). Las cosas empeoran cuando te pueden meter sin preguntar en una sala de conferencia, por ejemplo.

Ortega y Gasset ya lo ha dicho “recuerda que para ser ingeniero no basta con ser ingeniero”.

Y tiene toda la razón, lo que hacemos tiene efectos reales sobre la gente, debemos pensar muy bien las causas de lo que implementamos, y corregir inmediatamente si causan problemas. Esta es la responsabilidad de cualquier ingeniero. Pero parece que la tendencia en informáticos es “lo implemento porque se puede”, sin pararse a pensar siquiera en lo básico de privacidad, respeto y no molestar innecesariamente.

Cada día me molesta más este pasotismo y “solucionismo” (como diría Eugeny Morozov) de mis colegas. Últimamente lo pienso cada vez que recibo el aviso, varias veces al día, del sistema de bloqueo de DoS de Menéame (en pocas semanas tenemos ya varios cientos de IPs que hacían “DoS” involuntarios). Bots descontrolados que podrían tirar sitios completos (y/o causar gastos innecesarios), programas que generan cientos de conexiones por segundo, a veces durante meses (como nos pasa con la IP 46.105.237.95 de un servidor de DreaMule). No se salva nadie, tenemos bloqueadas IPs de muchas empresas importantes, incluido proxies corporativos de Google, servidores de Automattic/Wordpress, buscadores e indexadores sociales, y hasta con el bot del buscador Bing de Microsoft [*].

Demasiadas molestias innecesarias causadas por programadores.  Lo de los bots descontrolados que hacen DoS y generan tanto tráfico inútil es de locos, además de las molestias individuales debe tener un coste económico enorme globalmente (¿y cuántos deben pensar que están recibiendo ataques DoS o DDoS cuando es simple irresponsabilidad de programadores). Pero que por defecto y sin preguntar un programa te meta en salas grupales de vídeo conferencia es ya indescriptible: imaginaros que estáis con roaming y no os dais cuenta que vuestro teléfono entró en una conferencia de estas… para daros una idea del daño económico real que puede causar.

No es tan difícil si se piensa un poco, sobre todo si los programas afectan a lo cotidiano de millones de personas, y lo molesto y el daño que pueden causar. Me enerva cada vez más esta incapacidad de pensar profesionalmente en las consecuencias de lo que hacemos. No llegamos ni a ingenieros.

—-
[*] En el caso de Microsoft tuve que darme de alta en Outlook.con, luego agregar los dominios de Menéame, y luego configurar la frecuencia de rastreo para evitar el problema, no ofrecían otra opción. En el caso de Google, envié un email a la dirección de abuse de registros de sus direcciones IP (en ARIN), me devolvió un email automático de que no leen emails, me envió a  un formulario de Google, después de varios intentos, no hubo forma de dejar el comentario. Al final me dijo que lo comente en un foro de Google (que ya ni me acuerdo), nadie me contestó, al final dejamos bloqueadas esas IPs de Google.

Monitorización y “self-healing” de AutoScaler/LoadBalancer de Amazon AWS

octubre 14, 2013 3 comentarios

Aunque está cada vez más fiable y con menos fallas, al principio los fallos de sincronización del AutoScaler con el ElasticLoadBalancer eran bastante frecuentes. Aún así todavía pueden ocurrir errores de programas que ponen la CPU de un servidor al 100%, o que se cuelgue algún servicio, o que deje de responder y el LoadBalancer lo elimine de su lista pero aún así sigan ejecutándose y consumiendo vuestro dinero.

El AutoScaler también tiene otro problema derivado de la extrema simplicidad de las reglas (del CloudWatch) para escalar hacia arriba y hacia abajo, especialmente esta última. Supongamos que para minimizar los costes queréis mantener las instancias entre un 70 y 85% de uso de CPU (así lo tenemos en Menéame), para ello usareis las métricas agregadas del grupo del auto escalador, pero en éste no hay forma de indicar una regla que como:

Cuando la carga con una instancia menos sea menor al 70%, decrementar una instancia

Por ello, en 2009 implementé un programa que monitoriza la carga de cada instancia del grupo que implementa este tipo de reglas. Además este programa monitoriza que todas las instancias estén dentro del margen (entre 70 y 85% de CPU), si alguna se desvía mucho toma otras decisiones. Por ejemplo: si una está cercana al 100% y la diferencia con la media de carga es superior al 50%, asume que hay un fallo en esa instancia y la terminará. Lo mismo hará que para instancias que estén muy cercanas al 0% de CPU mientras las demás están bastante por encima (lo típico de instancias “descolgadas” del LoadBalancer, por ejemplo por fallo de hardware o de algún servicio.

La verdad es que además de ahorrarnos bastante dinero manteniendo a todas las instancias “saludables” y dentro de los márgenes de CPU, me quitó dolores de cabeza. Salvo catástrofes y cosas muy raras, no tenía que preocuparme para nada del estado de los servidores web.

Pero nunca liberé ese código, cuando lo programé (hace casi cuatro años) las librerías de Python y Perl estaban bastante mal documentadas, así que lo hice en PHP porque pude entender las clases muy rápidamente. Pero el código era infumable, y ni quería liberarlo. Ahora que las librerías de Python, las boto, tienen muy buena calidad, me decidí a portar el código a Python. Ya está funcionando, y ahora lo libero y explico brevemente (haced con el código lo que queráis).

Precondiciones

Tenéis que tener instalado el paquete boto. Está probado con la versión 2.14, podéis usar el que trae vuestra distribución si es al mínimo la versión 2, o bien instalar la última con el pip (pip install -U boto). Ya está, eso es suficiente, en principio no necesitáis nada más de software.

Lo que hay que hacer es poner la configuración con vuestras claves en el /etc/boto.cfg o ~/boto. En nuestro caso, que tenemos los servidores en Dublin, la configuración es la siguiente:

[Credentials]
aws_access_key_id = XXXXXXXXXXXXXXXXXX
aws_secret_access_key = YYYYYYYYYYYYYYYYYYY

[Boto]
ec2_region_name = eu-west-1
ec2_region_endpoint = ec2.eu-west-1.amazonaws.com
autoscale_region_name = eu-west-1
autoscale_endpoint = autoscaling.eu-west-1.amazonaws.com
elb_region_name = eu-west-1
cloudwatch_region_endpoint = monitoring.eu-west-1.amazonaws.com

El código

Consiste de tres ficheros Python, los dos primeros obligatorios para hacer los controles, el tercero es para visualizar información de las instancias:

ec2_watchdata.py: Define la clase WatchData que implementa los métodos para leer los datos de AWS, manipular datos y hla lógica de controles.

ec2_watch.py: Es el script que ejecuto desde el cron cada minuto y hace lo que he explicado antes. Intenté que la lógica quede muy sencilla, y se puede cambiar todo por argumentos en la línea de comandos (con -h sale una pequeña ayuda). Permite especificar el nombre del grupo del autoescalador, si se quiere que envíe un email de las “emergencias”, para cambiar los límites de CPU, y otra para que grabe los resultados en JSON en la base de datos de Menéame como “annotation” (usado para poder visualizar el estado vía web). Lo podéis ejecutar como queráis, incluso con la opción -d o –dry si sólo queréis ver qué es lo que va a hacer, yo lo tengo en el cron para que se ejecute cada minuto, que es lo que recomiendo:

* * * * * meneame/scripts/ec2_watch.py -g web -a -m gallir@gmail.com &gt; $HOME/watch.log

ec_instances.py: Es un pequeño script (pero que lo usamos mucho) que también usa la clase WatchData, fudamentalmente para visualizar el estado de las instancias del grupo, y también permite cambiar manualmente el número de instancias deseadas (opción -i), o matar instancias (opción -k). La siguiente captura muestra varias ejecuciones de este script, con un par para cambiar el número de instancias deseadas:

ec2_instances.py

Opcional: Si miráis el código, cuando se indica la opción -a llama a la función store_annotation() en el fichero utils.py. Esta es la que guarda los datos en formato JSON en la base de datos de Menéame y que me permite controlar desde la web y mi móvil:

ec2_watch web

Ejemplos de fallos (provocados)

Primero hice que una instancia se ponga al 100% de CPU (con el comando “yes > /dev/null”), así simulaba el fallo de algún programa. ec2_watch lo detectó y primero incrementó el número de instancias de 2 a 3. Como es una “emergencia”, me avisó por email de lo que pasaba, y lo que hizo:

100% de CPU, incrementa una instancia

Minutos después esa instancia seguía al 100%, por lo que la mató:

100% CPU, la mata

La siguiente es otra prueba, pero a la inversa. Desconecté manualmente una instancia del LoadBalancer, así el uso de CPU se pondría casi a cero, lo detectó a los pocos minutos, la terminó y el autoescalador levantó otra instancia nueva (al no cambiar el número de instancias deseadas):

0% de CPU, mata la instancia

Fin

Espero que os sea útil. No aceptaré sugerencias, pero sí parches ;)

Detección de DoS y bloqueo automático de IPs con el LoadBalancer de Amazon AWS

septiembre 11, 2013 9 comentarios

En Menéame teníamos un problema no solucionado correctamente. Cada vez sufrimos más ataques DoS voluntarios e involuntarios (bots mal programados, como los de Dreamule) que en el mejor de los casos nos ocasionan gastos innecesarios (ancho de banda e instancias adicionales) y en el peor sobrecargan tanto que impiden el acceso normal a las páginas. A esto se suma un gran problema: las instancias webs (que están autoescaladas horizontalmente) están detrás del balanceador de carga de Amazon AWS (ELB, Elastic Load Balancer) y éste no permite gestionar, ni manual ni automáticamente, el bloqueo de direcciones IP.

Por ello había que buscar una solución que detecte los DoS a conexiones que se hacen a las diferentes instancias web, y que sea el propio software de Menéame que lo haga y rechace las conexiones lo más rápido posible, y consumiendo los mínimos recursos. Esto obligaba a que se registren en un sólo servidor todas las conexiones desde las diferentes instancias, se analice en él en “tiempo real” y se guarden los datos en la base de datos para que estén disponibles para todas las instancias. Éstas deberían ser capaces de rechazar esas conexiones consumiendo la cantidad mínima de recursos y ancho de banda (tanto en la de Internet, como a la base de datos, como para enviar los logs al servidor central).

Después de pensarlo durante meses, y de analizar decenas de alternativas, en unos pocos días se me ocurrió la solución “óptima”. Esto ocurrió después de un mes de vacaciones casi completamente desconectado. Es el valor que tiene el descanso, pero eso es otro tema.

Leer más…

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

Únete a otros 480 seguidores