Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Ola Habr!

Lembrámosvos que seguindo o libro sobre Kafka publicamos un traballo igualmente interesante sobre a biblioteca API de Kafka Streams.

Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Polo momento, a comunidade só está a aprender os límites desta poderosa ferramenta. Entón, recentemente publicouse un artigo, cuxa tradución queremos presentarvos. Dende a súa propia experiencia, o autor conta como converter Kafka Streams nun almacenamento de datos distribuído. Disfruta da lectura!

Biblioteca Apache Kafka Streams usado en todo o mundo en empresas para o procesamento de fluxos distribuídos enriba de Apache Kafka. Un dos aspectos pouco apreciados deste marco é que che permite almacenar o estado local producido en base ao procesamento de fíos.

Neste artigo, contarei como a nosa empresa conseguiu aproveitar esta oportunidade de xeito rendible ao desenvolver un produto para a seguridade das aplicacións na nube. Usando Kafka Streams, creamos microservizos de estado compartidos, cada un dos cales serve como unha fonte de información fiable sobre o estado dos obxectos do sistema e altamente dispoñible con tolerancia a fallos. Para nós, este é un paso adiante tanto en termos de fiabilidade como de facilidade de soporte.

Se estás interesado nun enfoque alternativo que che permita utilizar unha única base de datos central para apoiar o estado formal dos teus obxectos, léao, será interesante...

Por que pensamos que era hora de cambiar a forma de traballar co estado compartido

Necesitabamos manter o estado de varios obxectos en función dos informes dos axentes (por exemplo: estaba o sitio atacado)? Antes de migrar a Kafka Streams, a miúdo confiabamos nunha única base de datos central (+ API de servizo) para a xestión do estado. Este enfoque ten os seus inconvenientes: situacións intensivas de datas manter a coherencia e a sincronización convértese nun verdadeiro reto. A base de datos pode converterse nun pescozo de botella ou acabar condición de carreira e padecen imprevisibilidade.

Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Figura 1: un escenario típico de estado dividido visto antes da transición a
Kafka e Kafka Streams: os axentes comunican as súas opinións a través da API, o estado actualizado calcúlase a través dunha base de datos central

Coñece Kafka Streams, facilitando a creación de microservizos de estado compartidos

Hai aproximadamente un ano, decidimos darlle unha ollada aos nosos escenarios de estado compartidos para abordar estes problemas. Inmediatamente decidimos probar Kafka Streams: sabemos o escalable, altamente dispoñible e tolerante a fallos que é, que funcionalidade de streaming ten (transformacións, incluídas as con estado). Xusto o que necesitabamos, sen esquecer o maduro e fiable que se fixo o sistema de mensaxería en Kafka.

Cada un dos microservizos con estado que creamos construíuse sobre unha instancia de Kafka Streams cunha topoloxía bastante sinxela. Consistía en 1) unha fonte 2) un procesador cunha tenda de valores-clave persistente 3) un sumidoiro:

Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Figura 2: a topoloxía predeterminada das nosas instancias de streaming para microservizos con estado. Teña en conta que tamén hai un repositorio aquí que contén metadatos de planificación.

Neste novo enfoque, os axentes compoñen mensaxes que se introducen no tema de orixe e os consumidores, por exemplo, un servizo de notificación por correo electrónico, reciben o estado compartido calculado a través do sumidoiro (tema de saída).

Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Figura 3: Novo exemplo de fluxo de tarefas para un escenario con microservizos compartidos: 1) o axente xera unha mensaxe que chega ao tema fonte de Kafka; 2) un microservizo con estado compartido (usando Kafka Streams) procesao e escribe o estado calculado no tema final de Kafka; despois de que 3) os consumidores aceptan o novo estado

Esta tenda de clave-valor integrada é moi útil.

Como se mencionou anteriormente, a nosa topoloxía de estado compartido contén un almacén de clave-valor. Atopamos varias opcións para usalo, e dúas delas descríbense a continuación.

Opción n.º 1: use unha tenda de valores-clave para os cálculos

A nosa primeira tenda de clave-valor contiña os datos auxiliares que necesitabamos para os cálculos. Por exemplo, nalgúns casos o estado compartido estaba determinado polo principio de "maioría de votos". O repositorio podería albergar todos os últimos informes dos axentes sobre o estado dalgún obxecto. Despois, cando recibimos un novo informe dun axente ou doutro, podíamos gardalo, recuperar informes de todos os demais axentes sobre o estado do mesmo obxecto do almacenamento e repetir o cálculo.
A figura 4 a continuación mostra como expuxemos o almacén de clave/valor ao método de procesamento do procesador para que a nova mensaxe puidese ser procesada.

Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Ilustración 4: Abrimos o acceso ao almacén de clave-valor para o método de procesamento do procesador (despois disto, cada script que funcione con estado compartido debe implementar o método doProcess)

