Table of Contents
回复内容:
用户抽象次数限制
奖品数量限制
奖品发放的分布
中奖的概率的可控性
关于优化
附录(简单流程图)
Home Backend Development PHP Tutorial 如何设计高并发下的抽奖?

如何设计高并发下的抽奖?

Jun 06, 2016 pm 08:30 PM
java mysql php ruby concurrent

我写的伪代码如下,但出现了个bug,抽奖现在要限制每日抽奖结果出现的次数,但实际运行是在并发时不能限制住,如何解决?

<code>resultDayLimitTimes = {

   resultA => 2 # 每天最多出现2次  

   resultB => 5 # 每天最多出现5次  

   resultC => 20 # 每天最多出现20次    

   resultD => Infinite # 每天出现次数没有限制

}

Begin transaction

select * from lottery_chance where id =XX and result = null limit 1 for update 

#bug 就在下面这个循环里,如果resultA今天已经出现过一次了,
#然后有2个人(这2人的XX是不同的,所以前面的for update对
#于这种并发不能限制,前面的for update是用来防止同一次抽奖机会被并发时使用多次的)
#同时抽到YY=resultA,由于事务还未提
#交那么yyCount都是1,小于每日限制2,于是跳出循环,这2人
#都中了resultA,这时当天出现了3个resultA 超出2个限制,
#我应该怎么写才能解决这个问题?            
while true {    
    YY = randomIn [resultA,resultB,resultC,resultD]

    yyCount =  select count(*) from lottery_chance where result=YY and used_time > todayDate 
    if yyCount </code>
Copy after login
Copy after login

回复内容:

我写的伪代码如下,但出现了个bug,抽奖现在要限制每日抽奖结果出现的次数,但实际运行是在并发时不能限制住,如何解决?

<code>resultDayLimitTimes = {

   resultA => 2 # 每天最多出现2次  

   resultB => 5 # 每天最多出现5次  

   resultC => 20 # 每天最多出现20次    

   resultD => Infinite # 每天出现次数没有限制

}

Begin transaction

select * from lottery_chance where id =XX and result = null limit 1 for update 

#bug 就在下面这个循环里,如果resultA今天已经出现过一次了,
#然后有2个人(这2人的XX是不同的,所以前面的for update对
#于这种并发不能限制,前面的for update是用来防止同一次抽奖机会被并发时使用多次的)
#同时抽到YY=resultA,由于事务还未提
#交那么yyCount都是1,小于每日限制2,于是跳出循环,这2人
#都中了resultA,这时当天出现了3个resultA 超出2个限制,
#我应该怎么写才能解决这个问题?            
while true {    
    YY = randomIn [resultA,resultB,resultC,resultD]

    yyCount =  select count(*) from lottery_chance where result=YY and used_time > todayDate 
    if yyCount </code>
Copy after login
Copy after login

暂时能想到的是:
再增加一个表来专门记录某天某个result的发放次数,缺点是需要预先创建好期间每天每个result初始数据,并且循环里使用行锁在高并发里效率就非常低了,这是不能被接受的:

<code>resultDayLimitTimes = {

   resultA => 2 # 每天最多出现2次  

   resultB => 5 # 每天最多出现5次  

   resultC => 20 # 每天最多出现20次    

   resultD => Infinite # 每天出现次数没有限制

}

Begin transaction

select * from lottery_chance where id =XX and result = null limit 1 for update 

todayDate = now.Date
while true {             
    YY = randomExcludeBeforeIn [resultA,resultB,resultC,resultD] 
    dayResultTimes = select * from result_day_times where date=todayDate and result=YY limit 1 for update
    if dayResultTimes['times'] </code>
Copy after login

关于抽奖,需要考虑的点有很多,这里稍微整理了下主要需要考虑以下三点:

  • 用户抽奖次数限制
  • 奖品数量限制
  • 奖品发放的分布
  • 中奖的概率的可控性

用户抽象次数限制

一个用户必须限制抽奖的次数,而同一个用户的并发几率其实是很小的,所以这里可以用悲观锁来控制用户的抽奖次数。

奖品数量限制

因为并发修改一个奖品的数量可能性是很大的,特别是一些安慰奖,如果这里我们再用悲观锁的话,很容易造成锁超时。所以这里我选择用乐观锁来解决可能出现的并发脏读的情况。

奖品发放的分布

为了防止用脚本来刷抽奖,所以这里需要控制一下奖品发放的一个分布,中大奖需要一个时间间隔,当然这里通过代码来控制是很容易实现的(当然这里也需要考虑一下并发中到两个大奖的情况,也可以通过乐观锁来控制)

中奖的概率的可控性

当我们开始估计抽奖大概会有10W人参加,所以我在设计概率的时候是按照10w来设计的,但是突然发现活动开始一个小时候以后抽奖人数就达到了5W,这个时候就需要可以动态来调整中奖的概率了。这里最好的方式是,不要把中奖概论写死在数据库,而是通过中奖次数/参加人数来计算出来,这样就可以方便的动态的改变中奖概率了。

关于优化

如果并发量实在是太大,导致数据库的QPS异常的高。那么可以在数据库前面加一层缓存来挡一下,把需要写进数据库的数据放入队列。当使用了这种架构架构,就需要考虑一些数据一致性的问题了,比如说

  • 怎么保证数据库的数据和缓存的数据是一致的
  • 如果队列挂掉了,怎么保证缓存的数据能够及时更新到数据库中。如果缓存挂掉了,怎么保证抽奖能够继续进行下去(当然这里可以进行业务妥协,如果缓存挂掉整个抽奖挂掉,如果来不及写进数据库的数据,就当做这些事情没有发生,这就会导致某些人抽奖次数超过限定次数,或者某些奖中奖次数超过了限定次数)

关于优化中我对一些异常情况的解决方法不是很了解,希望懂的朋友可以指教一下

附录(简单流程图)

如何设计高并发下的抽奖?

先插入中奖结果 之后根据唯一主键取得中奖数量

select count(*) from table where id

数量超出返回失败 后台根据限定的中奖数取前n个即可

高并发下抽奖跟秒杀系统有些类似。

比如,中奖只是少数,大部分人并不会中奖。所以可以在第一步便限制只有少数用户的请求能够打到真正抽奖逻辑上。这样一来服务器压力就小了很多。

真正参与抽奖的用户,先随机下该用户能不能中奖,中什么奖, 如果是中了,再去查询有没有该奖(若没有奖则显示未中)。这样,又减少了一些对数据库的请求。

这样,高并发也只限于http服务器,对数据库的压力不是很大。

把中奖逻辑倒过来看,当他还没有抽奖的时候其实就相当于某个人已经中奖。

在向服务器请求的时候就已经把中奖结果在过程中分发下去,抽奖过程就一个简单的显示结果。这样就没有抽奖的压力了,非中奖用户根本没有走抽奖逻辑。压力自然就降下来了。

参考一下小米的抢手机

我觉得这个是设计思路的问题,
你应该先取当天已发奖品的数量,并且加上排它锁

<code>yyCount =  select count(*) from lottery_chance where result=YY and used_time > todayDate for update
</code>
Copy after login

这样当存在并发时,取奖品数量能保证有唯一进程在(奖品等于 YY 上)抽奖,其他进程处于等待加锁状态,直到上一次抽奖结束,然后获取锁,继续下面的操作

高并发还想着用mysql解决问题,恐怕就不太合适.
建议考虑下队列.或者将数据放在redis这类单线处理数据的功能中.
memcache不行啦,需要注意下.
reids是个好选择,可以考虑使用.或者考虑使用队列系统处理

高并发下,我觉得大概是这么几个步骤:
1、是否丢弃该抽奖请求(根据服务器的承受能力,会有一部分请求直接丢弃);
2、用户本次抽奖是否符合业务逻辑(是否有剩余抽奖次数等);
3、如果有多个奖品,那么去掉不符合规则的奖品(比如有的奖品只能中一次,而该用户已经中了一次);
4、在剩下的奖品中按照规则抽取(这里的规则可能简单也可能复杂);
5、如果抽中了某奖品,立刻尝试从奖品队列(这里可以是缓存队列,也可以是数据库记录,但要保证该操作的原子性)中拿取奖品,如果拿取成功(即奖品有剩余)则告诉用户已经中奖。

最OK的办法就是乐观锁
只要是抽奖,必然有并发问题。
涉及到利益的东西,必然有人通过工具刷请求

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

MySQL: An Introduction to the World's Most Popular Database MySQL: An Introduction to the World's Most Popular Database Apr 12, 2025 am 12:18 AM

MySQL is an open source relational database management system, mainly used to store and retrieve data quickly and reliably. Its working principle includes client requests, query resolution, execution of queries and return results. Examples of usage include creating tables, inserting and querying data, and advanced features such as JOIN operations. Common errors involve SQL syntax, data types, and permissions, and optimization suggestions include the use of indexes, optimized queries, and partitioning of tables.

PHP and Python: Comparing Two Popular Programming Languages PHP and Python: Comparing Two Popular Programming Languages Apr 14, 2025 am 12:13 AM

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

PHP's Current Status: A Look at Web Development Trends PHP's Current Status: A Look at Web Development Trends Apr 13, 2025 am 12:20 AM

PHP remains important in modern web development, especially in content management and e-commerce platforms. 1) PHP has a rich ecosystem and strong framework support, such as Laravel and Symfony. 2) Performance optimization can be achieved through OPcache and Nginx. 3) PHP8.0 introduces JIT compiler to improve performance. 4) Cloud-native applications are deployed through Docker and Kubernetes to improve flexibility and scalability.

