Translate
domingo, 7 de abril de 2019
Consultas y el coordinador de nodos en Apache Cassandra
Vamos a discutir como Cassandra coordina los nodos ante una consulta o escritura de un cliente.
Un cliente puede conectarse con cualquier nodo del anillo para realizar consultas o escrituras. Este nodo se denomina coordinator node o nodo coordinador. El coordinador identifica que nodos son replicas del dato que debe ser guardado o leido y luego procesa la consulta o escritura.
Para escribir, el coordinador contancta a todas las replicas que debe contactar según el consistency level o nivel de consistencia y el factor de replicación y considera la escritura exitosa cuando el numero de replicaciónes escritas son compatibles con el numero determinado en el nivel de consistencia.
Para la lectura, el coordinador contacta las replicas que son necesarias para aplicar con el nivel de consistencia, y retorna el dato al cliente.
Estos son los “caminos felices”, pero no todo es color de rosas y luego debemos discutir que sucede cuando no tenemos el numero de replicaciones para aplicar al nivel de consistencia.
sábado, 6 de abril de 2019
Consistency Levels en Apache Cassandra
El teorema de CAP de Brewer nos indica que en el que la consistencia, la disponibilidad y la tolerancia de partición se intercambian entre sí es deci no puede haber base que cumpla los 3 pero se pueden intercambiar. Cassandra proporciona niveles de consistencia ajustables que le permiten realizar estas compensaciones en un nivel de grano fino.
Se puede especificar un nivel de consistencia en cada consulta de lectura o escritura que indica cuánta consistencia necesita. Un nivel de consistencia más alto significa que más nodos deben responder a una consulta de lectura o escritura, lo que le da más seguridad de que los valores presentes en cada réplica son los mismos.
Para las consultas de lectura, el nivel de consistencia especifica cuántos nodos de réplica deben responder a una solicitud de lectura antes de devolver los datos. Para las operaciones de escritura, el nivel de consistencia especifica cuántos nodos de réplica deben responder para que la escritura se informe como exitosa al cliente. Debido a que Cassandra finalmente es consistente, las actualizaciones a otros nodos de réplica pueden continuar en segundo plano.
Los niveles de consistencia disponibles incluyen UNO, DOS y TRES, cada uno de los cuales especifica un número absoluto de nodos de réplica que deben responder a una solicitud. El nivel de consistencia QUORUM requiere una respuesta de la mayoría de los nodos de réplica (a veces expresados como "factor de replicación / 2 + 1"). El nivel de consistencia de ALL requiere una respuesta de todas las réplicas. Examinaremos estos niveles de consistencia y otros más detalladamente en el Capítulo 9.
Tanto para las lecturas como para las escrituras, los niveles de consistencia de ANY, ONE, TWO y THREE se consideran débiles, mientras que QUORUM y ALL se consideran fuertes. La coherencia se puede ajustar en Cassandra porque los clientes pueden especificar el nivel de consistencia deseado tanto en las lecturas como en las escrituras. Hay una ecuación que se usa popularmente para representar la manera de lograr una consistencia fuerte en Cassandra: R + W> N = consistencia fuerte. En esta ecuación, R, W y N son el recuento de réplicas de lectura, el recuento de réplicas de escritura y el factor de replicación, respectivamente; todas las lecturas de los clientes verán la escritura más reciente en este escenario, y tendrá una consistencia sólida.
Si eres nuevo en Cassandra, el factor de replicación a veces se puede confundir con el nivel de consistencia. El factor de replicación se establece por espacio de teclas. El nivel de consistencia es especificado por consulta, por el cliente.
El factor de replicación indica cuántos nodos desea utilizar para almacenar un valor durante cada operación de escritura. El nivel de consistencia especifica cuántos nodos ha decidido el cliente debe responder
Para sentirse seguro de una operación de lectura o escritura exitosa. La confusión surge porque el nivel de consistencia se basa en el factor de replicación, no en el número de nodos en el sistema.
Tipos que pueden ser referencia a nulos en F# 5
La introducción de tipos que pueden ser referencia a nulos en en C # representa el mayor cambio en la forma en que los desarrolladores de .NET escriben código desde async / await. Una vez que esté en funcionamiento, se tendrán que actualizar innumerables bibliotecas con anotaciones que admiten nulos para que esta característica funcione correctamente. Y para garantizar la interoperabilidad, F # deberá tambien modificarse.
F# actualmente soporta varias versiones de nulabilidad. Primero hay tipos normales de referencia en .NET. Hoy en día no hay manera de informar inequívocamente al compilador si una variable de tipo de referencia específica es nullable o no, por lo que se desaconseja su uso en F #.
La alternativa preferida es la Option<T>. También conocido como un tipo de "tal vez", esta es una forma segura para expresar el concepto de nulabilidad. Cuando se usa con el código F # idiomático, solo puede leer el valor después de verificar si no es nulo (no es "ninguno" en el lenguaje F #). Esto generalmente se hace a través de la comparación de patrones. Por ejemplo,
F# actualmente soporta varias versiones de nulabilidad. Primero hay tipos normales de referencia en .NET. Hoy en día no hay manera de informar inequívocamente al compilador si una variable de tipo de referencia específica es nullable o no, por lo que se desaconseja su uso en F #.
La alternativa preferida es la Option<T>. También conocido como un tipo de "tal vez", esta es una forma segura para expresar el concepto de nulabilidad. Cuando se usa con el código F # idiomático, solo puede leer el valor después de verificar si no es nulo (no es "ninguno" en el lenguaje F #). Esto generalmente se hace a través de la comparación de patrones. Por ejemplo,
match ParseDateTime inputString with
| Some(date) -> printfn "%s" (date.ToLocalTime().ToString())
| None -> printfn "Failed to parse the input."
| Some(date) -> printfn "%s" (date.ToLocalTime().ToString())
| None -> printfn "Failed to parse the input."
Option<T> es un tipo de referencia. Esto puede llevar a una gran cantidad de uso de memoria innecesaria, por lo que se creó una alternativa basada en estructura llamada ValueOption<T> en F # 4.5. Sin embargo, a ValueOption<T> le faltan algunas características que no estarán completas hasta que se lance F # 4.6.
Otro tipo de null F # con el que los desarrolladores deben tratar es Nullable<T>. Esto es similar a ValueOption<T>, pero está restringido a solo tipos de valor.
Las clases también se pueden marcar como nullables. Si el tipo tiene el atributo AllowNullLiteral, entonces todas las variables de ese tipo se consideran nullables. Esto puede ser problemático cuando desea que algunas variables de ese tipo sean nullables, pero no otras.
Las clases también se pueden marcar como nullables. Si el tipo tiene el atributo AllowNullLiteral, entonces todas las variables de ese tipo se consideran nullables. Esto puede ser problemático cuando desea que algunas variables de ese tipo sean nullables, pero no otras.
Un problema fundamental de diseño con F # tal como se encuentra actualmente es que todas estas formas diferentes de nulabilidad son incompatibles. No solo se necesitan conversiones entre los diferentes tipos de nulos, sino que también existen diferencias importantes en la forma en que funcionan. Por ejemplo, una Option<T> es recursiva, lo que le permite tener una Option<Option<Int32>> mientras que Nullable<T> no lo es. Esto puede llevar a problemas inesperados cuando se mezclan.
Otra forma en que esta incompatibilidad entra en juego es el atributo CLIMutable. Normalmente, los tipos de registro son inmutables, pero eso los hace incompatibles con los ORM. Este atributo soluciona ese problema, pero introduce uno nuevo. Ahora que el registro es mutable, los nulos se pueden deslizar después de crear el objeto, rompiendo la suposición de que los registros no contienen nulos.
El plan actual es indicar variables anulables con un ? sufijo como vemos en C#. Y al igual que C# 8, recibirá advertencias si intenta invocar un método o una propiedad en una variable que puede contener nulos sin verificar primero si es nulo. Del mismo modo, la asignación de un valor nulo a una variable no anulable es solo una advertencia, por lo que el código heredado continúa compilando.
Esta funcionalidad se considera como opt-in. Los nuevos proyectos lo tendrán activado de forma predeterminada, mientras que los proyectos existentes lo desactivarán de forma predeterminada.
Los ejemplos a continuación fueron proporcionados por la propuesta de Tipos de Referencia de Nullable y están sujetos a cambios.
// Declared type at let-binding
let notAValue : string? = null
// Declared type at let-binding
let isAValue : string? = "hello world"
let isNotAValue2 : string = null // gives a nullability warning
let getLength (x: string?) = x.Length // gives a nullability warning since x is a nullable string
// Parameter to a function
let len (str: string?) =
match str with
| null -> -1
| NonNull s -> s.Length // binds a non-null result
// Parameter to a function
let len (str: string?) =
let s = nullArgCheck "str" str // Returns a non-null string
s.Length // binds a non-null result
// Declared type at let-binding
let maybeAValue : string? = hopefullyGetAString()
// Array type signature
let f (arr: string?[]) = ()
// Generic code, note 'T must be constrained to be a reference type
let findOrNull (index: int) (list: 'T list) : 'T? when 'T : not struct =
match List.tryItem index list with
| Some item -> item
| None -> null
let notAValue : string? = null
// Declared type at let-binding
let isAValue : string? = "hello world"
let isNotAValue2 : string = null // gives a nullability warning
let getLength (x: string?) = x.Length // gives a nullability warning since x is a nullable string
// Parameter to a function
let len (str: string?) =
match str with
| null -> -1
| NonNull s -> s.Length // binds a non-null result
// Parameter to a function
let len (str: string?) =
let s = nullArgCheck "str" str // Returns a non-null string
s.Length // binds a non-null result
// Declared type at let-binding
let maybeAValue : string? = hopefullyGetAString()
// Array type signature
let f (arr: string?[]) = ()
// Generic code, note 'T must be constrained to be a reference type
let findOrNull (index: int) (list: 'T list) : 'T? when 'T : not struct =
match List.tryItem index list with
| Some item -> item
| None -> null
Como puede ver, la nueva sintaxis se adapta bien a los patrones F # existentes, incluso admite la coincidencia de patrones de manera similar a la Option<T>.
También hay un conjunto de funciones de ayuda para agregar en el código general y la coincidencia de patrones.
isNull: determina si el valor dado es nulo.
nonNull: afirma que el valor no es nulo. Provoca una NullReferenceException cuando el valor es nulo, de lo contrario, devuelve el valor.
withNull: convierte el valor en un tipo que admite nulo como un valor normal.
(| NonNull |): cuando se usa en un patrón, se afirma que el valor que se compara no es nulo.
(| Null | NotNull |): Un patrón activo que determina si el valor dado es nulo.
Las firmas de funciones completas están disponibles en la propuesta.
jueves, 4 de abril de 2019
Nuevos libros de Java Code Geeks
Download IT Guides!
|
|
martes, 2 de abril de 2019
Estrategias de replicación en Cassandra
Antes de ponernos a hablar de la replicación veamos, para que replicar?
- prevenir pérdida de datos
- acercar los datos.
- segregación de tipos de tareas
Un nodo sirve como una réplica para diferentes rangos de datos. Si un nodo se cae, otras réplicas pueden responder a las consultas para ese rango de datos. Cassandra replica datos a través de nodos de manera transparente para el usuario, y el factor de replicación es el número de nodos en su grupo que recibirá copias (réplicas) de los mismos datos. Si su factor de replicación es 3, entonces tres nodos en el anillo tendrán copias de cada fila.
La primera réplica siempre será el nodo que reclama el rango en el que cae el token, pero el resto de las réplicas se colocan de acuerdo con la estrategia de replicación (a veces también se conoce como la estrategia de colocación de réplicas).
Para determinar la ubicación de la réplica, Cassandra implementa el patrón Strategy, que se describe en la clase abstracta común org.apache.cassandra.locator.AbstractReplicationStrategy, que permite diferentes implementaciones de un algoritmo (diferentes estrategias para lograr el mismo trabajo). Cada implementación de algoritmo está encapsulada dentro de una sola clase que extiende la estrategia de integración de elementos abstractos
Cassandra proporciona dos implementaciones principales de esta interfaz (extensiones de la clase abstracta): SimpleStrategy y NetworkTopologyStrategy.
SimpleStrategy coloca réplicas en nodos consecutivos alrededor del anillo, comenzando con el nodo indicado por el particionador.
La NetworkTopologyStrategy le permite especificar un factor de replicación diferente para cada centro de datos. Dentro de un centro de datos, asigna réplicas a diferentes racks para maximizar la disponibilidad.
La estrategia se establece de forma independiente para cada espacio de claves y es una opción requerida para crear un espacio de claves.
domingo, 31 de marzo de 2019
Por qué Cristal es un lenguaje de programación importante?
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/
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/
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
Suscribirse a:
Entradas (Atom)