表關(guān)系描述
類似于好友之間的關(guān)聯(lián)關(guān)系,有表N调炬,M以及N與M的關(guān)聯(lián)關(guān)系表坏怪,N表與M表假設(shè)均有100W的數(shù)據(jù),M與N兩者關(guān)系是一個(gè)稀疏矩陣(只有少部分之間有關(guān)系奠伪,大約10%)。
業(yè)務(wù)場景
通過表N中的一條記錄首懈,來查詢關(guān)聯(lián)的M有哪些人绊率,并且這是一個(gè)高頻次操作。
存在的問題
mysql單庫承受如此多的查詢請(qǐng)求究履,容易拖垮整個(gè)庫滤否。
解決方案
以下解決方案的目的是為了過濾掉空查詢。
Redis設(shè)置空值
方案描述
在查詢到N與M關(guān)聯(lián)關(guān)系表中的空值時(shí)最仑,就往Redis存儲(chǔ)一個(gè)空值藐俺,設(shè)置一個(gè)的過期時(shí)間(固定時(shí)間+隨機(jī)時(shí)間),大約是3天泥彤。
問題
這個(gè)關(guān)系的N*M紊搪,需要把所有的空值都放進(jìn)去,按照假設(shè)的數(shù)據(jù)量全景,極限情況下Redis中需要存儲(chǔ)100W * 100W的數(shù)據(jù)耀石,這個(gè)數(shù)據(jù)量是很大的。按照實(shí)際項(xiàng)目預(yù)估值,Redis大小是128G滞伟,每天增長在7GB左右揭鳞,Redis滿了以后,會(huì)出現(xiàn)部分打在DB上的情況梆奈。
方案優(yōu)化
- 優(yōu)化Key的長度野崇,降低內(nèi)存占用;
- 慢慢縮短過期時(shí)間亩钟,直到DB能夠承受的穿透查詢量乓梨;
- 調(diào)整Redis的緩存淘汰策略,從noevication(默認(rèn)清酥,除了del請(qǐng)求扶镀,不會(huì)繼續(xù)服務(wù)寫請(qǐng)求)改為volatile-lru(淘汰設(shè)計(jì)了過期時(shí)間的key,最少使用的key被淘汰)焰轻;
- 加內(nèi)存臭觉,硬件相對(duì)人力成本很便宜。
將Redis當(dāng)做數(shù)據(jù)庫
方案描述
因?yàn)镹與N關(guān)系表是一個(gè)稀疏矩陣辱志,按照10%的比例蝠筑,數(shù)據(jù)大概在1000w左右,可以將Redis作為數(shù)據(jù)庫揩懒,直接將1000W數(shù)據(jù)放入Redis中什乙。
問題
- 緩存與數(shù)據(jù)庫雙寫存在數(shù)據(jù)一致性問題;
- 業(yè)務(wù)變得更復(fù)雜,當(dāng)業(yè)務(wù)數(shù)據(jù)量增長后已球,需要付出很大的遷移代價(jià)臣镣。
方案優(yōu)化
針對(duì)問題1,可以通過訂閱mysql的binlog和悦,主動(dòng)變更Redis的緩存。問題2是業(yè)務(wù)取舍渠缕,沒有什么很好的辦法鸽素。
使用布隆過濾器
布隆過濾器判斷數(shù)據(jù)不存在,則一定不存在亦鳞。判斷數(shù)據(jù)存在馍忽,存在誤判概率。
方案描述
對(duì)于新增的數(shù)據(jù)燕差,寫入Redis實(shí)現(xiàn)的布隆過濾器遭笋,刪除的數(shù)據(jù)不進(jìn)行處理。定時(shí)的重建布隆過濾器徒探,例如每小時(shí)重建一次瓦呼,那么在單位時(shí)間內(nèi)刪除量不是很大的情況下,打到數(shù)據(jù)庫層的空請(qǐng)求請(qǐng)求不會(huì)很多测暗。并且央串,全量的數(shù)據(jù)使用布隆過濾器磨澡,對(duì)于3億的數(shù)據(jù),內(nèi)存只需要大概十幾MB质和。額外需要再保證存在的數(shù)據(jù)也緩存一份到Redis中稳摄,如果有必要可以通過Guava做JVM級(jí)別的緩存。
判斷邏輯如下
- 判斷布隆過濾器中是否存在饲宿,若不存在厦酬,則返回;
- 布隆過濾器中存在瘫想,則判斷Redis是否存在仗阅,若存在,則返回殿托;
- 若Redis中不存在霹菊,則去數(shù)據(jù)庫中查詢。
問題
- 布隆過濾器重建需要掃描全表支竹,對(duì)與數(shù)據(jù)量多的表來說旋廷,mysql的壓力還是比較大;
方案優(yōu)化
需要小心平衡布隆過濾器重建間隔與mysql的訪問壓力礼搁。若布隆過濾器重建時(shí)間間隔太長饶碘,則被刪除的空數(shù)據(jù)還是會(huì)打入DB,若布隆過濾器重建時(shí)間間隔太短馒吴,全表查詢掃描會(huì)對(duì)mysql造成壓力扎运。