Rumah  >  Artikel  >  Java  >  Bagaimana untuk memastikan konsistensi cache dalam Java

Bagaimana untuk memastikan konsistensi cache dalam Java

王林
王林ke hadapan
2023-05-02 13:13:161112semak imbas

Pilihan 1: Kemas kini cache, kemas kini pangkalan data

Kaedah ini boleh dihapuskan dengan mudah, kerana jika cache berjaya dikemas kini terlebih dahulu, tetapi kemas kini pangkalan data gagal, ia pasti akan menyebabkan data tidak konsisten.

Pilihan 2: Kemas kini pangkalan data dan kemas kini cache

Strategi kemas kini cache ini biasanya dikenali sebagai tulis dua kali Masalahnya ialah: dalam senario kemas kini pangkalan data serentak, data kotor akan berlaku disiram ke cache

updateDB();
updateRedis();

Contoh: Jika pangkalan data dan cache diubah suai oleh permintaan berikutnya antara dua operasi, mengemas kini cache pada masa ini akan menjadi data tamat tempoh.

Bagaimana untuk memastikan konsistensi cache dalam Java

Pilihan 3: Padam cache dan kemas kini pangkalan data

Terdapat masalah: Sebelum mengemas kini pangkalan data, jika ada permintaan pertanyaan, Data kotor disiram ke cache

deleteRedis();
updateDB();

Contoh: Jika pertanyaan data berlaku antara dua operasi, maka data lama akan dimasukkan ke dalam cache.

Bagaimana untuk memastikan konsistensi cache dalam Java

Penyelesaian ini akan membawa kepada data permintaan yang tidak konsisten

Jika terdapat satu permintaan A untuk operasi kemas kini dan satu lagi permintaan B untuk operasi pertanyaan. Kemudian situasi berikut akan berlaku:

  • Minta A untuk melaksanakan operasi tulis dan memadam cache

  • Minta B untuk bertanya dan mendapati bahawa cache tidak wujud

  • Minta B untuk menanyakan pangkalan data untuk mendapatkan nilai lama

  • Minta B untuk menulis nilai lama ke dalam cache

  • Minta A untuk menulis nilai lama ke dalam cache Apabila nilai baru ditulis ke dalam pangkalan data

situasi di atas akan membawa kepada ketidakkonsistenan . Selain itu, jika anda tidak menetapkan strategi masa tamat tempoh untuk cache, data akan sentiasa menjadi data kotor.

Pilihan 4: Kemas kini pangkalan data dan padamkan cache

Terdapat masalah: Terdapat permintaan pertanyaan sebelum mengemas kini pangkalan data, dan cache tidak sah, pangkalan data akan ditanya, dan kemudian cache akan dikemas kini. Jika operasi kemas kini pangkalan data dilakukan antara menanyakan pangkalan data dan mengemas kini cache, maka data yang kotor akan dibuang ke cache

updateDB();
deleteRedis();

Contoh: Jika terdapat pertanyaan antara pangkalan data dan cache Jika data dikemas kini dan cache dipadamkan semasa operasi, data lama akan dimasukkan ke dalam cache.

Bagaimana untuk memastikan konsistensi cache dalam Java

Andaikan terdapat dua permintaan, satu meminta A melakukan operasi pertanyaan dan satu lagi meminta B melakukan operasi kemas kini, maka situasi berikut akan berlaku

  • Cache baru sahaja tamat tempoh

  • Minta A untuk menanyakan pangkalan data dan mendapatkan nilai lama

  • Minta B untuk tulis nilai baharu ke dalam pangkalan data

  • Minta B untuk memadam cache

  • Minta A untuk menulis nilai lama yang ditemui ke dalam cache

Jika ini berlaku Dalam situasi di atas, data kotor memang akan berlaku. Walau bagaimanapun, terdapat keadaan kongenital untuk situasi di atas berlaku, iaitu menulis operasi pangkalan data mengambil masa yang lebih singkat daripada membaca operasi pangkalan data

Namun, kelajuan operasi membaca pangkalan data adalah lebih cepat. daripada operasi tulis

Jadi keadaan ini sukar berlaku.

Perbandingan Pelan

Kekurangan biasa Pelan 1 dan Pelan 2:

Dalam senario kemas kini pangkalan data serentak, data kotor akan dibuang ke cache, tetapi Secara umumnya, kebarangkalian senario penulisan serentak adalah agak kecil; mengemas kini pangkalan data

    Thread B mengemas kini pangkalan data
  • Thread B mengemas kini cache
  • Thread A mengemas kini cache
  • Kekurangan biasa pilihan 3 dan 4:

  • Tidak kira pesanan mana yang diterima pakai, terdapat beberapa masalah dengan kedua-duanya kaedah:

Masalah kelewatan induk-hamba: Sama ada ia dipadamkan dahulu atau terakhir, kelewatan induk-hamba pangkalan data boleh menyebabkan penjanaan data kotor.

    Gagal pemadaman cache: Jika pemadaman cache gagal, data kotor akan dijana.
  • Idea penyelesaian masalah: tangguhkan pemadaman dua kali, tambah mekanisme cuba semula, diperkenalkan di bawah!
  • Kemas kini cache atau padamkan cache?

1 Mengemas kini cache cache memerlukan kos penyelenggaraan tertentu, dan akan ada masalah dengan kemas kini serentak

    2 terlalu banyak Apabila terdapat sedikit bacaan, permintaan baca belum datang, dan cache telah dikemas kini berkali-kali, yang tidak memainkan peranan cache
  • 3 dalam cache mungkin telah dikira dengan rumit , jika nilai yang ditulis pada cache dikira setiap kali ia dikemas kini, ia adalah satu pembaziran prestasi
  • Memadamkan kelebihan cache. :

    Mudah, kos rendah, mudah dibangunkan; Kelemahan: Akan Menyebabkan kehilangan cache

  • Jika kos mengemas kini cache adalah kecil dan terdapat lebih banyak bacaan dan kurang penulisan, dan pada dasarnya tiada penulisan concurrency, cache boleh dikemas kini Jika tidak, pendekatan umum adalah untuk memadam cache.

总结

方案 问题 问题出现概率 推荐程度
更新缓存 -> 更新数据库 为了保证数据准确性,数据必须以数据库更新结果为准,所以该方案绝不可行 不推荐
更新数据库 -> 更新缓存 并发更新数据库场景下,会将脏数据刷到缓存 并发写场景,概率一般 写请求较多时会出现不一致问题,不推荐使用。
删除缓存 -> 更新数据库 更新数据库之前,若有查询请求,会将脏数据刷到缓存 并发读场景,概率较大 读请求较多时会出现不一致问题,不推荐使用
更新数据库 -> 删除缓存 在更新数据库之前有查询请求,并且缓存失效了,会查询数据库,然后更新缓存。如果在查询数据库和更新缓存之间进行了数据库更新的操作,那么就会把脏数据刷到缓存 并发读场景&读操作慢于写操作,概率最小 读操作比写操作更慢的情况较少,相比于其他方式出错的概率小一些。勉强推荐。

推荐方案

延迟双删

采用更新前后双删除缓存策略

public void write(String key,Object data){
  redis.del(key);
     db.update(data);
     Thread.sleep(1000);
     redis.del(key);
 }
  • 先淘汰缓存

  • 再写数据库

  • 休眠1秒,再次淘汰缓存

大家应该评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上即可。

这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

问题及解法:

1、同步删除,吞吐量降低如何处理

将第二次删除作为异步的,提交一个延迟的执行任务

2、解决删除失败的方式:

添加重试机制,例如:将删除失败的key,写入消息队列;但对业务耦合有些严重;

Bagaimana untuk memastikan konsistensi cache dalam Java

延时工具可以选择:

最普通的阻塞Thread.currentThread().sleep(1000);

Jdk调度线程池,quartz定时任务,利用jdk自带的delayQueue,netty的HashWheelTimer,Rabbitmq的延时队列,等等

实际场景

我们有个商品中心的场景,是读多写少的服务,并且写数据会发送MQ通知下游拿数据,这样就需要严格保证缓存和数据库的一致性,需要提供高可靠的系统服务能力。

写缓存策略

  • 缓存key设置失效时间

  • 先DB操作,再缓存失效

  • 写操作都标记key(美团中间件)强制走主库

  • 接入美团中间件监听binlog(美团中间件)变化的数据在进行兜底,再删除缓存

Bagaimana untuk memastikan konsistensi cache dalam Java

读缓存策略

  • 先判断是否走主库

  • 如果走主库,则使用标记(美团中间件)查主库

  • 如果不是,则查看缓存中是否有数据

  • 缓存中有数据,则使用缓存数据作为结果

  • 如果没有,则查DB数据,再写数据到缓存

Bagaimana untuk memastikan konsistensi cache dalam Java

注意

关于缓存过期时间的问题

如果缓存设置了过期时间,那么上述的所有不一致情况都只是暂时的。

但是如果没有设置过期时间,那么不一致问题就只能等到下次更新数据时解决。

所以一定要设置缓存过期时间

Atas ialah kandungan terperinci Bagaimana untuk memastikan konsistensi cache dalam Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam