portaldacalheta.pt
  • Principal
  • La Technologie
  • Personnes Et Équipes
  • Gestion De Projet
  • Équipes Distribuées
Science Des Données Et Bases De Données

Un guide pour un hachage cohérent



Ces dernières années, avec l'avènement de concepts tels que le cloud computing et le big data, les systèmes distribués ont gagné en popularité et en pertinence.

Un tel type de système, caches distribués qui alimentent de nombreux sites Web dynamiques et applications Web à fort trafic, consistent généralement en un cas particulier de hachage distribué. Celles-ci tirent parti d'un algorithme appelé hachage cohérent .



Qu'est-ce que le hachage cohérent? Quelle est la motivation derrière cela et pourquoi devriez-vous vous en soucier?



Dans cet article, je vais d'abord passer en revue le concept général du hachage et son objectif, suivi d'une description du hachage distribué et des problèmes qu'il entraîne. En retour, cela nous mènera à notre sujet titre.



Qu'est-ce que le hachage?

Qu'est-ce que le «hachage»? Merriam Webster définit le nom hacher comme «viande hachée mélangée avec des pommes de terre et dorée» et le verbe comme «hacher (comme de la viande et des pommes de terre) en petits morceaux». Donc, mis à part les détails culinaires, hash signifie en gros «hacher et mélanger» - et c'est précisément de là que vient le terme technique.

Une fonction de hachage est une fonction qui mappe un élément de données - décrivant généralement un type d'objet, souvent de taille arbitraire - à un autre élément de données, généralement un entier, appelé code de hachage , ou simplement hacher .



Par exemple, une fonction de hachage conçue pour hacher des chaînes, avec une plage de sortie de 0 .. 100, peut mapper la chaîne Hello à, disons, le nombre 57, Hasta la vista, baby au nombre 33, et toute autre chaîne possible à un certain nombre dans cette plage. Puisqu'il y a beaucoup plus d'entrées possibles que de sorties, tout nombre donné aura de nombreuses chaînes différentes mappées dessus, un phénomène connu sous le nom de collision . Les bonnes fonctions de hachage devraient en quelque sorte «hacher et mélanger» (d'où le terme) les données d'entrée de telle sorte que les sorties pour différentes valeurs d'entrée soient réparties aussi uniformément que possible sur la plage de sortie.

Les fonctions de hachage ont de nombreuses utilisations et pour chacune, des propriétés différentes peuvent être souhaitées. Il existe un type de fonction de hachage appelé fonctions de hachage cryptographiques , qui doivent répondre à un ensemble restrictif de propriétés et sont utilisées à des fins de sécurité, y compris des applications telles que la protection par mot de passe, la vérification de l'intégrité et la prise d'empreintes digitales des messages, et la détection de la corruption des données, entre autres, mais celles-ci sortent du cadre de cet article.



Les fonctions de hachage non cryptographiques ont également plusieurs utilisations, la plus courante étant leur utilisation dans tables de hachage , qui est celle qui nous concerne et que nous allons explorer plus en détail.

Présentation des tables de hachage (cartes de hachage)

Imaginez que nous devions garder une liste de tous les membres d'un club tout en étant capable de rechercher un membre spécifique. Nous pourrions le gérer en conservant la liste dans un tableau (ou une liste chaînée) et, pour effectuer une recherche, itérer les éléments jusqu'à ce que nous trouvions celui souhaité (nous pourrions rechercher en fonction de leur nom, par exemple). Dans le pire des cas, cela signifierait vérifier tous les membres (si celui que nous recherchons est le dernier, ou pas du tout présent), soit la moitié d'entre eux en moyenne. En termes de théorie de la complexité, la recherche aurait alors une complexité O(n), et elle serait raisonnablement rapide pour une petite liste, mais elle deviendrait de plus en plus lente proportionnellement au nombre de membres.



Comment cela pourrait-il être amélioré? Supposons que tous ces membres du club aient un membre ID, qui se trouve être un numéro séquentiel reflétant l'ordre dans lequel ils ont rejoint le club.

En supposant que la recherche par ID étaient acceptables, nous pourrions placer tous les membres dans un tableau, avec leurs index correspondant à leurs ID s (par exemple, un membre avec ID=10 serait à l'index 10 dans le tableau). Cela nous permettrait d'accéder directement à chaque membre, sans aucune recherche. Ce serait très efficace, en fait, aussi efficace que possible, correspondant à la complexité la plus faible possible, O(1), également appelée temps constant .



Mais, certes, notre membre du club ID scénario est quelque peu artificiel. Et si ID s était de grands nombres non séquentiels ou aléatoires? Ou, si vous recherchez par ID n'étaient pas acceptables, et nous devions effectuer une recherche par nom (ou dans un autre champ) à la place? Il serait certainement utile de conserver notre accès direct rapide (ou quelque chose de proche) tout en étant capable de gérer des ensembles de données arbitraires et des critères de recherche moins restrictifs.

Voici où les fonctions de hachage viennent à la rescousse. Une fonction de hachage appropriée peut être utilisée pour mapper une donnée arbitraire à un entier, qui jouera un rôle similaire à celui du membre de notre club ID, mais avec quelques différences importantes.



Premièrement, une bonne fonction de hachage a généralement une large plage de sortie (généralement, toute la plage d'un entier de 32 ou 64 bits), donc la création d'un tableau pour tous les indices possibles serait soit peu pratique, soit carrément impossible, et un gaspillage colossal de mémoire . Pour surmonter cela, nous pouvons avoir un tableau de taille raisonnable (disons, juste deux fois le nombre d'éléments que nous nous attendons à stocker) et effectuer un module opération sur le hachage pour obtenir l'index du tableau. Ainsi, l'index serait index = hash(object) mod N, où N est la taille du tableau.

Deuxièmement, les hachages d'objets ne seront pas uniques (sauf si nous travaillons avec un ensemble de données fixe et un fonction de hachage parfaite , mais nous n'en discuterons pas ici). Il y aura collisions (encore augmenté par l'opération modulo), et donc un simple accès direct à l'index ne fonctionnera pas. Il existe plusieurs façons de gérer cela, mais une méthode typique consiste à joindre une liste, communément appelée seau , à chaque index de tableau pour contenir tous les objets partageant un index donné.

Donc, nous avons un tableau de taille N, avec chaque entrée pointant vers un compartiment d'objets. Pour ajouter un nouvel objet, nous devons calculer son hash modulo N et vérifier le compartiment à l'index résultant, en ajoutant l'objet s'il n'y est pas déjà. Pour rechercher un objet, nous faisons de même, il suffit de regarder dans le seau pour vérifier si l'objet est là. Une telle structure s'appelle un table de hachage , et bien que les recherches dans les buckets soient linéaires, une table de hachage correctement dimensionnée doit avoir un nombre raisonnablement petit d'objets par bucket, ce qui entraîne presque accès à temps constant (une complexité moyenne de O(N/k), où k est le nombre de buckets).

Avec les objets complexes, la fonction de hachage n'est généralement pas appliquée à l'objet entier, mais à un clé au lieu. Dans notre exemple de membre du club, chaque objet peut contenir plusieurs champs (comme le nom, l'âge, l'adresse, l'adresse e-mail, le téléphone), mais nous pourrions choisir, par exemple, l'e-mail pour agir comme clé afin que la fonction de hachage soit appliquée à l'e-mail seulement. En fait, la clé n'a pas besoin de faire partie de l'objet; il est courant de stocker des paires clé / valeur, où la clé est généralement une chaîne relativement courte, et la valeur peut être une donnée arbitraire. Dans de tels cas, la table de hachage ou la carte de hachage est utilisée comme dictionnaire , et c’est ainsi que certains langages de haut niveau implémentent des objets ou des tableaux associatifs.

quel est l'un des moyens les plus courants pour une entreprise de réduire le pouvoir de ses fournisseurs ?

Mise à l'échelle: hachage distribué

Maintenant que nous avons discuté du hachage, nous sommes prêts à examiner hachage distribué .

Dans certaines situations, il peut être nécessaire ou souhaitable de diviser une table de hachage en plusieurs parties, hébergées par différents serveurs. L'une des principales motivations pour cela est de contourner les limitations de mémoire liées à l'utilisation d'un seul ordinateur, permettant la construction de tables de hachage arbitrairement grandes (avec suffisamment de serveurs).

Dans un tel scénario, les objets (et leurs clés) sont distribué parmi plusieurs serveurs, d'où le nom.

Un cas d'utilisation typique pour cela est l'implémentation de caches en mémoire, tels que Memcached .

Ces configurations consistent en un pool de serveurs de mise en cache qui hébergent de nombreuses paires clé / valeur et sont utilisées pour fournir un accès rapide aux données initialement stockées (ou calculées) ailleurs. Par exemple, pour réduire la charge sur un serveur de base de données et en même temps améliorer les performances, une application peut être conçue pour extraire d’abord les données des serveurs de cache, et uniquement si elles n’y sont pas présentes - une situation appelée cache manque : Effectuer un tri dans la base de données, exécuter la requête appropriée et mettre en cache les résultats avec une clé appropriée, afin qu’elle puisse être trouvée la prochaine fois qu’elle en aura besoin.

Maintenant, comment se déroule la distribution? Quels critères sont utilisés pour déterminer quelles clés héberger sur quels serveurs?

Le moyen le plus simple est de prendre le hachage module du nombre de serveurs. Autrement dit, server = hash(key) mod N, où N est la taille de la piscine. Pour stocker ou récupérer une clé, le client calcule d'abord le hachage, applique un modulo N et utilise l'index résultant pour contacter le serveur approprié (probablement en utilisant une table de recherche d'adresses IP). Notez que la fonction de hachage utilisée pour la distribution des clés doit être la même sur tous les clients, mais il n'est pas nécessaire qu'elle soit la même que celle utilisée en interne par les serveurs de mise en cache.

Voyons un exemple. Disons que nous avons trois serveurs, A, B et C, et nous avons des clés de chaîne avec leurs hachages:

CLÉ HACHER HASH mod 3
'John' 1633428562 2
'facture' 7594634739 0
'Jeanne' 5000799124 un
«Steve» 9787173343 0
«Kate» 3421657995 2

Un client souhaite récupérer la valeur de la clé john. Son hash modulo 3 est 2, il doit donc contacter le serveur C. La clé n'y est pas trouvée, donc le client récupère les données de la source et les ajoute. La piscine ressemble à ceci:

À B C
'John'

Ensuite, un autre client (ou le même) veut récupérer la valeur de la clé bill. Son hash modulo 3 est 0, il doit donc contacter le serveur A. La clé n'y est pas trouvée, donc le client récupère les données de la source et les ajoute. La piscine ressemble à ceci maintenant:

À B C
'facture' 'John'

Une fois les clés restantes ajoutées, le pool ressemble à ceci:

À B C
'facture' 'Jeanne' 'John'
«Steve» «Kate»

Le problème du ressassement

Ce schéma de distribution est simple, intuitif et fonctionne correctement. Autrement dit, jusqu'à ce que le nombre de serveurs change. Que se passe-t-il si l'un des serveurs tombe en panne ou devient indisponible? Les clés doivent être redistribuées pour tenir compte du serveur manquant, bien sûr. Il en va de même si un ou plusieurs nouveaux serveurs sont ajoutés au pool; les clés doivent être redistribuées pour inclure les nouveaux serveurs. Cela est vrai pour n'importe quel schéma de distribution, mais le problème avec notre distribution modulo simple est que lorsque le nombre de serveurs change, la plupart hashes modulo N va changer, donc la plupart des clés devront être déplacées vers un autre serveur. Ainsi, même si un seul serveur est supprimé ou ajouté, toutes les clés devront probablement être remises en place sur un serveur différent.

De notre exemple précédent, si nous supprimions le serveur C, nous devrons modifier toutes les clés en utilisant hash modulo 2 au lieu de hash modulo 3, et les nouveaux emplacements des clés deviendraient:

CLÉ HACHER HASH mod 2
'John' 1633428562 0
'facture' 7594634739 un
'Jeanne' 5000799124 0
«Steve» 9787173343 un
«Kate» 3421657995 un
À B
'John' 'facture'
'Jeanne' «Steve»
«Kate»

Notez que tous les emplacements clés ont changé, pas seulement ceux du serveur C.

Dans le cas d'utilisation typique que nous avons mentionné précédemment (mise en cache), cela signifierait que, tout à coup, les clés ne seront pas trouvées car elles ne seront pas encore présentes à leur nouvel emplacement.

Ainsi, la plupart des requêtes entraîneront des erreurs, et les données d'origine devront probablement être extraites à nouveau de la source pour être remaniées, plaçant ainsi une lourde charge sur le (s) serveur (s) d'origine (généralement une base de données). Cela peut très bien dégrader les performances et éventuellement planter les serveurs d'origine.

La solution: un hachage cohérent

Alors, comment résoudre ce problème? Nous avons besoin d'un système de distribution qui ne pas dépendent directement du nombre de serveurs, de sorte que, lors de l'ajout ou de la suppression de serveurs, le nombre de clés à déplacer est minimisé. Un de ces schémas - intelligent, mais étonnamment simple - est appelé hachage cohérent , et a été décrit pour la première fois par Karger et coll. au MIT dans un article académique de 1997 (selon Wikipedia).

Le hachage cohérent est un schéma de hachage distribué qui fonctionne indépendamment du nombre de serveurs ou d'objets dans un table de hachage en leur attribuant une position sur un cercle abstrait, ou anneau de hachage . Cela permet aux serveurs et aux objets d'évoluer sans affecter le système global.

Imaginons que nous mappions la plage de sortie de hachage sur le bord d'un cercle. Cela signifie que la valeur de hachage minimale possible, zéro, correspondrait à un angle de zéro, la valeur maximale possible (un grand entier que nous appellerons INT_MAX) correspondrait à un angle de 2 ¢ radians (ou 360 degrés) , et toutes les autres valeurs de hachage s'inscriraient linéairement quelque part entre les deux. Ainsi, nous pourrions prendre une clé, calculer son hachage et savoir où elle se trouve sur le bord du cercle. En supposant un INT_MAX sur 10dix(par exemple), les clés de notre exemple précédent ressembleraient à ceci:

comment utiliser bootstrap en html

Exemple de hachage cohérent: clés

CLÉ HACHER ANGLE (DEG)
'John' 1633428562 58,8
'facture' 7594634739 273,4
'Jeanne' 5000799124 180
«Steve» 9787173343 352,3
«Kate» 3421657995 123,2

Imaginez maintenant que nous ayons également placé les serveurs sur le bord du cercle, en leur attribuant également des angles pseudo-aléatoirement. Cela doit être fait de manière répétable (ou du moins de manière à ce que tous les clients s’accordent sur les angles des serveurs). Un moyen pratique de procéder consiste à hacher le nom du serveur (ou l’adresse IP, ou un identifiant) - comme nous le ferions avec toute autre clé - pour trouver son angle.

Dans notre exemple, les choses pourraient ressembler à ceci:

Exemple de hachage cohérent: serveurs

CLÉ HACHER ANGLE (DEG)
'John' 1633428562 58,8
'facture' 7594634739 273,4
'Jeanne' 5000799124 180
«Steve» 9787173343 352,3
«Kate» 3421657995 123,2
'À' 5572014558 200,6
«B» 8077113362 290,8
«C» 2269549488 81,7

Puisque nous avons les clés à la fois des objets et des serveurs sur le même cercle, nous pouvons définir une règle simple pour associer les premiers aux seconds: chaque clé d'objet appartiendra au serveur dont la clé est la plus proche, dans le sens antihoraire (ou sens horaire, selon les conventions utilisées). En d'autres termes, pour savoir quel serveur demander une clé donnée, nous devons localiser la clé sur le cercle et se déplacer dans le sens de l'angle ascendant jusqu'à ce que nous trouvions un serveur.

Dans notre exemple:

Exemple de hachage cohérent: objets

CLÉ HACHER ANGLE (DEG)
'John' 1633428562 58,7
«C» 2269549488 81,7
«Kate» 3421657995 123,1
'Jeanne' 5000799124 180
'À' 5572014557 200,5
'facture' 7594634739 273,4
«B» 8077113361 290,7
«Steve» 787173343 352,3
CLÉ HACHER ANGLE (DEG) ÉTIQUETTE SERVEUR
'John' 1632929716 58,7 «C» C
«Kate» 3421831276 123,1 'À' À
'Jeanne' 5000648311 180 'À' À
'facture' 7594873884 273,4 «B» B
«Steve» 9786437450 352,3 «C» C

Du point de vue de la programmation, ce que nous ferions serait de conserver une liste triée de valeurs de serveur (qui pourraient être des angles ou des nombres dans n'importe quel intervalle réel), et parcourir cette liste (ou utiliser une recherche binaire) pour trouver le premier serveur avec une valeur supérieure supérieure ou égale à celle de la clé souhaitée. Si aucune valeur de ce type n'est trouvée, nous devons terminer en prenant la première de la liste.

Pour nous assurer que les clés d'objet sont uniformément réparties entre les serveurs, nous devons appliquer une astuce simple: attribuer non pas une, mais plusieurs étiquettes (angles) à chaque serveur. Donc au lieu d'avoir des étiquettes A, B et C, on pourrait avoir, disons, A0 .. A9, B0 .. B9 et C0 .. C9, tous intercalés le long du cercle. Le facteur d'augmentation du nombre d'étiquettes (clés de serveur), appelé poids , dépend de la situation (et peut même être différent pour chaque serveur) pour ajuster la probabilité que des clés se retrouvent sur chacun. Par exemple, si serveur B étaient deux fois plus puissants que les autres, il pouvait être attribué deux fois plus d'étiquettes, et par conséquent, il finirait par contenir deux fois plus d'objets (en moyenne).

Pour notre exemple, nous supposerons que les trois serveurs ont un poids égal de 10 (cela fonctionne bien pour trois serveurs, pour 10 à 50 serveurs, un poids compris entre 100 et 500 fonctionnerait mieux, et des pools plus importants peuvent nécessiter des poids encore plus élevés. ):

Exemple de hachage de contenu 5

CLÉ HACHER ANGLE (DEG)
«C6» 408965526 14,7
«A1» 473914830 17
«A2» 548798874 19,7
«A3» 1466730567 52,8
«C4» 1493080938 53,7
'John' 1633428562 58,7
«B2» 1808009038 65
«C0» 1982701318 71,3
«B3» 2058758486 74,1
«A7» 2162578920 77,8
«B4» 2660265921 95,7
«C9» 3359725419 120,9
«Kate» 3421657995 123,1
«A5» 3434972143 123,6
«C1» 3672205973 132,1
«C8» 3750588567 135
«B0» 4049028775 145,7
«B8» 4755525684 171,1
«A9» 4769549830 171,7
'Jeanne' 5000799124 180
«C7» 5014097839 180,5
«B1» 5444659173 196
«A6» 6210502707 223,5
«A0» 6511384141 234,4
«B9» 7292819872 262,5
«C3» 7330467663 263,8
«C5» 7502566333 270
'facture' 7594634739 273,4
«A4» 8047401090 289,7
«C2» 8605012288 309,7
«A8» 8997397092 323,9
«B7» 9038880553 325,3
«B5» 9368225254 337,2
'B6' 9379713761 337,6
«Steve» 9787173343 352,3
CLÉ HACHER ANGLE (DEG) ÉTIQUETTE SERVEUR
'John' 1632929716 58,7 «B2» B
«Kate» 3421831276 123,1 «A5» À
'Jeanne' 5000648311 180 «C7» C
'facture' 7594873884 273,4 «A4» À
«Steve» 9786437450 352,3 «C6» C

Alors, quel est l'avantage de toute cette approche circulaire? Imaginez le serveur C est retiré. Pour en tenir compte, nous devons supprimer les étiquettes C0 .. C9 du cercle. Il en résulte que les clés d'objet auparavant adjacentes aux étiquettes supprimées sont désormais étiquetées au hasard Ax et Bx, en les réaffectant aux serveurs A et B.

Mais que se passe-t-il avec les autres clés d'objet, celles qui appartenaient à l'origine à A et B? Rien! C’est ça la beauté: l’absence de Cx labels n'affecte en aucun cas ces clés. Ainsi, la suppression d'un serveur entraîne la réaffectation aléatoire de ses clés d'objet au reste des serveurs, laissant toutes les autres touches intactes :

Exemple de hachage cohérent 6

CLÉ HACHER ANGLE (DEG)
«A1» 473914830 17
«A2» 548798874 19,7
«A3» 1466730567 52,8
'John' 1633428562 58,7
«B2» 1808009038 65
«B3» 2058758486 74,1
«A7» 2162578920 77,8
«B4» 2660265921 95,7
«Kate» 3421657995 123,1
«A5» 3434972143 123,6
«B0» 4049028775 145,7
«B8» 4755525684 171,1
«A9» 4769549830 171,7
'Jeanne' 5000799124 180
«B1» 5444659173 196
«A6» 6210502707 223,5
«A0» 6511384141 234,4
«B9» 7292819872 262,5
'facture' 7594634739 273,4
«A4» 8047401090 289,7
«A8» 8997397092 323,9
«B7» 9038880553 325,3
«B5» 9368225254 337,2
'B6' 9379713761 337,6
«Steve» 9787173343 352,3
CLÉ HACHER ANGLE (DEG) ÉTIQUETTE SERVEUR
'John' 1632929716 58,7 «B2» B
«Kate» 3421831276 123,1 «A5» À
'Jeanne' 5000648311 180 «B1» B
'facture' 7594873884 273,4 «A4» À
«Steve» 9786437450 352,3 «A1» À

Quelque chose de similaire se produit si, au lieu de supprimer un serveur, nous en ajoutons un. Si nous voulions ajouter un serveur D à notre exemple (disons, en remplacement de C), nous aurions besoin d'ajouter des étiquettes D0 .. D9. Le résultat serait qu'environ un tiers des clés existantes (appartenant toutes à A ou B) seraient réaffectées à D, et, encore une fois, le reste resterait le même:

Exemple de hachage cohérent 7

CLÉ HACHER ANGLE (DEG)
«D2» 439890723 15,8
«A1» 473914830 17
«A2» 548798874 19,7
«D8» 796709216 28,6
«D1» 1008580939 36,3
«A3» 1466730567 52,8
«D5» 1587548309 57,1
'John' 1633428562 58,7
«B2» 1808009038 65
«B3» 2058758486 74,1
«A7» 2162578920 77,8
«B4» 2660265921 95,7
«D4» 2909395217 104,7
«Kate» 3421657995 123,1
«A5» 3434972143 123,6
«D7» 3567129743 128,4
«B0» 4049028775 145,7
«B8» 4755525684 171,1
«A9» 4769549830 171,7
'Jeanne' 5000799124 180
«B1» 5444659173 196
«D6» 5703092354 205,3
«A6» 6210502707 223,5
«A0» 6511384141 234,4
«B9» 7292819872 262,5
'facture' 7594634739 273,4
«A4» 8047401090 289,7
«D0» 8272587142 297,8
«A8» 8997397092 323,9
«B7» 9038880553 325,3
«D3» 9048608874 325,7
«D9» 9314459653 335,3
«B5» 9368225254 337,2
'B6' 9379713761 337,6
«Steve» 9787173343 352,3
CLÉ HACHER ANGLE (DEG) ÉTIQUETTE SERVEUR
'John' 1632929716 58,7 «B2» B
«Kate» 3421831276 123,1 «A5» À
'Jeanne' 5000648311 180 «B1» B
'facture' 7594873884 273,4 «A4» À
«Steve» 9786437450 352,3 «D2» ré

C'est ainsi que le hachage cohérent résout le problème du ressassement.

En général, seulement k/N les clés doivent être remappées lorsque k est le nombre de touches et N est le nombre de serveurs (plus précisément, le maximum du nombre initial et final de serveurs).

Et ensuite?

Nous avons observé que lors de l'utilisation de la mise en cache distribuée pour optimiser les performances, il peut arriver que le nombre de serveurs de mise en cache change (les raisons peuvent être un plantage du serveur ou la nécessité d'ajouter ou de supprimer un serveur pour augmenter ou diminuer la capacité globale). En utilisant un hachage cohérent pour distribuer les clés entre les serveurs, nous pouvons être assurés que si cela se produisait, le nombre de clés remaniées - et par conséquent, l'impact sur les serveurs d'origine - sera minimisé, évitant ainsi les temps d'arrêt potentiels ou les problèmes de performances.

Il existe des clients pour plusieurs systèmes, tels que Memcached et Redis, qui prennent en charge le hachage cohérent prêt à l'emploi.

Alternativement, vous pouvez implémenter l'algorithme vous-même, dans la langue de votre choix, et cela devrait être relativement facile une fois que le concept est compris.

Si la science des données vous intéresse, ApeeScape a certains des meilleurs articles sur le sujet à la Blog

Comment voyager en travaillant: le guide de survie de l'ingénieur itinérant

Mode De Vie

Comment voyager en travaillant: le guide de survie de l'ingénieur itinérant
Mise en cache au printemps avec les annotations EhCache

Mise en cache au printemps avec les annotations EhCache

Back-End

Articles Populaires
Ingénieur Senior Ruby on Rails
Ingénieur Senior Ruby on Rails
Repenser l'interface utilisateur de la plate-forme TV
Repenser l'interface utilisateur de la plate-forme TV
Soutenir l'offre technologique grâce à l'éducation STEM
Soutenir l'offre technologique grâce à l'éducation STEM
UX personnalisé et puissance du design et de l'émotion
UX personnalisé et puissance du design et de l'émotion
Explication du flux Git amélioré
Explication du flux Git amélioré
 
Un guide sur les moteurs Rails dans la nature: Exemples concrets de moteurs Rails en action
Un guide sur les moteurs Rails dans la nature: Exemples concrets de moteurs Rails en action
Conception d'une VUI - Interface utilisateur vocale
Conception d'une VUI - Interface utilisateur vocale
Huit raisons pour lesquelles Microsoft Stack est toujours un choix viable
Huit raisons pour lesquelles Microsoft Stack est toujours un choix viable
Tirer le meilleur parti des actions - Leçons d'un ancien analyste de recherche
Tirer le meilleur parti des actions - Leçons d'un ancien analyste de recherche
Addiction au rachat d'actions: études de cas de succès
Addiction au rachat d'actions: études de cas de succès
Articles Populaires
  • quels sont les principes du design dans l'art
  • modèle commercial lift vs uber
  • comment faire de l'apprentissage automatique
  • applications mobiles différentes de l'application web
  • est ma llc an s ou c corp
  • plan comptable de l'entreprise manufacturière
  • vous avez obtenu un brevet logiciel pour votre nouvelle application logicielle. cela signifie que:
Catégories
  • La Technologie
  • Personnes Et Équipes
  • Gestion De Projet
  • Équipes Distribuées
  • © 2022 | Tous Les Droits Sont Réservés

    portaldacalheta.pt