数据计数/订单号生成
Last updated
Was this helpful?
Last updated
Was this helpful?
数据计数/订单号生成
唯一计数是网站系统中十分常见的一个功能特性,例如网站需要统计每天访问的人数 unique visitor (也就是 UV)。计数问题很常见,但解决起来可能十分复杂:一是需要计数的量可能很大,比如大型的站点每天有数百万的人访问,数据量相当大;二是通常还希望扩展计数的维度,比如除了需要每天的 UV,还想知道每周或每月的 UV,这样导致计算十分复杂。
在关系数据库存储的系统里,实现唯一计数的方法就是 select count(distinct ),它十分简单,但是如果数据量很大,这个语句执行是很慢的。用关系数据库另外一个问题是插入数据性能也不高。
Redis 解决这类计数问题得心应手,相比关系数据库速度更快,消耗资源更少,甚至提供了 3 种不同的方法。
数据计数
INCR key
将key中储存的数字值增一。
如果key不存在,那么key的值会先被初始化为0,然后再执行操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
这是一个针对字符串的操作,因为 Redis 没有专用的整数类型,所以 key 内储存的字符串被解释为十进制 64 位有符号整数来执行 INCR 操作。
可用版本:
>= 1.0.0
时间复杂度:
O(1)
返回值:
执行 INCR 命令之后 key 的值。
Redis 的 set 用于保存唯一的数据集合,通过它可以快速判断某一个元素是否存在于集合中,也可以快速计算某一个集合的元素个数,另外和可以合并集合到一个新的集合中。涉及的命令如下:
代码如下:
Redis 的 bit 可以用于实现比 set 内存高度压缩的计数,它通过一个 bit 1 或 0 来存储某个元素是否存在信息。例如网站唯一访客计数,可以把 user_id 作为 bit 的偏移量 offset,设置为 1 表示有访问,使用 1 MB的空间就可以存放 800 多万用户的一天访问计数情况。涉及的命令如下:#p#分页标题#e#
代码如下:
基于 bit 的方法比起 set 空间消耗小得多,但是它要求元素能否简单映射为位偏移,适用面窄了不少,另外它消耗的空间取决于最大偏移量,和计数值无关,如果最大偏移量很大,消耗内存也相当可观。
实现超大数据量精确的唯一计数都是比较困难的,但是如果只是近似的话,计算科学里有很多高效的算法,其中 HyperLogLog Counting 就是其中非常著名的算法,它可以仅仅使用 12 k左右的内存,实现上亿的唯一计数,而且误差控制在百分之一左右。涉及的命令如下:
代码如下:
订单号生成
订单前缀可以设置在订单中心或配置文件里,这样可以在不同环境获得不同的订单号,避免因不同数据中心,导致出现订单号重复的情况。
JedisManager.incr()方法,该方法是订单号生成的一个亮点,也是支持能够高并发的主要原因。
Incr 命令会将 redis的key 中储存的数字值增一。
decr 命令会将 redis的key 中存储的数字值减一。
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR / DECR 操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
之前看到过说 Incr 命令最高支持每秒1000万级别的递增(没有测试过),且该命令支持原子性,用来生成订单号来说还是比较轻松的。
同样的该方式也适用于 ”秒杀“库存的递减 等场景。