国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Jadual Kandungan
1、讀請(qǐng)求長時(shí)阻塞
2、讀請(qǐng)求并發(fā)量過高
3、多服務(wù)實(shí)例部署的請(qǐng)求路由
4、熱點(diǎn)商品的路由問題,導(dǎo)致請(qǐng)求的傾斜
Rumah Java JavaAsas java實(shí)現(xiàn)保證緩存與數(shù)據(jù)庫的雙寫的一致性

java實(shí)現(xiàn)保證緩存與數(shù)據(jù)庫的雙寫的一致性

Dec 30, 2020 pm 05:51 PM
mysql sql pangkalan data

java基礎(chǔ)教程欄目保證緩存與數(shù)據(jù)庫的雙寫的一致性

java實(shí)現(xiàn)保證緩存與數(shù)據(jù)庫的雙寫的一致性

請(qǐng)?zhí)鹉愕念^,我的公主,不然皇冠會(huì)掉下來的。

分布式緩存是現(xiàn)在很多分布式應(yīng)用中必不可少的組件,但是用到了分布式緩存,就可能會(huì)涉及到緩存與數(shù)據(jù)庫雙存儲(chǔ)雙寫,你只要是雙寫,就一定會(huì)有數(shù)據(jù)一致性的問題,那么你如何解決一致性問題?

Cache Aside Pattern

最經(jīng)典的緩存+數(shù)據(jù)庫讀寫的模式,就是 Cache Aside Pattern。 ?
讀的時(shí)候,先讀緩存,緩存沒有的話,就讀數(shù)據(jù)庫,然后取出數(shù)據(jù)后放入緩存,同時(shí)返回響應(yīng)。

更新的時(shí)候,先更新數(shù)據(jù)庫,然后再刪除緩存。

為什么是刪除緩存,而不是更新緩存?

原因很簡單,很多時(shí)候,在復(fù)雜點(diǎn)的緩存場景,緩存不單單是數(shù)據(jù)庫中直接取出來的值。

比如可能更新了某個(gè)表的一個(gè)字段,然后其對(duì)應(yīng)的緩存,是需要查詢另外兩個(gè)表的數(shù)據(jù)并進(jìn)行運(yùn)算,才能計(jì)算出緩存最新的值的。

另外更新緩存的代價(jià)有時(shí)候是很高的。是不是說,每次修改數(shù)據(jù)庫的時(shí)候,都一定要將其對(duì)應(yīng)的緩存更新一份?也許有的場景是這樣,但是對(duì)于比較復(fù)雜的緩存數(shù)據(jù)計(jì)算的場景,就不是這樣了。如果你頻繁修改一個(gè)緩存涉及的多個(gè)表,緩存也頻繁更新。但是問題在于,這個(gè)緩存到底會(huì)不會(huì)被頻繁訪問到?

舉個(gè)栗子,一個(gè)緩存涉及的表的字段,在 1 分鐘內(nèi)就修改了 20 次,或者是 100 次,那么緩存更新 20 次、100 次;但是這個(gè)緩存在 1 分鐘內(nèi)只被讀取了 1 次,有大量的冷數(shù)據(jù)。實(shí)際上,如果你只是刪除緩存的話,那么在 1 分鐘內(nèi),這個(gè)緩存不過就重新計(jì)算一次而已,開銷大幅度降低,用到緩存才去算緩存。

其實(shí)刪除緩存,而不是更新緩存,就是一個(gè) lazy 計(jì)算的思想,不要每次都重新做復(fù)雜的計(jì)算,不管它會(huì)不會(huì)用到,而是讓它到需要被使用的時(shí)候再重新計(jì)算。像 mybatis,hibernate,都有懶加載思想。查詢一個(gè)部門,部門帶了一個(gè)員工的 list,沒有必要說每次查詢部門,都里面的 1000 個(gè)員工的數(shù)據(jù)也同時(shí)查出來啊。80% 的情況,查這個(gè)部門,就只是要訪問這個(gè)部門的信息就可以了。先查部門,同時(shí)要訪問里面的員工,那么這個(gè)時(shí)候只有在你要訪問里面的員工的時(shí)候,才會(huì)去數(shù)據(jù)庫里面查詢 1000 個(gè)員工。

最初級(jí)的緩存不一致問題及解決方案

