Por qué opino que Cristal es un lenguaje de programación importante? Es una buena pregunta. Cristal implementa un lenguaje de tipado dinámico como Ruby como un lenguaje de tipado estático mediante la inferencia de tipos.
Parece una tontería pero permite obtener código de tipado estático, lo cual nos trae con sigo una herramienta fundamental para la búsqueda de errores que es el chequeo por tipo. Sin tener que sacrificar casi nada de nuestro lenguaje de tipado dinámico.
Digo casi nada porque por ejemplo no podemos cambiar el tipo de una variable, por ejemplo :
var a = 2
a = "hola"
no compilaría, pero la pregunta del millón es ¿ eso es útil ?
Es decir a alguien realmente le interesa cambiar de tipo una variable, yo creo que no. No escribo código de tipado dinámico pero imagino, que no existe un interés de reutilizar las variables. Por lo tanto festejo que no se pueda hacer esto en Cristal.
Por ultimo, ¿que piensan, otros lenguajes le seguirán los pasos a Cristal?
Dejo link: https://crystal-lang.org/
Translate
domingo, 31 de marzo de 2019
Apache Spark llega a Apache HBase con HBase-Spark
HBase-Spark fue commiteado por primera vez a Github en julio de 2014. HBase-Spark salió de una simple solicitud de clientes para tener un nivel de interacción entre HBase y Spark similar al ya disponible entre HBase y MapReduce. Aquí hay un breve resumen de la funcionalidad que brinda dicha librería:
Acceso completo a HBase:
- Posibilidad de hacer una carga masiva.
- Posibilidad de realizar operaciones masivas como put, get o delete
- Posibilidad de ser una fuente de datos para motores SQL.
El enfoque que se le dio a la librería tiene los siguientes objetivos:
- Hacer las conexiones HBase sin problemas.
- Hacer la integración de Kerberos sin problemas.
- Crear RDDs a través de acciones de escaneo o desde un RDD existente que se usando comandos Get.
- Tomar cualquier RDD y permita que se realice cualquier combinación de operaciones HBase.
- Proporcione métodos simples para operaciones comunes mientras permite operaciones avanzadas desconocidas sin restricciones a través de la API.
- Soporte Scala y Java.
- Soporta Spark y Spark Streaming con una API similar.
- Crear RDD / DStream desde una Scaneo.
- Poner / Eliminar el contenido de un RDD / DStream en HBase
- Crear un RDD / DStream a partir de los contenidos de un RDD / DStream
- Tomar el contenido de un RDD / DStream y realizar cualquier operación si se le entregó una HConnection en el proceso de trabajo.
Veamos unos ejemplos por ejemplo como podemos hacer un bulk delete :
val hbaseContext = new HBaseContext(sc, config)
rdd.hbaseBulkDelete(hbaseContext,
TableName.valueOf(tableName),
putRecord => new Delete(putRecord),
4)
Aquí hay un ejemplo de una función de partición de mapa donde podemos obtener un objeto de conexión a medida que iteramos sobre nuestros valores:
val getRdd = rdd.hbaseMapPartitions(hbaseContext, (it, conn) => {
val table = conn.getTable(TableName.valueOf("t1"))
var res = mutable.MutableList[String]()
...
})
MapPartitions funciona como map es decir toma un rdd y lo transforma en otro rdd.
Veamos un ejemplo completo donde guardamos los objetos con ids 1, 2, 3, 4, 5 :
// Nothing to see here just creating a SparkContext like you normally would
val sparkConf = new SparkConf().setAppName("HBaseBulkPutExample " + tableName + " " + columnFamily)
val sc = new SparkContext(sparkConf)
//This is making a RDD of
//(RowKey, columnFamily, columnQualifier, value)
val rdd = sc.parallelize(Array(
(Bytes.toBytes("1"), Array((Bytes.toBytes(columnFamily), Bytes.toBytes("1"), Bytes.toBytes("1")))),
(Bytes.toBytes("2"), Array((Bytes.toBytes(columnFamily), Bytes.toBytes("1"), Bytes.toBytes("2")))),
(Bytes.toBytes("3"), Array((Bytes.toBytes(columnFamily), Bytes.toBytes("1"), Bytes.toBytes("3")))),
(Bytes.toBytes("4"), Array((Bytes.toBytes(columnFamily), Bytes.toBytes("1"), Bytes.toBytes("4")))),
(Bytes.toBytes("5"), Array((Bytes.toBytes(columnFamily), Bytes.toBytes("1"), Bytes.toBytes("5"))))
)
)
//Create the HBase config like you normally would then
//Pass the HBase configs and SparkContext to the HBaseContext
val conf = HBaseConfiguration.create();
conf.addResource(new Path("/etc/hbase/conf/core-site.xml"));
conf.addResource(new Path("/etc/hbase/conf/hbase-site.xml"));
val hbaseContext = new HBaseContext(sc, conf);
//Now give the rdd, table name, and a function that will convert a RDD record to a put, and finally
// A flag if you want the puts to be batched
hbaseContext.bulkPut[(Array[Byte], Array[(Array[Byte], Array[Byte], Array[Byte])])](rdd,
tableName,
//This function is really important because it allows our source RDD to have data of any type
// Also because puts are not serializable
(putRecord) > {
val put = new Put(putRecord._1)
putRecord._2.foreach((putValue) > put.add(putValue._1, putValue._2, putValue._3))
put
},
true);
Ahora, cada partición de ese RDD se ejecutará en paralelo (en diferentes subprocesos en un número de trabajadores de Spark en el clúster), algo así como lo que habría ocurrido si hiciéramos Puts en una tarea MapReduce.
Una cosa a tener en cuenta es que se aplican las mismas reglas cuando se trabaja con HBase de MapReduce o Spark en términos de rendimiento de Get y Put. Si tiene Puts que no están particionados, lo más probable es que se envíe un lote de Put a cada RegionServer, lo que dará como resultado menos registros por RegionServers por lote. La imagen a continuación ilustra cómo se vería esto con seis RegionServers:
Ahora veamos el mismo diagrama si utilizamos Spark para particionar primero antes de hablar con HBase.
miércoles, 27 de marzo de 2019
Fue lanzado Java 12 con Switch Expressions y Shenandoah GC
Java 12, la última versión de Java, se lanzó a tiempo, el 19 de marzo. Con la nueva versión viene una serie de nuevas y notables características y mejoras. Específicamente, Java 12 incluye una nueva función de lenguaje llamada Switch Expressions , un nuevo recolector de basura llamado Shenandoah (experimental) y mejoras al recolector de basura G1 predeterminado.
De acuerdo con el nuevo esquema de nombres y el ciclo de lanzamiento de Oracle, esta versión llega solo seis meses después de Java 11 y no se considera una versión de soporte a largo plazo (LTS), por lo que solo se admitirá durante seis meses.
Las expresiones de switch son una nueva función de lenguaje que se basa en y mejora la declaración de switch existente. Permiten una manera más concisa y menos detallada de expresar un condicional de múltiples vías. Se escriben usando un poco de sintaxis recientemente introducida:
int value = switch (number) {
case ONE -> 1;
case TWO -> 2;
case THREE -> 3;
};
El uso de la flecha (->) en lugar de dos puntos (:) y la falta de declaraciones de ruptura. Las expresiones de cambio no tienen caída a través de la semántica. En su lugar, cada etiqueta debe producir un valor, y cada valor posible para la variable que se está probando debe corresponder a una rama en el conmutador.
Java 12 incluye un nuevo recolector de basura, Shenandoah, que se esfuerza por ser "un recolector de basura de baja latencia". Funciona al intentar ejecutarse de forma más concurrente con subprocesos de aplicaciones en un programa Java para realizar sus tareas de recolección de basura (evacuación, marcado, compactación, etc.). Al hacer esto, el trabajo restante, que no se ejecuta de forma simultánea, debería dar como resultado solo breves pausas.
Las aplicaciones que requieren capacidad de respuesta y pausas predecibles son buenas candidatas para usar Shenandoah. También vale la pena señalar que el objetivo del equipo de Red Hat que contribuyó con Shenandoah es que "los tiempos de pausa con Shenandoah son independientes del tamaño del montón, lo que significa que tendrá los mismos tiempos de pausa consistentes si su montón es de 200 MB o 200 GB", pero real el rendimiento dependerá del tamaño real del montón y la carga de trabajo.
Shenandoah está actualmente marcado como un proyecto experimental y debe habilitarse con la opción -XX: + UnlockExperimentalVMO. A Red Hat se le atribuye la implementación inicial y continuará admitiéndola tanto para la arquitectura aarch64 como para la arquitectura amd64.
Java 12 no solo vino con un nuevo recolector de basura, sino que también se hicieron mejoras al recolector de basura G1 existente. Las propuestas de mejora JEP 344 y JEP 346 se incluyeron en el lanzamiento.
El primero de los dos, JEP 344, mejora la forma en que el recolector de basura G1 cumple sus objetivos de tiempo para las pausas de recolección. El problema que resuelve es cuando el recolector de basura G1 selecciona erróneamente una cantidad de trabajo (a través de heurísticas de aplicación) que no se puede lograr dentro del tiempo de pausa definido. En estos casos, no se puede evitar exceder el objetivo de tiempo de pausa.
Para mejorar esto, el recolector de basura G1 ahora detecta si selecciona repetidamente una cantidad incorrecta de trabajo y ajusta. Para ello, divide el trabajo en colecciones obligatorias y opcionales y permite que G1 detenga su trabajo en cualquier momento mientras realiza el trabajo en la colección opcional.
La segunda mejora, JEP 346, mejora el uso de la memoria del recolector de basura G1 devolviendo la memoria del montón de Java no utilizada al sistema operativo (OS) durante los períodos de inactividad.
Java 12 no solo vino con un nuevo recolector de basura, sino que también se hizo mejoras en el recolector de basura G1 existente. Las propuestas de mejora JEP 344 y JEP 346 se incluyen en el lanzamiento.
El primero de los dos, JEP 344, mejora de la forma en que el recolector de basura G1 cumple con sus objetivos de tiempo para las pausas de recolección. El problema que resuelve es cuando el recolector de basura G1 selecciona erróneamente una cantidad de trabajo (a través de heurísticas de aplicación) que no se puede lograr dentro del tiempo de pausa definido. En estos casos, no se puede evitar el objetivo de tiempo de pausa.
Para mejorar esto, el recolector de basura G1 ahora detecta y selecciona repetidamente una cantidad correcta de trabajo y ajusta. Para ello, divide el trabajo en colecciones obligatorias y opcionales y permite que G1 detenga su trabajo en cualquier momento mientras realiza el trabajo en la colección opcional.
La segunda mejora, JEP 346, mejora el uso de la memoria del recolector de basura G1 devolviendo la memoria del montón de Java no se encuentra en los períodos de inactividad.
Antes de esta mejora, el recolector G1 rara vez devolvía la memoria del montón de Java al sistema operativo porque solo lo hace durante una recolección de basura completa. Para lograr esto, el recolector G1 ahora tiene un mejor uso de su tiempo de inactividad para devolver al sistema operativo la memoria.
domingo, 24 de marzo de 2019
Partitioners en Apache Cassandra
Un particionador determina cómo se distribuyen los datos entre los nodos del clúster. Cassandra almacena los datos en filas extensas o "particiones". Cada fila tiene una clave de partición que se usa para identificar la partición. Un particionador, entonces, es una función hash para calcular el token de una clave de partición. Cada fila de datos se distribuye dentro del anillo de acuerdo con el valor del token de clave de partición.
Cassandra proporciona varios particionadores diferentes en el paquete org.apache.cassandra.dht (DHT significa "tabla hash distribuida"). El Murmur3Partitioner se agregó en 1.2 y ha sido el particionador predeterminado desde entonces; es una implementación eficiente de Java en el algoritmo de MurmurHash desarrollado por Austin Appleby. Genera hashes de 64 bits. El valor predeterminado anterior fue el RandomPartitioner.
Debido al diseño generalmente conectable de Cassandra, también puede crear su propio particionador implementando la clase org.apache.cassandra.dht.IPartitioner y colocándolo en el classpath de Cassandra.
miércoles, 20 de marzo de 2019
Nuevos libros gratuitos de Java Code Geeks.
martes, 19 de marzo de 2019
Los VNodes de Cassandra
Las primeras versiones de Cassandra asignaron un solo token a cada nodo, de una manera bastante estática, que requiere que se calcule tokens para cada nodo. Aunque hay herramientas disponibles para calcular tokens en función de un número dado de nodos, todavía era un proceso manual para configurar la propiedad initial_token para cada nodo en un archivo cassandra.yaml. Esto también hizo que agregar o reemplazar un nodo fuera una operación costosa, ya que rebalancear el clúster requería mover una gran cantidad de datos.
La versión 1.2 de Cassandra introdujo el concepto de nodos virtuales, también llamados vnodos para abreviar. En lugar de asignar un solo token a un nodo, el rango del token se divide en múltiples rangos más pequeños. A cada nodo físico se le asignan múltiples tokens. De forma predeterminada, a cada nodo se le asignarán 256 de estos tokens, lo que significa que contiene 256 nodos virtuales. Los nodos virtuales han sido habilitados por defecto desde 2.0.
Los Vnodes facilitan el mantenimiento de un clúster que contiene máquinas heterogéneas. Para los nodos de un clúster que tienen más recursos informáticos disponibles, se puede aumentar el número de vnodos estableciendo, la propiedad num_tokens en el archivo cassandra.yaml. A la inversa, puede establecer num_tokens más bajo para disminuir el número de vnodes para máquinas menos capaces.
Cassandra maneja automáticamente el cálculo de los rangos de token para cada nodo en un clúster en proporción a su valor num_tokens. Las asignaciones de tokens para vnodes se calculan mediante la clase org.apache.cassandra.dht.tokenallocator.ReplicationAwareTokenAllocator.
Una ventaja adicional de los nodos virtuales es que aceleran algunas de las operaciones más pesadas de Cassandra, como el arranque de un nuevo nodo, la clausura de un nodo y la reparación de un nodo. Esto se debe a que la carga asociada con las operaciones en múltiples rangos más pequeños se distribuye de manera más uniforme entre los nodos del clúster. Onda como se ve en la imagen de arriba.
domingo, 17 de marzo de 2019
Rings and Tokens en Apache Cassandra
Veamos cómo Cassandra distribuye los datos a través de estos nodos.
Cassandra representa los datos gestionados por un grupo como un anillo. A cada nodo del anillo se le asigna uno o más rangos de datos descritos por un token, que determina su posición en el anillo. Un token es un ID de entero de 64 bits que se utiliza para identificar cada partición. Esto da un rango posible para tokens de –2 a la 63 a 2 a la 63 –1.
Un nodo pide un token entre este rango y mayor que el token del nodo anterior. El nodo con el token más bajo posee el rango menor o igual que su token y el rango mayor que el token más alto, que también se conoce como el "rango de ajuste". De esta manera, los tokens especifican un anillo completo. El anillo incluye los nodos en un solo centro de datos. Esta disposición particular está estructurada de tal manera que los rangos de token consecutivos se reparten entre nodos en diferentes racks.
Los datos se asignan a los nodos utilizando una función hash para calcular un token para la clave de partición. Este token de clave de partición se compara con los valores de token de los distintos nodos para identificar el rango y, por lo tanto, el nodo que posee los datos. Los intervalos de tokens están representados por la clase org.apache.cassandra.dht.Range.
sábado, 16 de marzo de 2019
Free ebook: The State of Machine Learning Adoption in the Enterprise
Me llego este mail y que más decir a aprovechar :
| ||
Hi Emanuel,
Who sets machine learning priorities in other organizations? What methodologies (such as Agile) do they use to develop ML? Do they build their ML models using internal teams, external consultants, or cloud APIs? How long have they deployed ML in production? How do they evaluate success with machine learning?
If you’re curious (we were), check out our free ebook, The State of Machine Learning Adoption in the Enterprise.
| ||
| ||
Ben Lorica
Chief Data Scientist
P.S. This ebook shows you what the more sophisticated companies do when they adopt machine learning. Learn how they do it at the AI Conference in New York April 15–18.
| ||
This message was sent to emanuelpeg@yahoo.com.ar. You are receiving this because you’re a customer of O’Reilly Media, or you’ve signed up to receive email from us. We hope you found this message to be useful. However, if you’d rather not receive future emails of this type from O’Reilly, please manage your preferences or unsubscribe here.
Please read our Privacy Policy.
O’Reilly Media, Inc. 1005 Gravenstein Highway North, Sebastopol, CA 95472 (707) 827-7000
|
viernes, 15 de marzo de 2019
Hace 25 años que se lanzó Linux 1.0 !!
Que los cumpla feliz!!
El 14 de marzo de 2019, se cumplen 25 años desde el lanzamiento de Linux 1.0. Fue la primera versión redonda del núcleo para sistemas operativos que mueve gran parte del entramado tecnológico actual, así como la consagración del que se ha convertido en el proyecto de software colaborativo más importante de la historia, uno cuyo impulso ha puesto al código abierto como tendencia imperante en la industria.
Que mejor forma de homenajearlo que con un video de los viejos:
Dejo link de la noticia: https://www.clarin.com/tecnologia/sistema-operativo-planto-batalla-windows-cumplio-25-anos_0_VIVaR9HdP.html
El 14 de marzo de 2019, se cumplen 25 años desde el lanzamiento de Linux 1.0. Fue la primera versión redonda del núcleo para sistemas operativos que mueve gran parte del entramado tecnológico actual, así como la consagración del que se ha convertido en el proyecto de software colaborativo más importante de la historia, uno cuyo impulso ha puesto al código abierto como tendencia imperante en la industria.
Que mejor forma de homenajearlo que con un video de los viejos:
Dejo link de la noticia: https://www.clarin.com/tecnologia/sistema-operativo-planto-batalla-windows-cumplio-25-anos_0_VIVaR9HdP.html
Inscripciones Abiertas 2019 a cursos Gugler!!
Me llego este mail de los cursos de Gugler. Puede anotarse, el curso de Java esta muy bueno:
PRENSA GUGLER LAB 20192019 | |||||
NOTICIAS ACTUALES
| OFERTA ACADÉMICA | ||||
Estimado Goette Emanuel :
Esta instancia de inscripción especial comienza hoy, hasta el Lunes 18 de Marzo, luego se abren las inscripciones al público en general, publicando las mismas en todos los medios oficiales.
Las clases estarían iniciándose el miércoles 3, jueves 4, viernes 5 o sábado 6 de Abril,según el curso y modalidad que elegiste.
Inscribirte: clic aquí
Horarios y comisiones: clic aquí.
Saludos cordiales y te esperamos!!.
| Dictamos nuestros cursos en la Facultad de Ciencia y Tecnología, perteneciente a la Universidad Autónoma de Entre Ríos. En nuestro portafolio de capacitación encontrarás: MODALIDAD PRESENCIAL
| ||||
MÁS INFORMACIÓN | LABORATORIO DE INVESTIGACIÓN GUGLER | ||||
Si deseas comunicarte con nosotros, te recordamos que podes hacerlo a través de los siguientes portales, en los cuales encontrarás información sobre Gugler. TEL: (0343) - 4975066 Interno 108 Sitio Oficial: www.gugler.com.ar Campus: campusvirtual.gugler.com.ar Sistema de Gestión Cursos: sgc.gugler.com.ar Sistema de Gestión Cursos Móvil: Aquí Sistema de Documentación: sgd.gugler.com.ar Sistema de Validación: giua.gugler.com.ar |
| ||||
GUGLER PRESS | |||||
martes, 12 de marzo de 2019
Parámetros y argumentos: una manera fácil de recordar la diferencia en Kotlin
Si alguna vez has tenido problemas para recordar la diferencia entre parámetros y argumentos:
Es un parámetro cuando estás dentro de la definición.
Es un argumento cuando estás fuera de la definición.
La forma más fácil de recordar la diferencia entre los dos es asociar la palabra argumento con la palabra afuera.
Aquí hay una función simple que calcula el cuadrado de un entero. ¿Qué datos se pasarán? Solo el número que queremos al cuadrado.
fun square(number: Int): Int {
return number * number
}
Aquí, dentro de la definición de esta función, decimos que el número es un parámetro.
Ahora que hemos definido nuestra función, vamos a usarla. Pasaremos algunos datos a nuestra función cuando la llamemos.
val radius = 5
val area = Math.PI * square(radius)
Aquí, fuera de la definición de la función, decimos que el radius es un argumento de la función square ().
Una clase genérica es aquella que tiene varibles o funciones que no tienen un tipo determinado. Por ejemplo, aquí hay una clase Box muy simple que simplemente envuelve algún otro objeto.
class Box<T>(var item: T)
Aquí, dentro de la definición de la clase, decimos que T es un parámetro de tipo.
Usar esta clase es bastante fácil: simplemente invocamos a su constructor y pasamos los datos que queremos ajustar.
val box = Box <String> ("Hola")
Aquí, fuera de la definición de la clase Box, lo construimos con un argumento de tipo String.
De hecho, Kotlin hace una inferencia de tipo fantástica, por lo que ni siquiera tenemos que especificarlo explícitamente:
caja de val = caja ("Hola")
En este caso, todavía hay un argumento de tipo, y sigue siendo String. Simplemente está implícito en el tipo de argumento "Hola" que le estamoResumen
Es un parámetro cuando estás dentro de la definición.
Es un argumento cuando estás fuera de la definición.
La forma más fácil de recordar la diferencia entre los dos es asociar la palabra argumento con la palabra afuera.
Aquí hay una función simple que calcula el cuadrado de un entero. ¿Qué datos se pasarán? Solo el número que queremos al cuadrado.
fun square(number: Int): Int {
return number * number
}
Aquí, dentro de la definición de esta función, decimos que el número es un parámetro.
Ahora que hemos definido nuestra función, vamos a usarla. Pasaremos algunos datos a nuestra función cuando la llamemos.
val radius = 5
val area = Math.PI * square(radius)
Aquí, fuera de la definición de la función, decimos que el radius es un argumento de la función square ().
Una clase genérica es aquella que tiene varibles o funciones que no tienen un tipo determinado. Por ejemplo, aquí hay una clase Box muy simple que simplemente envuelve algún otro objeto.
class Box<T>(var item: T)
Aquí, dentro de la definición de la clase, decimos que T es un parámetro de tipo.
Usar esta clase es bastante fácil: simplemente invocamos a su constructor y pasamos los datos que queremos ajustar.
val box = Box <String> ("Hola")
Aquí, fuera de la definición de la clase Box, lo construimos con un argumento de tipo String.
De hecho, Kotlin hace una inferencia de tipo fantástica, por lo que ni siquiera tenemos que especificarlo explícitamente:
caja de val = caja ("Hola")
En este caso, todavía hay un argumento de tipo, y sigue siendo String. Simplemente está implícito en el tipo de argumento "Hola" que le estamoResumen
viernes, 8 de marzo de 2019
Seminario web de MongoDB
Me llego un mail de la gente de MongoDB y quería compartirlo con ustedes:
|
miércoles, 6 de marzo de 2019
Libros gratuitos de Java Code Geeks
Download Dev Guides!
|
| ||||||
|
|
martes, 5 de marzo de 2019
Snitches en Cassandra
El trabajo de un snitch es determinar la proximidad del host relativa para cada nodo en un clúster, que se utiliza para determinar de qué nodos leer y escribir. Los snitches recopilan información sobre la topología de su red para que Cassandra pueda enrutar las solicitudes de manera eficiente. El snitch descubrirá dónde están los nodos en relación con otros nodos.
A modo de ejemplo, examinemos cómo participa el snitch en una operación de lectura. Cuando Cassandra realiza una lectura, debe contactar una cantidad de réplicas determinadas por el nivel de consistencia. Para admitir la velocidad máxima para las lecturas, Cassandra selecciona una única réplica para consultar el objeto completo y solicita réplicas adicionales para los valores de hash para garantizar que se devuelva la última versión de los datos solicitados. La función de el snitch es ayudar a identificar la réplica que devolverá este dato de forma rápida, y esta es la réplica que se consulta para obtener los datos completos.
El snitch predeterminado (el SimpleSnitch) es la topología inconsciente; es decir, no conoce los racks y los centros de datos en un clúster, lo que lo hace inadecuado para implementaciones de centros de datos múltiples. Por esta razón, Cassandra viene con varios snitches para diferentes entornos de nube, incluyendo Amazon EC2, Google Cloud y Apache Cloudstack.
Los snitches se pueden encontrar en el paquete org.apache.cassandra.locator. Cada snitch implementa la interfaz IEndpointSnitch.
Si bien Cassandra proporciona una manera conectable de describir de forma estática la topología de su clúster, también proporciona una función llamada "snitching dinámico" que ayuda a optimizar el enrutamiento de las lecturas y escrituras a lo largo del tiempo. Así es como funciona. Su snitch seleccionado se envuelve con otro snitch llamado DynamicEndpointSnitch. El snitch dinámico obtiene su comprensión básica de la topología de la snitch seleccionada. A continuación, supervisa el rendimiento de las solicitudes a los otros nodos, e incluso realiza un seguimiento de cosas como qué nodos realizan la compactación. Los datos de rendimiento se utilizan para seleccionar la mejor réplica para cada consulta. Esto permite a Cassandra evitar las solicitudes de enrutamiento a réplicas que tienen un bajo rendimiento.
La implementación de snitching dinámico utiliza una versión modificada del mecanismo de detección de fallas Phi utilizado por los Gossiper(que hablamos el post anterior). El "umbral de maldad" es un parámetro configurable que determina cuánto peor debe realizar un nodo preferido que el nodo con el mejor desempeño para perder su estado preferencial. Las puntuaciones de cada nodo se restablecen periódicamente para permitir que un nodo con un rendimiento deficiente demuestre que se ha recuperado y reclamar su estado preferido.
A modo de ejemplo, examinemos cómo participa el snitch en una operación de lectura. Cuando Cassandra realiza una lectura, debe contactar una cantidad de réplicas determinadas por el nivel de consistencia. Para admitir la velocidad máxima para las lecturas, Cassandra selecciona una única réplica para consultar el objeto completo y solicita réplicas adicionales para los valores de hash para garantizar que se devuelva la última versión de los datos solicitados. La función de el snitch es ayudar a identificar la réplica que devolverá este dato de forma rápida, y esta es la réplica que se consulta para obtener los datos completos.
El snitch predeterminado (el SimpleSnitch) es la topología inconsciente; es decir, no conoce los racks y los centros de datos en un clúster, lo que lo hace inadecuado para implementaciones de centros de datos múltiples. Por esta razón, Cassandra viene con varios snitches para diferentes entornos de nube, incluyendo Amazon EC2, Google Cloud y Apache Cloudstack.
Los snitches se pueden encontrar en el paquete org.apache.cassandra.locator. Cada snitch implementa la interfaz IEndpointSnitch.
Si bien Cassandra proporciona una manera conectable de describir de forma estática la topología de su clúster, también proporciona una función llamada "snitching dinámico" que ayuda a optimizar el enrutamiento de las lecturas y escrituras a lo largo del tiempo. Así es como funciona. Su snitch seleccionado se envuelve con otro snitch llamado DynamicEndpointSnitch. El snitch dinámico obtiene su comprensión básica de la topología de la snitch seleccionada. A continuación, supervisa el rendimiento de las solicitudes a los otros nodos, e incluso realiza un seguimiento de cosas como qué nodos realizan la compactación. Los datos de rendimiento se utilizan para seleccionar la mejor réplica para cada consulta. Esto permite a Cassandra evitar las solicitudes de enrutamiento a réplicas que tienen un bajo rendimiento.
La implementación de snitching dinámico utiliza una versión modificada del mecanismo de detección de fallas Phi utilizado por los Gossiper(que hablamos el post anterior). El "umbral de maldad" es un parámetro configurable que determina cuánto peor debe realizar un nodo preferido que el nodo con el mejor desempeño para perder su estado preferencial. Las puntuaciones de cada nodo se restablecen periódicamente para permitir que un nodo con un rendimiento deficiente demuestre que se ha recuperado y reclamar su estado preferido.
lunes, 4 de marzo de 2019
Gossip y Detección de fallos en Apache Cassandra
Para admitir la descentralización y la tolerancia de partición, Cassandra usa un protocolo de Gossip que permite a cada nodo realizar un seguimiento de la información de estado sobre los otros nodos en el clúster. El gossiper se ejecuta cada segundo en un temporizador.
Los protocolos de Gossip (a veces llamados "protocolos epidémicos") generalmente asumen una red defectuosa, se emplean comúnmente en sistemas de redes muy grandes y descentralizados, y se usan a menudo como un mecanismo automático para la replicación en bases de datos distribuidas.
Toman su nombre del concepto de chisme humano, una forma de comunicación en la que los compañeros pueden elegir con quién desean intercambiar información y no solo intercambian información de ellos mismos sino tambien de otros compañeros, lo que permite disminuir el trafico de la red, ya que no todos se comunican con todos.
El protocolo de Gossip en Cassandra se implementa principalmente mediante la clase org.apache.cassandra.gms.Gossiper, que es responsable de administrar los chismes para el nodo local. Cuando se inicia un nodo de servidor, se registra con el gossiper para recibir información del estado del punto final.
Debido a que los Gossip de Cassandra se usan para la detección de fallas, la clase Gossiper mantiene una lista de nodos que están vivos y muertos.
Así es como funciona el Gossiper:
- Una vez por segundo, el Gossiper elegirá un nodo aleatorio en el clúster e iniciará una sesión de chismes con él. Cada ronda de chismes requiere tres mensajes.
- El iniciador de chismes envía a su amigo elegido un GossipDigestSynMessage.
- Cuando el amigo recibe este mensaje, devuelve un GossipDigestAckMessage.
- Cuando el iniciador recibe el mensaje de acuse de recibo del amigo, le envía un mensaje de GossipDigestAck2 para que complete la ronda de chismes.
Cuando el Gossiperer determina que otro punto final está muerto, "condena" ese punto final al marcarlo como muerto en su lista local y registrar ese hecho.
Cassandra tiene un soporte robusto para la detección de fallas, como lo especifica un algoritmo popular para la computación distribuida llamada Phi Accrual Failure Detection. Esta forma de detección de fallas se originó en el Instituto Avanzado de Ciencia y Tecnología en Japón en 2004.
La detección del fracaso acumulado se basa en dos ideas principales. La primera idea general es que la detección de fallas debe ser flexible, lo que se logra al desacoplarla de la aplicación que se está monitoreando. La segunda y más novedosa idea desafía la noción de detectores de falla tradicionales, que se implementan mediante simples "latidos" y deciden si un nodo está muerto o no, según si se recibe un latido o no. Pero la detección de fallos acumulados decide que este enfoque es ingenuo, y encuentra un lugar entre los extremos de muertos y vivos, un nivel de sospecha.
Por lo tanto, el sistema de monitoreo de fallas genera un nivel continuo de "sospecha" con respecto a la confianza de que un nodo ha fallado. Esto es deseable porque puede tener en cuenta las fluctuaciones en el entorno de red. Por ejemplo, solo porque una conexión quede atrapada no significa necesariamente que todo el nodo esté muerto.
Por lo tanto, la sospecha ofrece una indicación más fluida y proactiva de la posibilidad de falla más débil o más fuerte basada en la interpretación (el muestreo de los latidos), en lugar de una simple evaluación binaria.
La detección de fallos se implementa en Cassandra mediante la clase org.apache.cassandra.gms.FailureDetector, que implementa la interfaz org.apache.cassandra.gms.IFailureDetector. Juntos, permiten operaciones que incluyen:
- isAlive (InetAddress) : Lo que el detector informará sobre la vida de un nodo dado.
- interpret (InetAddress): Utilizado por el Gossiper para ayudarlo a decidir si un nodo está vivo o no basado en nivel de sospecha alcanzado mediante el cálculo de Phi.
- report (InetAddress) : Cuando un nodo recibe un latido, invoca este método.
Suscribirse a:
Entradas (Atom)