17 ago

Añadir nodo a un cluster Voldemort

Después de explicar ¿qué es voldemort? y ¿cómo instalarlo? nos quedamos con un cluster de dos nodos, en este post explicaré como añadir en nuevo nodo a un cluster Voldemort.

cluster voldemort

Como impresiones generales diré, que no es sencillo, no es intuitivo y no es rápido, pero que hacer, se puede hacer.

Me pareció algo así

Tarea

Primero de todo nos ponemos en situación, en el ultimo post, teníamos un cluster de dos nodos, con 5 particiones.


<cluster>
 <name>Test</name>
 <server>
 <id>0</id>
 <host>node1</host>
 <http-port>8081</http-port>
 <socket-port>6666</socket-port>
 <partitions>0, 2, 4</partitions>
 </server>
 <server>
 <id>1</id>
 <host>node2</host>
 <http-port>8081</http-port>
 <socket-port>6666</socket-port>
 <partitions>1, 3, 5</partitions>
 </server>
</cluster>

Como sabemos al ser la particiones estáticas deberemos utilizar las 6 que disponemos, el sistema de voldemort trae herramientas que nos dan una idea de cómo debería quedar el cluster.

Los pasos son

  1. Reparticionar
  2. Rebalancear
  3. Lanzar la tarea
  4. Limpiar datos huérfanos

Paso 1 .- Repartition.

Para una expansion del cluster deberemos crear un fichero cluster xml provisional  “interim”, en el que añadiremos los nuevos nodos , pero con la parte de particiones vacía.


<cluster>
<name>qacluster</name>
<server>
<id>0</id>
<host>nodo1</host>
<http-port>8081</http-port>
<socket-port>6666</socket-port>
<partitions>0, 2, 4</partitions>
</server>
<server>
<id>1</id>
<host>nodo2</host>
<http-port>8081</http-port>
<socket-port>6666</socket-port>
<partitions>1, 3, 5</partitions>
</server>
<server>
<id>2</id>
<host>nodo3</host>
<http-port>8081</http-port>
<socket-port>6666</socket-port>
<partitions></partitions>
</server>
</cluster>

Como podemos ver añadimos el nodo 3 en un fichero cluster-interim, pero con las particiones vacías.

Lanzamos la herramienta de RepartitionerCLI, la encontramos dentro de la carpeta bin.

bin/run.class.sh voldemort.tools.RepartitionerCLI --current-cluster <current-cluster> --current-stores <current_stores> --interim-cluster <interim-cluster> --output-dir <output_dir>

Os recomiendo que os creáis unas carpetas para tener cada fichero ordenado, deberemos añadir todos los stores en un solo fichero, el ejemplo de la llamada sería.

bin/run-class.sh voldemort.tools.RepartitionerCLI --current-cluster repo_stores/cluster.xml --current-stores repo_stores/prueba.xml --interim-cluster repo_stores/interim/cluster.xml --output-dir repo_stores/plan/

Dentro de la carpeta repo_stores/plan tendremos

current-cluster.xml.analysis
final-cluster.xml
final-cluster.xml0
final-cluster.xml0.analysis
final-cluster.xml.analysis

En los ficheros de analysis tendremos los pasos que realizar para llegar a la estructura final del cluster, que es el fichero final-cluster.xml

Paso 2 .- Rebalancing 

Deberemos crear el plan para hacer el rebalancing, usaremos el fichero final-cluster.xml que obtuvimos del paso anterior.

bin/run-class.sh voldemort.tools.RebalancePlanCLI --current-cluster repo_stores/cluster.xml --current-stores repo_stores/prueba.xml --final-cluster repo_stores/planRepartitioner/final-cluster.xml --output-dir repo_stores/planRebalance/

En la carpeta planRebalance deberemos tener el fichero final-cluster.xml, recordemos que tenemos 2 nodos que estan trabajando, pero un tercero que no esta dentro del cluster ni tienes las stores, asi que debemos añadirlo y  crear las stores en el tercer nodo antes de continuar.

