Las bases de datos de grafos te ayudan a descubrir información valiosa mediante el modelado de tus entidades de datos y las relaciones entre ellas. JanusGraph es una base de datos de grafos que permite trabajar con grandes cantidades de datos. En este instructivo, se muestra cómo ejecutar JanusGraph en Google Cloud con Google Kubernetes Engine como la plataforma de organización y Bigtable como backend de almacenamiento. El instructivo es para arquitectos de sistemas, administradores de bases de datos y profesionales de DevOps que estén interesados en ejecutar la base de datos de grafos de JanusGraph en Google Cloud con una base de datos administrada como backend de almacenamiento. Suponemos que estás familiarizado conGoogle Kubernetes Engine (GKE), los Pods de Kubernetes, los gráficos de Helm, Bigtable y Elasticsearch. Conocimiento del Apache TinkerPop framework de computación por grafos y de la Gremlin un lenguaje y una máquina de recorrido de grafos, pero ese conocimiento es necesario usar Janusgraph más allá de los ejemplos proporcionados en este instructivo.
Descripción general
En la terminología de los grafos, las entidades se conocen como nodos o vértices y las relaciones como aristas. En JanusGraph, tanto los vértices como las aristas pueden tener datos asociados adicionales que están disponibles a través de propiedades.
La ilustración anterior es un ejemplo de un grafo de propiedades.
Las bases de datos de grafos te ayudan a modelar diferentes dominios y actividades:
- Redes sociales
- Transacciones financieras (para análisis de fraudes)
- Redes de sistemas físicos o virtuales
Cuando se crean bases de datos de grafos, a veces se generan millones o incluso miles de millones de vértices y aristas. Cuando utilizas JanusGraph con Bigtable como la capa de almacenamiento subyacente, puedes ejecutar consultas rápidas (conocidas como recorridos de grafos) y escalar tu capa de almacenamiento de forma independiente según el tamaño. y la capacidad de procesamiento que necesites. JanusGraph también utiliza un backend de indexación conectable a fin de proporcionar indexación de texto completo para las propiedades de vértices y aristas. En este instructivo, implementarás una infraestructura escalable de JanusGraph en GKE. Usarás Elasticsearch como el backend de indexación que se ejecuta en Pods en un StatefulSet, y usarás Bigtable como backend de almacenamiento. Cuando termines, podrás recorrer las relaciones que existen en tus datos de grafos. En el siguiente diagrama, se muestra cómo estos elementos se conectan entre sí.
En el diagrama anterior, se muestra la implementación de JanusGraph en GKE con Elasticsearch y Bigtable.
Datos de JanusGraph en Bigtable
JanusGraph almacena los datos de grafos como una lista de adyacencia. Cada fila representa un vértice, cualquier vértice adyacente (aristas) y metadatos de propiedad sobre los vértices y las aristas. La clave de fila es el identificador único del vértice. Cada relación entre el vértice y otro vértice y cualquier propiedad que defina aún más la relación, se almacena como una columna de arista o de propiedad de arista. El calificador de columnas y el valor de columna almacenan datos que definen la arista, de conformidad con las prácticas recomendadas de Bigtable. Cada propiedad de vértice se almacena como una columna separada, usando el calificador de columna y el valor de columna para definir la propiedad.
En el siguiente diagrama, se muestra esta estructura de almacenamiento.
El diagrama muestra la estructura de almacenamiento lógica para un fragmento de grafo pequeño con detalles lógicos para dos filas de vértices. En el diagrama, las dos filas de ejemplo representan dos vértices. El primer vértice está etiquetado con una sola propiedad de vértice y está relacionado con otros dos vértices mediante dos aristas independientes. El segundo vértice tiene columnas que contienen dos propiedades y una arista.
En la siguiente ilustración del modelo de datos lógicos de vértices, se proporcionan algunos detalles sobre los calificadores y los valores de columnas para una columna de arista o propiedad de arista.
Para cada vértice adyacente, una columna almacena los metadatos sobre esa arista. El calificador de columnas contiene metadatos sobre la relación de arista y la dirección de arista, y un puntero al vértice adyacente. El valor de la columna contiene la etiqueta de arista y cualquier propiedad de arista adicional. Debido a que los recorridos se pueden seguir en cualquier dirección, las aristas se almacenan dos veces, una para cada extremo de la relación de arista. El almacenamiento arista bidireccional aumenta significativamente el rendimiento del recorrido, pero conlleva algunas compensaciones debido a la redundancia del espacio de almacenamiento adicional y las mutaciones de arista no atómicas.
En el siguiente diagrama, se muestra el modelo de datos lógico de una columna de propiedad de vértice.
En la ilustración anterior, se proporcionan detalles sobre los calificadores y los valores de una columna de arista.
Cada propiedad de vértice se almacena como una columna separada. El calificador de columna es un identificador único para la clave de propiedad. El valor de columna contiene un identificador para la propiedad y el valor de la propiedad.
JanusGraph también se basa en el orden lexicográfico de Bigtable de las filas y los calificadores de columna para mejorar el rendimiento de las consultas.
Objetivos
- Crear una instancia de Bigtable.
- Crea un clúster de GKE.
- Instalar Helm.
- Usar un gráfico Helm para implementar JanusGraph y Elasticsearch.
- Usa el Gremlin consola y conectarse con JanusGraph.
- Cargar y, luego, consultar los datos de muestra.
Costos
En este documento, usarás los siguientes componentes facturables de Google Cloud:
- Google Kubernetes Engine (GKE)
- Compute Engine VMs are provisioned by GKE
- Bigtable
Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.
Cuando finalices las tareas que se describen en este documento, puedes borrar los recursos que creaste para evitar que continúe la facturación. Para obtener más información, consulta Cómo realizar una limpieza.
Requisitos previos
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Bigtable, Compute Engine, and GKE APIs.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Bigtable, Compute Engine, and GKE APIs.
Prepare el entorno
En este instructivo, usarás Cloud Shell para ingresar comandos. Cloud Shell te brinda acceso a la línea de comandos en la consola de Google Cloud e incluye Google Cloud CLI y otras herramientas que necesitas para el desarrollo en Google Cloud. Cloud Shell aparece como una ventana en la parte inferior de la consola de Google Cloud. Es posible que la inicialización tome unos minutos, pero la ventana aparecerá de inmediato.
-
In the Google Cloud console, activate Cloud Shell.
En Cloud Shell, configura las variables de entorno para la zona de Compute Engine en la que crearás el clúster de Bigtable y el clúster de GKE, y el nombre, el tipo de nodo y la versión de tu clúster de GKE:
export PROJECT_ID=PROJECT_ID export GCP_ZONE=REGION export GKE_CLUSTER_NAME=GKE_CLUSTER_NAME export GKE_NODE_TYPE=n1-standard-4 export GKE_VERSION=1.20
Reemplaza lo siguiente:
PROJECT_ID
por el identificador de tu proyecto.REGION
por la zona en la que se crearán el clúster de Bigtable y el clúster de GKE.GKE_CLUSTER_NAME
por el nombre de tu clúster de GKE.
El comando debe ser similar al siguiente ejemplo:
export PROJECT_ID=bt-janusgraph-project-id export GCP_ZONE=us-central1-f export GKE_CLUSTER_NAME=janusgraph-gke export GKE_NODE_TYPE=n1-standard-4 export GKE_VERSION=1.20
Crea un clúster de GKE en el que se implementará JanusGraph:
gcloud container clusters create ${GKE_CLUSTER_NAME} \ --zone=${GCP_ZONE} \ --cluster-version=${GKE_VERSION} \ --machine-type ${GKE_NODE_TYPE} \ --scopes "https://www.googleapis.com/auth/cloud-platform"
Crear una instancia de Bigtable.
Para el backend de almacenamiento de JanusGraph, en este instructivo se usa Bigtable, que puede escalar con rapidez para adaptarse a tus necesidades. En el instructivo se usa un clúster de nodo único, una opción rentable y suficiente para este caso. Puedes comenzar tus proyectos con un clúster más pequeño y, luego, pasar a un clúster más grande cuando estés listo para trabajar con datos de producción. La documentación de Bigtable incluye un análisis detallado sobre el rendimiento y el escalamiento que te ayudará a elegir el tamaño de clúster para tu trabajo.
En Cloud Shell, configura la variable de entorno para el identificador de instancias de Bigtable:
export BIGTABLE_INSTANCE_ID=BIGTABLE_INSTANCE_ID
Reemplaza
BIGTABLE_INSTANCE_ID
por el identificador de tu instancia de Bigtable.Crea la instancia de Bigtable:
gcloud bigtable instances create ${BIGTABLE_INSTANCE_ID} \ --cluster-config=id=${BIGTABLE_INSTANCE_ID}-${GCP_ZONE},zone=${GCP_ZONE},nodes=1 \ --display-name=${BIGTABLE_INSTANCE_ID}-${GCP_ZONE}
Instala y configura Helm
Helm se utiliza para implementar aplicaciones en tu clúster de Kubernetes. En este instructivo, usarás Helm para implementar los servicios de JanusGraph y Elasticsearch en tu clúster de GKE.
En Cloud Shell, instala Helm:
curl -fsSL -o get_helm.sh \ https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 chmod 700 get_helm.sh DESIRED_VERSION=v3.5.0 ./get_helm.sh
Agrega el repositorio de chart
elastic
para que se pueda encontrar la dependencia del chart de Elasticsearch durante la implementación del chart de JanusGraph:helm repo add elastic https://helm.elastic.co
Elastic, el creador de Elasticsearch, aloja este repositorio de chart.
Usa de Helm para instalar JanusGraph y Elasticsearch
En esta sección, usas un gráfico de Helm para implementar JanusGraph y Elasticsearch en tu clúster de Kubernetes.
El chart de Helm se extrae de GitHub. El Deployment incluido en el repositorio de chart de Helm implementa un conjunto de tres Pods de JanusGraph detrás de un Service que iniciará un balanceador de cargas de aplicaciones interno. Cuando los Pods se ejecutan, los sondeos de inicio y funcionamiento realizan solicitudes HTTP para realizar verificaciones de estado en el servidor de JanusGraph de cada Pod. Además, el chart incluye un chart de dependencias proporcionado por Elastic que implementa tres Pods de Elasticsearch en un StatefulSet.
En Cloud Shell, configura las variables de entorno para los nombres de Helm y JanusGraph:
export HELM_REPO=bigtable-janusgraph-helm export JANUSGRAPH_VERSION=0.5.3 export HELM_CHART_RELEASE_VERSION=1 export HELM_CHART_RELEASE_TAG=${JANUSGRAPH_VERSION}-${HELM_CHART_RELEASE_VERSION} export HELM_CHART_RELEASE_TAG_HASH=f8b271a4854d4a553dd5e9ba014d077fb098d9ab export HELM_CHART_NAME=janusgraph-bigtable
Extrae el chart de Helm desde GitHub:
git clone https://github.com/GoogleCloudPlatform/${HELM_REPO} \ --branch ${HELM_CHART_RELEASE_TAG}
Navega al directorio del gráfico de Helm:
cd ${HELM_REPO}
Por motivos de seguridad, verifica mediante el hash de confirmación:
HEAD_COMMIT_HASH=$(git rev-parse --verify HEAD) if [ _${HEAD_COMMIT_HASH} == _${HELM_CHART_RELEASE_TAG_HASH} ] then echo "Commit hash verified" fi
Si el resultado no es similar al siguiente, no continúes, ya que la integridad de la etiqueta clonada no se verificó.
Commit hash verified
Actualiza las dependencias del chart:
helm dep update
Navega al directorio superior:
cd ..
Establece variables de entorno para los nombres de las entidades de Helm y JanusGraph:
export HELM_RELEASE_NAME=janusgraph-bigtable-elastic export ELASTICSEARCH_CLUSTER_NAME=${HELM_RELEASE_NAME}-elasticsearch export BIGTABLE_JANUSGRAPH_TABLE=janusgraph-table
Crea un archivo
values.yaml
que proporcione a Helm las propiedades de configuración que se deben usar cuando se implemente el chart de JanusGraph:cat > values.yaml << EOF image: repository: docker.io/janusgraph/janusgraph tag: 0.5.3 pullPolicy: IfNotPresent replicaCount: 3 service: type: LoadBalancer port: 8182 serviceAnnotations: networking.gke.io/load-balancer-type: "Internal" elasticsearch: deploy: true clusterName: ${ELASTICSEARCH_CLUSTER_NAME} properties: storage.backend: hbase storage.directory: null storage.hbase.ext.google.bigtable.instance.id: ${BIGTABLE_INSTANCE_ID} storage.hbase.ext.google.bigtable.project.id: ${PROJECT_ID} storage.hbase.ext.hbase.client.connection.impl: com.google.cloud.bigtable.hbase2_x.BigtableConnection storage.hbase.short-cf-names: true storage.hbase.table: ${BIGTABLE_JANUSGRAPH_TABLE} index.search.backend: elasticsearch index.search.hostname: ${ELASTICSEARCH_CLUSTER_NAME}-master index.search.directory: null index.search.elasticsearch.health-request-timeout: 90s cache.db-cache: true cache.db-cache-clean-wait: 20 cache.db-cache-time: 180000 cache.db-cache-size: 0.5 cluster.max-partitions: 1024 graph.replace-instance-if-exists: true persistence: enabled: false debugLevel: INFO EOF
Implementa el gráfico de Helm de JanusGraph mediante el archivo
values.yaml
que creaste:helm upgrade --install \ --wait \ --timeout 600s \ ${HELM_RELEASE_NAME} \ ./${HELM_REPO} \ -f values.yaml
El proceso de instalación espera hasta que todos los recursos estén listos antes de finalizar. Este proceso puede tardar varios minutos.
Verifica la implementación de JanusGraph
Cuando finalice el proceso de instalación de Helm, se mostrará una sección NOTES
en la que se describe una experiencia de inicio. Puedes seguir los pasos detallados en la sección NOTES
para verificar que tu entorno JanusGraph funcione.
En Cloud Shell, verifica que los componentes del chart de Helm se hayan implementado en GKE:
Comprueba la implementación de JanusGraph:
kubectl get deployments
Si la implementación se realizó de forma correcta, el resultado es el siguiente:
NAME READY UP-TO-DATE AVAILABLE AGE janusgraph-bigtable-elastic 3/3 3 3 3m28s
Verifica el StatefulSet de Elasticsearch:
kubectl get statefulsets
Si todo funciona, el resultado es el siguiente:
NAME READY AGE janusgraph-bigtable-elastic-elasticsearch-master 3/3 4m13s
Establece una variable de entorno para el nombre de un Pod de Kubernetes que ejecute el servidor JanusGraph Gremlin. La etiqueta
app
para el Pod que ejecuta el servidor Gremlin se deriva del nombre del gráfico de Helm que se define en el archivoChart.yaml
.export APP_LABEL_FROM_CHART_NAME=${HELM_CHART_NAME} export POD_NAME=$(kubectl get pods \ --namespace default \ -l "app=${APP_LABEL_FROM_CHART_NAME}, \ release=${HELM_RELEASE_NAME}" \ -o jsonpath="{.items[0].metadata.name}")
Conéctate al Pod y ejecuta la consola Gremlin, una shell de bucle de lectura, evaluación e impresión (REPL). El nombre del contenedor también se deriva del nombre del chart de Helm en
Chart.yaml
.export GREMLIN_CONTAINER=${HELM_CHART_NAME} kubectl exec \ -c ${GREMLIN_CONTAINER} \ -it $POD_NAME \ -- /opt/janusgraph/bin/gremlin.sh
En la consola Gremlin conéctate al servidor Apache TinkerPop:
Inicia la sesión:
:remote connect tinkerpop.server conf/remote.yaml session
El resultado es similar al siguiente:
==>Configured localhost/127.0.0.1:8182-[b08972f2-a2aa-4312-8018-bcd11bc9812c]
Conéctate al servidor:
:remote console
El resultado es similar al siguiente:
==>All scripts will now be sent to Gremlin Server - [localhost/127.0.0.1:8182]-[b08972f2-a2aa-4312-8018-bcd11bc9812c] - type ':remote console' to return to local mode>
En la consola Gremlin verifica que el servidor Gremlin se ejecute correctamente mediante la inspección de la variable
graph
, que representa la instancia de grafo:graph
El resultado indica que el servidor de JanusGraph se ejecuta con una base de datos compatible con HBase (en este caso, Bigtable) como backend de almacenamiento.
==>standardjanusgraph[hbase:[127.0.0.1]]
En Gremlin, crea dos vértices
v1 = graph.addVertex(label, 'hello') v2 = graph.addVertex(label, 'world')
Si el resultado de la consola es similar al siguiente, indica que se agregaron los dos vértices:
==>v[4344] ==>v[4152]
Crea una arista que conecte los dos vértices:
v1.addEdge('followedBy', v2)
Si el resultado de la consola es similar al siguiente, indica que se agregó la arista entre los dos vértices:
==>e[17j-3co-4fmd-oe054][4344-followedBy->4152]
Confirma la transacción:
graph.tx().commit()
Si el resultado de la consola es
null
, indica que las operaciones se confirmaron:==>null
En el siguiente diagrama, se ilustra el grafo que crean los comandos.
El vértice etiquetado como
hello
está conectado por una arista dirigida con la etiquetafollowedBy
al vértice etiquetado comoworld
.Genera una consulta de Gremlin para ver cuál es la etiqueta del vértice que sigue a una arista etiquetada como
followedBy
desde el vértice que está etiquetado comohello
:g.V().has(label, 'hello').out('followedBy').label()
La sintaxis de la consulta se explica en la siguiente sección. Por ahora ves la palabra
world
como el resultado de la consulta:==>world
Carga y consulta un conjunto de datos de muestra
Ahora que implementaste JanusGraph y puedes conectarte a él mediante Gremlin, es momento de comenzar a cargar y consultar tus propios datos. Para ver cómo se ve ese proceso, carga el conjunto de datos de muestra que viene incluido en JanusGraph: Graph of the Gods (Gráfico de los dioses), que representa las deidades mitológicas del pantheon clásico y sus propiedades.
En Gremlin, carga el grafo que creaste antes:
GraphOfTheGodsFactory.load(graph)
El resultado es el siguiente:
==>null
Genera una consulta de recorrido de grafos que encuentre todos los hermanos de Júpiter:
g.V().has('name', 'jupiter').out('brother').values('name')
En la siguiente tabla, se explican los pasos que recorre la consulta.
Paso de recorrido Explicación g.V()
Comienza con la recolección de vértices. has('name', 'jupiter')
Encuentra uno que tenga la propiedad name
con el valorjupiter
.out('brother')
Desde allí sigue cualquier arista etiquetada como brother
.values('name')
Para los vértices a los que conducen esas aristas, obtén la propiedad name
.==>neptune ==>pluto
Para familiarizarte con las consultas de recorrido que son posibles en el conjunto de datos del grafo de los dioses, prueba otras consultas de muestra incluidas en los documentos de JanusGraph.
Verifica que los datos estén almacenados en Bigtable
Ahora que ya creaste datos de muestra en el clúster de JanusGraph, puedes verificar que Bigtable se haya usado como backend de almacenamiento.
Cierra la consola Gremlin:
:q
En Cloud Shell, verifica que los datos se hayan conservado en la tabla
janusgraph
en Bigtable:cbt -project=${PROJECT_ID} \ -instance=${BIGTABLE_INSTANCE_ID} \ count ${BIGTABLE_JANUSGRAPH_TABLE}
El resultado es similar al siguiente.
2021/03/02 02:32:19 -creds flag unset, will use gcloud credential 101
El valor
101
en el resultado representa la cantidad de filas en lajanusgraph table
y puede ser diferente en tu caso.
Verifica la creación del índice de búsqueda en Elasticsearch
En Cloud Shell, configura las variables para el índice y el nombre de los Pods de Elasticsearch:
export ELASTICSEARCH_POD_ORDINAL=0 export ELASTICSEARCH_POD_NAME_ROOT=${ELASTICSEARCH_CLUSTER_NAME}-master export ELASTICSEARCH_POD=${ELASTICSEARCH_POD_NAME_ROOT}-0
Los nombres de los Pods de Elasticsearch se definen mediante las dependencias de Helm para Elasticsearch. Los nombres de los Pods constan del nombre del clúster que se proporciona en el archivo
values.yaml
que creaste, la palabramaster
y un número ordinal no indexado, todo separado por guiones. Para este paso, debes elegir el primer Pod, representado como cero (0).Usa la API de REST de Elasticsearch Alias para inspeccionar los índices:
kubectl exec \ -c elasticsearch \ -it ${ELASTICSEARCH_POD} \ -- \ curl -XGET "127.0.0.1:9200/_aliases?pretty=true";
El resultado muestra dos índices,
janusgraph_vertices
yjanusgraph_edges
, creados por JanusGraph para proporcionar búsquedas eficientes mediante vértices y propiedades perimetrales:{ "janusgraph_vertices" : { "aliases" : { "janusgraph" : { } } }, "janusgraph_edges" : { "aliases" : { "janusgraph" : { } } } }
Consulta los valores de uno de los índices mediante la API de REST de búsqueda de Elasticsearch:
kubectl exec \ -c elasticsearch \ -it ${ELASTICSEARCH_POD} \ -- \ curl -XGET "127.0.0.1:9200/janusgraph_edges/_search?pretty=true&q=*";
Los resultados de la búsqueda muestran que hay entradas en los índices creados por JanusGraph. El resultado que ves es similar a los siguientes resultados truncados, que muestran que hay entradas en el índice
janusgraph_edges
.{ "took" : 94, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 6, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "janusgraph_edges", "_type" : "_doc", "_id" : "6bvp-5ovc-b2t-2yko", "_score" : 1.0, "_source" : { "reason" : "loves waves" } }, { …
Borra el proyecto
Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
¿Qué sigue?
- Más información sobre JanusGraph y bases de datos de grafos.
- Más información sobre Apache TinkerPop de procesamiento de grafos y exploras el Gremlin lenguaje de recorrido de grafo.
- Obtén más información sobre cómo JanusGraph almacena datos en Bigtable.
- Profundiza sobre los casos de uso de grafos mediante la implementación de una aplicación de ejemplo de JanusGraph.