問題:先修改數(shù)據(jù)庫,再刪除緩存。如果刪除緩存失敗了,那么會(huì)導(dǎo)致數(shù)據(jù)庫中是新數(shù)據(jù),緩存中是舊數(shù)據(jù),數(shù)據(jù)就出現(xiàn)了不一致。
f0459c3e196eb791c30cebb2305877a.png

解決思路:先刪除緩存,再修改數(shù)據(jù)庫。如果數(shù)據(jù)庫修改失敗了,那么數(shù)據(jù)庫中是舊數(shù)據(jù),緩存中是空的,那么數(shù)據(jù)不會(huì)不一致。因?yàn)樽x的時(shí)候緩存沒有,則讀數(shù)據(jù)庫中舊數(shù)據(jù),然后更新到緩存中。

比較復(fù)雜的數(shù)據(jù)不一致問題分析

數(shù)據(jù)發(fā)生了變更,先刪除了緩存,然后要去修改數(shù)據(jù)庫,此時(shí)還沒修改。一個(gè)請(qǐng)求過來,去讀緩存,發(fā)現(xiàn)緩存空了,去查詢數(shù)據(jù)庫,查到了修改前的舊數(shù)據(jù),放到了緩存中。隨后數(shù)據(jù)變更的程序完成了數(shù)據(jù)庫的修改。

完了,數(shù)據(jù)庫和緩存中的數(shù)據(jù)不一樣了。。。

為什么上億流量高并發(fā)場景下,緩存會(huì)出現(xiàn)這個(gè)問題?

只有在對(duì)一個(gè)數(shù)據(jù)在并發(fā)的進(jìn)行讀寫的時(shí)候,才可能會(huì)出現(xiàn)這種問題。其實(shí)如果說你的并發(fā)量很低的話,特別是讀并發(fā)很低,每天訪問量就 1 萬次,那么很少的情況下,會(huì)出現(xiàn)剛才描述的那種不一致的場景。但是問題是,如果每天的是上億的流量,每秒并發(fā)讀是幾萬,每秒只要有數(shù)據(jù)更新的請(qǐng)求,就可能會(huì)出現(xiàn)上述的數(shù)據(jù)庫+緩存不一致的情況。

解決方案如下:

更新數(shù)據(jù)的時(shí)候,根據(jù)數(shù)據(jù)的唯一標(biāo)識(shí),將操作路由之后,發(fā)送到一個(gè) jvm 內(nèi)部隊(duì)列中。讀取數(shù)據(jù)的時(shí)候,如果發(fā)現(xiàn)數(shù)據(jù)不在緩存中,那么將重新讀取數(shù)據(jù)+更新緩存的操作,根據(jù)唯一標(biāo)識(shí)路由之后,也發(fā)送同一個(gè) jvm 內(nèi)部隊(duì)列中。

一個(gè)隊(duì)列對(duì)應(yīng)一個(gè)工作線程,每個(gè)工作線程串行拿到對(duì)應(yīng)的操作,然后一條一條的執(zhí)行。這樣的話,一個(gè)數(shù)據(jù)變更的操作,先刪除緩存,然后再去更新數(shù)據(jù)庫,但是還沒完成更新。此時(shí)如果一個(gè)讀請(qǐng)求過來,讀到了空的緩存,那么可以先將緩存更新的請(qǐng)求發(fā)送到隊(duì)列中,此時(shí)會(huì)在隊(duì)列中積壓,然后同步等待緩存更新完成。

這里有一個(gè)優(yōu)化點(diǎn),一個(gè)隊(duì)列中,其實(shí)多個(gè)更新緩存請(qǐng)求串在一起是沒意義的,因此可以做過濾,如果發(fā)現(xiàn)隊(duì)列中已經(jīng)有一個(gè)更新緩存的請(qǐng)求了,那么就不用再放個(gè)更新請(qǐng)求操作進(jìn)去了,直接等待前面的更新操作請(qǐng)求完成即可。

待那個(gè)隊(duì)列對(duì)應(yīng)的工作線程完成了上一個(gè)操作的數(shù)據(jù)庫的修改之后,才會(huì)去執(zhí)行下一個(gè)操作,也就是緩存更新的操作,此時(shí)會(huì)從數(shù)據(jù)庫中讀取最新的值,然后寫入緩存中。

如果請(qǐng)求還在等待時(shí)間范圍內(nèi),不斷輪詢發(fā)現(xiàn)可以取到值了,那么就直接返回;如果請(qǐng)求等待的時(shí)間超過一定時(shí)長,那么這一次直接從數(shù)據(jù)庫中讀取當(dāng)前的舊值。

高并發(fā)的場景下,該解決方案要注意的問題:

1、讀請(qǐng)求長時(shí)阻塞

由于讀請(qǐng)求進(jìn)行了非常輕度的異步化,所以一定要注意讀超時(shí)的問題,每個(gè)讀請(qǐng)求必須在超時(shí)時(shí)間范圍內(nèi)返回。

該解決方案,最大的風(fēng)險(xiǎn)點(diǎn)在于說,可能數(shù)據(jù)更新很頻繁,導(dǎo)致隊(duì)列中積壓了大量更新操作在里面,然后讀請(qǐng)求會(huì)發(fā)生大量的超時(shí),最后導(dǎo)致大量的請(qǐng)求直接走數(shù)據(jù)庫。務(wù)必通過一些模擬真實(shí)的測試,看看更新數(shù)據(jù)的頻率是怎樣的。

另外一點(diǎn),因?yàn)橐粋€(gè)隊(duì)列中,可能會(huì)積壓針對(duì)多個(gè)數(shù)據(jù)項(xiàng)的更新操作,因此需要根據(jù)自己的業(yè)務(wù)情況進(jìn)行測試,可能需要部署多個(gè)服務(wù),每個(gè)服務(wù)分?jǐn)傄恍?shù)據(jù)的更新操作。如果一個(gè)內(nèi)存隊(duì)列里居然會(huì)擠壓 100 個(gè)商品的庫存修改操作,每隔庫存修改操作要耗費(fèi) 10ms 去完成,那么最后一個(gè)商品的讀請(qǐng)求,可能等待 10 * 100 = 1000ms = 1s 后,才能得到數(shù)據(jù),這個(gè)時(shí)候就導(dǎo)致讀請(qǐng)求的長時(shí)阻塞。

一定要做根據(jù)實(shí)際業(yè)務(wù)系統(tǒng)的運(yùn)行情況,去進(jìn)行一些壓力測試,和模擬線上環(huán)境,去看看最繁忙的時(shí)候,內(nèi)存隊(duì)列可能會(huì)擠壓多少更新操作,可能會(huì)導(dǎo)致最后一個(gè)更新操作對(duì)應(yīng)的讀請(qǐng)求,會(huì) hang 多少時(shí)間,如果讀請(qǐng)求在 200ms 返回,如果你計(jì)算過后,哪怕是最繁忙的時(shí)候,積壓 10 個(gè)更新操作,最多等待 200ms,那還可以的。

如果一個(gè)內(nèi)存隊(duì)列中可能積壓的更新操作特別多,那么你就要加機(jī)器,讓每個(gè)機(jī)器上部署的服務(wù)實(shí)例處理更少的數(shù)據(jù),那么每個(gè)內(nèi)存隊(duì)列中積壓的更新操作就會(huì)越少。

其實(shí)根據(jù)之前的項(xiàng)目經(jīng)驗(yàn),一般來說,數(shù)據(jù)的寫頻率是很低的,因此實(shí)際上正常來說,在隊(duì)列中積壓的更新操作應(yīng)該是很少的。像這種針對(duì)讀高并發(fā)、讀緩存架構(gòu)的項(xiàng)目,一般來說寫請(qǐng)求是非常少的,每秒的 QPS 能到幾百就不錯(cuò)了。

實(shí)際粗略測算一下

如果一秒有 500 的寫操作,如果分成 5 個(gè)時(shí)間片,每 200ms 就 100 個(gè)寫操作,放到 20 個(gè)內(nèi)存隊(duì)列中,每個(gè)內(nèi)存隊(duì)列,可能就積壓 5 個(gè)寫操作。每個(gè)寫操作性能測試后,一般是在 20ms 左右就完成,那么針對(duì)每個(gè)內(nèi)存隊(duì)列的數(shù)據(jù)的讀請(qǐng)求,也就最多 hang 一會(huì)兒,200ms 以內(nèi)肯定能返回了。

經(jīng)過剛才簡單的測算,我們知道,單機(jī)支撐的寫 QPS 在幾百是沒問題的,如果寫 QPS 擴(kuò)大了 10 倍,那么就擴(kuò)容機(jī)器,擴(kuò)容 10 倍的機(jī)器,每個(gè)機(jī)器 20 個(gè)隊(duì)列。

