目標是每月寫一篇文章,對從事編程開發的基礎知識作一個學習總結。這個月的計劃原本是對基礎的數據結構作一個沉澱,可是,可是,可是......這個月的的狀態就是工做工做...既然這樣就總結下這個月的工做吧。php
促銷活動的抽獎工具,具有以下功能:前端
一看到上面的需求,很顯然的咱們會想到策略模式,制定三種不一樣的策略實體類:mysql
創建了具體的三個策略實體類以後,因爲不一樣的抽獎策略其實有不少的類似行爲,咱們開始進行抽象,最後整個的抽獎行爲以下:linux
接着,創建抽象類:LotteryAbstract。抽象完成之後:nginx
具體抽象類以下:git
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... } }
接着咱們發現其實不一樣的抽獎策略的抽獎流程基本一致,這樣咱們就聯想到了設計模式的「模板模式」,咱們對抽象類作些小的調整,咱們把抽獎的算法調用流程實如今抽象類中,最後抽象類就構成了一個抽獎類的模板。之後咱們增長新的抽象方式,只須要實現抽獎模板的抽象方法便可,變動後的抽象類以下:github
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毫秒,下降搶鎖的頻率,方案以下:sql
僞代碼: do { 搶鎖... if (! 失敗) { usleep(5000); } } while (! 失敗);
上面的方案有效的下降了峯值,可是又形成了499的請求,接着方案三出來了,具體方案以下:
經過這個方案,redis,mysql主庫的壓力基本減輕。
接着來講說這段時間工做中遇到的一些問題:
我的問題:
svn問題
提出了問題,固然得給出對應的解決方案:
我的問題:
svn問題