Maison  >  Article  >  base de données  >  Comment utiliser caffeine_redis pour personnaliser le cache de deuxième niveau

Comment utiliser caffeine_redis pour personnaliser le cache de deuxième niveau

WBOY
WBOYavant
2023-05-27 10:08:241199parcourir

    Questions

    Sur la base des exigences soulevées, je pense qu'il y a deux problèmes principaux :

    • Comment assurer la cohérence des données car il existe un cache local. Lorsque les données d’un nœud changent, comment les données des autres nœuds deviennent-elles invalides ?

    • Les données sont incorrectes et doivent être resynchronisées Comment invalider le cache ?

    Organigramme

    L'étape suivante consiste à coopérer avec le produit et d'autres développeurs pour dessiner un organigramme, comme suit :

    • Utilisez un tableau de configuration pour enregistrer si la mise en cache est nécessaire et si la mise en cache est activée pour obtenir une notification de échec du cache.

    • Parce que les exigences du projet sont moyennes, même si le message est perdu, il n'y aura pas beaucoup d'impact, j'ai donc finalement choisi les fonctions d'abonnement et de publication dans redis pour avertir les autres nœuds d'un cache local invalide.

    Développement

    Les questions ci-dessus sont claires, et l'organigramme est également clair. Alors préparez-vous à commencer à écrire des bugs. L'idée générale est de personnaliser les aspects d'implémentation des annotations et d'essayer de réduire le couplage avec le code métier.

    CacheConfig

    est principalement expliqué dans le code, définissant un CacheManager à intégrer au business. Une attention particulière doit être accordée au nombre maximum d'éléments pouvant être mis en cache pour éviter d'occuper trop de mémoire de programme et de provoquer une saturation de la mémoire. Bien entendu, il ne peut pas être trop petit, car la question du taux de réussite doit également être prise en compte. Par conséquent, la taille finale doit être déterminée en fonction de l’activité réelle.

    @Bean(name = JKDDCX)
    @Primary
    public CacheManager cacheManager() {
         CaffeineCacheManager cacheManager  = new CaffeineCacheManager();
            cacheManager.setCaffeine(Caffeine.newBuilder()
                    // 设置最后一次写入或访问后经过固定时间过期
                    .expireAfterAccess(EXPIRE, TIME_UNIT)
                    //设置本地缓存写入后过期时间
                    .expireAfterWrite(EXPIRE, TIME_UNIT)
                    // 初始的缓存空间大小
                    .initialCapacity(500)
                    // 缓存的最大条数
                    .maximumSize(1000));// 使用人数 * 5 (每个人不同的入参 5 条)\
      return cacheManager;
    }

    @CaffeineCache

    Annotation personnalisée, ajoutez tous les paramètres disponibles.

    @Target({ ElementType.METHOD ,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CaffeineCache {
    
         public String moudleId() default "";
        
         //用于在数据库中配置参数
         public String methodId() default "";
         public String cachaName() default "";
        
         //动态切换实际的 CacheManager
         public String cacheManager() default "";
    
    }

    CacheMessageListener

    L'écouteur de cache est principalement chargé d'assurer la cohérence des données multi-nœuds. Lorsqu'un cache de nœuds est mis à jour, les autres nœuds sont informés de le gérer en conséquence. Utilisez la fonction de publication et d'abonnement de Redis et implémentez l'interface MessageListener pour implémenter la technologie principale.

    Bien sûr, un autre détail ci-dessous est que la commande Redis#keys est désactivée dans les environnements de production généraux, vous devez donc scanner les clés correspondantes d'une autre manière.

    public class CacheMessageListener implements MessageListener {
         @Override
        public void onMessage(Message message, byte[] pattern) {
            CacheMessage cacheMessage = (CacheMessage) redisTemplate.getValueSerializer().deserialize(message.getBody());
            logger.info("收到redis清除缓存消息, 开始清除本地缓存, the cacheName is {}, the key is {}", cacheMessage.getCacheName(), cacheMessage.getKey());
    //		redisCaffeineCacheManager.clearLocal(cacheMessage.getCacheName(), cacheMessage.getKey());
    
            /**
             * 如果是一个类上使用了 注解 @CaffeineCache ,那么所有接口都会缓存。
             * 下面的逻辑是:除了当前模块的接口访问的入参 key,其他的 redis 缓存都会被清除
             * (比如此模块的表更新了,但是当前调用此接口只是缓存了当前这个入参的redis,其他的数据删除)
             */
            String prefixKey = RedisConstant.WXYMG_DATA_CACHE + cacheMessage.getCacheName();
            Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
                Set<String> keysTmp = new HashSet<>();
                Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder().
                        match(prefixKey + "*").
                        count(50).build());
                while (cursor.hasNext()) {
                    keysTmp.add(new String(cursor.next()));
                }
                return keysTmp;
            });
            Iterator iterator = keys.iterator();
            while (iterator.hasNext()) {
                if (iterator.next().toString().equals(cacheMessage.getKey())) {
                    iterator.remove();
                }
            }
            redisTemplate.delete(keys);
    
            cacheConfig.cacheManager().getCache(cacheMessage.getCacheName()).clear(); //cacheName 下的都删除
        }
    }

    CaffeineCacheAspect

    Ensuite, il y a le traitement logique de l'aspect. Le contenu à l'intérieur est exactement le même que l'organigramme, mais le code est utilisé pour implémenter les exigences.

    Parmi eux : Le code suivant est celui de la publication de messages Redis.

    redisTemplate.convertAndSend(CacheConfig.TOPIC, new CacheMessage(caffeineCache.cachaName(), redisKey));

    CacheMessage

    Il s'agit d'un corps de message lorsque Redis publie un message. Il est également personnalisé et peut ajouter plus d'attributs de paramètres

    public class CacheMessage implements Serializable {
    
    	private static final long serialVersionUID = -1L;
    
    	private String cacheName;
    
    	private Object key;
    
    	public CacheMessage(String cacheName, Object key) {
    		super();
    		this.cacheName = cacheName;
    		this.key = key;
    	}
    
    }
    .

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer