Résumé des connaissances de base de rabbitmq!

Programmeur Dabin 2021-09-15 10:04:57
sum des connaissances base rabbitmq


Cet article a été inclus dansgithubEntrepôt,Cet entrepôt est utilisé pour partagerJavaRésumé des connaissances pertinentes,Y compris:JavaBase、MySQL、Spring Boot、MyBatis、Redis、RabbitMQ、Réseau informatique、Structure des données et algorithmes, etc,Bienvenue.prEtstar!

githubAdresse:https://github.com/Tyson0314/Java-learning

SigithubImpossible d'accéder,AccessiblegiteeEntrepôt.

giteeAdresse:https://gitee.com/tysondai/Java-learning

Catalogue des articles:

Introduction

RabbitMQC'est unerlangFiles d'attente de messages développées.Les files d'attente de messages sont utilisées pour la collaboration asynchrone entre les applications.

Concepts de base

Message:Se compose de l'en - tête et du corps du message.Le corps du message est opaque,L'en - tête du message se compose d'une série d'attributs optionnels,Ces propriétés incluentrouting-key、priority、delivery-mode(Stockage persistant ou non)Attendez..

Publisher:Producteur du message.

Exchange:Recevoir des messages et les acheminer vers un ou plusieursQueue.default exchange Est le commutateur direct par défaut,Le nom est une chaîne vide,Chaque nouvelle file d'attente est automatiquement liée au commutateur par défaut,Le nom de la clé de routage liée est le même que le nom de la file d'attente.

Binding:AdoptionBindingOui.ExchangeEtQueueLiens,Voilà.ExchangePour savoir où acheminer le messageQueueMoyenne.

Queue:Stocker les messages,Les caractéristiques de la file d'attente sont FIFO.Un message peut être distribué à une ou plusieurs files d'attente.

Virtual host:Chaque vhost C'est essentiellement un mini Edition RabbitMQ Serveur,Avoir sa propre file d'attente、Commutateur、Mécanismes de liaison et d'autorisation.vhost - Oui. AMQP La base du concept,Doit être spécifié lors de la connexion,RabbitMQ Par défaut vhost - Oui. / .Lorsque plusieurs utilisateurs différents utilisent le mêmeRabbitMQ serverLorsque le service est fourni,Peut être divisé en plusieursvhost,Chaque utilisateur a son proprevhostCréationexchangeEtqueue.

Broker:Entité du serveur de mise en file d'attente des messages.

Quand utiliserMQ

Pour certaines opérations qui ne nécessitent pas d'effet immédiat,Peut être divisé en,Exécution asynchrone,Mise en œuvre en utilisant la file d'attente des messages.

Prenons l'exemple du système de commande commun,La logique d'entreprise après que l'utilisateur clique sur le bouton de commande peut inclure:Réduction des stocks、Générer les documents correspondants、Envoyer une notification par SMS.Dans ce scénario, on peut utiliser MQ .Envoyer une notification SMS à MQ Exécution asynchrone,Dans le processus de commande(Comme réduire les stocks、Générer les documents correspondants)Envoyez un message à MQ, Laissez le processus principal se terminer rapidement,Et consommés par d'autres filsMQMessage de.

Avantages et inconvénients

Inconvénients:UtilisererlangRéalisation,Défavorable au développement et à l'entretien secondaires;Performances plus élevéeskafkaMauvais,Messages persistants etACKLe débit autonome des messages de production et de consommation est d'environ1-2Environ 10 000.,kafkaLe débit d'une seule machine est de 100 000.

Avantages:Il y a une interface de gestion,Facile à utiliser;Haute fiabilité;Riche en fonctionnalités,Prise en charge de la persistance des messages、Mécanisme de confirmation des messages、Plusieurs mécanismes de distribution de messages.

Exchange Type

ExchangeLa distribution des messages varie selon le type de politique de distribution,Il existe actuellement quatre types de:direct、fanout、topic、headers .headers Le mode est basé surheadersRoutage,En outre headers L'interrupteur et direct L'interrupteur est parfaitement cohérent,Mais les performances sont beaucoup plus faibles.

ExchangeLes règles.

Nom du type Description du type
fanout Envoyez tout àExchangeLe message est acheminé vers tous lesQueueMoyenne
direct Routing Key==Binding Key
topic Correspondance floue
headers ExchangeNe dépend pasrouting keyAvecbinding keyRègles de correspondance pour acheminer les messages,Mais selon le contenu du message envoyéheaderLes propriétés correspondent.

direct

directL'échange achemine les messages versbinding key Et routing keyDans une file d'attente parfaitement appariée.Ça correspond parfaitement、Mode Unicast.

fanout

Tous envoyés à fanout Les messages d'un commutateur de type sont acheminés vers toutes les files d'attente liées à ce commutateur.fanout Le type de message transmis est le plus rapide.

topic

topicUtilisation du commutateurrouting keyEtbinding keyFaire une correspondance floue,Une correspondance réussie envoie le message à la file d'attente appropriée.routing keyEtbinding keyCe sont des points“. ”Chaînes séparées,binding keyIl peut y avoir deux caractères spéciaux“*”Avec“#”,Utilisé pour faire une correspondance floue,Parmi eux“*”Utilisé pour correspondre à un mot,“#”Utilisé pour correspondre à plusieurs mots.

headers

headersLe commutateur est basé sur le contenu du message envoyéheadersPropriété pour le routage.En liaisonQueueAvecExchangeSpécifie un ensemble de paires de valeurs clés;Quand le message est envoyé àExchangeHeure,RabbitMQLe message sera reçuheaders(C'est aussi une forme de paire de valeurs clés),Comparez si les paires de clés correspondent exactementQueueAvecExchangePaire de valeurs clés spécifiée lors de la liaison;Si elle correspond exactement, le message est acheminé versQueue,Sinon, il n'y aura pas de route versQueue.

Message manquant

Scénario de perte de message:Message de production du producteur àRabbitMQ ServerMessage manquant、RabbitMQ ServerMessages stockés manquants etRabbitMQ ServerPerte de message au consommateur.

.La perte de message est résolue de trois façons:Mécanisme de reconnaissance des producteurs、Message de confirmation manuelle du consommateur et persistance.

Mécanisme de reconnaissance des producteurs

Le producteur envoie un message à la file d'attente,Impossible de s'assurer que le message envoyé arrive avec succèsserver.

Solutions:

  1. Mécanisme de transaction.L'expéditeur est bloqué après l'envoi d'un message,Attendez.RabbitMQRéponse de,Avant de continuer à envoyer le message suivant.Mauvais rendement.
  2. Ouverture du mécanisme de confirmation du producteur,Tant que le message est envoyé avec succès au commutateur,RabbitMQEt envoyer unackAux producteurs(Même si le message n'est pasQueueRéception,Sera également envoyéack).Si le message n'est pas envoyé avec succès au commutateur,Il envoie un messagenackMessage,Échec de l'envoi de l'invite.

In Springboot C'est par publisher-confirms Paramètres à définir confirm Mode:

spring:
rabbitmq:
#Ouvert confirm Mécanisme de confirmation
publisher-confirms: true

Fournir une méthode de rappel du côté de la production,Lorsque le serveur a confirmé un ou plusieurs messages,Les producteurs vont revenir sur cette méthode,Traitement ultérieur des messages en fonction des résultats spécifiques,Comme envoyer à nouveau、Journal de bord, etc..

// Le message a - t - il été envoyé avec succès àExchange
final RabbitTemplate.ConfirmCallback confirmCallback = (CorrelationData correlationData, boolean ack, String cause) -> {
log.info("correlationData: " + correlationData);
log.info("ack: " + ack);
if(!ack) {
log.info("Gestion des exceptions....");
}
};
rabbitTemplate.setConfirmCallback(confirmCallback);

Le routage ne peut pas atteindre le message

Le mécanisme de confirmation du producteur garantit seulement que le message arrive correctement au commutateur,Pour le routage du commutateur versQueueMessages échoués,Sera jeté,Perte de message.

Pour les messages non routables,Il y a deux traitements:ReturnMécanisme de messagerie et commutateur de sauvegarde.

ReturnMécanisme de messagerie

ReturnLe mécanisme de message fournit une fonction de rappel ReturnCallback,Lorsque le message est acheminé du commutateur versQueueCe n'est qu'en cas d'échec que cette méthode sera rappelée.Il fautmandatory Set to true ,Pour écouter un message inaccessible.

spring:
rabbitmq:
#DéclencheurReturnCallbackVous devez définirmandatory=true, SinonExchangeJe n'ai pas trouvéQueueEt jeter le message, Sans déclencherReturnCallback
template.mandatory: true

Adoption ReturnCallback Le routage d'écoute ne peut pas atteindre le message.

 final RabbitTemplate.ReturnCallback returnCallback = (Message message, int replyCode, String replyText, String exchange, String routingKey) ->
log.info("return exchange: " + exchange + ", routingKey: "
+ routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);
rabbitTemplate.setReturnCallback(returnCallback);

Lorsque le message est acheminé du commutateur versQueueEn cas d'échec,Il reviendra. return exchange: , routingKey: MAIL, replyCode: 312, replyText: NO_ROUTE.

Commutateur de secours

Commutateur de secoursalternate-exchange C'est normal.exchange,Quand vous envoyez un message à votre correspondantexchangeHeure,Ça ne correspond pas àqueue,Sera automatiquement transféré au commutateur de sauvegarde correspondant àqueue,Pour que le message ne soit pas perdu.

Confirmation manuelle du message du consommateur

Il est possible que le consommateur n'ait pas eu le temps de traiter le messageMQLe Service s'est arrêté,Perte de message.Parce que le message par défaut est automatiqueack,Une fois que le consommateur aura reçu le messageMQ ServerCe message a été traité,MQ Ce message sera supprimé.

Solutions:Le consommateur est configuré pour reconnaître manuellement le message.Après que le consommateur a traité la logiquebrokerRéponseack,Indique que le message a été consommé avec succès,Peut être obtenu à partir debrokerSupprimer.Quand la consommation de l'informateur a échoué,Voilà.brokerRéponsenack,En fonction de la configuration, décider de rejoindre l'équipe ou de partir debrokerSupprimer,Ou dans la file d'attente des lettres mortes.Tant que le consommateur n'a pas reçu acknowledgment,broker Et ce message sera toujours sauvegardé,Mais non requeue,Et ne sera pas attribué à d'autres Consommateurs.

Configuration manuelle du consommateurack:

#Réglage manuel du consommateur ack
spring.rabbitmq.listener.simple.acknowledge-mode=manual

Traitement du message terminé,Confirmation manuelle:

 @RabbitListener(queues = RabbitMqConfig.MAIL_QUEUE)
public void onMessage(Message message, Channel channel) throws IOException {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long deliveryTag = message.getMessageProperties().getDeliveryTag();
//Manuelack;Le deuxième paramètre estmultiple,Set totrue,ReprésentationdeliveryTagAvant le numéro de série(Inclure soi - même)Tous les messages ont été reçus,Set tofalsePour recevoir un message
channel.basicAck(deliveryTag, true);
System.out.println("mail listener receive: " + new String(message.getBody()));
}

Lorsque la consommation de messages échoue,Le consommateur donnebrokerRéponsenack,SiconsumerC'est réglé.requeuePourfalse,EtnackAprèsbrokerSupprimera le message ou entrera dans la file d'attente des lettres mortes,Sinon, le message reviendra dans l'équipe.

Persistance

SiRabbitMQUne exception de service a causé un redémarrage,Le message sera perdu.RabbitMQFournit un mécanisme de persistance,Persister les messages en mémoire sur le disque dur,Même redémarrerRabbitMQ,Le message ne sera pas perdu non plus.

La persistance des messages nécessite les conditions suivantes:

  1. Persistance des paramètres du message.Avant de publier un message,Définir le mode de livraisondelivery modePour2,Indique que le message doit être persistant.
  2. QueueDéfinir la persistance.
  3. Persistance des paramètres de commutation.

Quand un message est envoyé au commutateur,RabbitLe message sera d'abord écrit dans le journal de persistance,Avant d'envoyer la réponse au producteur.Une fois qu'un message a été consommé de la file d'attente et confirmé,RabbitMQCe message sera supprimé du Journal de persistance.Avant le message de consommation,SiRabbitMQSi vous redémarrez,Le serveur reconstruira automatiquement les commutateurs et les files d'attente,Charger les messages du Journal de persistance dans la file d'attente ou le commutateur approprié,Garantie que le message ne sera pas perdu.

File d'attente miroir

QuandMQEn cas de défaillance,Cela peut entraîner l'indisponibilité du service.IntroductionRabbitMQMécanisme de file d'attente miroir pour,Oui.queueMiroir sur d'autres noeuds du cluster.Si un noeud du cluster échoue,Possibilité de passer automatiquement à un autre noeud dans le miroir pour assurer la disponibilité du service.

Habituellement, chaque file d'attente miroir contient unmasterEt plusieursslave,Correspond à différents noeuds.Tous les messages envoyés à la file d'attente miroir sont toujours envoyés directement àmasterEt tous lesslaveAu - dessus de.Sauf quepublishTous les mouvements extérieurs ne font quemasterEnvoyer,Puis parmasterDiffuser les résultats de l'exécution de la commande àslave,L'opération de consommation à partir de la file d'attente miroir est en faitmasterMise en œuvre.

Consommation répétée

Les messages sont répétés pour deux raisons:1.Message répété en production,2.Message répété lors de la consommation.

Le producteur envoie un message àMQ,InMQIl y a eu des fluctuations du réseau au moment de la confirmation,Le producteur n'a pas reçu de confirmation,À ce moment - là, le producteur envoie à nouveau le message,CauseMQUn message en double sera reçu.

Après une consommation réussie,Voilà.MQIl y a eu des fluctuations du réseau au moment de la confirmation,MQAucune confirmation reçue,Pour s'assurer que le message n'est pas perdu,MQIl va continuer à envoyer des messages aux consommateurs avant.Le consommateur reçoit alors deux messages identiques.Parce que les messages dupliqués sont dus à des raisons de réseau,Impossible à éviter.

Solutions:Envoyer des messages avec un message unique à l'échelle mondiale pour chaque messageID,Déterminer si le message a été consommé avant de consommer le message,Garantir l'idémpotence de la logique de consommation du message.Le processus de consommation spécifique est:

  1. Après avoir reçu le message, le consommateur commence paridPour vérifierredis/dbLe message existe - t - il?
  2. S'il n'existe pas,Alors la consommation normale,Écrivez après consommationredis/db
  3. Si elle existe,Pour prouver que le message a été consommé,Jeter directement

Limite de courant côté consommateur

Quand RabbitMQ Quand le serveur a un énorme arriéré de messages,Les messages dans la file d'attente vont inonder les consommateurs,Peut provoquer un crash du serveur client.Dans ce cas, il est nécessaire de limiter le courant du côté consommateur.

Spring RabbitMQ Fournir les paramètres prefetch Vous pouvez définir le nombre de messages traités par une seule requête.Si le message que le consommateur traite simultanément atteint son maximum,Le consommateur bloquera,Ne consomme pas de nouvelles nouvelles,Jusqu'à ce qu'il y ait des nouvelles ack Pour consommer de nouvelles informations.

Ouverture de la limite de courant côté consommateur:

#Nombre de messages traités dans une seule demande,unackNombre maximum de
spring.rabbitmq.listener.simple.prefetch=2

Primitive RabbitMQ Également disponible prefetchSize Et global Deux paramètres.Spring RabbitMQSans ces deux paramètres.

//Limite de taille d'un seul message,0La représentation n'est pas limitée
//global:La fonction limit Current estchannelNiveau ouconsumerNiveau.Lorsque défini àfalse,consumerNiveau,La fonction de limitation du courant est en vigueur,Set totrueSans limitation de courant,Parce quechannelNiveau non atteint.
void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException;

File d'attente des lettres mortes

La file d'attente dans laquelle le message de consommation a échoué.

Raison de l'échec de la consommation de messages:

  • Le message a été rejeté et le message n'a pas été repêché(requeue=false)
  • Message timeout not consumed
  • Longueur maximale de la file d'attente atteinte

Configurer la file d'attente des lettres mortes exchange Et queue,Et puis on se lie:

 @Bean
public DirectExchange dlxExchange() {
return new DirectExchange(RabbitMqConfig.DLX_EXCHANGE);
}
@Bean
public Queue dlxQueue() {
return new Queue(RabbitMqConfig.DLX_QUEUE, true);
}
@Bean
public Binding bindingDeadExchange(Queue dlxQueue, DirectExchange deadExchange) {
return BindingBuilder.bind(dlxQueue).to(deadExchange).with(RabbitMqConfig.DLX_QUEUE);
}

Ajoutez deux paramètres à la file d'attente normale,Lier la file d'attente normale à la file d'attente des lettres mortes.Lorsque la consommation de messages échoue,Les messages sont acheminés vers la file d'attente des lettres mortes.

 @Bean
public Queue sendSmsQueue() {
Map<String,Object> arguments = new HashMap<>(2);
// Lier la file d'attente au commutateur de message privé
arguments.put("x-dead-letter-exchange", RabbitMqConfig.DLX_EXCHANGE);
arguments.put("x-dead-letter-routing-key", RabbitMqConfig.DLX_QUEUE);
return new Queue(RabbitMqConfig.MAIL_QUEUE, true, false, false, arguments);
}

Code complet du producteur:

@Component
@Slf4j
public class MQProducer {
@Autowired
RabbitTemplate rabbitTemplate;
@Autowired
RandomUtil randomUtil;
@Autowired
UserService userService;
final RabbitTemplate.ConfirmCallback confirmCallback = (CorrelationData correlationData, boolean ack, String cause) -> {
log.info("correlationData: " + correlationData);
log.info("ack: " + ack);
if(!ack) {
log.info("Gestion des exceptions....");
}
};
final RabbitTemplate.ReturnCallback returnCallback = (Message message, int replyCode, String replyText, String exchange, String routingKey) ->
log.info("return exchange: " + exchange + ", routingKey: "
+ routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);
public void sendMail(String mail) {
//On dirait que les fils ne sont pas sûrs Champ d'application100000 - 999999
Integer random = randomUtil.nextInt(100000, 999999);
Map<String, String> map = new HashMap<>(2);
String code = random.toString();
map.put("mail", mail);
map.put("code", code);
MessageProperties mp = new MessageProperties();
//Dans un environnement de production, il n'est pas nécessaire deMessage,Mais utiliser fastJson Attendre que l'outil Convertit l'objet en json Format envoyer
Message msg = new Message("tyson".getBytes(), mp);
msg.getMessageProperties().setExpiration("3000");
//Si le consommateur doit être réglé manuellement ACK ,Alors le côté production envoie le message correlationData ,Et globalement unique,Pour identifier de façon unique le message.
CorrelationData correlationData = new CorrelationData("1234567890"+new Date());
rabbitTemplate.setMandatory(true);
rabbitTemplate.setConfirmCallback(confirmCallback);
rabbitTemplate.setReturnCallback(returnCallback);
rabbitTemplate.convertAndSend(RabbitMqConfig.MAIL_QUEUE, msg, correlationData);
//Dépôtredis
userService.updateMailSendState(mail, code, MailConfig.MAIL_STATE_WAIT);
}
}

Code complet du consommateur:

@Slf4j
@Component
public class DeadListener {
@RabbitListener(queues = RabbitMqConfig.DLX_QUEUE)
public void onMessage(Message message, Channel channel) throws IOException {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long deliveryTag = message.getMessageProperties().getDeliveryTag();
//Manuelack
channel.basicAck(deliveryTag,false);
System.out.println("receive--1: " + new String(message.getBody()));
}
}

Quand il y a des lettres mortes dans la file d'attente normale,RabbitMQ Ce message sera automatiquement republié dans le commutateur de lettre morte défini,Puis il est acheminé vers la file d'attente des lettres mortes.Vous pouvez écouter les messages dans la file d'attente des lettres mortes et les traiter en conséquence.

Autres

pullMode

pullLe mode passe principalement parchannel.basicGetComment obtenir un message,Voici un exemple de code::

GetResponse response = channel.basicGet(QUEUE_NAME, false);
System.out.println(new String(response.getBody()));
channel.basicAck(response.getEnvelope().getDeliveryTag(),false);

Délai d'expiration du message

Un délai d'expiration peut être fixé pour les messages envoyés par le fabricant,En millisecondes(ms)

Message msg = new Message("tyson".getBytes(), mp);
msg.getMessageProperties().setExpiration("3000");

Vous pouvez également spécifier la file d'attente lors de la création de la file d'attentettl,Calculé à partir du message dans la file d'attente,Les messages qui dépassent ce délai seront supprimés.

Liens de référence

RabbitMQBase

SpringbootIntégrationRabbitMQ

RabbitMQPersistance du message

RabbitMQEnvoyer le Code du message

En lignerabbitmqQuestions

Enfin, partagez ungithubEntrepôt,Il y a200Plusieurs livres informatiques classiques,Y compris:CLangues、C++、Java、Python、Front End、Base de données、Système d'exploitation、Réseau informatique、Structure des données et algorithmes、Apprentissage automatique、Programmer la vie, etc,C'est bon.starUn instant.,La prochaine fois que vous cherchez un livre, cherchez directement dessus,Mise à jour continue de l'entrepôt~

githubAdresse:https://github.com/Tyson0314/java-books

SigithubImpossible d'accéder,AccessiblegiteeEntrepôt.

giteeAdresse:https://gitee.com/tysondai/java-books

版权声明
本文为[Programmeur Dabin]所创,转载请带上原文链接,感谢
https://javamana.com/2021/09/20210915085853018z.html

  1. 10天拿到字節跳動Java崗比特offer,Java知識點思維導圖
  2. 10 jours pour obtenir un Byte Jump Java post offer, Java Knowledge point Mind Map
  3. 10 jours pour obtenir l'octet Jump Java post offer, apprendre les étapes du développement Java
  4. Java version of gppc Reality Three: server side stream
  5. Linux Series: Dites - lui qu'il ne connaît pas kill du tout
  6. "Data structure and algorithm" of front end -- binary search
  7. 2020-2021京东Java面试真题解析,如何才能通过一线互联网公司面试
  8. 13 SpringBoot整合RocketMQ实现过滤消息-根据SQL表达式过滤消息
  9. 12 SpringBoot整合RocketMQ实现过滤消息-根据TAG方式过滤消息
  10. 11 SpringBoot整合RocketMQ实现事务消息
  11. 11 springboot Consolidated rocketmq Implementation transaction message
  12. 12 springboot Consolidated rocketmq Implements Filtering messages - Filtering messages according to tag method
  13. 13 springboot Consolidated rocketmq Implementation Filtering messages - Filtering messages according to SQL expressions
  14. linux系列之:告诉他,他根本不懂kill
  15. (1)java Spring Cloud+Spring boot企业快速开发架构之微服务是什么?它的优缺点有哪些?
  16. Oracle 检查 DATE 列 RANGE 分区表已有分区的最大日期时间
  17. ConcurrentHashMap--原理
  18. 2020 - 2021 JD Java interview Real question Analysis, How can interview through First - Line Internet Company
  19. Concurrenthashmap - - Principes
  20. Oracle vérifie l'heure de date maximale d'une partition existante dans la colonne date
  21. Docker Compose 实践及梳理
  22. Qu'est - ce qu'un microservice pour Java Spring Cloud + Spring Boot Enterprise Quick Development architecture?Quels sont ses avantages et ses inconvénients?
  23. Plus sign interview knowledge points in Java
  24. Pratique et organisation de la composition des dockers
  25. Linux Series: Dites - lui qu'il ne connaît pas kill du tout
  26. Convenient CSS and jQuery drop-down menu solution
  27. Linux analog packet loss rate
  28. Redis:我是如何与客户端进行通信的
  29. 15 useful cron work examples commonly used by Senior Linux system administrators
  30. 24个 JavaScript 循环遍历方法,你都知道吗?
  31. Reading notes of JavaScript advanced programming (3rd Edition) 4
  32. 30分钟学会Docker里面开启k8s(Kubernetes)登录仪表盘(图文讲解)
  33. 24 méthodes de traversée de boucle Javascript, vous savez?
  34. 30 minutes pour apprendre à ouvrir le tableau de bord k8s (kubernets) dans le docker (explication graphique)
  35. Redis: comment je communique avec les clients
  36. Wsl2: Windows native Linux subsystem
  37. 30分钟学会Docker里面开启k8s(Kubernetes)登录仪表盘(图文讲解)
  38. Docker Compose 实践及梳理
  39. Python高级用法总结(8)-函数式编程
  40. 261页前端面试题宝典,JavaScript变量声明提升
  41. The performance of JVM and Java applications of the same version differs by 30% on X86 and aarch64 platforms. Why?
  42. Page 261: dictionnaire des questions d'entrevue de première ligne, promotion de la Déclaration des variables JavaScript
  43. Python Advanced use Summary (8) - functional Programming
  44. Pratique et organisation de la composition des dockers
  45. 30 minutes pour apprendre à ouvrir le tableau de bord k8s (kubernets) dans le docker (explication graphique)
  46. [design pattern series] simple factory
  47. 2021Java最新大厂面试真题,阿里技术专家深入讲解
  48. Java equals and==
  49. Spring5(五)——AOP
  50. 海量列式非关系数据库HBase 原理深入
  51. java collections
  52. 海量列式非關系數據庫HBase 原理深入
  53. Base de données non relationnelle à grande échelle
  54. Printemps 5 (v) - AOP
  55. 2021 le dernier vrai problème d'entrevue d'usine de Java, expliqué en profondeur par les experts techniques d'Ali
  56. Java knowledge structure diagram and thinkinjava PDF file
  57. Do redis transactions satisfy atomicity?
  58. Java programmers must master 10 open source tools!
  59. [Cao Gong's essay] talk about the contract between Maven framework and plug-ins
  60. What books are better for learning Java