portaldacalheta.pt
  • Principal
  • Design De Marque
  • Personnes Et Équipes Produit
  • Innovation
  • Kpi Et Analyses
Back-End

Intégration logicielle optimisée: un didacticiel Apache Camel



Les logiciels ont rarement, voire jamais, un vide informationnel. C'est du moins l'hypothèse que les ingénieurs logiciels peuvent faire pour la plupart des applications que nous développons.

A n'importe quelle échelle, chaque logiciel - d'une manière ou d'une autre - communique avec d'autres logiciels pour diverses raisons: pour obtenir des données de référence de quelque part, pour envoyer des signaux de surveillance, pour rester en contact avec d'autres services, tout en faisant partie d'un système distribué et plus.



Apache Camel pour une intégration logicielle optimisée



Dans ce didacticiel, vous découvrirez certains des plus grands défis liés à l'intégration de gros logiciels et comment Apache Camel les résout facilement.



Le problème: conception d'architecture pour l'intégration de systèmes

Vous avez peut-être effectué les opérations suivantes au moins une fois dans votre vie d'ingénieur logiciel:

  • Identifiez un élément de logique métier sur lequel vous devez lancer l'envoi de données.
  • Dans la même couche d'application, écrivez les transformations de données en fonction de ce que le destinataire attend.
  • Il enveloppe les données dans une structure adaptée au transfert et au routage à travers un réseau.
  • Ouvrez une connexion à une application cible à l'aide d'un pilote ou d'un SDK client approprié.
  • Envoyez les données et gérez la réponse.

Pourquoi est-ce un mauvais plan d'action?



Bien que vous n'ayez que quelques connexions de ce type, cela reste gérable. Avec un nombre croissant de relations entre systèmes, la logique métier de l'application se mêle à la logique d'intégration qui tente d'adapter les données, de compenser les différences technologiques entre deux systèmes et de transférer des données vers le système externe avec des requêtes SOAP, REST ou plus exotiques.

Si vous intégriez plusieurs applications, il serait extrêmement difficile de redessiner l'image complète des dépendances dans un tel code: où les données sont-elles produites et quels services les consomment? Vous aurez de nombreux endroits où la logique d'intégration est dupliquée pour démarrer.



Avec cette approche, même si la tâche est techniquement terminée, nous nous retrouvons avec de gros problèmes de maintenabilité et d'évolutivité de l'intégration. Une réorganisation rapide des flux de données dans ce système est presque impossible, sans parler de problèmes plus profonds tels que le manque de surveillance, l'interruption de circuit, la recherche laborieuse de données, etc.

Ceci est particulièrement important lors de l'intégration de logiciels dans le cadre d'une entreprise de taille considérable. S'attaquer à l'intégration commerciale signifie travailler avec un ensemble d'applications qui fonctionnent sur un large éventail de plates-formes et sont situées à différents endroits. L'échange de données dans un tel environnement logiciel est assez exigeant. Il doit répondre aux normes de sécurité élevées de l'industrie et fournir un moyen fiable de transférer des données. Dans un environnement d'entreprise, l'intégration de systèmes nécessite une conception d'architecture distincte et entièrement élaborée.



Cet article vous présentera les difficultés uniques rencontrées par l'intégration de logiciels et fournira des solutions basées sur l'expérience pour les tâches d'intégration. Nous ferons connaissance avec Chameau Apache , un cadre utile qui peut atténuer les pires aspects des maux de tête d'un développeur d'intégration. Nous continuerons avec un exemple de la façon dont Camel peut aider à établir la communication dans un cluster de microservices alimenté par Kubernetes.

Difficultés d'intégration

Une approche largement utilisée pour résoudre le problème consiste à découpler une couche d'intégration dans votre application. Il peut exister dans l'application elle-même ou en tant que logiciel dédié qui s'exécute indépendamment - dans ce dernier cas, il est appelé middleware .



Quels problèmes rencontrez-vous normalement lors du développement et du soutien middleware ? En général, il comporte les éléments clés suivants:

développeur et concepteur front-end
  • Tous les canaux de données ne sont pas fiables dans une certaine mesure. Les problèmes découlant de ce manque de fiabilité peuvent ne pas se produire tant que l'intensité des données est faible ou modérée. Chaque niveau de stockage de la mémoire d'application aux caches inférieurs et l'équipement ci-dessous est sujet à une panne potentielle. Certaines erreurs rares surviennent uniquement avec de gros volumes de données. Même les produits matures de fournisseurs prêts pour la production ont des problèmes de suivi des bogues non résolus liés à la perte de données. Un système de middleware Il devrait être en mesure de vous informer sur ces données victimes et de transmettre le message de provisionnement en temps opportun.



  • Les applications utilisent différents protocoles et formats de données. Cela signifie qu'un système d'intégration est un rideau pour les transformations de données et les adaptateurs pour les autres participants et utilise une variété de technologies. Celles-ci peuvent inclure de simples appels d'API REST, mais peuvent également accéder à un courtier de files d'attente, envoyer des commandes CSV via FTP ou extraire des données par lots vers une table de base de données. C'est une longue liste et elle ne sera jamais raccourcie.

  • Les modifications des formats de données et des règles de routage sont inévitables. Chaque étape du processus de développement d'une application, qui modifie la structure des données, entraîne généralement des changements dans les formats de données d'intégration et des transformations. Parfois, des changements d'infrastructure avec des flux de données d'entreprise réorganisés sont nécessaires. Par exemple, ces modifications peuvent se produire lorsqu'un seul point de validation des données de référence est entré et doit traiter toutes les entrées de données de base dans toute l'entreprise. Avec les systèmes N, on peut finir par avoir un maximum de presque connexions N^2 entre eux, de sorte que le nombre d'endroits où des changements doivent être appliqués augmente assez rapidement. Ce sera comme une avalanche. Pour maintenir la maintenabilité, une couche de middleware vous devez fournir une image claire des dépendances avec un routage polyvalent et une transformation des données.

