?????本周做了一個項(xiàng)目棕诵,競價公式優(yōu)化:CTR預(yù)估優(yōu)化纪蜒,邏輯其實(shí)不太復(fù)雜蹭秋,就是把原來固定值的CTR用一系列的公式計算出來扰付,但整個過程卻進(jìn)行得一波三折。
?????自助廣告分為merchant-backend和ad-bidding兩個工程仁讨。merchant-backend主要用來做廣告后臺的配置以及相關(guān)定時任務(wù)悯周,ad-bidding則用來實(shí)現(xiàn)從APP過來的請求做廣告競價排序,承擔(dān)高并發(fā)的請求陪竿。
?????1.第一版:merchant定時任務(wù)把計算出來的CTR寫到redis緩存,用的是hset方法屠橄,bidding讀取族跛,直接hget。當(dāng)時這么寫是直接參照自助全量定時任務(wù)锐墙,結(jié)果代碼review的時候礁哄,直接被老大打回了。因?yàn)樵诟卟l(fā)的情況下溪北,頻繁hget會對性能產(chǎn)生很大的影響桐绒。有可能導(dǎo)致redis集群掛掉。
?????2.第二版:merchant定時任務(wù)把計算出來的CTR寫到redis緩存之拨,用的是set方法茉继。(其實(shí)最開始沒必要用hset,因?yàn)閿?shù)據(jù)結(jié)構(gòu)比較簡單蚀乔,所以這里改成了set)烁竭。bidding讀取的時候,使用了redisProxy.getWithLocalCache方法吉挣,這是common包自定義方法派撕,作用是先從本地緩存取數(shù)據(jù)婉弹,如果本地緩存取不到,就從redis讀取數(shù)據(jù)再存入到本地緩存终吼,下次直接從本地緩存讀取镀赌,這樣就提高了性能。
?????3.第三版:merchant定時任務(wù)寫到redis緩存set际跪,并持久化到數(shù)據(jù)庫表商佛,方便查看ctr
?????本來想這第三版改了沒問題,結(jié)果晚上上線的時候垫卤,發(fā)現(xiàn)響應(yīng)時間持續(xù)飆升威彰,最后分析可能是存在緩存穿透的情況。從redis上獲取到的對象為null穴肘,但是并沒有保存到本地緩存歇盼。所以下次讀取的時候,還是會跳過本地緩存评抚,去請求redis豹缀。
這里有兩種解法:1.修改redisProxy.getWithLocalCache這個公共方法,從redis上獲取到的對象為null時慨代,也去寫本地緩存邢笙,但是這樣會影響到其他代碼;2.以下第四版的方法
?????4.第四版:merchant定時任務(wù)只寫表侍匙,不寫緩存氮惯。bidding實(shí)現(xiàn)一個自刷新類 RefreshableLocalCache,啟動時會從持久化的表中讀取數(shù)據(jù)想暗,并寫入本地緩存妇汗,并且實(shí)現(xiàn)每隔30分鐘刷新緩存。由于每天更新的數(shù)據(jù)量小说莫,目前大概1400多條杨箭,不會占用太多內(nèi)存,所有暫時采用這個方案储狭。
?????5.第五版: 分頁讀表優(yōu)化互婿,如果一次性讀的表數(shù)據(jù)過多,會導(dǎo)致慢sql辽狈,所以采用分頁分批讀取
?????看起來一個不大的需求慈参,最后卻陸陸續(xù)續(xù)做了一個星期,這說明了完成基本功能很容易刮萌,但想要提升性能懂牧,必須要下大功夫才行!