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