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