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