目标是每月写一篇文章,对从事编程开发的基础知识作一个学习总结。这个月的计划原本是对基础的数据结构作一个沉淀,可是,可是,可是......这个月的的状态就是工做工做...既然这样就总结下这个月的工做吧。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问题