ホームページ  >  記事  >  データベース  >  caffeine_redis を使用して 2 次キャッシュをカスタマイズする方法

caffeine_redis を使用して 2 次キャッシュをカスタマイズする方法

WBOY
WBOY転載
2023-05-27 10:08:241199ブラウズ

    質問

    提起された要件に基づいて、主に次の 2 つの質問があると思います。

    • ローカルキャッシュがあるため、データの整合性を確保する方法。あるノードのデータが変更されると、他のノードのデータはどのようにして無効になりますか?

    • データが正しくないため、再同期する必要があります。キャッシュを無効にするにはどうすればよいですか?

    フローチャート

    次のステップでは、製品および他の開発者と協力して、次のようなフローチャートを作成します。

    Use a 構成テーブルには、キャッシュが必要かどうか、および通知時にキャッシュを無効にするためにキャッシュが有効になっているかどうかが記録されます。
    • プロジェクトの要件が一般的なため、メッセージが失われたとしても大きな影響はないため、最終的に無効なメッセージを他のノードに通知するために Redis のサブスクリプションとパブリッシュ機能を選択しました。ローカルキャッシュ。
    • 開発
    上記の質問は明確であり、フローチャートも明確です。次に、バグを書き始める準備をします。全体的な考え方は、アノテーションの実装面をカスタマイズし、ビジネス コードとの結合を減らすことです。

    CacheConfig

    主にコードで説明され、ビジネスと統合するための CacheManager を定義します。プログラム メモリを占有しすぎてメモリがいっぱいになるのを避けるために、キャッシュ可能な項目の最大数に特別な注意を払う必要があります。もちろん、ヒット率の問題も考慮する必要があるため、小さすぎることはできません。したがって、最終的な規模は実際のビジネスに基づいて決定する必要があります。

    @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

    注釈をカスタマイズし、使用可能なパラメータをすべて追加します。

    @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

    キャッシュ リスナーは主に、マルチノード データの一貫性を確保する役割を果たします。ノード キャッシュが更新されると、他のノードはそれを適切に処理するように通知されます。 Redis のパブリッシュおよびサブスクライブ機能を使用し、MessageListener インターフェースを実装して主要なテクノロジーを実装します。

    もちろん、以下のもう 1 つの詳細は、Redis#keys コマンドが一般的な運用環境では無効になっているため、対応するキーを別の方法でスキャンする必要があるということです。

    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

    次にアスペクトの論理処理ですが、要件を実装するためにコードが使用されることを除いて、内部の内容はフローチャートとまったく同じです。

    その中には次のコードがあります。Redis がメッセージを公開するコードです。

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

    CacheMessage

    これは、Redis がメッセージを発行するときのメッセージ本文です。これもカスタマイズされています。さらにパラメーター属性を追加できます

    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;
    	}
    
    }

    以上がcaffeine_redis を使用して 2 次キャッシュをカスタマイズする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。