Berdasarkan keperluan yang dibangkitkan, saya rasa ada dua isu utama:
Kerana ada adalah Cache setempat, bagaimana untuk memastikan konsistensi data. Apabila data satu nod berubah, bagaimanakah data nod lain menjadi tidak sah?
Data tidak betul dan perlu disegerakkan semula. Bagaimana untuk membatalkan cache?
Langkah seterusnya ialah bekerjasama dengan produk dan pembangun lain untuk melukis carta alir, seperti berikut:
Gunakan jadual konfigurasi merekodkan sama ada caching diperlukan dan sama ada caching didayakan untuk mencapai ketidaksahihan cache apabila diberitahu.
Oleh kerana keperluan projek adalah umum, walaupun mesej hilang, tidak akan banyak kesan, jadi saya akhirnya memilih fungsi langganan dan penerbitan dalam redis untuk memberitahu nod lain tidak sah cache tempatan.
Soalan di atas adalah jelas dan carta alir juga jelas. Kemudian bersedia untuk mula menulis pepijat. Idea keseluruhan adalah untuk menyesuaikan aspek pelaksanaan anotasi dan cuba mengurangkan gandingan kepada kod perniagaan.
diterangkan terutamanya dalam kod dan mentakrifkan CacheManager untuk disepadukan dengan perniagaan. Perhatian khusus perlu diberikan kepada bilangan maksimum item boleh cache untuk mengelak daripada menduduki terlalu banyak memori program dan menyebabkan memori menjadi penuh. Sudah tentu, ia tidak boleh terlalu kecil, kerana isu kadar hit juga perlu dipertimbangkan. Oleh itu, saiz akhir mesti ditentukan berdasarkan perniagaan sebenar.
@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; }
Anotasi tersuai, tambah semua parameter yang tersedia.
@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 ""; }
Pendengar cache, terutamanya untuk memastikan konsistensi data berbilang nod. Apabila cache nod dikemas kini, nod lain dimaklumkan untuk mengendalikannya dengan sewajarnya. Gunakan fungsi terbitkan dan langgan Redis dan laksanakan antara muka MessageListener untuk melaksanakan teknologi utama.
Sudah tentu, butiran lain di bawah ialah arahan Redis#keys dilumpuhkan dalam persekitaran pengeluaran umum, jadi anda perlu mengimbas kekunci yang sepadan dengan cara lain.
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 下的都删除 } }
Kemudian terdapat pemprosesan logik aspek tersebut.
Antaranya: Kod berikut ialah mesej penerbitan Redis.
redisTemplate.convertAndSend(CacheConfig.TOPIC, new CacheMessage(caffeineCache.cachaName(), redisKey));
Ini ialah badan mesej apabila Redis menerbitkan mesej Anda juga boleh menambah atribut parameter
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; } }
Atas ialah kandungan terperinci Cara menggunakan caffeine_redis untuk menyesuaikan cache tahap kedua. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!