2、讀請(qǐng)求并發(fā)量過高

這里還必須做好壓力測試,確保恰巧碰上上述情況的時(shí)候,還有一個(gè)風(fēng)險(xiǎn),就是突然間大量讀請(qǐng)求會(huì)在幾十毫秒的延時(shí) hang 在服務(wù)上,看服務(wù)能不能扛的住,需要多少機(jī)器才能扛住最大的極限情況的峰值。

但是因?yàn)椴⒉皇撬械臄?shù)據(jù)都在同一時(shí)間更新,緩存也不會(huì)同一時(shí)間失效,所以每次可能也就是少數(shù)數(shù)據(jù)的緩存失效了,然后那些數(shù)據(jù)對(duì)應(yīng)的讀請(qǐng)求過來,并發(fā)量應(yīng)該也不會(huì)特別大。

3、多服務(wù)實(shí)例部署的請(qǐng)求路由

可能這個(gè)服務(wù)部署了多個(gè)實(shí)例,那么必須保證說,執(zhí)行數(shù)據(jù)更新操作,以及執(zhí)行緩存更新操作的請(qǐng)求,都通過 Nginx 服務(wù)器路由到相同的服務(wù)實(shí)例上。

比如說,對(duì)同一個(gè)商品的讀寫請(qǐng)求,全部路由到同一臺(tái)機(jī)器上??梢宰约喝プ龇?wù)間的按照某個(gè)請(qǐng)求參數(shù)的 hash 路由,也可以用 Nginx 的 hash 路由功能等等。

4、熱點(diǎn)商品的路由問題,導(dǎo)致請(qǐng)求的傾斜

萬一某個(gè)商品的讀寫請(qǐng)求特別高,全部打到相同的機(jī)器的相同的隊(duì)列里面去了,可能會(huì)造成某臺(tái)機(jī)器的壓力過大。就是說,因?yàn)橹挥性谏唐窋?shù)據(jù)更新的時(shí)候才會(huì)清空緩存,然后才會(huì)導(dǎo)致讀寫并發(fā),所以其實(shí)要根據(jù)業(yè)務(wù)系統(tǒng)去看,如果更新頻率不是太高的話,這個(gè)問題的影響并不是特別大,但是的確可能某些機(jī)器的負(fù)載會(huì)高一些。

Atas ialah kandungan terperinci java實(shí)現(xiàn)保證緩存與數(shù)據(jù)庫的雙寫的一致性. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Tutorial PHP
1502
276
Mengoptimumkan interaksi pangkalan data dalam aplikasi Java Mengoptimumkan interaksi pangkalan data dalam aplikasi Java Jul 27, 2025 am 02:32 AM

Useconnectionpoolingwithhikaricptoreusedatabaseconnectionsandreduceoverhead.2.UsePreparedStatementTopreventsqlinjectionAndroveProveQueryperformance.3.fetchonLyRequiredDataByselectingsPecificColumnSandapplyFilation.4.Se

Bagaimana cara membiakkan pangkalan data di Laravel? Bagaimana cara membiakkan pangkalan data di Laravel? Jul 28, 2025 am 04:23 AM

Buat Fail Seeder: Gunakan PhPartisanMake: SeederSerseeder untuk menghasilkan kelas Seeder, dan masukkan data melalui kilang model atau pertanyaan pangkalan data dalam kaedah RUN; 2. Panggil penyokong lain dalam DatabaseSeeder: Daftar Usereeder, Postseeder, dan lain-lain. Sehingga melalui $ this-> call () untuk memastikan kebergantungan adalah betul; 3. Jalankan Seeder: Jalankan PhPartisandb: Benih untuk menjalankan semua Seeders berdaftar, atau gunakan PhPartisanMigrate: segar-Seed untuk menetapkan semula dan mengisi semula data; 4

Bagaimana untuk melaksanakan pertanyaan SQL di Python? Bagaimana untuk melaksanakan pertanyaan SQL di Python? Aug 02, 2025 am 01:56 AM

