Amazon DynamoDB - Amazon DynamoDB

Amazon DynamoDB
DynamoDB.png
Desarrollador (es) Amazon.com
Versión inicial Enero de 2012 ; Hace 9 años ( 2012-01 )
Sistema operativo Multiplataforma
Disponible en inglés
Tipo
Licencia Propiedad
Sitio web aws .amazon .com / dynamodb /

Amazon DynamoDB es un servicio de base de datos NoSQL patentado y totalmente administrado que admite estructuras de datos de documentos y valor clave y lo ofrece Amazon.com como parte de la cartera de servicios web de Amazon . DynamoDB expone un modelo de datos similar y deriva su nombre de Dynamo , pero tiene una implementación subyacente diferente. Dynamo tenía un diseño de múltiples líderes que requería que el cliente resolviera los conflictos de versiones y DynamoDB usa la replicación sincrónica en múltiples centros de datos para una alta durabilidad y disponibilidad. DynamoDB fue anunciado por el CTO de Amazon Werner Vogels el 18 de enero de 2012 y se presenta como una evolución de Amazon SimpleDB .

Fondo

Werner Vogels , director de tecnología de Amazon.com, motivó el proyecto en su anuncio de 2012. Amazon comenzó como una red descentralizada de servicios. Originalmente, los servicios tenían acceso directo a las bases de datos de los demás. Cuando esto se convirtió en un cuello de botella en las operaciones de ingeniería, los servicios se alejaron de este patrón de acceso directo a favor de las API de cara al público . Aún así, los sistemas de administración de bases de datos relacionales de terceros tuvieron problemas para manejar la base de clientes de Amazon. Esto culminó durante la temporada navideña de 2004, cuando varias tecnologías fallaron bajo un alto tráfico.

Los ingenieros estaban normalizando estos sistemas relacionales para reducir la redundancia de datos , un diseño que optimiza el almacenamiento. El sacrificio: almacenaron un "elemento" de datos determinado (por ejemplo, la información perteneciente a un producto en una base de datos de productos) en varias relaciones, y se necesita tiempo para ensamblar partes separadas para una consulta. Muchos de los servicios de Amazon exigían principalmente lecturas de clave primaria en sus datos, y con la velocidad como una prioridad máxima, juntar estas piezas fue extremadamente agotador.

Contento con comprometer la eficiencia del almacenamiento, la respuesta de Amazon fue Dynamo : una tienda de valor clave de alta disponibilidad construida para uso interno. Dynamo, al parecer, era todo lo que necesitaban sus ingenieros, pero la adopción se retrasó. Los desarrolladores de Amazon optaron por patrones de diseño "simplemente funciona" con S3 y SimpleDB. Si bien estos sistemas tenían defectos de diseño notables, no exigían la sobrecarga de aprovisionamiento de hardware y escalado y particionamiento de datos. La próxima versión de Amazon de la tecnología NoSQL , DynamoDB, automatizó estas operaciones de administración de bases de datos.

Descripción general

Consola web
Consola web

DynamoDB se diferencia de otros servicios de Amazon al permitir a los desarrolladores comprar un servicio en función del rendimiento , en lugar del almacenamiento . Si Auto Scaling está habilitado, la base de datos se escalará automáticamente. Además, los administradores pueden solicitar cambios en el rendimiento y DynamoDB distribuirá los datos y el tráfico entre varios servidores que utilizan unidades de estado sólido , lo que permite un rendimiento predecible. Ofrece integración con Hadoop a través de Elastic MapReduce .

En septiembre de 2013, Amazon puso a disposición una versión de desarrollo local de DynamoDB para que los desarrolladores pudieran probar las aplicaciones respaldadas por DynamoDB localmente.

Consideraciones de desarrollo

Modelado de datos

Descripción general de la consola web

Una tabla de DynamoDB presenta elementos que tienen atributos, algunos de los cuales forman una clave principal . En los sistemas relacionales, sin embargo, un elemento presenta cada atributo de la tabla (o hace malabares con valores "nulos" y "desconocidos" en su ausencia), los elementos de DynamoDB no tienen esquema. La única excepción: al crear una tabla, un desarrollador especifica una clave principal y la tabla requiere una clave para cada elemento. Las claves primarias deben ser escalares ( cadenas , números o binarias ) y pueden tomar una de dos formas. Una clave primaria de un solo atributo se conoce como la "clave de partición" de la tabla, que determina la partición a la que un elemento realiza el hash (más sobre la partición a continuación), por lo que una clave de partición ideal tiene una distribución uniforme en su rango. Una clave principal también puede presentar un segundo atributo, que DynamoDB llama "clave de clasificación" de la tabla. En este caso, las claves de partición no tienen que ser únicas; se combinan con claves de clasificación para crear un identificador único para cada artículo. La clave de partición todavía se usa para determinar en qué partición se almacena el elemento, pero dentro de cada partición, los elementos se ordenan por clave de clasificación.

