Spanner: TrueTime y coherencia externa

TrueTime es un reloj distribuido de alta disponibilidad que se proporciona a las aplicaciones en todos los servidores de Google.1 TrueTime permite que las aplicaciones generen marcas de tiempo que aumenten de forma monótona: una aplicación puede calcular una marca de tiempo T que sea mayor que cualquier marca de tiempo T' si T' se ha generado antes de que se empezara a generar T. Esta garantía se aplica a todos los servidores y a todas las marcas de tiempo.

Spanner usa esta función de TrueTime para asignar marcas de tiempo a las transacciones. En concreto, a cada transacción se le asigna una marca de tiempo que refleja el instante en el que Spanner considera que se ha producido. Como Spanner usa el control de simultaneidad multiversión, la garantía de ordenación de las marcas de tiempo permite a los clientes de Spanner realizar lecturas coherentes en toda una base de datos (incluso en varias regiones de Cloud) sin bloquear las escrituras.

Coherencia externa

Spanner ofrece a los clientes las garantías de control de simultaneidad más estrictas para las transacciones, lo que se denomina coherencia externa.2 Con la coherencia externa, el sistema se comporta como si todas las transacciones se hubieran ejecutado de forma secuencial, aunque Spanner las ejecute en varios servidores (y posiblemente en varios centros de datos) para mejorar el rendimiento y la disponibilidad. Además, si una transacción se completa antes de que otra empiece a confirmarse, el sistema garantiza que los clientes nunca verán un estado que incluya el efecto de la segunda transacción, pero no el de la primera. De forma intuitiva, Spanner no se distingue semánticamente de una base de datos de una sola máquina. Aunque ofrece garantías tan sólidas, Spanner permite que las aplicaciones alcancen un rendimiento comparable al de las bases de datos que ofrecen garantías más débiles (a cambio de un mayor rendimiento). Por ejemplo, al igual que las bases de datos que admiten el aislamiento de instantáneas, Spanner permite que se realicen escrituras sin que las transacciones de solo lectura las bloqueen, pero sin mostrar las anomalías que permite el aislamiento de instantáneas.

La coherencia externa simplifica enormemente el desarrollo de aplicaciones. Por ejemplo, supongamos que has creado una aplicación bancaria en Spanner y que uno de tus clientes empieza con 50 $en su cuenta corriente y 50 $en su cuenta de ahorro. A continuación, tu aplicación inicia un flujo de trabajo en el que primero confirma una transacción T1 para ingresar 200 $en la cuenta de ahorros y, después, emite una segunda transacción T2 para retirar 150 $de la cuenta corriente. Además, supongamos que, al final del día, los saldos negativos de una cuenta se cubren automáticamente con los de otras cuentas y que un cliente incurre en una penalización si el saldo total de todas sus cuentas es negativo en cualquier momento de ese día. La coherencia externa garantiza que, como T2 empieza a confirmar después de que T1 termine, todos los lectores de la base de datos observarán que el depósito T1 se produjo antes del débito T2. Dicho de otro modo, la coherencia externa garantiza que nadie verá un estado en el que T2 se produzca antes que T1. En otras palabras, el débito nunca incurrirá en una penalización debido a fondos insuficientes.

Una base de datos tradicional que usa almacenamiento de una sola versión y un bloqueo estricto de dos fases proporciona coherencia externa. Por desgracia, en un sistema de este tipo, cada vez que tu aplicación quiera leer los datos más recientes (lo que llamamos "lectura fuerte"), el sistema adquiere un bloqueo de lectura en los datos, lo que impide que se escriban datos en los que se está leyendo.

Marcas de tiempo y control de simultaneidad multiversión (MVCC)

Para leer sin bloquear las escrituras, Spanner y muchos otros sistemas de bases de datos conservan varias versiones inmutables de los datos (a menudo, se denomina control de concurrencia multiversión). Una escritura crea una nueva versión inmutable cuya marca de tiempo es la de la transacción de escritura. Una "lectura de instantánea" en una marca de tiempo devuelve el valor de la versión más reciente anterior a esa marca de tiempo y no necesita bloquear las escrituras. Por lo tanto, es importante que las marcas de tiempo asignadas a las versiones sean coherentes con el orden en el que se pueden observar las transacciones para confirmarlas. A esta propiedad la llamamos "marca de tiempo adecuada". Ten en cuenta que la existencia de una marca de tiempo adecuada equivale a la coherencia externa.

Para ver por qué es importante que las marcas de tiempo sean correctas, consulta el ejemplo de banca de la sección anterior. Si no se asignan marcas de tiempo adecuadas, a T2 se le podría asignar una marca de tiempo anterior a la asignada a T1 (por ejemplo, si un sistema hipotético usara relojes locales en lugar de TrueTime y el reloj del servidor que procesa T2 estuviera ligeramente retrasado). Una lectura de la instantánea podría reflejar el cargo de T2, pero no el ingreso de T1, aunque el cliente haya visto que el ingreso se completó antes de iniciar el cargo.

Conseguir una marca de tiempo adecuada es trivial para una base de datos de una sola máquina (por ejemplo, puedes asignar marcas de tiempo a partir de un contador global que aumente de forma monótona). Conseguirlo en un sistema ampliamente distribuido como Spanner, en el que los servidores de todo el mundo deben asignar marcas de tiempo, es mucho más difícil de hacer de forma eficiente.

