摘要:需求描述某些頁(yè)面需要配置廣告或活動(dòng)宣傳圖,廣告或活動(dòng)需滿足隨時(shí)上下線過(guò)期自動(dòng)下線及到時(shí)自動(dòng)上線。第步給前端寫接口查詢頁(yè)面廣告按標(biāo)準(zhǔn)的控制層,業(yè)務(wù)層,數(shù)據(jù)訪問(wèn)層寫,第一步中的邏輯就是在業(yè)務(wù)層完成的。
背景引入
最近需要實(shí)現(xiàn)一個(gè)功能,關(guān)于頁(yè)面廣告自動(dòng)配置的,如支付寶的支付完成頁(yè)。這篇文章是記錄對(duì)這個(gè)需求從分析到實(shí)現(xiàn)以及優(yōu)化的過(guò)程,以免以后忘記。
需求描述某些頁(yè)面需要配置廣告或活動(dòng)宣傳圖,廣告或活動(dòng)需滿足隨時(shí)上下線、過(guò)期自動(dòng)下線及到時(shí)自動(dòng)上線。
如:現(xiàn)在時(shí)間2019-2-22 16:16:13,要在支付完成頁(yè)面配置領(lǐng)獎(jiǎng)活動(dòng),活動(dòng)要在2019-3-10 00:00:00準(zhǔn)時(shí)上線,在2019-3-30 23:59:59結(jié)束活動(dòng)。
所以要的效果是,在活動(dòng)上線前的任意時(shí)刻配置完活動(dòng)后,頁(yè)面到時(shí)間自動(dòng)上線這個(gè)活動(dòng)。
也可能會(huì)是其他的多個(gè)活動(dòng)或廣告,每個(gè)頁(yè)面廣告的個(gè)數(shù)可變,不同上下線時(shí)間可不同,其他頁(yè)面也需要實(shí)現(xiàn)這樣的功能,頁(yè)面與頁(yè)面之間的活動(dòng)不一定一樣。
需求簡(jiǎn)單的幾句話,那么我們來(lái)具體的分析一下。
提取關(guān)鍵詞廣告或活動(dòng)宣傳圖
隨時(shí)上下線、過(guò)期自動(dòng)下線及到時(shí)自動(dòng)上線
每個(gè)頁(yè)面廣告的個(gè)數(shù)可變
不同廣告上下線時(shí)間可不同
頁(yè)面與頁(yè)面之間的活動(dòng)不一定一樣
數(shù)據(jù)庫(kù)分析1、【廣告或活動(dòng)宣傳圖】
要為不同頁(yè)面設(shè)置不同的廣告,有的頁(yè)面廣告可能一樣,也就是廣告會(huì)復(fù)用,所有要有廣告表。
2、【每個(gè)頁(yè)面廣告的個(gè)數(shù)可變】【不同廣告上下線時(shí)間可不同】【頁(yè)面與頁(yè)面之間的活動(dòng)不一定一樣】
頁(yè)面可配置多個(gè)廣告,所有要有頁(yè)面配置表,以及廣告和頁(yè)面的關(guān)系表,即頁(yè)面廣告表。
頁(yè)面配置表主要配置頁(yè)面的廣告?zhèn)€數(shù),實(shí)現(xiàn)【每個(gè)頁(yè)面廣告的個(gè)數(shù)可變】,頁(yè)面廣告表主要配置頁(yè)面的每個(gè)廣告上下線時(shí)間,實(shí)現(xiàn)【不同廣告上下線時(shí)間可不同】
簡(jiǎn)單分析后得出如下表結(jié)構(gòu):廣告表adv,頁(yè)面配置表page_config,頁(yè)面廣告表page_adv
這些頁(yè)面配置的廣告在一段時(shí)間內(nèi)是不會(huì)變的,如果頁(yè)面請(qǐng)求次數(shù)較多,廣告查詢次數(shù)就會(huì)很頻繁,對(duì)數(shù)據(jù)庫(kù)造成不必要的壓力。所以可以引入緩存,降低數(shù)據(jù)庫(kù)請(qǐng)求次數(shù),緩解數(shù)據(jù)庫(kù)壓力。這里使用的Redis。
何時(shí)入緩存?
可以選擇在服務(wù)啟動(dòng)時(shí)異步把已在上下線時(shí)間區(qū)間內(nèi)的廣告先加載至緩存,或選擇在請(qǐng)求時(shí)取緩存,緩存內(nèi)沒(méi)有時(shí)再查庫(kù)然后放緩存。緩存時(shí)間視情況而定。
這里選擇的是,項(xiàng)目啟動(dòng)時(shí)異步把符合條件的頁(yè)面廣告配置信息存入Redis,那些還沒(méi)到指定時(shí)間的先不放Redis,等到訪問(wèn)頁(yè)面加載廣告時(shí),先查Redis,若無(wú)則按條件(>=nowtime)查庫(kù),查到后存Redis。
在接口中拿到廣告配置信息后,判斷當(dāng)前時(shí)間是否在配置的時(shí)間區(qū)間內(nèi),由于一個(gè)頁(yè)面配置多個(gè)廣告,不同廣告時(shí)間也不同,所以要迭代,把符合的返回,有過(guò)期的就做標(biāo)記,然后把整個(gè)頁(yè)面的配置信息在Redis里刪除。
(或者不選擇在啟動(dòng)時(shí)加載,就在用戶請(qǐng)求時(shí)加入緩存,但是下面的第1步的方法在刷新加載時(shí)會(huì)用到,故不能刪)
a、查詢所有pageId
SELECT pageId FROM page_config page_adv WHERE nowtime<=endtime AND GROUP BY pageId
兩個(gè)表內(nèi)連接,得List
b、查詢pegeId對(duì)應(yīng)的廣告圖片及跳轉(zhuǎn)鏈接
SELECT 字段名 FROM page_adv adv WHERE begintime<=nowtime<=endtime AND pageId={#pageId}
然后把查到的配置信息List
按標(biāo)準(zhǔn)的控制層,業(yè)務(wù)層,數(shù)據(jù)訪問(wèn)層寫,第一步中的邏輯就是在業(yè)務(wù)層完成的。
控制層:
控制層接參pageId,調(diào)用業(yè)務(wù)層查詢對(duì)應(yīng)頁(yè)面配置的廣告信息,判空,直接返回狀態(tài)碼0,即無(wú)廣告前端不展示。
不為空就根據(jù)業(yè)務(wù)邏輯處理數(shù)據(jù)(如img的URL加域名),然后返回狀態(tài)碼1,前端展示廣告。
這里控制層還可以加邏輯,迭代廣告list,把當(dāng)前時(shí)間在廣告起始時(shí)間內(nèi)的返回,不在的不返回,并且只要有一個(gè)廣告過(guò)期,就把這個(gè)頁(yè)面的廣告list緩存清掉。這個(gè)邏輯是把過(guò)期的清掉。
業(yè)務(wù)層:
先取緩存,沒(méi)有再查庫(kù)判斷不為空(本頁(yè)面配置的有廣告),放入緩存(pageId為KEY),然后返回。
數(shù)據(jù)訪問(wèn)層:
SQL:
SELECT 字段名 FROM page_config adv page_adv WHERE begintime<=nowtime<=endtime AND pageId={pageId}
三表聯(lián)查,根據(jù)pageId查詢當(dāng)前頁(yè)面配置的廣告活動(dòng)信息(已在廣告活動(dòng)時(shí)間內(nèi))
第3步、刷新加載為什么使用刷新加載?
因?yàn)橛羞@樣的場(chǎng)景:給頁(yè)面A配置了一個(gè)廣告(當(dāng)前時(shí)間在廣告的起始時(shí)間內(nèi)),那么這個(gè)頁(yè)面的廣告已經(jīng)在緩存里了,假如此時(shí)A頁(yè)面要新加一個(gè)廣告,在后臺(tái)配置后如果不做其他操作,這個(gè)廣告不會(huì)顯示(假設(shè)緩存時(shí)間較長(zhǎng),為一天),因?yàn)閹?kù)更新了,緩存沒(méi)有同步更新。
解決方案
使用Redis的發(fā)布訂閱機(jī)制實(shí)現(xiàn)緩存的刷新加載,使新配置的廣告及時(shí)能夠顯示。
刷新加載的回調(diào)方法即第1步中的方法。
想一想,目前的實(shí)現(xiàn)存在什么問(wèn)題?
存在的問(wèn)題
假如有頁(yè)面需要配置廣告,但是還沒(méi)有配(前端已經(jīng)開(kāi)發(fā)完上線,每次都會(huì)調(diào)接口查廣告信息),那么數(shù)據(jù)庫(kù)肯定查不到,緩存也沒(méi)有。如果這個(gè)頁(yè)面訪問(wèn)量很大,那么緩存沒(méi)命中就查庫(kù),這樣對(duì)庫(kù)的壓力就會(huì)很大,這就是緩存穿透,請(qǐng)求上來(lái)了很容易擊垮數(shù)據(jù)庫(kù)。那怎么辦呢?
解決方案
當(dāng)頁(yè)面沒(méi)有配置廣告時(shí),在緩存存標(biāo)志,查詢時(shí)先看標(biāo)志,在決定是否往下走。
具體方案
這時(shí),上面的第1步就要改了。
1、首先改第1步的步驟a的SQL,把所有的pageId都查詢出來(lái)。
使用左連接
SELECT pageId FROM page_config LEFT JOIN page_adv ON ... GROUP BY pageId
或者干脆查page_config
SELECT pageId FROM page_config
目的是把已在page_config表中配置,但關(guān)系表中page_adv未配置廣告的pageId也查出來(lái),這樣才能給未配置廣告的pageId在緩存里放標(biāo)志
2、第1步的步驟b的SQL改為
SELECT 字段名 FROM page_adv adv WHERE nowtime<=endtime AND pageId={#pageId}
然后把查到的配置信息放入緩存之前判斷【為空時(shí)的不做操作】改為【為空時(shí)存入一個(gè)標(biāo)志】假如這個(gè)標(biāo)志KEY為pageId+"EMPTY_FLAG",value為"DATABASE_IS_NULL"
為什么只判斷小于結(jié)束時(shí)間
因?yàn)槿绻擁?yè)面配置的廣告開(kāi)始時(shí)間大于當(dāng)前時(shí)間,那么這個(gè)是查不到的,會(huì)被處理為DATABASE_IS_NULL,如果在這個(gè)標(biāo)志還沒(méi)失效之前就到了配置的開(kāi)始時(shí)間了,那么這個(gè)廣告不會(huì)被展示。所有要讓未到開(kāi)始時(shí)間的也放入緩存,然后讓控制層去判斷在不在時(shí)間區(qū)間。
3、所以要在第2步也修改一下
在業(yè)務(wù)層里取緩存中的廣告列表之前,先從緩存取pageId+"EMPTY_FLAG"的value判斷為"DATABASE_IS_NULL"直接返回空,這樣就能解決緩存穿透的問(wèn)題了。
繼續(xù)修改第2步的業(yè)務(wù)層,查庫(kù)的SQL同樣要改:
SELECT 字段名 FROM page_config adv page_adv WHERE nowtime<=endtime AND pageId=#{pageId}
然后判斷為空的話,同上面的加粗斜體部分那樣處理。
4、最后,第3步的刷新加載調(diào)的是第1步的方法,不用改。
當(dāng)然這個(gè)緩存穿透的優(yōu)化方案只是其中一種。還可以這樣:
1、控制層攔截:根據(jù)pageId查詢page_adv表,查不到說(shuō)明沒(méi)配置,直接返回。
2、page_config 表增加字段,表示當(dāng)前頁(yè)面已經(jīng)配置的廣告?zhèn)€數(shù),默認(rèn)0,每配置一個(gè)該字段加1,把大于0的pageId緩存起來(lái),調(diào)接口時(shí)前判斷在不在緩存里。
總結(jié):實(shí)現(xiàn)這個(gè)功能并不是太難,主要用到了Redis的緩存技術(shù),Redis發(fā)布訂閱機(jī)制,關(guān)鍵就是細(xì)節(jié)的把控,以及緩存穿透的處理。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73634.html
摘要:和二級(jí)緩存影響狀態(tài)更新,縮短這兩個(gè)定時(shí)任務(wù)周期可減少滯后時(shí)間,例如配置更新周期更新周期服務(wù)提供者保證服務(wù)正常下線。服務(wù)提供者延遲下線。 引言 Eureka是Netflix開(kāi)源的、用于實(shí)現(xiàn)服務(wù)注冊(cè)和發(fā)現(xiàn)的服務(wù)。Spring Cloud Eureka基于Eureka進(jìn)行二次封裝,增加了更人性化的UI,使用更為方便。但是由于Eureka本身存在較多緩存,服務(wù)狀態(tài)更新滯后,最常見(jiàn)的狀況是:服務(wù)...
摘要:超過(guò)后則認(rèn)為服務(wù)端出現(xiàn)故障,需要重連。同時(shí)在每次心跳時(shí)候都用當(dāng)前時(shí)間和之前服務(wù)端響應(yīng)綁定到上的時(shí)間相減判斷是否需要重連即可??蛻舳藱z測(cè)到某個(gè)服務(wù)端遲遲沒(méi)有響應(yīng)心跳也能重連獲取一個(gè)新的連接。 showImg(https://segmentfault.com/img/remote/1460000017987884?w=800&h=536); 前言 說(shuō)道心跳這個(gè)詞大家都不陌生,當(dāng)然不是指男女...
摘要:就是一種灰度發(fā)布方式,讓一部分用戶繼續(xù)用,一部分用戶開(kāi)始用,如果用戶對(duì)沒(méi)有什么反對(duì)意見(jiàn),那么逐步擴(kuò)大范圍,把所有用戶都遷移到上面來(lái)?;叶劝l(fā)布可以保證整體系統(tǒng)的穩(wěn)定,在初始灰度的時(shí)候就可以發(fā)現(xiàn)調(diào)整問(wèn)題,以保證其影響度。 一、背景互聯(lián)網(wǎng)產(chǎn)品開(kāi)發(fā)有個(gè)非常特別的地方,就是不停的升級(jí),升級(jí),再升級(jí)。采用敏捷開(kāi)發(fā)的方式,基本上保持每周或者每?jī)芍芤淮蔚陌l(fā)布頻率,系統(tǒng)升級(jí)總是伴隨著各種風(fēng)險(xiǎn),新舊版本兼...
閱讀 1001·2023-04-25 14:20
閱讀 1879·2021-11-24 10:20
閱讀 3779·2021-11-11 16:55
閱讀 2926·2021-10-14 09:42
閱讀 3477·2019-08-30 15:56
閱讀 1173·2019-08-30 15:55
閱讀 1077·2019-08-30 15:44
閱讀 784·2019-08-29 11:28