Ces idées doivent être prises en compte lors de la conception de l'intégration et du choix de la solution pour middleware plus approprié. L'un des moyens possibles de le gérer est de profiter d'un bus de service d'affaires ( ESB ). Mais le ESB fournis par les principaux fournisseurs sont généralement trop lourds et souvent très gênants - il est presque impossible de démarrer rapidement avec un ESB , il a une courbe d'apprentissage assez raide et sa flexibilité est sacrifiée à une longue liste de fonctionnalités et d'outils intégrés. À mon avis, les solutions d'intégration open source légères sont bien supérieures: elles sont plus élastiques, faciles à déployer dans le cloud et à évoluer.

L'intégration logicielle n'est pas facile à faire. Aujourd'hui, alors que nous construisons des architectures de microservices et traitons des nuées de petits services, nous attendons également beaucoup de leur efficacité à communiquer.

Modèles d'intégration commerciale

Comme vous vous en doutez, comme le développement logiciel en général, la transformation des données et le développement du routage impliquent des opérations répétitives. L'expérience dans ce domaine a été résumée et systématisée par des professionnels confrontés à des problèmes d'intégration depuis un certain temps. Dans la sortie, il y a un ensemble de modèles extraits appelés modèles d'intégration commerciale utilisé pour concevoir des flux de données. Ces méthodes d'intégration ont été décrites dans le livre du même nom de Gregor Hophe et Bobby Wolfe, qui est très similaire à l'important livre Gang of Four, mais dans le domaine des logiciels de collage.

Pour donner un exemple, le modèle de normalisation introduit un composant qui mappe sémantiquement les mêmes messages qui ont des formats de données différents à un seul modèle canonique, ou l'agrégateur est un EIP qui combine une séquence de messages en un seul.

Puisqu'il s'agit d'abstractions technologiquement indépendantes utilisées pour résoudre des problèmes architecturaux, les EIP aident à écrire une conception d'architecture qui ne va pas en profondeur au niveau du code, mais décrit plutôt les flux de données avec suffisamment de détails. Une telle notation pour décrire les chemins d'intégration rend non seulement la conception concise, mais établit également une nomenclature commune et un langage commun, qui sont très importants dans le contexte de la résolution d'une tâche d'intégration avec des membres de l'équipe de divers domaines commerciaux

Présentation d'Apache Camel

Il y a plusieurs années, je construisais une intégration d'entreprise dans un grand réseau de vente au détail d'épicerie avec des magasins dans des endroits largement distribués. J'ai commencé avec une solution propriétaire de ESB qui s'est avéré trop lourd à entretenir. Notre équipe est donc tombée sur Apache Camel et après avoir effectué un travail de «preuve de concept», nous avons rapidement réécrit tous nos flux de données sur les routes Camel.

Chameau Apache peut être décrit comme un 'routeur de médiation', un cadre de middleware orienté message qui implémente la liste EIP , avec lequel je suis devenu familier. Il utilise ces modèles, prend en charge tous les protocoles de transport courants et comprend un ensemble complet d'adaptateurs utiles. Camel permet de gérer une série de routines d'intégration sans avoir besoin d'écrire votre propre code.

En dehors de cela, je voudrais souligner les fonctionnalités suivantes d'Apache Camel:

assez souvent, vous devez utiliser cette instruction pour mettre un groupe de classes à la disposition d'un programme.
  • Les chemins d'intégration sont écrits sous forme de tuyaux constitués de blocs. Crée une image entièrement transparente pour aider à suivre les flux de données.
  • Camel a des adaptateurs pour de nombreuses API populaires. Par exemple, obtenir des données d'Apache Kafka, surveiller les instances AWS EC2, intégrer à Salesforce - toutes ces tâches peuvent être résolues à l'aide des composants prêts à l'emploi disponibles.

Les routes Apache Camel peuvent être écrites en Java ou en DSL Scala. (Une configuration XML est également disponible mais elle devient trop verbeuse et a de pires capacités de débogage.) Il n'impose pas de restrictions sur la pile technologique des services de communication, mais si vous écrivez en Java ou Scala, vous pouvez intégrer Camel dans une application au lieu de l'exécuter indépendamment.

La notation de routage utilisée par Camel peut être décrite avec le pseudo-code simple suivant:

from(Source) .transform(Transformer) .to(Destination)

