El mecanismo de almacenamiento de mensajes de Pulsar y el principio del mecanismo GC de Bookie
[TOC]
Este artículo es un artículo de la serie de tecnología Pulsar. Resume principalmente brevemente el mecanismo de limpieza del almacenamiento de mensajes de Pulsar y los archivos de almacenamiento de BookKeeper. Entre ellos, BookKeeper puede entenderse como un sistema de almacenamiento NoSQL que utiliza RocksDB para almacenar datos de índice de forma predeterminada.
Los mensajes de Pulsar se almacenan en BookKeeper, que es un sistema de cliente pesado. La parte del cliente se llama BookKeeper y cada nodo de almacenamiento en el clúster del lado del servidor se llama bookie. El corredor del sistema Pulsar actúa como cliente del sistema de almacenamiento BookKeeper y almacena los mensajes Pulsar en el clúster de casas de apuestas a través del SDK del cliente proporcionado por BookKeeper.
Cada partición de cada tema en Pulsar (los temas no particionados pueden entenderse como la partición 0 y el número de temas particionados comienza desde 0) corresponderá a una serie de libros de contabilidad, y cada libro de contabilidad solo contiene mensajes bajo se almacenará la partición correspondiente. Para cada partición, solo un libro mayor estará abierto y se podrá escribir al mismo tiempo.
Cuando Pulsar produce y almacena mensajes, primero encontrará el libro mayor utilizado por la partición actual y luego generará el ID de entrada correspondiente al mensaje actual. El ID de entrada se incrementa dentro del mismo libro mayor. En el caso de producción no por lotes (el productor puede configurar este parámetro, el valor predeterminado es por lotes), una entrada contiene un mensaje. En el modo por lotes, una entrada puede contener varios mensajes. En las casas de apuestas, solo se realizan escritura, búsqueda y recuperación de acuerdo con la dimensión de entrada.
Por lo tanto, el ID de mensaje de cada mensaje en Pulsar debe constar de cuatro partes (la versión anterior consta de tres partes), a saber (ID del libro mayor, ID de entrada, índice de partición, índice de lote), donde partición - El índice es -1 para temas no particionados y el índice por lotes es -1 para mensajes que no son por lotes.
Cada libro mayor se cambiará cuando la duración de la existencia o el número de entradas guardadas exceda el umbral. Los mensajes nuevos bajo la misma partición se almacenarán en el siguiente libro mayor. Ledger es solo un concepto lógico, una dimensión de ensamblaje lógico de datos y no tiene una entidad correspondiente.
Después de que cada nodo de apuestas en el clúster BookKeeper reciba el mensaje, los datos se almacenarán y procesarán en tres partes: archivo de diario, archivo de registro de entrada y archivo de índice.
Entre ellos, el archivo de diario y los datos de entrada se escriben en el archivo de diario de acuerdo con el método wal. Cada archivo de diario tiene un límite de tamaño. Cuando se excede el límite de tamaño de un solo archivo, cambiará. Vaya al siguiente archivo para continuar escribiendo. Debido a que los archivos de diario se vacían en tiempo real, para mejorar el rendimiento y evitar interferencias mutuas de lectura y escritura de E/S, se recomienda separar el directorio de almacenamiento del directorio donde se almacena el registro de entrada y montarlo. un disco duro separado para el directorio de almacenamiento de cada archivo de diario (se recomienda utilizar un disco duro ssd). Solo se guardarán unos pocos archivos de diario y se eliminarán los archivos que excedan el número configurado. Las entradas se almacenan en el archivo de diario de forma completamente aleatoria y se escriben por orden de llegada. El archivo de diario está diseñado para garantizar que los mensajes no se pierdan.
Como se muestra en la siguiente figura, después de que cada corredor de apuestas reciba una solicitud para agregar una entrada, se asignará al directorio de diario y al directorio de registro de entradas almacenados de acuerdo con la identificación del libro mayor, y los datos de la entrada se almacenado en el directorio correspondiente. Actualmente, la casa de apuestas no admite cambiar el directorio de almacenamiento durante la operación (durante el uso, agregar o reducir el directorio hará que no se encuentren algunos datos).
Como se muestra en la figura siguiente, después de que el corredor de apuestas reciba la solicitud de escritura de entrada, escribirá el archivo de diario y lo guardará en la caché de escritura. La caché de escritura se divide en dos partes. Al escribir caché, una parte es la parte que vacía el disco y las dos partes se usan alternativamente.
Hay una estructura de datos de índice en el caché de escritura, y la entrada correspondiente se puede encontrar a través del índice. El índice en el caché de escritura está en el nivel de memoria y se implementa en función de la estructura ConcurrentLongLongPairHashMap definida por. corredor de apuestas en sí.
Además, cada directorio de almacenamiento de registro de entrada corresponderá a un objeto de instancia de clase SingleDirectoryDbLedgerStorage, y cada objeto SingleDirectoryDbLedgerStorage tendrá una estructura de índice basada en RocksDB. A través de este índice, se puede encontrar rápidamente cada entrada. se almacena la entrada del archivo. Cada caché de escritura realizará un procesamiento de clasificación al agregar entradas. En la misma caché de escritura, los datos en el mismo libro mayor son adyacentes y ordenados. De esta manera, cuando los datos en la caché de escritura se vacían en el archivo de registro de entrada, se escribirán. a Los datos en el archivo de registro de entrada están parcialmente ordenados. Este diseño puede mejorar en gran medida la eficiencia de lectura posterior.
Los datos del índice en SingleDirectoryDbLedgerStorage también se vaciarán en el archivo de índice a medida que se vacia la entrada. Cuando la casa de apuestas falla y se reinicia, los datos se pueden restaurar a través del archivo de diario y el archivo de registro de entrada para garantizar que no se pierdan.
Al consumir datos, el consumidor Pulsar realiza un procesamiento de aceleración de caché multicapa, como se muestra en la siguiente figura:
El orden de obtención de datos es el siguiente:
Arriba En cada paso, si se pueden obtener los datos, se devolverán directamente y se omitirán los pasos posteriores. Si los datos se obtienen de un archivo de disco, los datos se almacenarán en la caché de lectura cuando se devuelvan. Además, si la operación es leer el disco, se leerá una parte adicional del disco, porque hay una parte. ordenar durante el almacenamiento. Con este procesamiento, la probabilidad de obtener datos adyacentes es muy alta. Este tipo de procesamiento mejorará en gran medida la eficiencia de la adquisición de datos posteriores.
Durante el uso, debemos intentar evitar o reducir escenarios en los que el consumo de datos antiguos desencadene la lectura de mensajes en archivos de disco, para no afectar el rendimiento del sistema en general.
Cada corredor de apuestas en BookKeeper realizará operaciones de limpieza de datos periódicamente. De forma predeterminada, se verificarán y procesarán cada 15 minutos. El proceso principal de limpieza es el siguiente:
A través de lo anterior. proceso, podemos entender el corredor de apuestas El proceso general al limpiar el archivo de registro de entrada.
Cabe señalar que si el libro mayor se puede eliminar lo determina completamente el cliente. En Pulsar, lo activa el corredor.
El broker tiene un hilo de procesamiento periódico (por defecto 2 minutos), limpia el mecanismo del libro mayor donde se encuentran los mensajes consumidos, obtiene el último mensaje confirmado del cursor contenido en el tema y lo agrega al lista del libro mayor contenida en este tema, elimine todos los anteriores a esta identificación (tenga en cuenta que la identificación del libro mayor actual no está incluida) (incluidos los metadatos en zk y notifique al corredor de apuestas para que elimine el libro mayor correspondiente).
Durante el proceso de solicitud, nos encontramos con escenarios en los que el espacio en el disco de la casa de apuestas era insuficiente muchas veces. La casa de apuestas almacenaba una gran cantidad de archivos de registro de entrada. Las razones más típicas incluyen principalmente las dos siguientes.
Razón 1:
Los mensajes de producción están demasiado dispersos. Por ejemplo, en un escenario extremo, hay 10.000 temas, cada tema produce un mensaje y 10.000 temas producen un mensaje secuencialmente. . De esta manera, el libro mayor correspondiente a cada tema no se cambiará en un corto período de tiempo debido a la duración o el tamaño del almacenamiento, y los ID del libro mayor de estado activo se encuentran dispersos en una gran cantidad de archivos de registro de entrada. Estos archivos de registro de entrada no se pueden eliminar ni comprimir a tiempo.
Si te encuentras con este escenario, puedes reiniciarlo y forzar el cambio del libro mayor. Por supuesto, si el consumo no se mantiene en este momento, el libro mayor donde se encuentra el último registro de consumo también está en estado activo y no se puede eliminar.
Segunda razón:
En el proceso de tiempo de GC, si hay muchos archivos enrylog existentes y una gran cantidad de ellos alcanzan el umbral de gc menor o mayor, entonces un solo gc menor o major gc tardará demasiado y los archivos de registro de entrada caducados no se pueden limpiar durante este período.
Esto se debe a la ejecución secuencial de un único proceso de limpieza. La siguiente ronda no se ejecutará hasta que se complete la última ronda de ejecución. En la actualidad, esta área también está optimizando el proceso para evitar que la ejecución del subproceso sea demasiado larga y afecte el proceso general.