sábado 7 de enero de 2012

Construyendo kelinux

Si quieres desarrollar una web rápidamente puedes elegir python, un lenguaje de scripting muy sencillo, potente y con una cantidad inmensa de frameworks para lo que quieras.

Para los primero bocetos de kelinux elegí webpy, un framework minúsculo y sencillo. Tan sencillo como esto:
import web
        
urls = (
    '/(.*)', 'hello'
)
app = web.application(urls, globals())

class hello:        
    def GET(self, name):
        if not name: 
            name = 'World'
        return 'Hello, ' + name + '!'

if __name__ == "__main__":
    app.run()
Guardas el archivo como prueba.py, lo ejecutas (python prueba.py) y ya tienes un servidor andando en el puerto 8080. Era justo lo que necesitaba para empezar, pero en cuento le metes un poco de caña empiezas a encontrar deficiencias: servir archivos estáticos es un poco engorroso, y el acceso a la base de datos es prácticamente manual, las ayudas son muy pocas y por tanto no es idóneo para desarrollo rápido.

Lo único bueno que he encontrado en google app engine es precisamente la facilidad para trabajar con la base de datos (otra cosa son las inmensas limitaciones y la ridícula velocidad). Tan sólo tienes que crear una clase que herede de db.Model y ya tienes una tabla.

¿Y no se puede tener algo así sin necesidad de pasar por google app engine? si, como ya he dicho, python tiene infinidad de frameworks PARA LO QUE QUIERAS, incluido el acceso a bases de datos con mapeo de clases sobre tablas. El framework que he elegido para esto es SQLalchemy, que permite trabajar con numerosos motores de base de datos como SQLie, MySQL, PostgreSQL, Oracle y un largo etcétera. Yo he elegido MySQL con el motor Innodb que tiene un rendimiento genial.

Escribir HTML es un poco tedioso y repetitivo, por eso lo mejor es usar un motor de plantillas que permite "externalizar" o "independizar" la capa de presentación, todo el código HTML se generará aquí. En google app engine se suele usar Django, pero es un framework muy bestia y pesado, yo prefiero algo más ligero, algo que solo sea un motor de plantillas, por ese motivo he elegido Jinja2, por eso y porque la sintaxis el prácticamente la misma que en Django, y es más rápido.

Ya tenemos webpy + sqlalchemy + jinja2, pero teniendo en cuenta que webpy solamente lo quiero como servidor web ¿No sería mejor usar un framework que sea solamente un servidor? si, por eso finalmente elegí cherrypy, que además hace mejor su función, servir páginas. Y permite usar menos código:
import cherrypy
class HelloWorld(object):
    def index(self):
        return "Hello World!"
    index.exposed = True

cherrypy.quickstart(HelloWorld())
Menos código, más legible y más rápido.

Pero no es oro todo lo que reluce, una vez unes todas las piezas (cherrypy + sqlalchemy + mysql + jinja2) te encuentras con el primer enemigo de esta alianza, el UTF-8. ¿Cómo es posible que un servidor web que por defecto usa UTF-8, un framework para bases de datos que por defecto usa UTF-8 y un motor de plantillas que por defecto usa UTF-8 tengan problemas con UTF-8? fácil, la configuración por defecto es defectuosa, o por lo menos en mi caso lo es.

Cherrypy envía los datos al navegador usando el primer juego de caracteres que soporte, y no es el UTF-8, y te devuelve los datos conforme el navegador se los devuelva, y no es en UTF-8 ¿Solución? activar las herramientas de  codificación y decodificación:
cp_config = {
    'global': {
        'tools.encode.on': True,
        'toots.encode.encoding': 'utf-8',
        'tools.decode.on': True
    }
Yo pienso que deberían venir activadas por defecto, pero vete tú a saber porqué no lo hacen.

Siguiente víctima: SQLalchemy. No importa cuantas veces pongas que quieres los datos en UTF-8, SQLalchemy petará cada vez que intentes leer algo ¿Pero cuál es el problema? el unicode, el formato de string de python, SQLalchemy te devuelve los datos en UTF-8, e lugar de hacerlo en unicode y por eso peta ¿Cómo solucionarlo? con el flag convert_unicode:
Ke_engine = create_engine("mysql://%s:%s@%s:%s/%s" % (MYSQL_USER, MYSQL_PASS, MYSQL_HOST, MYSQL_PORT, MYSQL_DBNAME), encoding='utf-8', convert_unicode=True, echo=APP_DEBUG)
Se acabó el problema.

Con esto solo cubro una pequeña parte de las peripecias que he tenido, pero el artículo ya me está quedando muy largo, así que continuaré en sucesivos artículos ;-)