Spanner depende de TrueTime para generar marcas de tiempo que aumenten de forma monótona. Spanner usa estas marcas de tiempo de dos formas. En primer lugar, los usa como marcas de tiempo adecuadas para las transacciones de escritura sin necesidad de comunicación global. En segundo lugar, los usa como marcas de tiempo para lecturas sólidas, lo que permite que estas se ejecuten en una ronda de comunicación, incluso las que abarcan varios servidores.

Preguntas frecuentes

¿Qué garantías de coherencia ofrece Spanner?

Spanner ofrece coherencia externa, que es la propiedad de coherencia más estricta para los sistemas de procesamiento de transacciones. Todas las transacciones de Spanner cumplen esta propiedad de coherencia, no solo las que se realizan en una partición. La coherencia externa indica que Spanner ejecuta las transacciones de una forma que no se distingue de un sistema en el que las transacciones se ejecutan de forma secuencial y, además, que el orden secuencial es coherente con el orden en el que se pueden observar las transacciones. Como las marcas de tiempo generadas para las transacciones corresponden al orden de serie, si un cliente ve que una transacción T2 empieza a confirmarse después de que finalice otra transacción T1, el sistema asignará a T2 una marca de tiempo superior a la de T1.

¿Spanner proporciona linealizabilidad?

Sí. De hecho, Spanner proporciona coherencia externa, que es una propiedad más sólida que la linealizabilidad, ya que esta última no dice nada sobre el comportamiento de las transacciones. La linealizabilidad es una propiedad de los objetos simultáneos que admiten operaciones de lectura y escritura atómicas. En una base de datos, un "objeto" suele ser una sola fila o incluso una sola celda. La coherencia externa es una propiedad de los sistemas de procesamiento de transacciones en la que los clientes sintetizan dinámicamente transacciones que contienen varias operaciones de lectura y escritura en objetos arbitrarios. La linealizabilidad se puede considerar un caso especial de coherencia externa, en el que una transacción solo puede contener una única operación de lectura o escritura en un solo objeto.

¿Spanner proporciona serialización?

Sí. De hecho, Spanner proporciona coherencia externa, que es una propiedad más estricta que la serialización. Un sistema de procesamiento de transacciones es serializable si ejecuta las transacciones de una forma que no se distingue de un sistema en el que las transacciones se ejecutan de forma serial. Spanner también garantiza que el orden de serie sea coherente con el orden en el que se pueden observar las transacciones para confirmarse.

Volvamos al ejemplo del banco que hemos usado antes. En un sistema que proporciona serialización, pero no coherencia externa, aunque el cliente haya ejecutado T1 y, a continuación, T2 de forma secuencial, el sistema podría reordenarlos, lo que podría provocar que el débito incurriera en una penalización debido a que no había fondos suficientes.

¿Spanner ofrece una coherencia inmediata?

Sí. De hecho, Spanner proporciona coherencia externa, que es una propiedad más sólida que la coherencia inmediata. El modo predeterminado de las lecturas en Spanner es "sólido", que garantiza que se observen los efectos de todas las transacciones que se hayan confirmado antes del inicio de la operación, independientemente de la réplica que reciba la lectura.

¿Cuál es la diferencia entre la coherencia fuerte y la coherencia externa?

Un protocolo de replicación muestra una "coherencia fuerte" si los objetos replicados son linealizables. Al igual que la linealizabilidad, la coherencia fuerte es más débil que la coherencia externa, ya que no dice nada sobre el comportamiento de las transacciones.

¿Spanner ofrece coherencia eventual (o diferida)?

Spanner proporciona coherencia externa, que es una propiedad mucho más sólida que la coherencia final. La coherencia final ofrece garantías más débiles a cambio de un mayor rendimiento. La coherencia final es problemática porque significa que los lectores pueden observar la base de datos en un estado en el que nunca ha estado realmente (por ejemplo, una lectura podría observar un estado en el que la transacción B se ha confirmado, pero la transacción A no, aunque A haya ocurrido antes que B). Spanner ofrece lecturas obsoletas, que proporcionan ventajas de rendimiento similares a la coherencia final, pero con garantías de coherencia mucho más sólidas. Una lectura obsoleta devuelve datos de una marca de tiempo "antigua", que no puede bloquear las escrituras porque las versiones anteriores de los datos son inmutables.

Más información

Notas

  • 1J. C. Corbett, J. Dean, M. Epstein, A. Fikes, C. Frost, J. Furman, S. Ghemawat, A. Gubarev, C. Heiser, P. Hochschild, W. Hsieh, S. Kanthak, E. Kogan, H. Li, A. Lloyd, S. Melnik, D. Mwaura, D. Nagle, S. Quinlan, R. Rao, L. Rolig, Y. Saito, M. Szymaniak, C. Taylor, R. Wang y D. Woodford. Spanner: Google's Globally-Distributed Database. En Tenth USENIX Symposium on Operating Systems Design and Implementation (OSDI 12), págs. 261-264, Hollywood, California, octubre del 2012.
  • 2Gifford, D. K. Almacenamiento de información en un sistema informático descentralizado. Tesis doctoral, Universidad de Stanford, 1981.