摘要:這個月的計劃本來是對基礎的數(shù)據(jù)結構做一個沉淀,但是,但是,但是這個月的的狀態(tài)就是工作工作既然這樣就總結下這個月的工作吧。
前言
目標是每個月寫一篇文章,對從事編程開發(fā)的基礎知識做一個學習總結。這個月的計劃本來是對基礎的數(shù)據(jù)結構做一個沉淀,但是,但是,但是......這個月的的狀態(tài)就是工作工作...既然這樣就總結下這個月的工作吧。
工作內(nèi)容促銷活動的抽獎工具,具備如下功能:
根據(jù)不同的訂單金額抽獎,可設置最高訂單金額限制
根據(jù)不同的抽獎次數(shù)抽獎,可設置積分消耗限制
根據(jù)不同的時間段抽獎,可設置積分消耗限制
建模一看到上面的需求,很顯然的我們會想到策略模式,制定三種不同的策略實體類:
按訂單抽獎策略:LotteryOrderStrategy
按次數(shù)抽獎策略:LotteryTimesStrategy
時間段抽獎策略:LotteryTimeScopeStrategy
建立了具體的三個策略實體類之后,由于不同的抽獎策略其實有很多的相似行為,我們開始進行抽象,最后整個的抽獎行為如下:
活動參與條件驗證: check[抽象方法]
讀取規(guī)則信息: getRule[具體方法]
匹配符合的規(guī)則區(qū)間: getNodeByRule[抽象方法]
活動參與次數(shù)驗證: checkTimes[具體方法]
活動規(guī)則限制驗證: checkJoinLimit[抽象方法]
消費積分: consumePoints[抽象方法]
讀取該規(guī)則對應的所有獎品: getPrize[具體方法]
抽獎: draw[具體方法]
組裝獎品信息: packagePrizeInfo[具體方法]
接著,建立抽象類:LotteryAbstract。抽象完成以后:
相同的邏輯: 不同抽獎實體類直接繼承使用即可
不同的邏輯: 不同抽獎實體類具體實現(xiàn)即可
具體抽象類如下:
abstract class LotteryAbstract { abstract protected function check(); protected function getRule() { # code... } abstract protected function getNodeByRule(); protected function checkTimes() { # code... } abstract protected function checkJoinLimit(); abstract protected function consumePoints(); protected function getPrize() { # code... } protected function draw() { # code... } protected function packagePrizeInfo() { # code... } }
接著我們發(fā)現(xiàn)其實不同的抽獎策略的抽獎流程基本一致,這樣我們就聯(lián)想到了設計模式的“模板模式”,我們對抽象類做些小的調(diào)整,我們把抽獎的算法調(diào)用流程實現(xiàn)在抽象類中,最后抽象類就構成了一個抽獎類的模板。以后我們增加新的抽象方式,只需要實現(xiàn)抽獎模板的抽象方法即可,變更后的抽象類如下:
abstract class LotteryAbstract { /** * 抽獎算法 */ public function run () { $this->check(); $this->getRule(); $this->getNodeByRule(); $this->checkTimes(); $this->checkJoinLimit(); $this->consumePoints(); $this->getPrize(); $this->draw(); $this->packagePrizeInfo(); } abstract protected function check(); protected function getRule() { # code... } abstract protected function getNodeByRule(); protected function checkTimes() { # code... } abstract protected function checkJoinLimit(); abstract protected function consumePoints(); protected function getPrize() { # code... } protected function draw() { # code... } protected function packagePrizeInfo() { # code... } }并發(fā)
建模完成后,還存一個并發(fā)的問題:并發(fā)下對獎品領取數(shù)量的變更問題。當然可能都會想到加鎖,讓并發(fā)的過程變成串行的過程,這樣就不會存在問題了。一是使用mysql的悲觀鎖(for update),但是考慮到這個去抽獎的過程有在類似秒殺的場景中使用,所以我就考慮用redis的悲觀鎖實現(xiàn),畢竟內(nèi)存的io性能比磁盤要高的多,所以開始的方案一如下:
redis悲觀鎖
本地ab -c 100 -n 1000 壓測正常。
然后上線就出問題了,順時redis大量的操作,遠遠的超過了以前的峰值。然后方案二出來了,搶不到鎖,睡5毫秒,降低搶鎖的頻率,方案如下:
偽代碼: do { 搶鎖... if (! 失敗) { usleep(5000); } } while (! 失敗);
上面的方案有效的降低了峰值,但是又造成了499的請求,接著方案三出來了,具體方案如下:
由于redis是單線程的利用redis的decr自減,保證獎品庫存的準確性
活動開始前注入獎品庫存到redis
定時同步庫存到mysql(減少了直接從mysql中減少庫存的主庫壓力)
通過這個方案,redis,mysql主庫的壓力基本減輕。
問題接著來說說這段時間工作中遇到的一些問題:
個人問題:
錯誤的使用redis的悲觀鎖,搶鎖失敗沒有進行睡眠,導致線上redis瞬時大量的操作(本地壓測未發(fā)現(xiàn)問題),后期會對這塊進行深度的研究
沒有從頭到尾認真的進行code review(項目開發(fā)時間過于緊急)
項目排期混亂:每年定期搞的活動,卻只預留了5天開發(fā)時間
接口文檔:老式的wiki文檔,沒有返回值的示例,沒有返回值的類型說明。增加了前后端開發(fā)成本,低效率。
前端依賴:前端重度的依賴后端數(shù)據(jù)進行調(diào)試
測試低效:純手工的測試,也缺乏對一些基礎工具的使用
低效的后臺項目項目代碼:基本不具備代碼復用能力的代碼,組織混亂
各個環(huán)境的使用:目前我們開發(fā)測試灰度環(huán)境,每次使用前都靠“吼”,經(jīng)常會出現(xiàn)代碼被別人覆蓋的問題
svn問題
同事本地代碼丟失
代碼發(fā)布的分支,發(fā)布通過合并trunk,導致線上緊急修復分支被阻塞
代碼發(fā)布的分支,經(jīng)常導致忘記合并回trunk
每次發(fā)布前需要到專門的線上代碼diff機器進行代碼diff
解決方案提出了問題,當然得給出對應的解決方案:
個人問題:
繼續(xù)對基礎知識進行深度學習,目前對于nginx,linux,redis,mysql,mongo我都還需要大力的去學習。
有質(zhì)量的code review是必須的
項目排期混亂:對產(chǎn)品和上級反饋希望我們能從中挖掘出原因,避免和減少同樣的事情的發(fā)生
接口文檔:內(nèi)部推動試行api blueprint,和對snowboard,swagger等這樣工具的使用,目前從我做起。
前端依賴:推動前端同事自行打斷點調(diào)試和api mock
測試低效:推動至少目前對簡單代理工具的使用
低效的后臺項目項目代碼:有可能推動內(nèi)部使用yii2開發(fā)后臺,個人覺著開發(fā)后臺gii還是蠻有效率
各個環(huán)境的使用: 有空寫一個簡單的頁面,使用對應環(huán)境的機器checkbox選中即可,一目了然,完全避免以前的問題
svn問題
推動內(nèi)部轉(zhuǎn)向git
git stash 本地暫存未提交的代碼,從而避免丟代碼問題
緊急的修補分支,采用git workflow的熱補丁分之隨時上線即可
git workflow的工作流可以避免我們目前的使用svn代碼經(jīng)常忘記合并到trunk問題
git 本地diff分支代碼即可 提高了效率
經(jīng)驗寫代碼前一定要盡可能的弄清楚要做什么
寫代碼前進行必要的抽象過程,這樣通常可以寫出易于閱讀和擴展的代碼(不過,脫離業(yè)務的代碼是耍流氓哦,哈哈~)
code review 必不可少,慢慢養(yǎng)成習慣吧,騷年們
壓測,對我們寫完的代碼進行壓測,簡單的可以使用ab,siege
項目完成后的總結和沉淀
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/22882.html
摘要:它們的用處都是用來能讓數(shù)據(jù)正常插入到數(shù)據(jù)庫中,并防止注入,但是并不能做到防止注入。進來抽獎的用戶使用原子加鎖,實現(xiàn)抽獎次數(shù)自增,當抽獎次數(shù)到達時,返回不中獎。 轉(zhuǎn)載于:https://zhuanlan.zhihu.com/p/...答案并非標準,是作者經(jīng)驗之談,僅供參考 mysql_real_escape_string mysql_escape_string有什么本質(zhì)的區(qū)別,有什么用處...
摘要:前言與是目前圈子內(nèi)比較活躍的前端構建工具。對于初學者來說,對這二者往往容易認識不清,今天,就從事件的源頭,說清楚與。它可以將許多松散的模塊按照依賴和規(guī)則打包成符合生產(chǎn)環(huán)境部署的前端資源。打包后形成的文件出口。 前言:Webpack 與 gulp是目前圈子內(nèi)比較活躍的前端構建工具。網(wǎng)上有很多二者比較的文章,面試中也會經(jīng)常遇到gulp,Webpack的區(qū)別這樣的問題。對于初學者來說,對這二...
摘要:我們可以把取消發(fā)貨單和取消訂單看成一個被觀察或被訂閱的類實例的對象,一旦發(fā)生取消行為,我們立即通知各個觀察者做出相對應的行為。裝飾器模式裝飾器思想,不管以前業(yè)務邏輯,甚至不去讀,調(diào)用之前的接口裝飾上新的數(shù)據(jù),達到自己的目的。 前言 還是每月的目標至少寫一篇文章,一晃八月份就要過去了,這個月依然沒有什么產(chǎn)出,毫無疑問最近的狀態(tài)就是不停的工作,不停的加班。所以還是把最近工作進行一個總結,首...
閱讀 3326·2021-11-19 11:36
閱讀 2927·2021-09-27 13:34
閱讀 1990·2021-09-22 15:17
閱讀 2404·2019-08-30 13:49
閱讀 754·2019-08-26 13:58
閱讀 1359·2019-08-26 10:47
閱讀 2538·2019-08-23 18:05
閱讀 600·2019-08-23 14:25