Índices

En el modelo relacional, los índices suelen servir como estructuras de datos "auxiliares" para complementar una tabla. Permiten que el DBMS optimice las consultas bajo el capó y no mejoran la funcionalidad de las consultas. En DynamoDB, no hay un optimizador de consultas y un índice es simplemente otra tabla con una clave diferente (o dos) que se encuentra junto a la original. Cuando un desarrollador crea un índice, crea una nueva copia de sus datos, pero solo se copian los campos que especificaron (como mínimo, los campos en los que indexan y la clave principal de la tabla original).

Los usuarios de DynamoDB emiten consultas directamente a sus índices. Hay dos tipos de índices disponibles. Un índice secundario global presenta una clave de partición (y una clave de clasificación opcional) que es diferente de la clave de partición de la tabla original. Un índice secundario local presenta la misma clave de partición que la tabla original, pero una clave de clasificación diferente. Ambos índices introducen una funcionalidad de consulta completamente nueva en una base de datos de DynamoDB al permitir consultas sobre nuevas claves. De manera similar a los sistemas de administración de bases de datos relacionales, DynamoDB actualiza los índices automáticamente al agregarlos / actualizarlos / eliminarlos, por lo que debe ser prudente al crearlos o arriesgarse a ralentizar una base de datos de escritura pesada con una gran cantidad de actualizaciones de índices.

Sintaxis

DynamoDB usa JSON para su sintaxis debido a su ubicuidad. La acción de creación de tabla requiere solo tres argumentos: TableName, KeySchema –– una lista que contiene una clave de partición y una clave de clasificación opcional –– y AttributeDefinitions –– una lista de atributos a definir que al menos debe contener definiciones para los atributos usados ​​como partición y ordenar claves. Mientras que las bases de datos relacionales ofrecen lenguajes de consulta sólidos, DynamoDB ofrece solo operaciones de colocación, obtención, actualización y eliminación. Las solicitudes de venta contienen el atributo TableName y un atributo Item, que consta de todos los atributos y valores que tiene el elemento. Una solicitud de actualización sigue la misma sintaxis. De manera similar, para obtener o eliminar un elemento, simplemente especifique un TableName y Key.

Arquitectura del sistema

Tabla de creación en DynamoDB

Estructuras de datos

DynamoDB utiliza hash y árboles B para administrar los datos. Al ingresar, los datos se distribuyen primero en diferentes particiones mediante hash en la clave de partición. Cada partición puede almacenar hasta 10GB de datos y manejar por defecto 1,000 unidades de capacidad de escritura (WCU) y 3,000 unidades de capacidad de lectura (RCU). Una RCU representa una lectura muy consistente por segundo o dos lecturas eventualmente consistentes por segundo para elementos de hasta 4 KB de tamaño. Una WCU representa una escritura por segundo para un elemento de hasta 1 KB de tamaño.

Para evitar la pérdida de datos, DynamoDB cuenta con un sistema de copia de seguridad de dos niveles de replicación y almacenamiento a largo plazo. Cada partición cuenta con tres nodos, cada uno de los cuales contiene una copia de los datos de esa partición. Cada nodo también contiene dos estructuras de datos: un árbol B que se usa para ubicar elementos y un registro de replicación que anota todos los cambios realizados en el nodo. DynamoDB toma periódicamente instantáneas de estas dos estructuras de datos y las almacena durante un mes en S3 para que los ingenieros puedan realizar restauraciones puntuales de sus bases de datos.

Dentro de cada partición, uno de los tres nodos se denomina "nodo líder". Todas las operaciones de escritura viajan primero a través del nodo líder antes de propagarse, lo que hace que las escrituras sean consistentes en DynamoDB. Para mantener su estado, el líder envía un "latido" a cada uno de los otros nodos cada 1,5 segundos. Si otro nodo deja de recibir latidos, puede iniciar una elección de nuevo líder. DynamoDB utiliza el algoritmo de Paxos para elegir líderes.

