如何实现毫秒级别的抽奖系统

业务进行分析

我们首先对业务场景进行定义,如何快速的从 1000w 数据中找到 10 个数据作为中奖用户,重复100次,每次作为我们终将的名单,切每一个用户不能重复中奖。基于这个过程我们如何把这个过程高效的实现呢?

数据库实现:

使用数据库是最直接的方法,但在处理大规模数据时,性能可能成为瓶颈。

1
2
select id from User where status=0 order by rand() limit 10
update user set status=1 where id in(...)

使用Redis实现:

使用Set数据结构来存储中奖用户,可以提高抽奖效率。具体实现如下:

  • 使用Redis Set: 将中奖用户的ID存储在Redis的Set数据结构中,确保不会有重复的用户。
1
2
sadd usrlist uuid1
sadd usrlist uuid2
  • 抽奖逻辑优化: 通过Redis提供的spop命令,从Set中弹出指定数量的元素,实现高效的抽奖。
1
spop usrlist 10

需要注意的问题

在使用redis方案时候,需要考虑一下问题:

  1. 1000w数据如何预热到缓存中?
  2. 1000w数据大概占用多少空间?
  3. 整体的性能大概是多少?

对于上面几个问题我们分别来看:

  1. 预热我们可以采用job定时预热的模式,采用 sharding +多线程的方式写入redis
  2. 对于占用空间问题,如果一个userId 占用 n 个字节,1000w大概占用1000w/1024/1024 n=5n mb。经过测算,如果userid 采用长整型的话,预计占用 58 =40Mb.
  3. Redis的Set底层主要使用了两种数据结构进行存储:intset(整数集合)和hashtable(哈希表)。这两个数据结构的删除都是 O(1),所以效率非常高。