Debemos utilziar el fichero de cluster-interim del paso 1, para actualizarlo en todos los servidores, de esta manera el nodo 3 no tendrá particiones y será, la tarea de rebalancing del paso siguiente la que lo actualice las particiones.

bin/vadmin.sh meta set cluster.xml=repo_stores/interim/cluster.xml --node 0 --url tcp://127.0.0.1:6666
bin/vadmin.sh store add --file repo_stores/prueba.xml --node 2 --url tcp://127.0.0.1:6666

Utilizamos la herramienta vadmin.sh con la opcion –node 2, para añadir las stores únicamente en el servidor 3

 Paso 3 .- Lanzar el rebalancing 

Utilizaremos la siguiente herramienta.

bin/run-class.sh voldemort.tools.RebalanceControllerCLI --url $URL --final-cluster final-cluster.xml --parallelism 8 --proxy-pause 900
  • $URL: Será la direccion de uno de los nodos del cluster
  • Final-cluster :  EL fichero final-cluster que obtuvimos en el último paso, que es la situación final que estará el cluster cuando termine la tarea.
  • Parallelism: Numero de tareas de rebalancing que se pueden lanzar en el mismo momento.
  • Proxy-pause : El tiempo que esperará entre la actualizacion de la metadata y el inicio del rebalancing,

Nota: Antes de lanzarlo si paramos en medio del proceso, el sistema queda inestable asi que utilicemos algun screen o tmux o algo asi …

bin/run-class.sh voldemort.tools.RebalanceControllerCLI --url tcp://127.0.0.1:6666 --final-cluster repo_stores/planRepartitioner/final-cluster.xml --parallelism 8 --proxy-pause 900

Nos dará información sobre lo que va ha hacer y comenzara el proceso, ¿cómo podemos ver el estado?

bin/vadmin.sh async-job list --url tcp://127.0.0.1:6666

 

Aquí podemos ver que esta haciendo, como dato informativo en mi caso para 20Gb de información tardo 4 horas, o sea rápido rápido no es

Y por último.

 Paso 4 .- Limpieza de los datos huérfanos.

Este proceso solo mueve datos, con lo que una vez terminado habrá nodos que tendrán datos de particiones que ya no le pertenecen.

bin/vadmin.sh cleanup orphaned-data --all-nodes --url tcp://127.0.0.1:6666

Finalizado, cluster ampliado, en el siguiente post explicaré el concepto de zonas y como aprovecharlas para realizar replicaciones.

 

 Referencias: 

http://www.project-voldemort.com/voldemort/rebalance.html

https://github.com/voldemort/voldemort/wiki/Voldemort-Admin-to

 

 

 

 

 

 

 

 

10 ago

Instalación de Voldemort

Después de explicar una idea general de qué es voldemort, vamos a explicar como realizar la instalación de Voldemort, y montaremos un cluster de 2 nodos. En los siguientes post veremos como ampliarlo a tres nodos.

Preparación del paquete

Si nos vamos a la pagina del proyecto http://www.project-voldemort.com/voldemort/ veremos que la ultima version disponible que nos encontramos en la 1.6, versión muy antigua respecto a la actual, 1.9.12, ¿dónde encontramos esta versión?

https://github.com/voldemort/voldemort.git

Tenemos el código y deberemos compilarlo para poder utilizarlo.

Pues vamos a ello.

En mi caso voy a montar 2 instancias lxc,  lo haremos de la siguiente manera.

Crearemos 2 instancias de lxc, voldemort y voldemort1 (ya que querremos probar el cluster en los siguientes post).


[email protected]:~# lxc-create -t download -n voldemort1 -- --dist ubuntu --release trusty --arch amd64

Arrancamos y nos conectamos a la máquina voldemort


lxc-start -n voldemort1 ; lxc-attach -n voldemort1 

Necesitamos una serie de paquetes para compilar y hacer correr Voldemort.

 sudo apt-get install openjdk-7-jre openjdk-7-jre-headless gradle openjdk-7-jdk git 

Bajamos el codigo de github

 git clone https://github.com/voldemort/voldemort.git cd voldemort 