domingo 27 de noviembre de 2011

Mis problemas con Google App Engine

Google llevaba unos días anunciando la salida de fase beta y el nuevo plan de precios, y lo hacían mediante una bonita tabla comparativa, donde decían que con el nuevo plan te ofrecían el doble de horas de cpu de forma gratuita, etc ... para terminar me mostraban que con el actual plan pagaba 0€/día y con el nuevo, dado que los límites aumentaban, pagaría igualmente 0€.

La realidad ha sido muy distinta. Este fue el consumo de Ubuntu FAQ con el plan antiguo el día del cambio:


Me dije: "mi aplicación consume 0.85 horas de cpu/día y el nuevo plan aumenta el límite gratuito hasta 14 h/día, así que no tengo nada de que preocuparme" ... Este fue el consumo con el nuevo plan:


¿Cómo que 33.22 horas de cpu/día? rápidamente miré las estadísticas de la web, un consume tan desproporcionado (con respecto a lo anterior) debe ser consecuencia de un flujo de visitas igualmente desproporcionado. Pues NO, las visitas fueron prácticamente las mismas ~350.

Google aumentó los límites gratuitos, pero la trampa es que modificó la implementación interna de su API, y el consumo se disparó. Sus excusas son que los costes de mantenimiento son muy altos, que es un servicio nuevo y que les ha sido muy difícil poner precios ... pero eso no es una excusa para hacer trampas y mentir. ¿No hubiese sido más ético reducir los límites gratuitos?

Desde entonces me he estado peleando con el código para intentar reducir el consumo, me he leído mil foros y parece que todos llegamos a la misma conclusión: hoy en días es prácticamente imposible mantenerse dentro de los límites gratuitos, por muy simple e impopular que sea la web.

Mi primer cambio fue dotar a Ubuntu FAQ de una Super cache, una clase que se encargue de usar memcache para todos los elementos posibles, pero los resultados fueron desastrosos. Mis primeras pruebas lograron que los tiempos de carga se disparasen a casi 2 segundos por petición!!! Algo inaceptable. He tenido que hacer mil y un cambios hasta olvidarme de una cache de preguntas y enlaces y trabajar únicamente en memoria. He tenido que racanear ciclos de cpu por doquier como si estuviese programando para un puto comodore. Y al final he conseguido tiempos de carga inferiores a 100ms, pero los consumos son estos:


¡Todavía me toca pagar! Pero no sólo eso, es que además al app engine le ha dado por crearme dos instancias de la web, y eso sumado a que trabajo sobre memoria para no tocar la base de datos y que el consumo se dispare, conlleva fallos de sincronización!!! Si amigos, todos los problemas de una web con altísimo tráfico, pero sin ese altísimo tráfico! ¿Y cómo solucionas fallos de sincronización sin que eso suponga una caída brutal del rendimiento? pues he tenido que echar mano de ingenio y me he creado un diccionario de conflictos para comprobar si los datos de memoria han sido actualizados o no ... podéis verlo en el código de la clase Super_cache.

En resumen: huid de Google App Engine.

lunes 7 de noviembre de 2011

Google la caga con el App Engine

Google acaba de actualizar el servicio Google App Engine, un servicio que permite desplegar webs altamente escalables de forma muy sencilla. Servicio que uso para Ubuntu FAQ y Pystream.