Opción #2: Crear unha API CRUD encima de Kafka Streams

Unha vez establecido o noso fluxo de tarefas básico, comezamos a tentar escribir unha API RESTful CRUD para os nosos microservizos de estado compartidos. Queriamos poder recuperar o estado dalgúns ou todos os obxectos, así como establecer ou eliminar o estado dun obxecto (útil para o soporte do backend).

Para admitir todas as API de Get State, sempre que necesitábamos recalcular o estado durante o procesamento, almacenámolo nunha tenda de valores-clave integrada durante moito tempo. Neste caso, resulta bastante sinxelo implementar unha API deste tipo usando unha única instancia de Kafka Streams, como se mostra na seguinte lista:

Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Figura 5: Usando o almacén de clave-valor integrado para obter o estado precalculado dun obxecto

Actualizar o estado dun obxecto a través da API tamén é fácil de implementar. Basicamente, todo o que tes que facer é crear un produtor de Kafka e usalo para facer un rexistro que conteña o novo estado. Isto garante que todas as mensaxes xeradas a través da API serán procesadas do mesmo xeito que as recibidas doutros produtores (por exemplo, axentes).

Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Figura 6: Pode establecer o estado dun obxecto usando o produtor Kafka

Pequena complicación: Kafka ten moitas particións

A continuación, queriamos distribuír a carga de procesamento e mellorar a dispoñibilidade proporcionando un clúster de microservizos de estado compartido por escenario. A configuración foi moi sinxela: unha vez que configuramos todas as instancias para que se executasen baixo o mesmo ID de aplicación (e os mesmos servidores de arranque), case todo o demais fíxose automaticamente. Tamén especificamos que cada tema de orixe constaría de varias particións, de xeito que a cada instancia se lle podería asignar un subconxunto de tales particións.

Tamén mencionarei que é unha práctica común facer unha copia de seguridade da tenda estatal para, por exemplo, en caso de recuperación despois dun fallo, transferir esta copia a outra instancia. Para cada tenda estatal en Kafka Streams, créase un tema replicado cun rexistro de cambios (que rastrexa as actualizacións locais). Así, Kafka apoia constantemente a tenda estatal. Polo tanto, no caso de producirse un fallo nunha ou outra instancia de Kafka Streams, a tenda de estado pódese restaurar rapidamente noutra instancia, onde irán as particións correspondentes. As nosas probas demostraron que isto faise en cuestión de segundos, aínda que hai millóns de discos na tenda.

Pasando dun único microservizo con estado compartido a un clúster de microservizos, tórnase menos trivial implementar a API Get State. Na nova situación, o almacén de estado de cada microservizo contén só parte da imaxe xeral (aqueles obxectos cuxas claves foron asignadas a unha partición específica). Tivemos que determinar que instancia contiña o estado do obxecto que necesitabamos, e fixémolo en función dos metadatos do fío, como se mostra a continuación:

Non só procesamento: como fixemos unha base de datos distribuída a partir de Kafka Streams e que resultou

Figura 7: Usando metadatos de fluxo, determinamos a partir de que instancia consultar o estado do obxecto desexado; utilizouse un enfoque similar coa API GET ALL

Principais achados

As tendas estatais en Kafka Streams poden servir como unha base de datos distribuída de facto.

  • constantemente replicado en Kafka
  • Unha API CRUD pódese construír facilmente sobre un sistema deste tipo
  • O manexo de varias particións é un pouco máis complicado
  • Tamén é posible engadir un ou máis almacéns de estado á topoloxía de streaming para almacenar datos auxiliares. Esta opción pódese usar para:
  • Almacenamento a longo prazo dos datos necesarios para os cálculos durante o procesamento do fluxo
  • Almacenamento a longo prazo de datos que poden ser útiles a próxima vez que se fornece a instancia de streaming
  • moito máis...

Estas e outras vantaxes fan que Kafka Streams sexa ideal para manter o estado global nun sistema distribuído como o noso. Kafka Streams demostrou ser moi fiable na produción (practicamente non tivemos ningunha perda de mensaxes desde a súa implantación) e estamos seguros de que as súas capacidades non se deterán aí.

Fonte: www.habr.com

Engadir un comentario