Rendimiento / estabilidad de un archivo de Memoria Asignada - Nativo o MappedByteBuffer - vsllanura ol' FileOutputStream

StackOverflow https://stackoverflow.com/questions/537295

Pregunta

Estoy a favor de un legado de aplicaciones Java que utiliza archivos planos (texto sin formato) para la persistencia.Debido a la naturaleza de la aplicación, el tamaño de estos archivos puede llegar a 100 MB por día, y a menudo el factor limitante en el rendimiento de la aplicación es el archivo IO.En la actualidad, la aplicación utiliza una llanura ol' java.io.FileOutputStream para escribir datos en el disco.

Recientemente, hemos tenido varios desarrolladores afirman que el uso de los archivos asignados en memoria, implementado en código nativo (C/C++) y al que se accede a través de JNI, redundará en un mayor rendimiento.Sin embargo, FileOutputStream ya utiliza métodos nativos para su núcleo métodos (es decir,write(byte[])), por lo que aparece un tenue supuesto sin datos duros o, al menos, la evidencia anecdótica.

Tengo varias preguntas sobre esto:

  1. Es esta afirmación es realmente cierto?Se los archivos asignados en memoria siempre proporcionar más rápido IO en comparación con Java FileOutputStream?

  2. ¿La clase MappedByteBuffer se accede desde una FileChannel proporcionar la misma funcionalidad que un nativo archivo asignado en memoria de la biblioteca de acceso a través de JNI?¿Qué es MappedByteBuffer a falta de que podría conducir a un uso JNI solución?

  3. ¿Cuáles son los riesgos de usar los archivos asignados en memoria de e / s de disco en una producción aplicación?Es decir, las aplicaciones que tienen tiempo de actividad continuo con un mínimo de reinicios (una vez al mes, max).La vida Real de las anécdotas de la producción aplicaciones (Java o de otra manera) el preferido.

Pregunta #3 es importante - me podría contestar a esta pregunta a mí mismo parcialmente por la redacción de un "juguete" de la aplicación que perf pruebas IO uso de las diversas opciones descritas anteriormente, pero por publicar, ASÍ que estoy esperando para el mundo real anécdotas / datos para masticar.

[EDITAR] Aclaración - cada día de operación, la aplicación crea varios archivos que van en tamaño de 100 MB a 1 giga.En total, la aplicación puede ser escrito varios gigas de datos por día.

¿Fue útil?

Solución

Usted puede ser capaz de acelerar un poco las cosas mediante el examen de cómo se está amortiguada sus datos durante las escrituras. Esto tiende a ser aplicaciones específicas como necesitaría una idea de los patrones de escritura de datos esperados. Si la consistencia de datos es importante, habrá compensaciones aquí.

Si se acaba de escribir nuevos datos en el disco de su aplicación, la memoria mapeada de E / S, probablemente no ayudará mucho. No veo ninguna razón por la que tendría que invertir un tiempo de alguna solución nativa codificado personalizado. Sólo parece que demasiada complejidad para su aplicación, de lo que ha proporcionado hasta ahora.

Si está seguro de que realmente necesita un mejor rendimiento de E / S - o simplemente el rendimiento O en su caso, me gustaría ver en una solución de hardware, como un conjunto de discos sintonizado. Lanzar más hardware en el problema muchas veces es más rentable desde el punto de vista del negocio de dedicar tiempo a la optimización de software. También es generalmente más rápido de implementar y más fiable.

En general, hay una gran cantidad de trampas en más de optimización de software. Va a introducir nuevos tipos de problemas para su aplicación. Es posible que tenga problemas de memoria / GC paliza que conduciría a un mayor mantenimiento / sintonización. Lo peor es que muchos de estos temas será difícil de probar antes de entrar en producción.

Si se tratara de mi aplicación, probablemente me quedo con la FileOutputStream con un poco de amortiguación posiblemente sintonizado. Después de eso me gustaría usar la solución honrado momento de tirar más hardware en ella.

Otros consejos

Memoria E / S mapeada no va a hacer que los discos vayan más rápido (!). Para el acceso lineal parece un poco inútil.

Una memoria intermedia asignada NIO es la cosa real (advertencia habitual acerca de cualquier aplicación razonable).

Al igual que con otros tampones NIO asignados directa, los tampones no son normales memoria y no conseguirá GCed la manera más eficiente. Si crea muchos de ellos es posible que se le acaba el espacio / dirección de memoria sin el funcionamiento de almacenamiento dinámico de Java. Esto es obviamente una preocupación con los procesos de larga ejecución.

Desde mi experiencia, los archivos asignados en memoria de realizar MUCHO mejor que la llanura de acceso a archivos en tiempo real y la persistencia de casos de uso.He trabajado principalmente con C++ en Windows, pero Linux actuaciones son similares, y usted está planeando utilizar JNI de todos modos, así que creo que se aplica a su problema.