Pasang pemacu pangkalan data yang sepadan; 2. Gunakan Connect () untuk menyambung ke pangkalan data; 3. Buat objek kursor; 4. Gunakan melaksanakan () atau executemany () untuk melaksanakan SQL dan menggunakan pertanyaan parameter untuk mengelakkan suntikan; 5. Gunakan Fetchall (), dan sebagainya untuk mendapatkan hasil; 6. komit () diperlukan selepas pengubahsuaian; 7. Akhirnya, tutup sambungan atau gunakan pengurus konteks untuk mengendalikannya secara automatik; Proses lengkap memastikan operasi SQL selamat dan cekap.

Bagaimana anda mengira perbezaan antara dua tarikh dalam SQL? Bagaimana anda mengira perbezaan antara dua tarikh dalam SQL? Aug 02, 2025 pm 01:29 PM

Untuk mengira perbezaan antara dua tarikh, anda perlu memilih fungsi yang sepadan mengikut jenis pangkalan data: 1. Gunakan Datediff () untuk mengira perbezaan hari dalam MySQL, atau menentukan unit -unit seperti jam dan minit dalam timestampdiff (); 2. Gunakan Datediff (date_part, start_date, end_date) dalam sqlserver dan tentukan unit; 3. Gunakan penolakan langsung dalam PostgreSQL untuk mendapatkan perbezaan hari, atau menggunakan ekstrak (DayFromage (...)) untuk mendapatkan selang yang lebih tepat; 4. Gunakan fungsi Julianday () untuk menolak perbezaan hari dalam SQLite; Sentiasa perhatikan pesanan tarikh

Menjamin MySQL dengan keistimewaan tahap objek Menjamin MySQL dengan keistimewaan tahap objek Jul 29, 2025 am 01:34 AM

Tosecuremysqleffectely, useObject-levelprivilygestestestigmilimitusAracCessBasedontheArtheirspecificNeeds.beginbyBySpelythatthatThatBje-levelprivileGeGsapplyTaDataBases, Tabel, orcolumns.

SQL Cube and Rollup untuk Agregasi Multi-Dimensi SQL Cube and Rollup untuk Agregasi Multi-Dimensi Jul 29, 2025 am 12:28 AM

Cube digunakan untuk menjana pengagregatan semua kombinasi dimensi, sesuai untuk analisis silang; Rollup secara beransur -ansur diringkaskan pada tahap hierarki, sesuai untuk data dengan hubungan hierarki. Cube menjana sejumlah 8 kombinasi mengikut rantau, produk, dan suku, manakala Rollup menghasilkan ringkasan tahun, bulan, hari dan tahap lain mengikut tahun, bulan, dan hari. Cube sesuai untuk melihat semua hasil silang dimensi, Rollup sesuai untuk memaparkan hierarki. Perhatikan bahawa kiub boleh menyebabkan keputusan ditetapkan untuk meletup, dan rollup bergantung kepada susunan medan. Baris ringkasan boleh dikenalpasti melalui fungsi pengelompokan (), dan jumlah baris dinamakan dengan Gabungan untuk meningkatkan kebolehbacaan.

Melaksanakan Penapis Replikasi Pangkalan Data MySQL Melaksanakan Penapis Replikasi Pangkalan Data MySQL Jul 28, 2025 am 02:36 AM

Penapisan replikasi MySQL boleh dikonfigurasi di perpustakaan utama atau perpustakaan hamba. Perpustakaan utama mengawal generasi binlog melalui binlog-do-db atau binlog-ignore-db, yang sesuai untuk mengurangkan jumlah log; Aplikasi data dikawal oleh replication-db-db, replication-ignore-db, replicate-do-table, replicate-ignore-table dan wildcard rules meniru-liar-do-table dan replication-liar-ignore-meja. Ia lebih fleksibel dan kondusif untuk pemulihan data. Semasa mengkonfigurasi, anda perlu memberi perhatian kepada perintah peraturan, tingkah laku penyataan silang,

Mengoptimumkan MySQL untuk Sistem Pengurusan Kandungan (CMS) Mengoptimumkan MySQL untuk Sistem Pengurusan Kandungan (CMS) Jul 28, 2025 am 03:19 AM

ToimprovemyMySffeForcMSplatformsLikewAwewewewordPress, firstimplemememememememememementerangkangkangkangkangkuNerGENGAgingPluginsLIKLIKLIKLIKeDIsdemeMemCached, enabheMySqlQueryCaching (ifipplicababable), andusePageCachingplugIsvestatiCatiCS

See all articles