À propos de l'auteur
En bref, responsable du développement back-end de Ctrip, axé sur l'architecture technique, l'optimisation des performances, la planification des transports et d'autres domaines.
En raison des limites de la planification des transports et des ressources de transport, il se peut qu'il n'y ait pas de transport direct entre les deux lieux demandés par l'utilisateur, ou pendant les grandes vacances, le transport directa été épuisé. Cependant, les utilisateurs peuvent toujours atteindre leur destination via des transferts bidirectionnels ou multidirectionnels tels que des trains, des avions, des voitures, des navires, etc. De plus, le transport par transfert est parfois plus avantageux en termes de prix et de consommation de temps. Par exemple, de Shanghai à Yuncheng, la correspondance en train peut être plus rapide et moins chère qu'un train direct.
Figure 1 Liste de transport de transfert en train Ctrip
Lors de la fourniture de solutions de transport de transfert, un lien très important est de fusionner deux ou plusieurs voyages de trains, avions, voitures, navires, etc. en un transfert réalisable plan. La première difficulté du raccordement du trafic de transit est que l'espace de raccordement est énorme. En considérant simplement Shanghai comme une ville de transit, près de 100 millions de combinaisons peuvent être générées. Une autre difficulté réside dans l'exigence de performances en temps réel, car les données de la chaîne de production changent en même temps. à tout moment et doit être constamment mis à jour. Interrogez les données sur les trains, les avions, les voitures et les navires. L'épissage du trafic de transit nécessite beaucoup de ressources informatiques et de surcharge d'E/S, il est donc particulièrement important d'optimiser ses performances.
Cet article utilisera des exemples pour présenter les principes, les méthodes d'analyse et d'optimisation suivies dans le processus d'optimisation des performances d'épissage du trafic de transfert, dans le but de fournir aux lecteurs une référence et une inspiration précieuses.
2. Principes d'optimisationL'optimisation des performances nécessite d'équilibrer et de faire des compromis entre diverses ressources et contraintes dans le but de répondre aux besoins de l'entreprise. Plus précisément, les trois principes suivants sont principalement suivis lors du processus d'optimisation de l'épissage du trafic de transfert :
2.1 L'optimisation des performances est un moyen plutôt qu'une finBien que cet article porte sur l'optimisation des performances, il doit encore être souligné au début : Ne le faites pas pour l'optimisation Et optimiser. Il existe de nombreuses façons de répondre aux besoins de l'entreprise, et l'optimisation des performances n'est que l'une d'entre elles. Parfois, le problème est très complexe et il existe de nombreuses restrictions. Sans affecter de manière significative l’expérience utilisateur, réduire l’impact sur les utilisateurs en assouplissant les restrictions ou en adoptant d’autres processus est également un bon moyen de résoudre les problèmes de performances. Dans le développement de logiciels, il existe de nombreux exemples de réductions de coûts significatives obtenues en sacrifiant une petite quantité de performances. Par exemple, l'algorithme HyperLogLog utilisé pour les statistiques de cardinalité (suppression des duplications) dans Redis ne nécessite que 12 Ko d'espace pour compter 264 données avec une erreur standard de 0,81 %.
Retour au problème lui-même, en raison de la nécessité d'interroger fréquemment les données de la chaîne de production et d'effectuer des opérations d'épissage massives, si chaque utilisateur doit renvoyer immédiatement le plan de transfert le plus récent lors de l'interrogation, le coût sera très élevé. Pour réduire les coûts, il faut trouver un équilibre entre temps de réponse et fraîcheur des données. Après un examen attentif, nous choisissons d'accepter les incohérences de données au niveau minute. Pour certains itinéraires et dates impopulaires, il se peut qu'il n'y ait pas de bon plan de transfert lors de la première requête. Dans ce cas, il suffit de guider l'utilisateur pour actualiser la page.
2.2 Une optimisation incorrecte est la racine de tous les mauxDonald Knuth mentionné dans "Programmation structurée avec instructions Go To" : "Les programmeurs perdent beaucoup de temps à réfléchir et à s'inquiéter des performances des chemins non critiques, et essaient L'optimisation de cette partie des performances aura un impact négatif très sérieux sur le débogage et la maintenance du code global, donc dans 97% des cas, il faudra oublier les petits points d'optimisation." En bref, avant que le véritable problème de performances ne soit découvert, une optimisation excessive et ostentatoire au niveau du code non seulement n’améliorera pas les performances, mais pourrait également conduire à davantage d’erreurs. Cependant, l'auteur a également souligné : « Pour les 3 % critiques restants, nous ne devons pas manquer l'occasion d'optimiser ». Par conséquent, vous devez toujours prêter attention aux problèmes de performances, ne pas prendre de décisions qui affecteront les performances et effectuer les optimisations correctes si nécessaire.
Comme mentionné dans la section précédente, avant d'optimiser, nous devons d'abord quantifier les performances et identifier les goulots d'étranglement, afin que l'optimisation peut être mieux Être ciblé. L'analyse quantitative des performances peut utiliser une surveillance chronophage, des outils d'analyse des performances Profiler, des outils de test de référence, etc., en se concentrant sur les domaines qui prennent particulièrement beaucoup de temps ou ont une fréquence d'exécution particulièrement élevée. Comme le dit la loi d'Amdahl : « Le degré d'amélioration des performances du système qui peut être obtenu en utilisant une méthode d'exécution plus rapide pour un certain composant du système dépend de la fréquence à laquelle cette méthode d'exécution est utilisée, ou de la proportion du temps d'exécution total. "
De plus, il est également important de noter que l'optimisation des performances est une bataille de longue haleine. À mesure que l'entreprise continue de se développer, l'architecture et le code évoluent constamment. Il est donc encore plus nécessaire de quantifier en permanence les performances, d'analyser en permanence les goulots d'étranglement et d'évaluer les effets d'optimisation.
Avant l'analyse des performances, nous doit d'abord trier le processus commercial. L'épissage des solutions de transport par transfert comprend principalement les quatre étapes suivantes :
a Le chargement de la feuille d'itinéraire, comme Pékin à Shanghai via le transfert de Nanjing, ne prend en compte que les informations de. l'itinéraire lui-même et les vols spécifiques ne sont pas pertinents ;
b. Vérifiez les données de la chaîne de production des trains, des avions, des voitures et des navires, y compris l'heure de départ et l'heure d'arrivée. , gare de départ, gare d'arrivée, prix et informations sur les billets restants, etc.
c. être trop court pour éviter de ne pas pouvoir terminer le transfert en même temps ; il ne doit pas être trop long pour éviter d'attendre trop longtemps ; Après avoir assemblé une solution réalisable, vous devez encore améliorer les champs commerciaux, tels que le prix total, la consommation de temps totale et les informations de transfert
d ; règles, parmi toutes les solutions de transfert réalisables, certaines solutions susceptibles d'intéresser les utilisateurs sont sélectionnées.
(1) Augmenter la surveillance chronophage# 🎜 🎜#
Le suivi chronophage est le moyen le plus intuitif d'observer la situation chronophage de chaque étape d'un point de vue macro. Il peut non seulement visualiser la valeur et la proportion de temps consommé à chaque étape du processus métier, mais également observer la tendance aux changements chronophages sur une longue période de temps.
Une surveillance chronophage peut utiliser le système de surveillance et d'alarme des indicateurs internes de l'entreprise pour ajouter une gestion fastidieuse au processus principal de connexion des solutions de transport en commun. Ces processus incluent le chargement des cartes d'itinéraire, l'interrogation des données d'équipe et leur épissage, le filtrage et l'enregistrement des plans d'épissage, etc. La situation chronophage de chaque étape est illustrée dans la figure 2. On peut voir que l'épissage (y compris les données de la chaîne de production) prend la plus grande proportion de temps, il est donc devenu un objectif d'optimisation clé à l'avenir.
Figure 2 Surveillance fastidieuse de l'épissage du trafic de transit
# 🎜 🎜#(2) Analyse des performances du Profiler
Une gestion chronophage peut envahir le code métier et avoir un impact sur les performances, ce n'est donc pas trop approprié, plus adapté à la surveillance des processus principaux. L'outil d'analyse des performances du Profiler correspondant (tel qu'Async-profiler) peut générer une arborescence d'appels plus spécifique et le taux d'utilisation du processeur de chaque fonction, aidant ainsi à analyser et à localiser les chemins critiques et les goulots d'étranglement des performances.Figure 3 Arbre d'appels d'épissage et ratio CPU
# 🎜 🎜#Comme le montre la figure 3, la solution d'épissage (combineTransferLines) représente 53,80 % et les données de la ligne de production de requêtes (querySegmentCacheable, cache utilisé) représentent 21,45 %. Dans le schéma d'épissage, le calcul du score du schéma (computeTripScore, représentant 48,22 %), la création de l'entité du schéma (buildTripBO, représentant 4,61 %) et la vérification de la faisabilité de l'épissage (checkCombineMatchCondition, représentant 0,91 %) sont les trois liens les plus importants.
Figure 4 Arbre d'appels de notation de solution et ratio CPU
En poursuivant l'analyse du score du plan de calcul (computeTripScore) avec la proportion la plus élevée, nous avons constaté qu'il est principalement lié à la fonction de formatage de chaîne personnalisée (StringUtils.format), y compris les appels directs (utilisés pour afficher les détails du score du plan), et appels indirects via getTripId Call (l'ID utilisé pour générer le schéma). La proportion la plus élevée de StringUtils.format personnalisé est java/lang/String.replace. Le remplacement de chaîne natif de Java 8 est implémenté via des expressions régulières, ce qui est relativement inefficace (ce problème a été amélioré après Java 9).
// 计算方案评分(computeTripScore) 中调用的StringUtils.format代码示例 StringUtils.format("AAAA-{0},BBBB-{1},CCCC-{2},DDDD-{3},EEEE-{4},FFFF-{5},GGGG-{6},HHHH-{7},IIII-{8},JJJJ-{9}", aaaa, bbbb, cccc, dddd, eeee, ffff, gggg, hhhh, iiii, jjjj) // getTripId 中调用StringUtils.format代码示例 StringUtils.format("{0}_{1}_{2}_{3}_{4}_{5}_{6}", aaaa, bbbb, cccc, dddd, eeee, ffff) // 通过Java replace实现的自定义format函数 public static String format(String template, Object... parameters) { for (int i = 0; i < parameters.length; i++) { template = template.replace("{" + i + "}", parameters[i] + ""); } return template; }
(3) Test de référence Benchmark
Avec l'aide de l'outil de référence Benchmark, vous pouvez mesurer le temps d'exécution de votre code avec plus de précision. Dans le tableau 1, nous utilisons JMH (Java Microbenchmark Harness) pour effectuer des tests fastidieux sur trois méthodes de formatage de chaînes et une méthode d'épissage de chaînes. Les résultats des tests montrent que le formatage de chaîne à l'aide de la méthode de remplacement de Java8 offre les pires performances, tandis que l'utilisation de la fonction d'épissage de chaîne d'Apache offre les meilleures performances.
Tableau 1 Comparaison des performances du formatage et de l'épissage des chaînes
implémentation | temps moyen (nous) pour 1000 exécutions |
StringUtils .format implémenté à l'aide du remplacement | 1988.982 |
StringUtils de Java8.format implémenté à l'aide du remplacement Apache | 656. |
Java8 est livré avec String. format | 1417.474 |
Apache's StringUtils.join | 116.812 |