Why Use MySQL? Benefits and Advantages Why Use MySQL? Benefits and Advantages Apr 12, 2025 am 12:17 AM

MySQL is chosen for its performance, reliability, ease of use, and community support. 1.MySQL provides efficient data storage and retrieval functions, supporting multiple data types and advanced query operations. 2. Adopt client-server architecture and multiple storage engines to support transaction and query optimization. 3. Easy to use, supports a variety of operating systems and programming languages. 4. Have strong community support and provide rich resources and solutions.

PHP: The Foundation of Many Websites PHP: The Foundation of Many Websites Apr 13, 2025 am 12:07 AM

The reasons why PHP is the preferred technology stack for many websites include its ease of use, strong community support, and widespread use. 1) Easy to learn and use, suitable for beginners. 2) Have a huge developer community and rich resources. 3) Widely used in WordPress, Drupal and other platforms. 4) Integrate tightly with web servers to simplify development deployment.

PHP: A Key Language for Web Development PHP: A Key Language for Web Development Apr 13, 2025 am 12:08 AM

PHP is a scripting language widely used on the server side, especially suitable for web development. 1.PHP can embed HTML, process HTTP requests and responses, and supports a variety of databases. 2.PHP is used to generate dynamic web content, process form data, access databases, etc., with strong community support and open source resources. 3. PHP is an interpreted language, and the execution process includes lexical analysis, grammatical analysis, compilation and execution. 4.PHP can be combined with MySQL for advanced applications such as user registration systems. 5. When debugging PHP, you can use functions such as error_reporting() and var_dump(). 6. Optimize PHP code to use caching mechanisms, optimize database queries and use built-in functions. 7

MySQL's Place: Databases and Programming MySQL's Place: Databases and Programming Apr 13, 2025 am 12:18 AM

MySQL's position in databases and programming is very important. It is an open source relational database management system that is widely used in various application scenarios. 1) MySQL provides efficient data storage, organization and retrieval functions, supporting Web, mobile and enterprise-level systems. 2) It uses a client-server architecture, supports multiple storage engines and index optimization. 3) Basic usages include creating tables and inserting data, and advanced usages involve multi-table JOINs and complex queries. 4) Frequently asked questions such as SQL syntax errors and performance issues can be debugged through the EXPLAIN command and slow query log. 5) Performance optimization methods include rational use of indexes, optimized query and use of caches. Best practices include using transactions and PreparedStatemen

The Enduring Relevance of PHP: Is It Still Alive? The Enduring Relevance of PHP: Is It Still Alive? Apr 14, 2025 am 12:12 AM

PHP is still dynamic and still occupies an important position in the field of modern programming. 1) PHP's simplicity and powerful community support make it widely used in web development; 2) Its flexibility and stability make it outstanding in handling web forms, database operations and file processing; 3) PHP is constantly evolving and optimizing, suitable for beginners and experienced developers.

See all articles