¡Hola! Como proveedor de Combiner, últimamente he recibido muchas preguntas sobre lo que se necesita para que un Combiner sea seguro para subprocesos en un trabajo de MapReduce. Entonces, pensé en desglosarlo en esta publicación de blog.
En primer lugar, recapitulemos rápidamente qué es un Combinador en el contexto de un trabajo de MapReduce. Un combinador es una función opcional que se puede utilizar para realizar agregación local en la salida de los mapeadores antes de enviarla a los reductores. Esto puede reducir significativamente la cantidad de datos transferidos a través de la red, lo que a su vez acelera la ejecución general del trabajo.
Ahora, la gran pregunta es: ¿cuáles son los requisitos para que un combinador sea seguro para subprocesos?
Inmutabilidad de entrada y salida
Uno de los requisitos fundamentales para un combinador seguro para subprocesos es la inmutabilidad de su entrada y salida. Cuando varios subprocesos acceden al Combinador simultáneamente, no queremos que ninguno de ellos modifique los datos de una manera que pueda afectar a los otros subprocesos.
Por ejemplo, si los datos de entrada al Combinador son mutables, un subproceso podría cambiar los valores mientras otro intenta leerlos o procesarlos. Esto puede conducir a resultados inconsistentes. De manera similar, la salida del Combiner también debería ser inmutable. Si otras partes del marco MapReduce comienzan a modificar la salida del Combiner mientras otros subprocesos todavía lo utilizan, puede causar todo tipo de problemas.
Digamos que estamos trabajando en un trabajo de MapReduce de conteo de palabras. El asignador genera pares clave-valor donde la clave es una palabra y el valor es el recuento. El combinador agrega estos recuentos para cada palabra. Si los pares clave-valor son mutables, un hilo podría cambiar el valor del recuento mientras otro hilo intenta calcular el recuento total de esa palabra. Esto daría como resultado un recuento final incorrecto.
Operaciones atómicas
Las operaciones atómicas son otro aspecto crucial de los combinadores seguros para subprocesos. Una operación atómica es una operación que al resto del sistema le parece como si se hubiera realizado instantáneamente. En el contexto de un combinador, las operaciones atómicas garantizan que varios subprocesos puedan realizar operaciones en datos compartidos sin interferir entre sí.
Por ejemplo, al agregar valores en el Combinador, necesitamos usar operaciones de suma o incremento atómico. En Java, elEntero atómicoLa clase proporciona operaciones atómicas para números enteros. En lugar de utilizar una variable entera normal para realizar un seguimiento del recuento, podemos utilizar unaEntero atómico. De esta manera, cuando varios subprocesos intentan incrementar el recuento simultáneamente, se garantiza que la operación será atómica y no terminaremos con resultados inconsistentes.
Tomemos nuevamente el ejemplo de contar palabras. En lugar de usar un número entero normal para realizar un seguimiento del recuento de cada palabra, podemos usar unEntero atómico. Cuando un hilo quiere incrementar el recuento de una palabra en particular, puede llamar alincrementarAndGet()método de laEntero atómico. Este método es atómico, por lo que incluso si varios subprocesos intentan incrementar el recuento al mismo tiempo, la operación se realizará correctamente.
Mecanismos de sincronización
A veces, las operaciones atómicas pueden no ser suficientes y necesitamos utilizar mecanismos de sincronización para garantizar la seguridad de los subprocesos. La sincronización nos permite controlar el acceso a los recursos compartidos para que solo un hilo pueda acceder a ellos a la vez.
En Java podemos usar elsincronizadopalabra clave para crear métodos o bloques sincronizados. Por ejemplo, si nuestro Combiner tiene una estructura de datos compartida como unHashMapPara almacenar los valores agregados, podemos usar un bloque sincronizado para garantizar que solo un hilo pueda acceder alHashMapa la vez.

importar java.util.HashMap; clase pública MyCombiner { HashMap privado<Cadena, Entero> countMap = nuevo HashMap<>(); public void combine (clave de cadena, valor int) { sincronizado (esto) { if (countMap.containsKey (clave)) { countMap.put (clave, countMap.get (clave) + valor); } else { countMap.put(clave, valor); } } } }
En este ejemplo, elcombinarEl método está sincronizado, lo que significa que solo un subproceso puede ejecutar este método a la vez. Esto asegura que elHashMapse accede y se modifica de forma segura para subprocesos.
Evitar el estado global
El estado global puede ser una pesadilla cuando se trata de programación segura para subprocesos. Si un combinador depende de variables globales o recursos compartidos que pueden ser modificados por múltiples subprocesos, es muy probable que se encuentre con condiciones de carrera y otros problemas de seguridad de subprocesos.
En cambio, deberíamos intentar mantener el estado del Combiner lo más local posible. Cada hilo debe tener su propia copia de los datos que necesita para operar, y los resultados deben combinarse en un hilo, de forma segura al final.
Por ejemplo, en lugar de utilizar un globalHashMappara almacenar los valores agregados, podemos usar un localHashMappara cada hilo. Una vez que todas las agregaciones locales estén listas, podemos fusionar estas localesHashMapsen un hilo - de manera segura.
Pruebas de seguridad de hilos
Las pruebas son una parte esencial para garantizar que un Combiner sea seguro para subprocesos. Necesitamos probar el Combiner en diferentes escenarios con múltiples subprocesos para asegurarnos de que produzca resultados consistentes.
Una forma de probar la seguridad de los subprocesos es utilizar un marco de prueba de subprocesos múltiples. Por ejemplo, JUnit se puede utilizar para escribir casos de prueba de subprocesos múltiples. Podemos crear varios subprocesos que llamen al Combinador simultáneamente y luego verificar que la salida sea correcta.
También podemos utilizar herramientas como FindBugs o las herramientas de análisis estático integradas de IntelliJ IDEA para detectar posibles problemas de seguridad de subprocesos en el código. Estas herramientas pueden identificar errores comunes, como utilizar operaciones no atómicas en variables compartidas o no sincronizar correctamente el acceso a recursos compartidos.
Nuestros productos combinadores
Como proveedor de combinadores, ofrecemos una gama de combinadores de alta calidad diseñados teniendo en cuenta la seguridad de los hilos. NuestroCombinador de cabecera pasiva de 12 canalesyCombinador de cabecera pasiva de 24 canalesson perfectos para trabajos de MapReduce donde la seguridad de los subprocesos es una preocupación. Estos combinadores se construyen utilizando la última tecnología y se prueban rigurosamente para garantizar que cumplan con los más altos estándares de rendimiento y confiabilidad.
Si está buscando un combinador seguro para subprocesos para su trabajo de MapReduce, nos encantaría saber de usted. Ya sea que sea un desarrollador a pequeña escala o una gran empresa, tenemos la solución adecuada para usted. No dude en comunicarse e iniciar una conversación sobre sus requisitos específicos. Estamos aquí para ayudarlo a encontrar el mejor combinador para sus necesidades y garantizar que sus trabajos de MapReduce se ejecuten sin problemas y de manera eficiente.
Referencias
- Tom Blanco. "Hadoop: la guía definitiva". O'Reilly Medios, 2015.
- Brian Goetz y cols. "La simultaneidad de Java en la práctica". Addison - Wesley Profesional, 2006.