Los ingenieros de Amazon originalmente evitaban Dynamo debido a los gastos generales de ingeniería como el aprovisionamiento y la administración de particiones y nodos. En respuesta, el equipo de DynamoDB creó un servicio al que llama AutoAdmin para administrar una base de datos. AutoAdmin reemplaza un nodo cuando deja de responder copiando datos de otro nodo. Cuando una partición excede cualquiera de sus tres umbrales (RCU, WCU o 10GB), AutoAdmin agregará automáticamente particiones adicionales para segmentar aún más los datos.

Al igual que los sistemas de indexación en el modelo relacional, DynamoDB exige que cualquier actualización de una tabla se refleje en cada uno de los índices de la tabla. DynamoDB maneja esto mediante un servicio al que llama "propagador de registros", que se suscribe a los registros de replicación en cada nodo y envía solicitudes adicionales de colocación, actualización y eliminación a los índices según sea necesario. Debido a que los índices dan como resultado impactos de rendimiento sustanciales para las solicitudes de escritura, DynamoDB permite a un usuario como máximo cinco de ellos en una tabla determinada.

Ejecución de consultas

Suponga que un usuario de DynamoDB emite una operación de escritura (Put, Update o Delete). Mientras que un sistema relacional típico convertiría la consulta SQL en álgebra relacional y ejecutaría algoritmos de optimización, DynamoDB omite ambos procesos y se pone manos a la obra. La solicitud llega al enrutador de solicitudes de DynamoDB, que autentica - "¿La solicitud proviene de dónde / de quién dice ser?" - y verifica la autorización - "¿El usuario que envía la solicitud tiene los permisos necesarios?" Suponiendo que se aprueben estas comprobaciones, el sistema codifica la clave de partición de la solicitud para que llegue a la partición adecuada. Hay tres nodos dentro, cada uno con una copia de los datos de la partición. El sistema primero escribe en el nodo líder, luego escribe en un segundo nodo, luego envía un mensaje de "éxito" y finalmente continúa propagándose al tercer nodo. Las escrituras son consistentes porque siempre viajan primero a través del nodo líder.

Finalmente, el propagador de registros propaga el cambio a todos los índices. Para cada índice, toma el valor de la clave principal de ese índice del elemento y luego realiza la misma escritura en ese índice sin propagación del registro. Si la operación es una Actualización de un elemento preexistente, el atributo actualizado puede servir como clave principal para un índice y, por lo tanto, el árbol B para ese índice también debe actualizarse. Los árboles B solo manejan operaciones de inserción, eliminación y lectura, por lo que en la práctica, cuando el propagador de registros recibe una operación de actualización, emite una operación de eliminación y una operación de colocación para todos los índices.

Ahora suponga que un usuario de DynamoDB emite una operación Get. El enrutador de solicitud procede como antes con la autenticación y autorización. A continuación, como se indicó anteriormente, aplicamos el hash a nuestra clave de partición para obtener el hash apropiado. Ahora, nos encontramos con un problema: con tres nodos en eventual consistencia entre sí, ¿cómo podemos decidir cuál investigar? DynamoDB ofrece al usuario dos opciones al emitir una lectura: consistente y eventualmente consistente. Una lectura constante visita el nodo líder. Pero el equilibrio entre consistencia y disponibilidad vuelve a aparecer aquí: en los sistemas de lectura pesada, leer siempre del líder puede abrumar a un solo nodo y reducir la disponibilidad.

La segunda opción, una lectura eventualmente consistente, selecciona un nodo aleatorio. En la práctica, aquí es donde DynamoDB intercambia consistencia por disponibilidad. Si tomamos esta ruta, ¿cuáles son las probabilidades de una inconsistencia? Necesitaríamos una operación de escritura para devolver "éxito" y comenzar a propagarse al tercer nodo, pero no terminar. También necesitaríamos nuestro Get para apuntar a este tercer nodo. Esto significa una probabilidad de 1 en 3 de inconsistencia dentro de la ventana de propagación de la operación de escritura. ¿Cuánto mide esta ventana? Cualquier número de catástrofes podría hacer que un nodo se quede atrás, pero en la gran mayoría de los casos, el tercer nodo está actualizado en milisegundos del líder.

Actuación

Ficha de capacidad, escalado

DynamoDB expone métricas de rendimiento que ayudan a los usuarios a aprovisionarlo correctamente y a mantener las aplicaciones que utilizan DynamoDB funcionando sin problemas:

  • Solicitudes y limitación
  • Errores : ProvisionedThroughputExceededException, ConditionalCheckFailedException, Error interno del servidor (HTTP 500)
  • Métricas relacionadas con la creación del índice secundario global

