El programa C se atasca en una espera ininterrumpida mientras realizaba E/S de disco en Mac OS X Snow Leopard

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

  •  19-09-2019
  •  | 
  •  

Pregunta

Una línea de fondo:soy el desarrollador de Redis, una base de datos NoSQL.Una de las nuevas características que estoy implementando es la Memoria Virtual, porque Redis toma todos los datos en la memoria.Gracias a VM Redis es capaz de transferir objetos poco utilizados desde la memoria al disco, hay varias razones por las que esto funciona mucho mejor que dejar que el sistema operativo haga el trabajo por nosotros intercambiando (los objetos de Redis se construyen a partir de muchos objetos pequeños asignados en espacios no contiguos). lugares, cuando Redis los serializa en el disco, ocupan 10 veces menos espacio en comparación con las páginas de memoria donde viven, etc.).

Ahora tengo una implementación alfa que funciona perfectamente en Linux, pero no tan bien en Mac OS X Snow Leopard.De vez en cuando, mientras Redis intenta mover una página de la memoria al disco, el proceso de Redis entra en el estado de espera ininterrumpida durante minutos.No pude depurar esto, pero esto sucede en una llamada a fseeko() o fwrite().Después de unos minutos, la llamada finalmente regresa y redis continúa funcionando sin ningún problema:sin accidente.

La cantidad de datos transferidos es muy pequeño, algo así como 256 bytes.Por lo tanto, no debería tratarse de una gran cantidad de E/S realizadas.

Pero hay un detalle interesante sobre el archivo de intercambio objetivo de la operación de escritura.Es un archivo grande (26 Gigabytes) creado abriendo un archivo con fopen() y luego ampliado usando ftruncate().Finalmente el archivo es unlink()ed para que Redis continúe tomando una referencia a él, pero estamos seguros de que cuando el proceso de Redis salga, el sistema operativo realmente liberará el archivo de intercambio.

Ok, eso es todo, pero estoy aquí para más detalles.Y, por cierto, incluso puedes encontrar el código real en Redis git, pero no es trivial entenderlo en cinco minutos dado que es un sistema bastante complejo.

Muchas gracias por cualquier ayuda.

¿Fue útil?

Solución

Según tengo entendido, HFS+ tiene un soporte muy pobre para archivos dispersos. Por lo tanto, puede ser que su escritura active una expansión de archivo que inicializa/materializa una gran fracción del archivo.

Por ejemplo, sé que mmap'ing un nuevo archivo vacío grande y luego escribir en algunas ubicaciones aleatorias produce un archivo muy grande en el disco con HFS+. Es bastante molesto ya que los archivos MMAP y escasos son una forma extremadamente conveniente de trabajar con datos, y prácticamente cualquier otra plataforma/sistema de archivos lo maneja con gracia.

¿El archivo de intercambio está escrito en linealy? ¿Es decir, reemplazamos un bloque existente o escribimos un nuevo bloque al final e incrementamos un puntero de espacio libre? Si es así, quizás hacer llamadas ftruncadas más frecuentes para expandir el archivo daría como resultado pausas más cortas.

Como aparte, tengo curiosidad por qué Redis VM no usa MMAP y luego solo mueve los bloques en un intento de concentrar los bloques calientes en páginas calientes.

Otros consejos

Antirez, no estoy seguro de que sea de mucha ayuda ya que mi experiencia de Apple se limita a la Apple ][, pero le daré una oportunidad.

Lo primero es una pregunta. Hubiera pensado que, para la memoria virtual, la velocidad de operación sería una medida más importante que el espacio de disco (especialmente para un DB NoSQL donde la velocidad es todo el punto, de lo contrario estaría usando SQL, ¿no?). Pero, si su archivo de intercambio es 26 g, tal vez no :-)

Algunas cosas para probar (si es posible).

  1. Trate de aislar realmente el problema a la búsqueda o escritura. Me cuesta creer que una búsqueda podría llevar tan tiempo desde que, en el peor de los casos, debería ser un cambio de puntero de amortiguación. Aún así, no escribí OSX, así que no puedo estar seguro.
  2. Intente ajustar el tamaño del archivo de intercambio para ver si eso es lo que está causando el problema.
  3. ¿Alguna vez expanda dinámicamente el archivo de intercambio (en lugar de la pre-asignación)? Si lo hace, eso puede ser lo que está causando el problema.
  4. ¿Siempre escribe lo más bajo en el archivo como pueda? Puede ser que la creación de un archivo de 26G en realidad no lo complete con datos, pero, si lo crea, escriba al último byte, el sistema operativo puede tener que cero los bytes antes de entonces (diferir la inicialización, si lo hay).
  5. ¿Qué sucede si solo al alaban el archivo (escriba en cada byte) y no lo desintegue? En otras palabras, deje el archivo entre las ejecuciones de su programa (creándolo si ya no existe, por supuesto). Luego, en su código de inicio para Redis, simplemente inicie el archivo (punteros y tal). Esto puede deshacerse de cualquier problema como los del punto 4 anteriores.
  6. Pregunte en los diversos sitios BSD también. No estoy seguro de cuánto cambia la manzana debajo de las cubiertas, pero OSX es solo BSD en el nivel más bajo (PAX Ducks para cubrir).
  7. También considere preguntar en los sitios de Apple (si aún no lo ha hecho).

Bueno, esa es mi pequeña contribución, espero que ayude. Buena suerte con tu proyecto.

¿Ha desactivado el almacenamiento en caché del archivo para su archivo? es decir, fcntl (fd, f_global_nocache, 1)

¿Ha intentado la depuración con DTRACE y / o instrumentos (DTRACE DTRACE experimental de Apple)?

Explorando el leopardo con dtrace

Depuración de Chrome en OS X

Como dijo Linus una vez en la lista de correo de Git:

"Me doy cuenta de que las personas de OS X tienen dificultades para aceptarlo, pero los sistemas de archivos OS X son generalmente una basura total y absoluta, incluso más que Windows".

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