Les Fuente, Transformador et Destino sont les points de terminaison qui font référence aux composants d'implémentation par leurs URI.

Qu'est-ce qui permet à Camel de résoudre les problèmes d'intégration que j'ai décrits ci-dessus? Nous allons jeter un coup d'oeil. Tout d'abord, la logique de routage et de transformation ne se trouve désormais que dans une configuration Apache Camel dédiée. Deuxièmement, grâce au DSL concis et naturel associé à l'utilisation d'EIP, une image des dépendances entre les systèmes apparaît. Il est composé d'abstractions compréhensibles et la logique de routage est facilement réglable. Et enfin, nous n'avons pas besoin d'écrire beaucoup de code de transformation car les adaptateurs appropriés sont probablement déjà inclus.

Intégrations

Je dois ajouter qu'Apache Camel est un framework mature et reçoit des mises à jour régulières. Il a une grande communauté et une base de connaissances accumulée considérable.

Il a ses propres inconvénients. Camel ne doit pas être considéré comme une suite d'intégration complexe. Il s'agit d'une boîte à outils sans fonctionnalités de haut niveau telles que des outils de gestion des processus métier ou des moniteurs d'activité, mais elle peut être utilisée pour créer de tels logiciels.

Les systèmes alternatifs peuvent être, par exemple, Spring Integration ou Mule ESB . Pour Spring Integration, bien qu'il soit considéré comme léger, d'après mon expérience, l'assemblage et l'écriture de nombreux fichiers de configuration XML peuvent être étonnamment compliqués et pas une solution facile. Mule ESB Il s'agit d'un ensemble d'outils robustes et hautement fonctionnels, mais comme son nom l'indique, il s'agit d'un bus de services d'entreprise, il appartient donc à une classe de poids différente. Mule peut être comparé à Fuse ESB , un produit similaire basé sur Apache Camel avec un riche ensemble de fonctionnalités. Pour moi, utiliser Apache Camel pour coller des services de nos jours est une tâche évidente. Il est facile à utiliser et produit une description claire de ce qui se passe, en même temps, il est suffisamment fonctionnel pour construire des intégrations complexes.

Écrire un exemple de route

Commençons à écrire le code. Nous allons commencer par un flux de données synchrone qui achemine les messages d'une source unique vers une liste de destinataires. Les règles de routage seront écrites dans Java DSL .

Nous utiliserons Maven pour construire le projet. Ajoutez d'abord la dépendance suivante au pom.xml:

... org.apache.camel camel-core 2.20.0

Alternativement, l'application peut être construite au-dessus de l'archétype camel-archetype-java.

Les définitions de route de chameau sont déclarées dans la méthode RouteBuilder.configure.