Estas métricas se pueden rastrear usando la Consola de administración de AWS , usando la Interfaz de línea de comandos de AWS o una herramienta de monitoreo que se integre con Amazon CloudWatch .


Enlaces de idioma

Los lenguajes y marcos con un enlace DynamoDB incluyen Java , JavaScript , Node.js , Go , C # .NET , Perl , PHP , Python , Ruby , Rust , Haskell , Erlang , Django y Grails .

Ejemplos de código

AWS DynamoDB: vista de elementos

API HTTP

Contra la API HTTP , elementos de consulta:

POST / HTTP/1.1
Host: dynamodb.<region>.<domain>;
Accept-Encoding: identity
Content-Length: <PayloadSizeBytes>
User-Agent: <UserAgentString>
Content-Type: application/x-amz-json-1.0
Authorization: AWS4-HMAC-SHA256 Credential=<Credential>, SignedHeaders=<Headers>, Signature=<Signature>
X-Amz-Date: <Date>
X-Amz-Target: DynamoDB_20120810.Query

{
    "TableName": "Reply",
    "IndexName": "PostedBy-Index",
    "Limit": 3,
    "ConsistentRead": true,
    "ProjectionExpression": "Id, PostedBy, ReplyDateTime",
    "KeyConditionExpression": "Id = :v1 AND PostedBy BETWEEN :v2a AND :v2b",
    "ExpressionAttributeValues": {
        ":v1": {"S": "Amazon DynamoDB#DynamoDB Thread 1"},
        ":v2a": {"S": "User A"},
        ":v2b": {"S": "User C"}
    },
    "ReturnConsumedCapacity": "TOTAL"
}

Respuesta de muestra:

HTTP/1.1 200 OK
x-amzn-RequestId: <RequestId>
x-amz-crc32: <Checksum>
Content-Type: application/x-amz-json-1.0
Content-Length: <PayloadSizeBytes>
Date: <Date>
 {
    "ConsumedCapacity": {
        "CapacityUnits": 1,
        "TableName": "Reply"
    },
    "Count": 2,
    "Items": [
        {
            "ReplyDateTime": {"S": "2015-02-18T20:27:36.165Z"},
            "PostedBy": {"S": "User A"},
            "Id": {"S": "Amazon DynamoDB#DynamoDB Thread 1"}
        },
        {
            "ReplyDateTime": {"S": "2015-02-25T20:27:36.165Z"},
            "PostedBy": {"S": "User B"},
            "Id": {"S": "Amazon DynamoDB#DynamoDB Thread 1"}
        }
    ],
    "ScannedCount": 2
}

Ir

GetItem en Go :

getItemInput := &dynamodb.GetItemInput{
	TableName: aws.String("happy-marketer"),
	Key: map[string]*dynamodb.AttributeValue{
		"pk": {
			S: aws.String("project"),
		},
		"sk": {
			S: aws.String(email + " " + name),
		},
	},
}
getItemOutput, err := dynamodbClient.GetItem(getItemInput)

DeleteItem en Go :

deleteItemInput := &dynamodb.DeleteItemInput{
	TableName: aws.String("happy-marketer"),
	Key: map[string]*dynamodb.AttributeValue{
		"pk": {
			S: aws.String("project"),
		},
		"sk": {
			S: aws.String(email + " " + name),
		},
	},
}

_, err := dynamodbClient.DeleteItem(deleteItemInput)
if err != nil {
	panic(err)
}

UpdateItem en Go usando Expression Builder :

update := expression.Set(
	expression.Name(name),
	expression.Value(value),
)

expr, err := expression.NewBuilder().WithUpdate(update).Build()
if err != nil {
	panic(err)
}

updateItemInput := &dynamodb.UpdateItemInput{
	TableName: aws.String(tableName),
	Key: map[string]*dynamodb.AttributeValue{
		"pk": {
			S: aws.String("project"),
		},
		"sk": {
			S: aws.String("mySortKeyValue"),
		},
	},
	UpdateExpression:          expr.Update(),
	ExpressionAttributeNames:  expr.Names(),
	ExpressionAttributeValues: expr.Values(),
}
fmt.Printf("updateItemInput: %#v\n", updateItemInput)

_, err = dynamodbClient.UpdateItem(updateItemInput)
if err != nil {
	panic(err)
}

Ver también

Referencias

enlaces externos