如何异步生成10位的兑换码

1. 兑换码需求

  • 可读性好:兑换码是要给用户使用的,用户需要输入兑换码,因此可读性必须好。我们的要求:

    • 长度不超过10个字符

    • 只能是24个大写字母和8个数字:ABCDEFGHJKLMNPQRSTUVWXYZ23456789

  • 数据量大:优惠活动比较频繁,必须有充足的兑换码,最好有10亿以上的量

  • 唯一性:10亿兑换码都必须唯一,不能重复,否则会出现兑换混乱的情况

  • 不可重兑:兑换码必须便于校验兑换状态,避免重复兑换

  • 防止爆刷:兑换码的规律性不能很明显,不能轻易被人猜测到其它兑换码

  • 高效:兑换码生成、验证的算法必须保证效率,避免对数据库带来较大的压力

2. 算法分析

2.1 Base32转码 

将24个字母和8个数字放到数组中,如下:

角标

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

字符

A

B

C

D

E

F

G

H

J

K

L

M

N

P

Q

R

角标

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

字符

S

T

U

V

W

X

Y

Z

2

3

4

5

6

7

8

9

这样,0~31的角标刚好对应了我们的32个字符!而2的5次幂刚好就是32,因此5位二进制数的范围就是0~31。

那因此,只要我们让数字转为二进制的形式,然后每5个二进制位为一组,转10进制的结果是不是刚好对应一个角标,就能找到一个对应的字符呢?

这样是不是就把一个数字转为我们想要的字符个数了。这种把二进制数经过加密得到字符的算法就是Base32法,类似的还有Base64法。

举例:假如我们经过自增id计算出一个复杂数字,转为二进制,并每5位一组,结果如下:

01001 00010 01100 10010 01101 11000 01101 00010 11110 11010

此时,我们看看每一组的结果:

  • 01001转10进制是9,查数组得字符为:K

  • 00010转10进制是2,查数组得字符为:C

  • 01100转10进制是12,查数组得字符为:N

  • 10010转10进制是18,查数组得字符为:B

  • 01101转10进制是13,查数组得字符为:P

  • 11000转10进制是24,查数组得字符为:2

  • ...

依此类推,最终那一串二进制数得到的结果就是KCNBP2PC84,刚好符合我们的需求。

自增id从1增加到Integer的最大值,可以达到40亿以上个数字,而占用的字节仅仅4个字节,也就是32个bit位,距离50个bit位的限制还有很大的剩余,符合要求!

综上,我们可以利用自增id作为兑换码,但是要利用Base32加密,转为我们要求的格式。此时就符合了我们的几个要求了:

  • 可读性好:可以转为要求的字母和数字的格式,