public void configure() { errorHandler(defaultErrorHandler().maximumRedeliveries(0)); from('file:orders?noop=true').routeId('main') .log('Incoming File: ${file:onlyname}') .unmarshal().json(JsonLibrary.Jackson, Order.class) // unmarshal JSON to Order class containing List .split().simple('body.items') // split list to process one by one .to('log:inputOrderItem') .choice() .when().simple('${body.type} == 'Drink'') .to('direct:bar') .when().simple('${body.type} == 'Dessert'') .to('direct:dessertStation') .when().simple('${body.type} == 'Hot Meal'') .to('direct:hotMealStation') .when().simple('${body.type} == 'Cold Meal'') .to('direct:coldMealStation') .otherwise() .to('direct:others'); from('direct:bar').routeId('bar').log('Handling Drink'); from('direct:dessertStation').routeId('dessertStation').log('Handling Dessert'); from('direct:hotMealStation').routeId('hotMealStation').log('Handling Hot Meal'); from('direct:coldMealStation').routeId('coldMealStation').log('Handling Cold Meal'); from('direct:others').routeId('others').log('Handling Something Other'); }

Dans cette définition, nous créons une route qui récupère les enregistrements du fichier JSON, les divise en éléments et les achemine vers un ensemble de contrôleurs en fonction du contenu du message.

Exécutons-le sur les données de test préparées. Nous obtiendrons la sortie:

INFO | Total 6 routes, of which 6 are started INFO | Apache Camel 2.20.0 (CamelContext: camel-1) started in 10.716 seconds INFO | Incoming File: order1.json INFO | Exchange[ExchangePattern: InOnly, BodyType: com.antongoncharov.camel.example.model.OrderItem, Body: OrderItem{id='1', type='Drink', name='Americano', qty='1'}] INFO | Handling Drink INFO | Exchange[ExchangePattern: InOnly, BodyType: com.antongoncharov.camel.example.model.OrderItem, Body: OrderItem{id='2', type='Hot Meal', name='French Omelette', qty='1'}] INFO | Handling Hot Meal INFO | Exchange[ExchangePattern: InOnly, BodyType: com.antongoncharov.camel.example.model.OrderItem, Body: OrderItem{id='3', type='Hot Meal', name='Lasagna', qty='1'}] INFO | Handling Hot Meal INFO | Exchange[ExchangePattern: InOnly, BodyType: com.antongoncharov.camel.example.model.OrderItem, Body: OrderItem{id='4', type='Hot Meal', name='Rice Balls', qty='1'}] INFO | Handling Hot Meal INFO | Exchange[ExchangePattern: InOnly, BodyType: com.antongoncharov.camel.example.model.OrderItem, Body: OrderItem{id='5', type='Dessert', name='Blueberry Pie', qty='1'}] INFO | Handling Dessert

Comme prévu, Camel a envoyé des messages aux destinations.

Options de transfert de données

Dans l'exemple précédent, l'interaction entre les composants est synchrone et s'effectue via la mémoire de l'application. Cependant, il existe de nombreuses autres façons de communiquer lorsque nous gérons des applications distinctes qui ne partagent pas de mémoire:

  • Partage de fichiers. Une application produit des fichiers de données partagés que l'autre utilise. C'est là que vit l'esprit de la vieille école. Ce mode de communication a une pléthore de conséquences: manque de transactions et de cohérence, mauvaise performance et coordination isolée entre les systèmes. De nombreux développeurs ont fini par écrire des solutions d'intégration maison pour rendre le processus plus ou moins gérable.
  • Base de données commune. Demandez aux applications de stocker les données qu'elles souhaitent partager dans un schéma de base de données unique commun. La conception d'un schéma unifié et la gestion de l'accès simultané aux tables sont les plus grands défis de cette approche. Comme pour le partage de fichiers, il est facile que cela devienne un goulot d'étranglement permanent.
  • Appel d'API à distance. Fournit une interface pour permettre à une application d'interagir avec une autre application en cours d'exécution, comme un appel de méthode classique. Les applications partagent des fonctionnalités via des appels d'API, mais vous les liez étroitement dans le processus.
  • Service de messagerie. Demandez à chaque application de se connecter à un système de messagerie commun, d'échanger des données et d'appeler le comportement de manière asynchrone via des messages. Ni l'expéditeur ni le destinataire ne doivent être opérationnels en même temps pour délivrer le message.

Il existe d'autres façons d'interagir, mais nous devons garder à l'esprit que, de manière générale, il existe deux types d'interaction: synchrone et asynchrone. Le premier est comme appeler une fonction dans votre code - le flux d'exécution attendra jusqu'à ce qu'il s'exécute et renvoie une valeur. Avec une approche asynchrone, les mêmes données sont envoyées via une file d'attente de messages intermédiaire ou une rubrique d'abonnement. Vous pouvez implémenter un appel de fonction à distance asynchrone comme Demande-réponse EIP .

comment calculer je suis là

Cependant, la messagerie asynchrone n'est pas un remède; implique certaines restrictions. Vous voyez rarement des API de messagerie sur le Web; Les services REST synchrones sont beaucoup plus populaires. Mais le middleware La messagerie est largement utilisée dans l'intranet d'entreprise ou l'infrastructure backend de système distribué.

Utilisation des files d'attente de messages

Faisons notre exemple asynchrone. Un système logiciel qui gère les files d'attente et les sujets d'abonnement est appelé agent de messagerie . C'est comme un Système de gestion de base de données associé ( SGBDR ) pour les tableaux et les colonnes. Les files d'attente fonctionnent comme une intégration peer-to-peer, tandis que les rubriques sont destinées à la communication par publication-abonnement avec de nombreux destinataires. Nous utiliserons Apache ActiveMQ en tant que courtier de messages JMS car il est robuste et intégrable.

Ajoutez la dépendance suivante. Parfois, il est excessif d'ajouter activemq-all, qui contient tous les fichiers jar ActiveMQ, au projet, mais nous garderons nos dépendances d'application sans complications.

org.apache.activemq activemq-all 5.15.2

Ensuite, démarrez le courtier par programme. Dans Spring Boot, nous avons une configuration automatique pour cela lors de la connexion de la dépendance Maven. spring-boot-starter-activemq.

Exécutez un nouveau courtier de messages avec les commandes suivantes, en spécifiant uniquement le point de terminaison du connecteur:

BrokerService broker = new BrokerService(); broker.addConnector('tcp://localhost:61616'); broker.start();

Et ajoutez l'extrait de configuration suivant au corps de la méthode configure:

ConnectionFactory connectionFactory = new ActiveMQConnectionFactory('tcp://localhost:61616'); this.getContext().addComponent('activemq', ActiveMQComponent.jmsComponent(connectionFactory));

Nous pouvons maintenant mettre à jour l'exemple précédent en utilisant des files d'attente de messages. Les files d'attente seront créées automatiquement lors de la remise du message.

public void configure() { errorHandler(defaultErrorHandler().maximumRedeliveries(0)); ConnectionFactory connectionFactory = new ActiveMQConnectionFactory('tcp://localhost:61616'); this.getContext().addComponent('activemq', ActiveMQComponent.jmsComponent(connectionFactory)); from('file:orders?noop=true').routeId('main') .log('Incoming File: ${file:onlyname}') .unmarshal().json(JsonLibrary.Jackson, Order.class) // unmarshal JSON to Order class containing List .split().simple('body.items') // split list to process one by one .to('log:inputOrderItem') .choice() .when().simple('${body.type} == 'Drink'') .to('activemq:queue:bar') .when().simple('${body.type} == 'Dessert'') .to('activemq:queue:dessertStation') .when().simple('${body.type} == 'Hot Meal'') .to('activemq:queue:hotMealStation') .when().simple('${body.type} == 'Cold Meal'') .to('activemq:queue:coldMealStation') .otherwise() .to('activemq:queue:others'); from('activemq:queue:bar').routeId('barAsync').log('Drinks'); from('activemq:queue:dessertStation').routeId('dessertAsync').log('Dessert'); from('activemq:queue:hotMealStation').routeId('hotMealAsync').log('Hot Meals'); from('activemq:queue:coldMealStation').routeId('coldMealAsync').log('Cold Meals'); from('activemq:queue:others').routeId('othersAsync').log('Others'); }

D'accord, maintenant l'interaction est devenue asynchrone. Les consommateurs potentiels de ces informations peuvent y accéder lorsqu'ils sont prêts à le faire. Ceci est un exemple de couplage lâche que nous essayons de réaliser dans une architecture réactive. L'indisponibilité de l'un des services ne bloquera pas les autres. En outre, un consommateur peut mettre à l'échelle et lire à partir de la file d'attente en parallèle. La file d'attente elle-même peut évoluer et être partitionnée. Les files d'attente persistantes peuvent stocker des données sur le disque, en attente de traitement, même lorsque tous les participants se sont écrasés. Par conséquent, ce système est plus tolérant aux pannes.

Un fait surprenant est que Le CERN utilise Apache Camel et ActiveMQ pour surveiller les systèmes du Grand collisionneur de hadrons ( LHC ) . Il y a aussi une thèse de une expertise intéressante qui explique le choix d'une solution de middleware approprié pour cette tâche . Donc, comme on dit dans la partie clé, 'Sans JMS - pas de physique des particules!'

Moniteur

Dans l'exemple précédent, nous créons le canal de données entre deux services. C'est un point de défaillance potentiel supplémentaire dans une architecture, nous devons donc en prendre soin. Jetons un coup d'œil aux fonctionnalités de surveillance qu'offre Apache Camel. Fondamentalement, il expose des informations statistiques sur vos itinéraires à travers les MBeans auxquels JMX peut accéder. ActiveMQ expose les statistiques de la file d'attente de la même manière.

Nous allons activer le serveur JMX dans l'application pour lui permettre de fonctionner avec les options de ligne de commande:

-Dorg.apache.camel.jmx.createRmiConnector=true -Dorg.apache.camel.jmx.mbeanObjectDomainName=org.apache.camel -Dorg.apache.camel.jmx.rmiConnector.registryPort=1099 -Dorg.apache.camel.jmx.serviceUrlPath=camel

Maintenant, exécutez l'application pour que le chemin ait fait son travail. Ouvre l'outil standard jconsole et connectez-vous au processus de candidature. Connectez-vous à l'URL service:jmx:rmi:///jndi/rmi://localhost:1099/camel. Accédez au domaine org.apache.camel dans l'arborescence MBeans.

Capture d

Nous pouvons voir que tout ce qui concerne le routage est sous contrôle. Nous avons le nombre de messages en vol, le nombre d'erreurs et le nombre de messages dans les files d'attente. Ces informations peuvent être canalisées vers un ensemble d'outils de surveillance hautement fonctionnels tels que Graphana ou Kibana. Vous pouvez le faire en implémentant la célèbre pile ELK.

Il existe également une console Web enfichable et extensible qui fournit une interface utilisateur pour la gestion de Camel, ActiveMQ et bien d'autres, appelée hawt.io .

rendu côté client vs côté serveur

Capture d

Itinéraires de test

Apache Camel a des fonctionnalités assez étendues pour écrire des chemins de test avec des composants simulés . C'est un outil puissant, mais l'écriture de chemins séparés juste pour les tests est un processus qui prend du temps. Il serait plus efficace d'exécuter des tests sur les routes de production sans modifier votre pipeline. Camel a cette fonctionnalité et peut être implémentée à l'aide du composant ConseilsAvec .

Nous allons activer la logique de test dans notre exemple et exécuter un exemple de test.

junit junit 4.11 test org.apache.camel camel-test 2.20.0 test

La classe de test est:

public class AsyncRouteTest extends CamelTestSupport { @Override protected RouteBuilder createRouteBuilder() throws Exception { return new AsyncRouteBuilder(); } @Before public void mockEndpoints() throws Exception { context.getRouteDefinition('main').adviceWith(context, new AdviceWithRouteBuilder() { @Override public void configure() throws Exception { // we substitute all actual queues with mock endpoints mockEndpointsAndSkip('activemq:queue:bar'); mockEndpointsAndSkip('activemq:queue:dessertStation'); mockEndpointsAndSkip('activemq:queue:hotMealStation'); mockEndpointsAndSkip('activemq:queue:coldMealStation'); mockEndpointsAndSkip('activemq:queue:others'); // and replace the route's source with test endpoint replaceFromWith('file://testInbox'); } }); } @Test public void testSyncInteraction() throws InterruptedException { String testJson = '{'id': 1, 'order': [{'id': 1, 'name': 'Americano', 'type': 'Drink', 'qty': '1'}, {'id': 2, 'name': 'French Omelette', 'type': 'Hot Meal', 'qty': '1'}, {'id': 3, 'name': 'Lasagna', 'type': 'Hot Meal', 'qty': '1'}, {'id': 4, 'name': 'Rice Balls', 'type': 'Hot Meal', 'qty': '1'}, {'id': 5, 'name': 'Blueberry Pie', 'type': 'Dessert', 'qty': '1'}]}'; // get mocked endpoint and set an expectation MockEndpoint mockEndpoint = getMockEndpoint('mock:activemq:queue:hotMealStation'); mockEndpoint.expectedMessageCount(3); // simulate putting file in the inbox folder template.sendBodyAndHeader('file://testInbox', testJson, Exchange.FILE_NAME, 'test.json'); //checks that expectations were met assertMockEndpointsSatisfied(); } }

Exécutez maintenant des tests pour l'application avec mvn test. Nous pouvons voir que notre route a été exécutée avec succès avec les conseils de test. Aucun message n'est passé dans les files d'attente réelles et les tests ont réussi.

INFO | Route: main started and consuming from: file://testInbox INFO | Incoming File: test.json INFO | Asserting: mock://activemq:queue:hotMealStation is satisfied

Utilisation d'Apache Camel avec le cluster Kubernetes

L'un des problèmes d'intégration aujourd'hui est que les applications ne sont plus statiques. Dans une infrastructure cloud, nous travaillons avec des services virtuels qui s'exécutent sur plusieurs nœuds en même temps. Il permet l'architecture de microservices avec un réseau de petits services légers qui interagissent les uns avec les autres. Ces services ont une vie peu fiable et nous devons les découvrir de manière dynamique.

Coller des services cloud ensemble est une tâche qui peut être résolue avec Apache Camel. C'est particulièrement intéressant pour la saveur EIP et le fait que Camel dispose de nombreux adaptateurs et prend en charge une large gamme de protocoles. La version récente 2.18 ajoute le composant Appel de service , qui introduit une fonctionnalité d'appel d'une API et de résolution de son adresse via des mécanismes de découverte de cluster. Actuellement, il prend en charge Consul, Kubernetes, Ribbon, etc. Certains exemples de code, où ServiceCall est configuré avec Consul, peuvent être trouvés facilement. Nous utiliserons Kubernetes ici car c'est ma solution de cluster préférée.

Le schéma d'intégration sera le suivant:

Schème

Le service Order et le service Inventory sera quelques applications triviales Botte de printemps renvoyer des données statiques. Nous ne sommes pas liés à une pile technologique particulière ici. Ces services produisent les données que nous voulons traiter.

Contrôleur de service de commande:

@RestController public class OrderController { private final OrderStorage orderStorage; @Autowired public OrderController(OrderStorage orderStorage) { this.orderStorage = orderStorage; } @RequestMapping('/info') public String info() { return 'Order Service UUID = ' + OrderApplication.serviceID; } @RequestMapping('/orders') public List getAll() { return orderStorage.getAll(); } @RequestMapping('/orders/{id}') public Order getOne(@PathVariable Integer id) { return orderStorage.getOne(id); } }

Produit des données au format:

[{'id':1,'items':[2,3,4]},{'id':2,'items':[5,3]}]

Le contrôleur de service Inventory est absolument similaire au service Order:

@RestController public class InventoryController { private final InventoryStorage inventoryStorage; @Autowired public InventoryController(InventoryStorage inventoryStorage) { this.inventoryStorage = inventoryStorage; } @RequestMapping('/info') public String info() { return 'Inventory Service UUID = ' + InventoryApplication.serviceID; } @RequestMapping('/items') public List getAll() { return inventoryStorage.getAll(); } @RequestMapping('/items/{id}') public InventoryItem getOne(@PathVariable Integer id) { return inventoryStorage.getOne(id); } }

InventoryStorage c'est un référentiel générique qui contient des données. Dans cet exemple, il renvoie des objets prédéfinis statiques, qui sont classés selon le format suivant.

[{'id':1,'name':'Laptop','description':'Up to 12-hours battery life','price':499.9},{'id':2,'name':'Monitor','description':'27-inch, response time: 7ms','price':200.0},{'id':3,'name':'Headphones','description':'Soft leather ear-cups','price':29.9},{'id':4,'name':'Mouse','description':'Designed for comfort and portability','price':19.0},{'id':5,'name':'Keyboard','description':'Layout: US','price':10.5}]

Nous allons écrire un chemin de passerelle qui les connecte, mais sans ServiceCall dans cette étape:

rest('/orders') .get('/').description('Get all orders with details').outType(TestResponse.class) .route() .setHeader('Content-Type', constant('application/json')) .setHeader('Accept', constant('application/json')) .setHeader(Exchange.HTTP_METHOD, constant('GET')) .removeHeaders('CamelHttp*') .to('http4://localhost:8082/orders?bridgeEndpoint=true') .unmarshal(formatOrder) .enrich('direct:enrichFromInventory', new OrderAggregationStrategy()) .to('log:result') .endRest(); from('direct:enrichFromInventory') .transform().simple('${null}') .setHeader('Content-Type', constant('application/json')) .setHeader('Accept', constant('application/json')) .setHeader(Exchange.HTTP_METHOD, constant('GET')) .removeHeaders('CamelHttp*') .to('http4://localhost:8081/items?bridgeEndpoint=true') .unmarshal(formatInventory);

Imaginez maintenant que chaque service n'est plus une instance spécifique mais un nuage d'instances qui fonctionnent comme une seule. Nous utiliserons Minikube pour tester le cluster Kubernetes localement.

Configurez les chemins réseau pour voir les nœuds Kubernetes localement (l'exemple donné est pour un environnement Mac / Linux):

quelle est la difference entre s et c corporation
# remove existing routes sudo route -n delete 10/24 > /dev/null 2>&1 # add routes sudo route -n add 10.0.0.0/24 $(minikube ip) # 172.17.0.0/16 ip range is used by docker in minikube sudo route -n add 172.17.0.0/16 $(minikube ip) ifconfig 'bridge100' | grep member | awk '{print }’ # use interface name from the output of the previous command # needed for xhyve driver, which I'm using for testing sudo ifconfig bridge100 -hostfilter en5

Emballez les services dans Conteneurs Docker avec une configuration Dockerfile comme celle-ci:

FROM openjdk:8-jdk-alpine VOLUME /tmp ADD target/order-srv-1.0-SNAPSHOT.jar app.jar ADD target/lib lib ENV JAVA_OPTS='' ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar

Créez et soumettez les images de service au registre Docker. Exécutez maintenant les nœuds sur le cluster Kubernetes local.

Configuration du déploiement de Kubernetes.yaml:

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: inventory spec: replicas: 3 selector: matchLabels: app: inventory template: metadata: labels: app: inventory spec: containers: - name: inventory image: inventory-srv:latest imagePullPolicy: Never ports: - containerPort: 8081

Exposez ces déploiements en tant que services en cluster:

kubectl expose deployment order-srv --type=NodePort kubectl expose deployment inventory-srv --type=NodePort

Nous pouvons maintenant vérifier si les demandes sont servies par des nœuds choisis au hasard dans le cluster. Exécuter curl -X http://192.168.99.100:30517/info plusieurs fois de façon séquentielle pour accéder au minikube NodePort, pour le service exposé (en utilisant votre hôte et votre port). Dans le résultat, nous voyons que nous avons atteint l'équilibre des demandes. ~~~ UUID du service d'inventaire = 22f8ca6b-f56b-4984-927b-cbf9fcf81da5 UUID du service d'inventaire = b7a4d326-1e76-4051-a0a6-1016394fafda Service d'inventaire UUID = b7a4d326-1e76-4051-aUafUID Service d'inventaire 224d326-1e76-4051-a UafUID6- Service d'inventaire 224d326-1e76-4051-aUafUID6-104 4984-927b-cbf9fcf81da5 UUID du service d'inventaire = 50323ddb-3ace-4424-820a-6b4e85775af4 ~~~

Ajoutez les dépendances camel-kubernetes et camel-netty4-http al pom.xml du projet. Ensuite, configurez le composant ServiceCall pour utiliser la découverte de nœud maître Kubernetes partagé pour tous les appels de service entre les définitions de route:

KubernetesConfiguration kubernetesConfiguration = new KubernetesConfiguration(); kubernetesConfiguration.setMasterUrl('https://192.168.64.2:8443'); kubernetesConfiguration.setClientCertFile('/Users/antongoncharov/.minikube/client.crt'); kubernetesConfiguration.setClientKeyFile('/Users/antongoncharov/.minikube/client.key'); kubernetesConfiguration.setNamespace('default”); ServiceCallConfigurationDefinition config = new ServiceCallConfigurationDefinition(); config.setServiceDiscovery(new KubernetesClientServiceDiscovery(kubernetesConfiguration)); context.setServiceCallConfiguration(config);

Le ServiceCall EIP complète bien le Spring Boot. La plupart des options peuvent être définies directement dans le fichier application.properties.

Améliorez la route Camel avec le composant ServiceCall:

rest('/orders') .get('/').description('Get all orders with details').outType(TestResponse.class) .route() .hystrix() .setHeader('Content-Type', constant('application/json')) .setHeader('Accept', constant('application/json')) .setHeader(Exchange.HTTP_METHOD, constant('GET')) .removeHeaders('CamelHttp*') .serviceCall('customer-srv','http4:customer-deployment?bridgeEndpoint=true') .unmarshal(formatOrder) .enrich('direct:enrichFromInventory', new OrderAggregationStrategy()) .to('log:result') .endRest(); from('direct:enrichFromInventory') .transform().simple('${null}') .setHeader('Content-Type', constant('application/json')) .setHeader('Accept', constant('application/json')) .setHeader(Exchange.HTTP_METHOD, constant('GET')) .removeHeaders('CamelHttp*') .serviceCall('order-srv','http4:order-srv?bridgeEndpoint=true') .unmarshal(formatInventory);

Nous avons également activé le disjoncteur sur l'itinéraire. Il s'agit d'un hook d'intégration qui permet d'arrêter les appels distants du système, en cas d'erreurs de livraison ou de manque de disponibilité du destinataire. Ceci est conçu pour éviter les pannes système en cascade. Le composant Hystrix aide à atteindre cet objectif en mettant en œuvre le modèle de disjoncteur.

Exécutons-le et envoyons une demande de test; nous obtiendrons la réponse globale des deux services.

[{'id':1,'items':[{'id':2,'name':'Monitor','description':'27-inch, response time: 7ms','price':200.0},{'id':3,'name':'Headphones','description':'Soft leather ear-cups','price':29.9},{'id':4,'name':'Mouse','description':'Designed for comfort and portability','price':19.0}]},{'id':2,'items':[{'id':5,'name':'Keyboard','description':'Layout: US','price':10.5},{'id':3,'name':'Headphones','description':'Soft leather ear-cups','price':29.9}]}]

Le résultat est comme prévu.

Autres cas d'utilisation

J'ai montré comment Apache Camel peut intégrer des microservices dans un cluster. Quelles sont les autres utilisations de ce cadre? En général, il est utile partout où le routage basé sur des règles est une solution. Par exemple, Apache Camel peut être un middleware pour l'Internet des objets avec l'adaptateur Eclipse Kura. Il peut gérer la surveillance en transportant des signaux de journal à partir de divers composants et services, comme dans le système du CERN. Il peut également s'agir d'un cadre d'intégration pour la SOA d'entreprise ou d'un portefeuille pour le traitement de données par lots, bien qu'il ne soit pas en concurrence avec Apache Spark dans cette zone.

conclusion

Vous pouvez voir que l'intégration des systèmes n'est pas un processus facile. Nous avons de la chance car beaucoup d'expérience a été accumulée. Il est important de l'appliquer correctement pour créer des solutions flexibles et tolérantes aux pannes.

Pour garantir une application correcte, je recommande d'avoir une liste de contrôle des aspects d'intégration importants. Les articles indispensables comprennent:

  • Existe-t-il une couche d'intégration distincte?
  • Existe-t-il des tests d'intégration?
  • Connaissons-nous l'intensité maximale attendue des données?
  • Connaissons-nous le délai de livraison prévu des données?
  • La corrélation des messages est-elle importante? Que se passe-t-il si une séquence est interrompue?
  • Devrions-nous le faire de manière synchrone ou asynchrone?
  • Où les règles de routage et les formats changent-ils le plus souvent?
  • Avons-nous des moyens de surveiller le processus?

Dans cet article, nous avons testé Apache Camel, un cadre système d'intégration léger, qui permet d'économiser du temps et des efforts lors de la résolution des problèmes d'intégration. Comme nous l'avons montré, il peut servir d'outil prenant en charge l'architecture de microservices pertinente en prenant l'entière responsabilité de l'échange de données entre les microservices.

Si vous souhaitez en savoir plus sur Apache Camel, je vous recommande vivement le livre 'Camel in Action' du créateur du cadre , Claus Ibsen. La documentation officielle est disponible sur camel.apache.org .

Que faut-il pour un processus de rachat par la direction réussi?

Processus Financiers

Que faut-il pour un processus de rachat par la direction réussi?
Principales erreurs du Pitch Deck

Principales erreurs du Pitch Deck

Investisseurs Et Financement

Articles Populaires
Ingénieur senior full-stack, équipe post-embauche des talents
Ingénieur senior full-stack, équipe post-embauche des talents
En souvenir de Matthew Osborne
En souvenir de Matthew Osborne
Comment créer un pipeline de déploiement initial efficace
Comment créer un pipeline de déploiement initial efficace
L'impact du Brexit sur le secteur des services financiers
L'impact du Brexit sur le secteur des services financiers
Comment préparer un modèle de tableau des flux de trésorerie qui s'équilibre réellement
Comment préparer un modèle de tableau des flux de trésorerie qui s'équilibre réellement
 
Conquérir la recherche de chaînes avec l'algorithme Aho-Corasick
Conquérir la recherche de chaînes avec l'algorithme Aho-Corasick
Estimation des coûts logiciels dans la gestion de projet agile
Estimation des coûts logiciels dans la gestion de projet agile
5 qualités indispensables des meilleurs chefs de projet
5 qualités indispensables des meilleurs chefs de projet
Comment recréer gratuitement les ressources d'un terminal Bloomberg
Comment recréer gratuitement les ressources d'un terminal Bloomberg
Noyaux d'arbres: quantification de la similitude entre les données structurées en arborescence
Noyaux d'arbres: quantification de la similitude entre les données structurées en arborescence
Articles Populaires
  • ____ réduit la taille d'une base de données et rend les données plus faciles à utiliser.
  • comment mettre en place un conseil consultatif
  • exemple simple d'apprentissage automatique
  • faux numéros de carte de crédit 2017
  • principes de conception accent définition
  • comment former un conseil consultatif
Catégories
  • Design De Marque
  • Personnes Et Équipes Produit
  • Innovation
  • Kpi Et Analyses
  • © 2022 | Tous Les Droits Sont Réservés

    portaldacalheta.pt