Java: consejos sobre el manejo de grandes volúmenes de datos.(Parte Deux)
performance data-access (9)
@Será
Muy buenos resultados. Lectura de una comparación rápida de un gran archivo binario:
Prueba 1: lectura secuencial básica con RandomAccessFile. 2656 ms
Prueba 2: lectura secuencial básica con almacenamiento en búfer. 47 ms
Prueba 3: lectura secuencial básica con MappedByteBuffers y optimización adicional de búfer de cuadros. 16 ms
Bien. Así que tengo una gran cantidad de datos binarios (digamos, 10 GB) distribuidos en un grupo de archivos (digamos, 5000) de diferentes longitudes.
Estoy escribiendo una aplicación Java para procesar estos datos, y deseo instituir un buen diseño para el acceso a los datos. Por lo general, lo que sucederá es tal:
- De una forma u otra, todos los datos se leerán durante el curso del procesamiento.
- Cada archivo se lee (típicamente) secuencialmente, requiriendo solo unos pocos kilobytes a la vez. Sin embargo, a menudo es necesario tener, por ejemplo, los primeros kilobytes de cada archivo simultáneamente , o los pocos kilobytes intermedios de cada archivo simultáneamente, etc.
- Hay momentos en que la aplicación querrá acceso aleatorio a un byte o dos aquí y allá.
Actualmente estoy usando la clase RandomAccessFile para leer en búferes de bytes (y ByteBuffers). Mi objetivo final es encapsular el acceso a los datos en algunas clases de manera que sea rápido y nunca más tenga que preocuparme por ello. La funcionalidad básica es que le pediré que lea marcos de datos de archivos especificados, y deseo minimizar las operaciones de E / S dadas las consideraciones anteriores.
Ejemplos de acceso típico:
- ¡Dame los primeros 10 kilobytes de todos mis archivos!
- Dame el byte 0 al 999 del archivo F, luego dame el byte 1 a 1000, luego dame del 2 al 1001, etc., etc., ...
- ¡Dame un megabyte de datos del archivo F comenzando en tal y tal byte!
¿Alguna sugerencia para un buen diseño?
Guau. Básicamente está implementando una base de datos desde cero. ¿Hay alguna posibilidad de importar los datos en un RDBMS real y simplemente usar SQL?
Si lo hace usted mismo, eventualmente querrá implementar algún tipo de mecanismo de almacenamiento en caché, para que los datos que necesita salgan de la memoria RAM, si está allí, y está leyendo y escribiendo los archivos en una capa inferior.
Por supuesto, esto también implica una gran cantidad de lógica transaccional compleja para garantizar que sus datos permanezcan consistentes.
Use Java NIO y MappedByteBuffers, y trate sus archivos como una lista de matrices de bytes. Luego, permita que el sistema operativo se preocupe por los detalles de almacenamiento en caché, lectura, enjuague, etc.
Alguien me recomendó hadoop ( http://hadoop.apache.org ) el otro día. Parece que podría ser bastante agradable y podría tener cierta tracción en el mercado.
Es posible que desee echar un vistazo a una base de datos de objetos simples de código abierto llamada jdbm ; tiene muchas cosas desarrolladas de este tipo, incluidas las capacidades de ACID.
He hecho una serie de contribuciones al proyecto, y valdría la pena revisar el código fuente para ver cómo resolvimos muchos de los mismos problemas en los que podría estar trabajando.
Ahora, si sus archivos de datos no están bajo su control (es decir, está analizando archivos de texto generados por otra persona, etc.), entonces el tipo de almacenamiento estructurado por página que utiliza jdbm puede no ser apropiado para usted, pero si todos estos archivos son archivos con los que está creando y con los que puede trabajar, puede valer la pena examinarlos.
Me gustaría dar un paso atrás y preguntarme por qué está usando archivos como su sistema de registro, y qué ganancias le da el uso de una base de datos. Una base de datos sin duda le da la capacidad de estructurar sus datos. Dado el estándar SQL, podría ser más sostenible a largo plazo.
Por otro lado, sus datos de archivo pueden no estar estructurados tan fácilmente dentro de las restricciones de una base de datos. La compañía de búsqueda más grande del mundo :) no usa una base de datos para el procesamiento de su negocio. Mira aquí y aquí .
Iba a sugerirle que haga un seguimiento de la idea de la base de datos de Eric y aprenda cómo las bases de datos administran sus buffers, implementando efectivamente su propia administración de memoria virtual.
Pero a medida que lo pensaba más, llegué a la conclusión de que la mayoría de los sistemas operativos ya son una mejor opción para implementar el almacenamiento en caché del sistema de archivos de lo que probablemente pueda hacer sin el acceso de bajo nivel en Java.
Sin embargo, hay una lección de la gestión del búfer de la base de datos que podría considerar. Las bases de datos utilizan una comprensión del plan de consulta para optimizar la estrategia de gestión.
En una base de datos relacional, a menudo es mejor desalojar el bloque utilizado más recientemente de la memoria caché. Por ejemplo, un bloque "joven" que contenga un registro secundario en una unión no será examinado nuevamente, mientras que el bloque que contiene su registro padre aún está en uso aunque sea "anterior".
Los cachés de archivos del sistema operativo, por otro lado, están optimizados para reutilizar los datos usados recientemente (y para leer antes que los datos usados más recientemente). Si su aplicación no se ajusta a ese patrón, puede valer la pena administrar el caché usted mismo.
@Eric
Pero mis consultas van a ser mucho, mucho más simples que cualquier cosa que pueda hacer con SQL. ¿Y un acceso a la base de datos no sería mucho más costoso que una lectura de datos binarios?
Esto es para responder la parte sobre la minimización del tráfico de E / S. En el lado de Java, todo lo que realmente puede hacer es envolver a sus lectores en BufferedReaders. Aparte de eso, su sistema operativo manejará otras optimizaciones, como mantener los datos leídos recientemente en la memoria caché de la página y hacer la lectura anticipada en los archivos para acelerar las lecturas secuenciales. No tiene sentido hacer un búfer adicional en Java (aunque aún necesitará un búfer de bytes para devolver los datos al cliente).