Node.js + Couchbase 3.0 + SDK 2.0 + Bootstrap
Requisitos
Cuando llegó el momento de crear una demostración de producto para la Conferencia Couchbase Connect, se establecieron los siguientes requisitos:
[1] Debe ser una demostración en directo, con la participación del público: nada de películas enlatadas ni presentaciones únicamente en PowerPoint. El listón estaba muy alto y el riesgo era considerable.
[2] Debe demostrar la potencia de Couchbase 3.0 y mostrar la consistencia de los datos en tiempo real entre clusters en diferentes centros de datos (XDCR).
[3] Debe ser ágil, aprovechando la potencia de los nuevos SDK de Couchbase 2.0.
[4] La aplicación necesita tener el código completo en 4 días para reforzar cómo el desarrollo con Couchbase es ideal para la empresa ágil.
[5] Cuéntale al mundo cómo se ha hecho y demuéstralo publicando el código fuente.
Se decidió que una aplicación de subastas, repartida en dos servidores web en dos centros de datos diferentes hablando con dos clusters diferentes lograría el objetivo. Un clúster en Salt Lake City y otro en Londres mantendrán la consistencia con replicación bidireccional entre ellos usando XDCR. El nuevo protocolo DCP en Couchbase 3.0 significa que la consistencia sólo estaría limitada por la velocidad del cable. Un servidor de aplicaciones en cada centro de datos ejecutando node.js gestiona el tráfico en cada región. El código puede descargarse de couchbaselabs repo en github. **
Diseño de aplicaciones
Además de usando node.js con Express y el SDK 2.0 de Couchbase, se utilizó bootstrap para el desarrollo front-end. Los SDK 2.0 son un logro notable, e incluyen nuevos avances significativos que simplifican el desarrollo. La información sobre los SDK 2.0 y por qué Couchbase sigue ampliando su liderazgo en desarrollo dentro del mercado se puede encontrar en nuestro portal para desarrolladores.
Gestión de sesiones
Aunque no es necesaria la autenticación para una subasta sólo por diversión, sigue siendo necesario un medio para identificar a los usuarios y las sesiones concurrentes. Un simple formulario de inicio de sesión almacena una cookie con un identificador de usuario para cada sesión. La función de inicio de sesión comprueba si el usuario existe, y si hay alguna violación de las palabras filtradas antes de crear una cookie de sesión.
filterScan(nuevoUsuario, función (filtcb) {
si (filtcb) {
db.leer(nuevoUsuario, función (err, usuario) {
si (err && err.código === couchbase.errores.keyNotFound) {
res.galleta(usuario, nuevoUsuario);
db.upsert(nuevoUsuario, 0, función (err, res) {
si (err) {
consola.registro("LOGIN:ERROR CREANDO:" + err);
hecho("LOGIN:ERROR CREANDO:" + err, null);
devolver;
}
consola.registro("LOGIN:" + nuevoUsuario + ":ÉXITO");
hecho(null, "LOGIN:" + nuevoUsuario + ":ÉXITO");
devolver;
});
} si no {
si (usuario) {
consola.registro("LOGIN:ERROR:" + nuevoUsuario + " EXISTE");
hecho("LOGIN:ERROR:" + nuevoUsuario + " existe - por favor elija un nombre de usuario diferente", null);
devolver;
}
consola.registro("LOGIN:ERROR:END:" + err);
hecho("LOGIN:ERROR" + err, null);
devolver;
}
});
} si no {
consola.registro("LOGIN:ERROR:VIOLACIÓN DE PALABRA");
hecho("LOGIN:ERROR, TÉRMINO PROHIBIDO EN NOMBRE DE USUARIO", null);
devolver;
}
});
}
A continuación, una función "middleware" muy pequeña comprueba si un usuario ha establecido una sesión antes de enrutar las solicitudes entrantes.
si (req.galletas.usuario) {
devolver siguiente();
}
res.redirigir(‘/’);
}
Otra función "middleware" comprueba si se ha establecido una cuenta atrás o si esta subasta está cerrada.
db.leer(Estado,función(err,hecho){
si(Hecho.valor.activo) {
devolver siguiente();
}si no{
si(Hecho.valor.cuenta atrás != "ninguno")
{
res.render(Cuenta atrás.jade);
}si no {
db.leer(bicicleta, función (err, cb) {
res.render(ganador, {usuario: req.galletas.usuario, importe: cb.valor.oferta, alta: cb.valor.alta});
devolver;
});
}
}
});
}
Interacción con el usuario
El archivo app.js controla el funcionamiento de la aplicación. Todas las rutas se definen en el objeto routes.js en un archivo específico. El objeto de la aplicación se pasa al objeto routes. Se trata de una preferencia estilística que facilita una funcionalidad de middleware más sencilla (como la utilizada en los ejemplos anteriores). La API REST es sencilla: Se exponen los siguientes métodos:
POST api/auction/login [establecer una sesión, cookie, para cada usuario único].
GET api/auction/login [método de seguridad, en caso de actualización de la página]
GET api/auction/load [cargar la página de subastas]
POST api/auction/bid [establecer una puja, con validación].
GET api/subasta/oferta [método de seguridad, en caso de actualización de la página]
GET api/auction/get [obtener el mejor postor actual]
POST api/auction/open/:password [restablecer subasta, vaciar cubo y establecer subasta como abierta].
POST api/auction/close/:password [establecer subasta como cerrada]
POST api/auction/view/build [establecer una vista que se utilizará para ver el historial de pujas].
GET api/auction/view/get [obtener vista del historial de pujas]
GET api/auction/countdown/get [obtener el tiempo en segundos entre la subasta "go live" y ahora].
POST api/auction/countdown/set/:aaaa/:mm/:dd/:hh [fijar fecha de inicio de la subasta].
POST api/auction/countdown/del/:password [establecer la cuenta atrás de la subasta en ninguna, y la subasta en directo].
Actualizaciones dinámicas
En la demostración de la keynote, varios usuarios pujan simultáneamente contra dos clusters diferentes, y cualquier actualización debe propagarse inmediatamente a cualquier otro usuario que esté viendo la página de la subasta. Hay varias maneras de realizar esto, cada una con ventajas y desventajas. Esta aplicación en particular carga la página de subastas a través de una plantilla jade. La plantilla jade instancia un bucle de sondeo jquery ajax. Este bucle sondea el punto final /api/auction/get REST dos veces por segundo para determinar el mejor postor.
setInterval(función () {
pollBid()
}, 500);
función pollBid() {
$.consiga(/api/auction/get, función (cb) {
si (cb) {
$("#bid").html(“$” + cb.oferta);
$("1TP5Muslo").html(cb.alta);
}
si no {
}
});
}
Administración
Los siguientes métodos son llamados usando comandos curl durante la demo para establecer los estados de la subasta. La secuencia de la demostración es restablecer la subasta, establecer una fecha de inicio, establecer la subasta en directo cuando comience el discurso de apertura y cerrar la subasta.
curl -X POST http://localhost:3001/api/auction/open/un5ecure_pa55word
curl -X POST http://localhost:3001/api/countdown/set/2014/10/06/13
curl -X POST http://localhost:3001/api/countdown/del/un5ecure_pa55word
curl -X POST http://localhost:3001/api/auction/close/un5ecure_pa55word
Fuente y consideraciones
Gran parte de la funcionalidad de esta aplicación está codificada y es específica para este caso de uso de demostración de keynote. El modelo de datos es específico para este caso de uso y sólo es aplicable como prueba de concepto. El caso de uso no tiene acceso seguro ni autenticación. Cuando se despliega en diferentes clusters enlazados por XDCR se requiere administración adicional para "resetear" la subasta. No se pueden "vaciar" los cubos que estén participando actualmente en XDCR.
** Descargo de responsabilidad: Couchbase Labs proporciona código experimental sólo con fines de investigación y desarrollo. El código y las aplicaciones de Couchbase Labs no están soportados bajo ningún Acuerdo de Soporte de Couchbase y se proporcionan tal cual, sin garantía de ningún tipo.
Todd, gracias por el post y la demo. ¿Podría compartir las configuraciones de clúster que utilizó en la versión de AWS para lograr el rendimiento de 3M / seg? Es decir, ¿qué tipo de potencia de servidor se necesita?
TIA,
Dave
Hola Dave, estas eran instancias c3.4xlarge. Couchbase Server 3.0 se instaló con la configuración predeterminada.