Las novedades son:
  • Soporte de python 2.7.
  • Nuevo esquema de precios con el que difícilmente puedes mantenerte dentro de los límites gratuitos.

Tan limitado es el nuevo esquema de precios que Ubuntu FAQ, una web que apenas tiene 400 visitas diarias, ha sobrepasado el límite en apenas unas horas.




Los nuevos límites problemáticos son:
  • Datastore Read Operations: lo que viene a ser una query.
  • Datastore Small Operations: cada operación get().

¿De qué me sirve tener 1GB de ancho de banda de entrada y no-se-cuantas horas de cpu si con una par de gets ya me cepillo los límites diarios de operaciones?

Se me ocurren varias formas de modificar el código para no superar esos límites, pero sencillamente "me toca mucho los cojones" tener que andar con triquiñuelas para no pagar. Estos nuevos límites son absurdos, he estado leyendo de gente que con los nuevos límites les toca pagar $50/día cuando ayer estaban en los límites gratuitos!!!

Espero que Google se ponga las pilas y relaje estos límites. Yo por lo pronto voy a paralizar pystream, y a mirar de modificar Ubuntu FAQ o migrarlo a otro sitio...

sábado 15 de octubre de 2011

Las comparaciones son odiosas

Unity VS Gnome Shell:







Gnome Shell es el único que tiene un sistema de notificación completo, que agrupa todas las notificaciones por aplicación, para que no se te olvide nada.

Ambiance no incluye una versión oscura para las aplicaciones multimedia.


En Unity no les ha gustado la idea de los diálogos acoplados a la ventana.

Uno de los problemas más perturbadores de Unity: ¿Dónde está el menú de la ventana?

¡Sorpresa!
De verdad que no me entra en la cabeza ¿Para qué esconder el menú? ¿Para poner el título de la ventana dos veces?

Y una de las novedades de esta versión: ¿Dónde están los botones de la ventana?

¡Sorpresa!
¿Que será lo próximo? ¿Esconder todos los formularios de la ventana? Así tendrás que adivinar donde está cada cosa, otro motivo más para no aburrirte...

La única ventaja de Unity frente a Gnome Shell:
No hay que pulsar Alt para que aparezca la opción de apagar.

sábado 1 de octubre de 2011

Un paseo por Gnome 3.2

Después del buen sabor de boca que me dejó Gnome 3, decidí dar el salto directamente a Gnome 3.2 y probar sus novedades. Para ello instalé la beta 2 de Ubuntu 11.10 ... falló a mitad del instalador. Probé con la versión alternate ... y también falló, unicamente me dejó hacer una instalación pelada, sin escritorio. A partir de ahí instalé el metapaquete ubuntu-desktop y gnome-shell.

Y después de una hora:


Gnome 3.2 es mucho más completo, no al nivel del 2.x, pero avanza a buen ritmo. Incluso han solucionado muchas de las quejas de Linus Tordvals.

Abrir múltiples ventanas de una misma aplicación desde el dock.

Habilitar los iconos en el escritorio. Eso si, desde gnome-tweak-tool.

Las herramientas propias de Ubuntu se integran perfectamente en Gnome 3.2:



Y lo que más me ha llamado la atención es el nuevo estilo visual para las aplicaciones multimedia:
Interfaz oscura para Totem.

Lo mismo para el visor de imágenes.

Eso si, en el menú de sesión sigue apareciendo suspender, tienes que pulsar Alt para que aparezca apagar.

Los diálogos de selección de archivos están "pegados" a la ventana de la aplicación, pero eso ya era así en la 3.0

Estos diálogos se adaptan al estilo visual de la aplicación.

El nuevo sistema de notificaciones me sigue pareciendo un acierto.

Y si no te ha dado tiempo a leer alguna notificación, no te preocupes, que las tienes todas agrupadas abajo.

Nautilus 3.2 es mucho más práctico y elegante.

La lista completa de cambios de Gnome 3.2 la tenéis aquí.