Para un ejemplo de la persistencia de motor construido en memoria de archivo asignado, ver Metakit.Lo he utilizado en una aplicación donde los objetos eran simples puntos de vista sobre la memoria asignada a los datos, el motor se hizo cargo de todo el mapeo de las cosas detrás de las cortinas.Este fue rápido y eficiente de la memoria (al menos en comparación con los enfoques tradicionales, como los de la versión anterior), y tenemos commit/rollback de las transacciones de forma gratuita.

En otro proyecto que tenía que escribir de multidifusión aplicaciones de red.Los datos se envían de manera aleatoria para minimizar el impacto de consecutivos de pérdida de paquetes (combinado con la FEC y el bloqueo de los planes).Por otra parte los datos, bien podría superar el espacio de direcciones (archivos de vídeo eran más grandes que 2 gb) para la asignación de memoria estaba fuera de cuestión.En el lado del servidor, el archivo de las secciones fueron asignados en memoria de la demanda y la capa de red directamente recogido los datos de estos puntos de vista;como consecuencia, el uso de la memoria era muy baja.En el lado del receptor, no había manera de predecir el orden en que se recibieron paquetes, por lo que se tiene que mantener un número limitado de las vistas activas en el archivo de destino, y los datos se copian directamente en estos puntos de vista.Cuando un paquete se tuvo que poner en un área no asignada, el más antiguo punto de vista fue no asignados (y, eventualmente, se vacía en el archivo por el sistema) y se sustituye por una nueva vista en el área de destino.Las actuaciones quedaron pendientes, en particular debido a que el sistema hizo un gran trabajo en la consignación de datos como una tarea de fondo, y restricciones en tiempo real eran fáciles de cumplir.

Desde entonces estoy convencido de que incluso los mejores fino diseñado el software de régimen no puede vencer a la predeterminada del sistema I/O de la política con el archivo asignado en memoria, debido a que el sistema sabe más que el espacio de usuario de aplicaciones acerca de cuándo y cómo los datos deben ser por escrito.También, lo que es importante saber es que la asignación de memoria es una necesidad cuando se trata de grandes cantidades de datos, debido a que los datos nunca se asigna (por lo tanto consumiendo la memoria), pero dinámicamente asignada en el espacio de direcciones, y gestionados por el sistema del administrador de memoria virtual, que es siempre más rápido que el montón.De modo que el sistema utilice siempre la memoria de manera óptima, y compromete a los datos siempre que lo necesite, detrás de la aplicación de la espalda sin afectar a la misma.

Espero que ayude.

En cuanto a punto 3 - si se bloquea la máquina y hay páginas que no se vuelca en disco, entonces se pierden. Otra cosa es la pérdida de espacio de direcciones - la asignación de un archivo en la memoria consume espacio de direcciones (y requiere área contigua), y así, en máquinas de 32 bits que es un poco limitado. Pero usted ha dicho alrededor de 100 MB - por lo que no debería ser un problema. Y una cosa más -. Ampliar el tamaño del archivo mmaped requiere algo de trabajo

Por cierto, esta manera que la discusión también puede darle algunas ideas.

href="http://mentablog.soliveirajr.com/2012/12/asynchronous-logging-versus-memory-mapped-files/" estudio en el que comparo el rendimiento de escritura a un ByteBuffer prima en comparación con el rendimiento de escritura a un MappedByteBuffer. archivos mapeados en memoria son compatibles con el sistema operativo y sus latencias de escritura son muy buenos como se puede ver en mis números de referencia. Realizar escrituras sincrónicas a través de un FileChannel es aproximadamente 20 veces más lento y es por eso que las personas hacen de registro asíncrono todo el tiempo. En mi estudio también darle un ejemplo de cómo implementar el registro asíncrono a través de una cola sin bloqueo y libre de basura para un máximo rendimiento muy cerca de un ByteBuffer prima.

Si se escribe un menor número de bytes que será más rápido. ¿Qué pasa si ha filtrado a través de GZIPOutputStream, o lo que si usted escribió sus datos en zipfiles o JarFiles?

Como se mencionó anteriormente, usar NIO (también conocido como nuevo IO). También hay una nueva, nueva IO saliendo.

El uso adecuado de una solución de disco duro RAID le ayudaría, pero eso sería un dolor.

A mi me gusta la idea de comprimir los datos. Ir para el tipo GZIPOutputStream! Eso sería el doble de su rendimiento si la CPU puede mantener el ritmo. Es probable que usted puede tomar ventaja de las máquinas de doble núcleo ahora estándar, eh?

-Stosh

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top