8. Diseño orientado al SLA
Del dibujo de la arquitectura queda una pregunta pendiente: si los clientes acceden al data plane. Sí, acceden; y con eso en mente aparece una pieza de ubicación discutible. El request router es polémico. En los put y get es necesariamente parte del data plane, porque esas operaciones se resuelven en el momento; en los create table y las demás, no. Típicamente está compartido, en los dos lugares a la vez, y ahí la frontera se vuelve difusa. Suele decirse que es parte del control plane, pero si se cae tampoco funcionan los put ni los get, y eso lo empuja del otro lado. Es un caso ambiguo. Con el partition metadata no hay duda: los clientes definitivamente no acceden a él directamente. Pero el camino de llegar al router, y del router a los data nodes, es parte del data plane.
Si el request router está en el camino de todos los requests, ¿qué pasa cuando se cae? Lo esperable sería que los clientes reciban un 500, o un timeout; y cabe preguntarse si no habrá algún mecanismo para encolar requests y hacerle sentir al cliente que todavía funciona. Normalmente, cuando falla uno, no se percibe, porque que se caiga entero es raro: tendrían que caerse todos los nodos, y la redundancia redirige el tráfico a otros nodos. Un sistema de encolado podría ser una solución, pero viviría dentro del mismo data plane, y entonces ya no estaríamos ante el data plane entero caído. Típicamente, cuando eso se cae, se cae todo, y es muy indeseable; se hace todo lo posible para que no pueda caerse completo.
Además, DynamoDB y todos estos sistemas tratan de degradarse gracefully, delicadamente, aunque la palabra no tenga traducción cómoda. Si se muere un nodo, o los tres de un grupo de replicación, esa parte de la tabla deja de funcionar o responde con más lentitud, pero el resto sigue funcionando.
Y eso nos devuelve al SLA, que podría parecer un concepto de marketing. En realidad es un concepto legal: es el contrato firmado y lo que hay que cumplir. ¿Cómo se lo cumple? La intuición razonable sería que, si un request implica una operación muy grande, la acepten y la procesen de forma asincrónica, o algo así. La respuesta real es mejor, y es el corazón del diseño: DynamoDB está pensado para tener límites, para que uno no pueda hacer una operación muy grande. Hay un tope de tamaño, y es pequeño: no llega a los megabytes que uno imaginaría, sino que está en el orden de las decenas de kilobytes por item. Tampoco se admiten consultas complejas que requieran cálculos. Solo put y get.
El tope exacto es de 400 KB por item, contando tanto los nombres de los atributos como sus valores; un item más grande hace fallar la escritura con un
ValidationException. Fuente: “Quotas in Amazon DynamoDB”, documentación oficial de AWS. La recomendación para datos más grandes es guardarlos en S3 y dejar en el item solamente el identificador del objeto.
Todo esto está pensado al revés de como uno lo pensaría, y es el punto más importante de la clase. Nos ofrecen el SLA porque saben que lo pueden cumplir, y lo saben porque nos limitan mucho en lo que podemos hacer. No es el SLA que ofrecerían con una base relacional: ahí no pueden comprometerse a que nadie bloquee todas las tablas entre sí y quede todo bloqueado, y los SLA son otros. La estrategia es inteligente: no ofrecen lo que no pueden cumplir. Y cuando uno de verdad necesita esas consultas grandes que DynamoDB no permite, le ofrecen otro producto, un warehouse, que se cobra por separado.
Lo que garantizan y lo que no está todo escrito, y se puede leer. Cuando fallan con el SLA, devuelven dinero. Muchas veces se trata de montos simbólicos, como unos centavos por un minuto de caída. Pero también hubo caídas grandes de Amazon, de las que trascienden en los medios, y en esos casos perdieron sumas muy importantes y tuvieron que pagar, porque es parte del contrato. Por eso, en última instancia, el respaldo final es el marco legal: cuando fallan todos los sistemas, quedan los abogados, y a ellos se recurre para cobrar lo que se debe.
Pero lo que hay que deducir es que estos sistemas están diseñados a propósito para cumplir los SLA: para que no se caigan enteros, para que se degraden delicadamente, para que las fallas sean parciales y no totales. Y eso se observa desde afuera. En una base DynamoDB muy grande, a veces algunas claves tienen de repente un pico de latencia gigante mientras otras siguen bien: algunos storage nodes fallaron y el grupo tuvo que cambiar de líder —el mismo cambio de líder que estudiamos en Raft—, mientras el resto de las particiones no sufrió ningún efecto.
Hay algo más, que el paper no dice y que resulta interesante: las réplicas están repartidas a propósito en distintos data centers. AZ es lo que Amazon llama availability zone, una forma comercial de decir data center; son edificios separados. A veces una availability zone son varios edificios, pero conceptualmente se la vende como uno. Si el grupo de replicación son tres réplicas, como un Raft de tres, cada una está en un data center independiente, y esos data centers se conectan por fibra óptica propia para que la comunicación sea muy rápida.
¿Por qué separados? Contra un problema más global no alcanzaría: un corte de luz en toda una zona, o un terremoto, afectaría a todos, porque tiene un espectro demasiado amplio. Pero contra un problema del data center en sí —que se rompa algo, que un incendio consuma el edificio— el sistema entero sigue funcionando, precisamente porque está en lugares físicamente separados.
Pensaron hasta en eso, y, dado su volumen de recursos, construyeron tres data centers separados en cada una de sus regiones del mundo. Una inversión así es enormemente costosa, y resulta viable por la misma razón que el multi-tenant: los servicios cloud apuestan a tener muchos clientes y cobrarle relativamente poco a cada uno. La factura puede ser grande, pero es poco por lo que ofrecen; y con cientos de miles de clientes, el costo operativo promedio por cliente baja mucho. Eso es lo que se conoce como economía de escala.
Y ahí se cierra el círculo. El SLA que encabeza el contrato —los cuatro nueves, la latencia acotada, el dinero de vuelta si no se cumple— no es una promesa audaz: es lo último que se escribe, después de recortar la API a put y get, ponerle un tope al tamaño del item, partir el sistema en un control plane que puede caerse y un data plane que no, y poner cada réplica en un edificio distinto. Se promete lo que el diseño ya garantiza. Y ese diseño, que para un solo cliente sería absurdamente caro, se paga solo cuando los clientes son cientos de miles: la economía de escala no es un detalle del modelo de cobro, es la condición que hace posible el sistema entero.