Optimisation des performances Java pour créer un système de pointe de trafic d'un milliard de niveaux: 4. Optimisation des performances des requêtes: mise en cache multi-machines

4. Optimisation des performances des requêtes: mise en cache multi-machines

1. Objectifs d'apprentissage:

Dans la section précédente, grâce à l'expansion horizontale du serveur, le déploiement d'applications sur plusieurs machines pour traiter les requêtes a grandement amélioré le TPS, mais ces multiples bases de données utilisent toujours la base de données de la même machine.
Ensuite, certaines techniques d'optimisation des requêtes seront utilisées pour compléter la solution d'optimisation des requêtes pour la page de détails du produit.

  • Comprenez la définition du cache à plusieurs niveaux
  • Cache redis maître, cache local
  • Maîtrisez le cache chaud nginx lux

2. Présentation des principes de conception de cache

  • Cache pour utiliser l'équipement d'accès rapide, la mémoire
  • Poussez le cache à l'endroit le plus proche de l'utilisateur pour réduire la latence du réseau
  • Nettoyage du cache sale. Une fois la base de données modifiée, les anciennes données du cache indiquent 脏缓存comment nettoyer et la stratégie de nettoyage

** Cache à plusieurs niveaux **

  • cache redis
  • Données chaudes, cache mémoire local
  • cache de cache proxy nginx
  • cache nginx lua

Troisièmement, introduction du cache centralisé Redis

Voir ci-dessus pour l'installation, le principe, la gestion de session et la gestion des jetons.
Base de données au format clé-valeur.
memorycatch est une base de données mémoire complète.
Redis peut vider les données sur le disque, ce qui permet une certaine perte. Il est généralement considéré comme un stockage volatil.

Pourquoi la mise en cache centralisée?

Une fois le serveur d'applications étendu horizontalement, il est connecté au même serveur Redis.
image.png

1. Version autonome

Goulot d'étranglement en cas de panne, limite de capacité supérieure
image.png

2. mode sentinelle sentinale

Insérez la description de l'image ici

redis2 est le redis de sauvegarde esclave de redis1, et les modifications sur redis sont synchronisées avec redis2 pour la sauvegarde.
Mais lorsque la partie redis1 se bloque, il se peut que le serveur d'applications demande automatiquement des services à redis2, mais comme l'environnement concurrent est trop compliqué, il est difficile pour le serveur d'applications de percevoir que redis2 est en panne. D'où le mode sentinelle.

Lors de sa première utilisation, le serveur d'application demande d'abord à sentinel, quel redis doit être utilisé, la sentinelle répond et informe, le serveur d'application demande ensuite redis.
L'outil sentinelle établit un mécanisme de battement de cœur avec redis. Toute situation qui provoque la déconnexion du battement de cœur, sentinel la considère comme un échec de redis1. Envoyez une commande pour changer redis2 en maître et redis1 en esclave, et informez le serveur d'applications de changer (comme illustré dans la figure ci-dessous).

image.png

3. Mode cluster de cluster

Les lacunes du mode sentinelle sont également évidentes: dans le même temps, un seul redis fournit des services au monde extérieur.
Avant le cluster, utilisez la fragmentation et la séparation en lecture-écriture:
Insérez la description de l'image ici

Mais lorsque redis5 est ajouté, diverses migrations de données complexes sont nécessaires. L'évolutivité est encore médiocre.
Par conséquent, le mode cluster est apparu:
redis 2 lectures et 2 écritures. Et élisez automatiquement le maître et l'esclave. Et chaque redis connaît toutes les relations. Et envoyez cette table de routage relationnelle au serveur d'applications, et le serveur d'applications conserve les informations de fragmentation dans sa propre mémoire.
Lorsque redis3 échoue, l'état est automatiquement redistribué via le mécanisme Parker et les fragments de hachage sont automatiquement réajustés.
Mais il existe toujours une liste de routage de fragments incorrecte dans le serveur d'applications. Lorsque le serveur d'application trouve des données demandées par redis2 selon la liste d'erreurs, redis2 constate que la clé demandée par le serveur n'appartient pas à la catégorie de gestion après ajustement, et renvoie une demande de réexamen au serveur pour laisser le serveur re-pull la dernière table de routage des fragments.
Insérez la description de l'image ici
image.png
Ces trois modèles ont été jedisréalisés.

Quatrièmement, page de détails du produit de cache centralisé Redis

Au niveau de la couche contrôleur, les informations détaillées sont mises en cache et aucun appel de service en aval n'est effectué. Réduisez la dépendance à la base de données.
image.png

Mais le code brouillé après avoir été sérialisé par redis lui-même
Insérez la description de l'image ici

La méthode de sérialisation des valeurs de clé par défaut a été modifiée pour en faciliter la lecture.
image.png

Cinq, cache de hotspot local

Autrement dit, le local du serveur JVM

  • Données chaudes
  • Les lectures incorrectes sont très insensibles. Une fois la base de données modifiée, un grand nombre de données de cache incorrectes seront lues sans le savoir

Il peut être mis à jour via MQ, mais les gains l'emportent sur les pertes.

  • La mémoire est contrôlable et précieuse

Uniquement en tant qu'accès instantané, le temps effectif du cache est donc très court.

Doit prendre en charge la lecture et l'écriture simultanées. Un simple hashmap ne peut pas être satisfait. Il peut également être éliminé par des stratégies telles que LRU, et la KEY est automatiquement invalidée en fonction du temps.

atteindre:

Cache de goyave

  • Taille et délai d'expiration contrôlables uniquement
  • Stratégie lru configurable
  • Fil sûr

image.png

@Service
public class CacheServiceImpl implements CacheService {
    
    

