diff --git a/中间件/redis/redis.md b/中间件/redis/redis.md index 8019325..53f669c 100644 --- a/中间件/redis/redis.md +++ b/中间件/redis/redis.md @@ -134,6 +134,11 @@ - [single bit operations](#single-bit-operations) - [operations on group of bits](#operations-on-group-of-bits) - [longest streak of daily visits](#longest-streak-of-daily-visits) + - [Probabilistic](#probabilistic) + - [HyperLogLog](#hyperloglog) + - [Bloom Filter](#bloom-filter) + - [Example](#example-1) + - [Reserving Bloom filters](#reserving-bloom-filters) # redis @@ -2303,5 +2308,90 @@ bitcount的使用示例如下: bitmaps可以被轻松的拆分为多个key,通常来讲,也应当避免操作过大的key。将大的bitmap拆分为多个key时,通用策略是`限制每个key`存储`M`个bits,并且通过`{bit-index}/M`来决定当前bit位于哪个key,而`{bit-index} MOD M`则用于当前bit位于key的哪个位置。 +### Probabilistic +`Probabilistic data structure`向使用者提供了统计数据的`近似值`,例如`计数、频率、排名`等,而并非精确值。使用Probabilistic data structure可以提高计算效率。 +#### HyperLogLog +`HyperLogLog`数据结构用于估计set中的基数,HyperLogLog并不能保证结果的精确性,但是能够提高空间的使用效率。 +> Redis的HyperLogLog实现最多占用12KB空间,并提供了`0.81%`的标准误差。 + +通常,统计items中的唯一项个数需要花费的空间和items的个数成正比,但是,有一系列算法可以`牺牲精确性来换取内存使用大小`: +- 其能够返回唯一项个数的大致估计值,并且估计值存在标准误差,在redis HyperLogLog的实现中,标准误差小于1% +- 在使用该算法时,并不需要使用和items个数成正比的内存空间,而是使用常量大小的内存(在最坏情况下,使用空间大小为12KB,当HyperLogLog中包含元素较少时,其使用的空间也远小于12KB) + +在redis中,HyperLogLog是编码成Redis strings的。故而,对于`HyperLogLog`类型,可以通过`GET`来进行序列化,并通过`SET`来进行反序列化。 + +在使用HyperLogLog时,其API如下: +- `PFADD`: 可以通过该命令将new item添加到HyperLogLog +- `PFCOUNT`: 当想要获取唯一项个数的近似值时,可以调用`PFCOUNT`命令 +- `PFMERGE`: 如果想要对两个不同的HyperlogLog进行合并,可以使用`PFMERGE`命令 + +HyperLogLog的使用示例如下所示: +```redis-cli +> PFADD bikes Hyperion Deimos Phoebe Quaoar +(integer) 1 +> PFCOUNT bikes +(integer) 4 +> PFADD commuter_bikes Salacia Mimas Quaoar +(integer) 1 +> PFMERGE all_bikes bikes commuter_bikes +OK +> PFCOUNT all_bikes +(integer) 6 +``` +HyperLogLog数据结构通常有如下用例场景:统计页面或网站的每天用户访问量 + +#### Bloom Filter +Bloom Filter也是一种`Probabilistic data structure`,用于检测在set中item是否存在,其使用少量的的固定大小存储空间。 + +Bloom Filter并不会将items都存储在set中,相对的,其仅存储item在hash后的结果,故而在部分程度上会牺牲精确性。`通过对精确性的牺牲,Bloom Filter拥有十分高的内存效率,并且其执行效率也很高`。 + +`Bloom Filter仅能够保证某元素在set中不存在,但是关于元素的存在其仅能给出一个估计值`: +- 当Bloom Filter的返回结果表示某item不存在于set中时,`返回结果是精确的,该item一定在set中不存在` +- 但是,如果若Bloom Filter返回结果表示某item存在时,`每N个存在的返回结果就有一个是错误的`。 + +Bloom Filter通常用于`negative answer will prevent more costly operations`的场景,例如`用户名称是否被占用,信用卡是否被丢失,用户是否看过广告等` + +##### Example +假设自行车生产商已经生产了百万种不同型号的自行车,目前需要`在为新model指定名称时避免指定旧model已经使用过的名称`。 + +在该种用例场景下,可以使用bloom filter来检测重复。在如下实例中,创建的bloom filter可容纳100w entries,并且错误率仅为0.1%。 + +```redis-cli +> BF.RESERVE bikes:models 0.001 1000000 +OK +> BF.ADD bikes:models "Smoky Mountain Striker" +(integer) 1 +> BF.EXISTS bikes:models "Smoky Mountain Striker" +(integer) 1 +> BF.MADD bikes:models "Rocky Mountain Racer" "Cloudy City Cruiser" "Windy City Wippet" +1) (integer) 1 +2) (integer) 1 +3) (integer) 1 +> BF.MEXISTS bikes:models "Rocky Mountain Racer" "Cloudy City Cruiser" "Windy City Wippet" +1) (integer) 1 +2) (integer) 1 +3) (integer) 1 +``` +> 在上述示例中,即使bloom filter中仅存在少量元素,返回的`存在`结果也存在误报的可能,即元素其实根本不存在。 + +##### Reserving Bloom filters +在使用bloom filters时,大部分sizing工作都会自动完成: +```redis-cli +BF.RESERVE {key} {error_rate} {capacity} [EXPANSION expansion] [NONSCALING] +``` +- `error_rate`: 该参数代表`false positive rate`,该rate为0和1之间的decimal,例如,当希望的false positive rate为`0.1%`(1 in 1000)时,需要将error_rate设置为0.001 +- `expected capacity(capacity)`: 该参数代表`bloom filter中期望包含的元素数量`。需要确保该值的准确性: + - 如果该值设置过大,其会浪费内存空间 + - 如果该值设置过小,那么filter被填充满后,`a new one will have to be stacked on top of it (sub-filter stacking)` + - `when a filter consists of multiple sub-filters stacked on top of each other`,`其新增操作的延迟仍然会保持不变;但是存在性检查的延迟会增加` + - 存在性检查的原理如下:首先,会对top filter检查元素的存在性,如果返回为false,那么会继续检查以一个sub-filter,`该机制会导致存在性检查的延迟增加` +- `scaling(EXPANSION)`: 在向bloom filter中添加数据时,并不会因为数据结构的填充而失败。在向filter中添加元素时,error rate也会随之增加。为了保证错误率和bloom filter创建时指定的error rate相近,bloom filter需要自动扩容:`当capacity限制达到时,需要自动创建额外的sub-filter`。 + - `new sub filter`的size大小等于`last-sub-filter-size * EXPANSION`。 + - 如果filter中存储的items数量未知,可以将`EXPANSION`设置为`2 or more`,从而减少sub-filters的数量。 + - 否则,可以将`EXPANSION`设置为`1`,从而减少内存的消耗 + - 默认的EXPANSION为2 + > 在向filter中添加new sub-filter时,相比于前一个filter,会为new sub-filter分配更多的hash function + +- `NONSCALING`: 如果想要禁用scale,可以指定`NONSCALING`。如果达到了initially assigned \ No newline at end of file