Compilamos

 ./gradlew clean jar 

Esperamos y nos quedamos con los siguientes directorios.

dist/*.jar
lib/*.jar
contrib/*/lib/*.jar
contrib/*/lib/*.jar
src/java/log4j.properties
config/ bin/

Ya tenemos el paquete montado.

Configuración de Voldemort 

Vamos a ver los ficheros importantes

Cluster.xml – Fichero que debe ser igual en todos los nodos del cluster  y tendrá la información sobre puertos, hostnames, el nombre del cluster y por supuesto las particiones (explicadas en el post), donde definiremos como vamos a repartir los datos por nuestro cluster, debemos recordad que las particiones son estáticas en numero o sea que deberemos pensar bien cuantas seleccionamos.

Stores.xml  – Aquí nos encontraremos la definición de las tablas, así como todos parámetros para las mismas, por ejemplo el número de lecturas y escrituras que tiene que ir bien para dar el dato como bueno, o el tipo de replicación que tendremos por store.

Server.properties – Contiene los parámetros de optimización para cada nodo en particular, por ejemplo el id del nodo (único para todos nodos del cluster), este es un fichero diferente para cada nodo.

Entonces, deberemos tocar en ambos nodos el fichero cluster.xml, podemos poner algo así.

 

<cluster>
 <name>Test</name>
 <server>
 <id>0</id>
 <host>node1</host>
 <http-port>8081</http-port>
 <socket-port>6666</socket-port>
 <partitions>0, 2, 4</partitions>
 </server>
 <server>
 <id>1</id>
 <host>node2</host>
 <http-port>8081</http-port>
 <socket-port>6666</socket-port>
 <partitions>1, 3, 5</partitions>
 </server>
</cluster>

Definimos el hostname de los servidores, los puertos y las particiones, elegí 5 particiones ya que como sabemos son estáticas y tengo pensado añadir un nuevo nodo, con lo que deberemos rehacer la reasignación.

Arrancamos…  La última linea debe ser algo así,

[10:27:01,032 voldemort.server.VoldemortServer] INFO Startup completed in 566 ms. [main]

Si nos fijamos en el log de salida, la verdad es que no nos da mucha información de si el cluster esta activo o no, nuestro gran amigo para interactuar con el cluster es vadmin (lo encontramos en la carpeta /bin)

Podemos lanzar algo así.

bin/vadmin.sh meta check-version --url tcp://10.2.11.201:6666
Node : 0 Version : version() ts:1438175142424
Node : 1 Version : version() ts:1438175142424
All the nodes have the same metadata versions.
avro-example=0
stores.xml=0
cluster.xml=0
test=0

Parece que tenemos un cluster de voldemort!

Creación de Stores

Ahora que tenemos el cluster montado debemos crear algún store, podemos utilizar algunos de los xml que vienen de prueba en el paquete de instalación.


<store>
 <name>Primer_Store</name>
 <persistence>bdb</persistence>
 <description>Test store</description>
 <owners>[email protected], [email protected]</owners>
 <routing-strategy>consistent-routing</routing-strategy>
 <routing>client</routing>
 <replication-factor>1</replication-factor>
 <required-reads>1</required-reads>
 <required-writes>1</required-writes>
 <key-serializer>
 <type>string</type>
 </key-serializer>
 <value-serializer>
 <type>string</type>
 </value-serializer>
 <hinted-handoff-strategy>consistent-handoff</hinted-handoff-strategy>
</store>

Deberemos fijarnos en los siguientes campos.

routing-strategy: Definimos el tipo de estrategia para grabar los datos, en el caso que nuestro cluster no tenga zonas utilizaremos consisten-routing.
required-reads: Numero de lecturas necesarias para que la operación se de por buena.
required-writes: Numero de escrituras necesarias para que la operación se de por buena.

Creamos el store.

bin/vadmin.sh store add --file repo_stores/primer_store.xml --url tcp://nodo1:6666

Podemos comprobar en el log algo tal que así

Aug 02 10:57:47 voldemort-server.sh[3563]: [10:57:47,572 voldemort.utils.StoreDefinitionUtils] INFO Validating schema for store: Primera_Store [voldemort-admin-server-t8]Aug 02 voldemort-server.sh[3563]: [10:57:47,595 voldemort.store.metadata.MetadataStore] INFO Updating routing strategy for all stores [voldemort-admin-server-t8]
Aug 02 10:57:47 voldemort-server.sh[3563]: [10:57:47,595 voldemort.server.protocol.admin.AdminServiceRequestHandler] INFO Successfully added new store 'Primera_Store' [voldemort-admin-server-t8]

Por último vamos a realizar una pequeña prueba de stress, para comprobar si es tan rapido como dicen.

./bin/voldemort-performance-tool.sh --record-count 500000
                                    --value-size 10240
                                    --ops-count 1000000
                                    --target-throughput 100
                                    --url tcp://prod:6666
                                    --store-name Primera_Store
                                    -r 90 -m 10

Donde

record-count: Numero de registros insertados
value-size: tamaño de cada registro
target-throughput: Numero de operaciones por segundo.
Y 95% de lecturas.


bootstrapTime=1438673554246 [0/1956]
context=
deploymentPath=/opt/voldemort-1.9.12
localHostName=
sequence=0
storeName=prueba
updateTime=1438673554021
releaseVersion=1.9.18
clusterMetadataVersion=0
max_connections=50
max_total_connections=8
connection_timeout_ms=500
socket_timeout_ms=1500
routing_timeout_ms=1500
client_zone_id=-1
failuredetector_implementation=voldemort.cluster.failuredetector.ThresholdFailureDetector
failuredetector_threshold=95
failuredetector_threshold_count_minimum=30
failuredetector_threshold_interval=300000
failuredetector_threshold_async_recovery_interval=10000
[main]
Running warmup
[warmup] RunTime(ms): 1088442
[warmup] Throughput(ops/sec): 9187.4441
======================= iteration = 0 ======================================
[benchmark] RunTime(ms): 36187
[benchmark] Throughput(ops/sec): 13955.2878
[reads] Operations: 152027
[reads] Average(ms): 0.0179
[reads] Min(ms): 0
[reads] Max(ms): 201
[reads] Median(ms): 0
[reads] 95th(ms): 0
[reads] 99th(ms): 0
[writes] Operations: 251929
[writes] Average(ms): 0.0972
[writes] Min(ms): 0
[writes] Max(ms): 213
[writes] Median(ms): 0
[writes] 95th(ms): 0
[writes] 99th(ms): 1
[transactions] Operations: 50742
[transactions] Average(ms): 0.1662
[transactions] Min(ms): 0
[transactions] Max(ms): 212
[transactions] Median(ms): 0
[transactions] 95th(ms): 1
[transactions] 99th(ms): 2
[deletes] Operations: 50302
[deletes] Average(ms): 0.0149
[deletes] Min(ms): 0
[deletes] Max(ms): 132
[deletes] Median(ms): 0
[deletes] 95th(ms): 0
[deletes] 99th(ms): 0
[09:51:18,948 voldemort.common.service.VoldemortService] INFO Stopping scheduler-service [main]

Esto parece que va, ya tenemos hecha la Instalación de Voldemort con una media de:

0.017ms en lectura

0.09 en escritura

0.014 en borrado

No esta nada mal para las 13900 operaciones por segundo que le lanzamos….

 

Notes

http://www.project-voldemort.com/voldemort/

04 ago

Voldemort sistema de cache distribuida

En los últimos dias me topé con la necesidad de aprender y montar Voldemort, voy a intentar que este sea el primero de una serie de post donde explicaré todo aquello que vaya descubriendo sobre Voldemort sistema de cache distribuida

Empecemos, como todos sabemos Voldemort es bien conocido por ser el incomprendido de la serie de libros Harry Potter, pues entre hechizo y hechizo planeando su maquiavélica victoria y ayudado por Linkedin monto un sistema de cache distribuida, y la verdad es que no le quedó nada mal!

¿Cómo salio este proyecto?

Básicamente se unieron dos ideas, por un lado Amazon Dynamo Storage system que nos ofrece:

  • Poder trabajar en diferentes datacenters
  • Eventual Consistency
  • Y facil de poner en marcha.

Y por otro lado el bien conocido Memcache

  • Multiples lecturas y escrituras
  • Consisten Hashing para la distribución de datos
  • Clave-Valor
  • Versionado de datos

Si juntamos estos dos conceptos tendremos una idea de lo que es Voldemort.

¿Qué nos ofrece Voldemort?

Eligiendo las 2 opciones del Teorema de CAP

  • Particionamiento de datos a través del cluster
  • Alta disponibilidad

A más

  • Escalavilidad Horizontal
  • “Transparencia” para la aplicación

¿Qué no nos ofrece Voldemort?

Consistencia estricta de los datos, es muy importante el adjetivo estricto, nos ofrece Eventual Consistency, podemos “asegurar” que el dato escrito por el cliente será leído por la siguiente petición.

¿Cómo funciona  Eventual Consistency de Voldemort?

Principalmente necesitaremos dos puntos

  • Saber cual es el ultimo valor
  • Saber que valores no son comparables.

Soluciones

  • Timestamps
  • Vector Clocks
    • Nos ofrecen una manera de tener eventos ordenados en un sistema distribuido, cada vector es una tupla.
    • Como tenemos un sistema con particiones, cada valor tendrá un master del cluster
      • Cuando un dato es escrito en el master, todas las replicas reciben la misma versión
      • Con lo que no tenemos necesidad de bloqueos

¿Cómo trabajamos con los datos?

  • Los datos se organizan dentro de Stores, podríamos pensar que son como tablas en los sistemas tradicionales.
  • Solo disponemos de clave->valor, pero podremos hacer listas, mapas, juntando combinaciones
  • Los datos se reparten en particiones.

Partition voldemort distributed cache system

  • Repartimos los datos en particiones y las particiones entre los nodos.
  • Definimos en replicación de cada dato por store
  • Definimos el numero de lecturas/escrituras necesarias.
    • Esto quiere decir que si tenemos 3 nodos en un cluster, cuando un cliente lee o escribe, podremos definir cuantos OK de escritura debemos tener para que se de por buena la operación
    • O sea que si el numero de R+W > N(Numero de nodos) podremos leer nuestras propias escrituras.

Zonas

Disponemos de Zonas.

Zones architecture voldemort distributed cache system

Podemos crear tantas zonas como queramos, con ellas podemos conseguir tener servidores repartidos en diferentes datacenters, de esta manera el cluster sabrá donde tiene mas o menos latencia.

También las podemos utilizar en el caso de la virtualización, si disponemos de 4 zonas en 2 servidores, nos interesara que las replicaciones no se realicen en los nodos que corren en el mismo servidor, ya que en el caso de fallo del mismo… pues mal asunto.

Detección de errores

  1. Necesitamos que sea muy rápido
  2. Encontrar los servidores que tienen inconsistencia
    1. El servidor A puede hablar con el servidor B, pero C no puede
    2. A puede hablar con C, B puede hablar con A, pero no con C
    3. Actualmente se controla por los timeout, periodicidad de fallos

Mecanismos de Reparación

  • Read Repair
    1. Un cliente recibe valores de múltiples nodos
    2. Notifica al nodo si uno de los valores es antiguo entonces en nodo actualiza su valor
  • Hinted Handoff
    1. Si una escritura falla en cualquier nodo, es marcada como escritura especial
    2. Cada nodo periódicamente intenta deshacerse de todas las escrituras especiales.

Visión general tenemos 3 arquitecturas posibles

Architecture voldemort distributed cache system

  1.  La aplicación no conoce donde se encuentran los datos en el cluster, por cada petición, el cluster deberá ir a buscar el dato al nodo que a través de la partición lo tenga y lo entregara al cliente.
  2. La aplicación sabe que nodo tiene el dato, de tal manera que la petición es directa.
  3. Asociamos una instancia de Voldemort a cada servicio del Backend.