    private Cache<String,Object> commonCache = null;

    @PostConstruct
    public void init(){
    
    
        commonCache = CacheBuilder.newBuilder()
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存中最大可以存储100个KEY,超过100个之后会按照LRU的策略移除缓存项
                .maximumSize(100)
                //设置写缓存后多少秒过期
                .expireAfterWrite(60, TimeUnit.SECONDS).build();
    }

    @Override
    public void setCommonCache(String key, Object value) {
    
    
            commonCache.put(key,value);
    }

    @Override
    public Object getFromCommonCache(String key) {
    
    
        return commonCache.getIfPresent(key);
    }
}

Augmentez 1000TPS.

六 、 Prise de proxy Nginx

  • Proxy catch ne peut être utilisé que lorsque le proxy inverse nginx est pré-activé
  • Fiez-vous aux fichiers au niveau de l'index du système de fichiers pour terminer l'opération de cache
  • Fiez-vous à la mémoire pour mettre en cache les adresses des fichiers

Mais comme il stocke le cache dans le système de disque local au lieu de dans la mémoire, le QPS n'a pas été considérablement amélioré, et il est encore plus bas que les performances du cache local jvm. Le délai moyen est plus long.

Sept, principe de Nginx Lua

  • Mécanisme Lua Coroutine

Dans la station spatiale de thread, en s'appuyant sur le thread, selon la simulation de l'utilisateur

  • Mécanisme de coroutine Nginx

Pas besoin de considérer le modèle de programmation asynchrone

  • point de plug-in nginx lua
  • OpenResty

1. Mécanisme Coroutine

  • Dépend du modèle de mémoire de thread, faible surcharge de commutation
  • En cas de blocage, le droit d'exécution sera restitué à temps, et le code sera synchronisé
  • Pas besoin de verrouiller

image.png

2. coroutine de Nginx

  • Chaque processus de travail de nginx est encapsulé dans une coroutine au-dessus du modèle d'événement d'epoll ou de kqueue.

lorsque

  • Chaque demande est traitée par une coroutine
  • Même si ngx_lua exécute lua, il a une certaine surcharge par rapport à c, mais il peut toujours garantir une concurrence élevée.

3. Mécanisme de coroutine Nginx

  • Chaque processus de travail de nginx crée une machine virtuelle lua. Utilisé pour exécuter des fichiers lua
  • Toutes les coroutines du processus de travail partagent la même VM
  • Chaque requête externe est traitée par une coroutine lua, avec isolation des données entre elles
  • Lorsque le code lua appelle des interfaces asynchrones telles que io, la coroutine est suspendue et les données de contexte restent inchangées
  • Enregistrez automatiquement, sans bloquer le processus de travail
  • Une fois l'opération asynchrone io terminée, le contexte coroutine est restauré et le code continue de s'exécuter. Autrement dit, le code est une programmation synchrone, ce qui est relativement simple.

C'est-à-dire qu'après réception de la requête HTTP, une coroutine Lua est allouée pour la traiter, mais lorsque le proxy inverse doit attendre que le serveur principal renvoie des données, par exemple, il place le handle de socket dans la file d'attente d'écoute epoll et se bloque. Continuez à exécuter d'autres coroutines. Lorsque le serveur principal revient, epoll écoutera, puis la coroutine se réveillera pour traiter les opérations de réponse suivantes.
Pour cette raison, les données entre chaque coroutine sont isolées.
Nginx est un worker est un thread, et il y a de nombreuses coroutines en dessous. Le traitement série est entièrement basé sur la coroutine.
Lorsqu'un servlet java traite une requête http, il s'agit d'une requête et un thread est alloué pour la gérer.

4. Étape de traitement Nginx

Insérez la description de l'image ici

5. Point de montage Nginx lua

Insérez la description de l'image ici

Insérez la description de l'image ici

6.OpenResty

  • Avec l'aide du modèle événementiel de Nginx et des E / S non bloquantes, des applications Web hautes performances peuvent être réalisées.
  • Un grand nombre de composants tels que Mysql, redis, memcache, etc. sont fournis pour faciliter le développement d'applications Web sur nginx.

(1) bonjour le monde

image.png
Autrement dit, lors de la visite de helloworld, le résultat de la visite de / item / get? Id = 6 est renvoyé.

(2) dic partagé

Dictionnaire de mémoire partagée, visible par tous les processus de travail

Dictionnaire de mémoire similaire à guaua catch, et prend en charge l'élimination de lru

Mais il a des limitations de mémoire.
et donc

(3) Prise en charge d'Openresty redis

Nginx est certainement plus lent à lire à partir de redis qu'à partir de dic partagé.
Insérez la description de l'image ici

Le mécanisme de mise à jour est omis sur nginx, ce qui permet aux serveurs d'applications en aval de se mettre à jour, et nginx est en lecture seule et n'écrit pas.
Nginx peut percevoir les données dans Redis en temps réel et peut éviter une lecture sale.
Insérez la description de l'image ici

Par conséquent, nginx ne peut stocker que les données à chaud dans son propre cache mémoire, et les données non à chaud lisent l'esclave redis.

8. Résumé

Plus le système est proche de l'amont, plus les ressources système occupées par le cache sont chères, plus le mécanisme de mise à jour correspondant est difficile et plus les performances sont élevées.
Par conséquent, il n'y a pas de schéma de mise en cache général unifié et il est nécessaire de déterminer le schéma de mise en cache pour les demandes dynamiques en fonction du scénario métier réel, du degré de tolérance pour les lectures modifiées et du degré de données chaudes.

Je suppose que tu aimes

Origine blog.csdn.net/xiaohaigary/article/details/108010966
conseillé
Classement