一、GEO查询附近的人
引入
- 我们所处的任何位置都可以用经纬度和维度拉标识,经度的范围 -180°到 180°,维度的范围为 -90° 到 90°。维度以赤道为界。赤道以南为负数,赤道以北为整数;经度以本初子午线(英国格林尼治天文台)为界,东边为正数,西边为负数。
- Redis 在 3.2 版本中增加了 GEO 类型用于存储和查询地理位置,关于 GEO 的命令不多,主要包含以下6个:
命令 | 说明 | 语法 |
---|---|---|
geoadd | 添加地理位置 | geoadd key longitude latitude member |
geopos | 查询位置信息,可看多个 | geopos key member [member…] |
geodist | 距离统计 | geodist key member1 member2 [unit] |
georadius | 查询某位置内的其他成员信息 | geoadius key longitude latitude radius unit [WITHCOORD][WITHDIST] [COUNT [ASC/DESC] |
geohash | 查询位置的哈希值,可以查多个 | geohash key member [member …] |
zrem | 删除地理位置,可以删多个 | zrem key member [member …] |
重点参数说明如下:
- longitude 表示经度
- latitude 表示纬度
- member 是为此经纬度起的名字 此命令支持一次添加一个或多个位置信息。
- unit:统计单位
- 1.WITHCOORD:返回满足条件位置的经纬度信息。
2.WITHHDIST:返回满足条件位置与查询位置的直线距离。
3.COUNT:指定返回满足条件位置的个数。
4.[ASC/DESC]:从近到远 | 从远到近排序返回。
基础使用
- 添加地理位置
- 我们先用百度地图提供的经纬度查询工具,地址:http://api.map.baidu.com/lbsapi/getpoint/index.html
- 找了以下4个地点,添加到 Redis 中
天安门:116.404269,39.913164
月坛公园:116.36,39.922461
北京欢乐谷:116.499705,39.874635
香山公园:116.193275,39.996348geoadd site 16.404269 39.913164 tiananmen geoadd site 116.36 39.922461 yuetan geoadd site 116.499705 39.874635 huanle geoadd site 116.193275 39.996348 xiangshan
- 查询位置信息
- geopos site tiananmen
- 距离统计
- geodist site tianan yuetan km
- https://www.hhlink.com/经纬度(经纬度计算距离)校验结果
- 查询某位置内的其他成员信息
- georadius site 116.405419 39.913164 5 km
- 此命令的意思是查询天安门(116.405419,39.913164)附近5公里范围内的成员列表。
- 查询哈希值
- geohash site tiananmen
- 删除地理位置
- zrem site xiaoming
应用场景
- 查询附近的人、附近的地点等;
- 计算相关的距离信息。
小结
- GEO 是 Redis 3.2 版本中新增的功能,只有升级到 3.2+ 才能使用,GEO 本质上是基于 ZSet 实现的,这点在 Redis 源码找到相关信息,我们可以 GEO 使用实现查找附近的人 或者附近的地点,还可以用它来计算两个位置相隔的直线距离。
二、基数统计算法-HyperLogLog
基数为什么要使用 HyperLogLog?
- 在我们实际开发的过程中,可能会遇到这样一个问题,当我们需要统计一个大型网站的独立访问次数时,该用什么什么的类型来统计?
- 如果我们使用 Redis 中的集合来统计,当它每天有数千万级别的访问时,将会是一个巨大的问题。因为这些访问量不能被清空,我们运营人员可能会随时查看这些信息,那么随着时间的推移,这些统计数据所占用的空间会越来越大,逐渐超出我们能承受最大空间。
- 例如,我们用 IP 来作为独立访问的判断依据,那么我们就要把每个独立 IP 进行存储,以 IP4 来计算,IP4最对需要 15 个字节来存储信息,例如:
110.110.110.110。当有一千万独立 IP 时,所占用的空间就是 15 bit*10000000 约等于 143 MB,但这只是一个页面的统计信息,假如我们有1千万个个这样的页面,那么我们需要 1T 以上的空间来存储这些数据,而且随着 IP6 的普及,这个存储数字会越来越大,那我们就不能用集合的方式来存储了,这个时候我们需要开发新的数据类型 HyperLogLog 来做这件事了。
HyperLogLog 介绍
- 集合保存数据,会去重,无序
- HyperLogLog (下文简称HLL)是 Redis 2.8.9 版本添加的数据结构,它用于高性能的基数(去重)统计功能,它的缺点就是存在极低的误差率。
HLL 特点:
- 能够使用极少的内存来统计巨量的数据,它只需要12 k 空间就能统计 2^64 的数据;
- 统计存在一定的误差,误差率整体较低,标准误差为 0.81%;
- 误差可以被设置辅助计算因子进行降低。
基础使用
命令 | 说明 | 使用 |
---|---|---|
pfadd | 添加元素,支持添加一个或多个元素至HLL结构中 | pfadd key element [element …] |
pfcount | 统计不重复的元素,支持一个或多个 HLL 结构。 | pfcount key [key…] |
pfmerge | 合并一个或多个 HLL 至新结构,如果已经存在新key会覆盖 | pfmerge 新key 旧key [旧key…] |
三、布隆过滤器
定义
- 我们前面有讲到过 HyperLogLog 可以用来做基数统计,但它没提供判断一个值是否存在的查询方法,那我们如何才能查询一个值是否存在于海量数据之中呢?
- 如果使用传递的方式,例如 SQL 中的传统查询,因为数据量太多,查询效率又低有占用系统的资源2,因此我们需要一个优秀的算法和功能来实现这个需求,这是我们今天要讲的——布隆过滤器。
- 开启布隆过滤器在 Redis 中不能直接使用布隆过滤器,但我们可以通过 Redis 4.0 版本之后提供的 modules (扩展模块)的方式引入,本文提供两种方式的开启方式。
作用
- 缓存穿透的解决方案
安装使用
```
linux下载并安装布隆过滤器
```
git clone https://github.com/RedisLabsModules/redisbloom.git
cd redisbloom
make ## 编译,编译正常执行,会在跟目录生成一个 redisbloom.so 文件。
```
启动 Redis 服务器
```
./src/redis-server redis.conf --loadmodule ./src/modules/RedisBloom-master/redisbloom.so
## 其中–loadmodule 为加载扩展模块的意思,后面跟的是 redisbloom.so 文件的目录。
## 如果有命令提示则表名 Redis 服务器已经开启了布隆过滤器。
命令 | 说明 | 使用 |
---|---|---|
bf.add | 添加元素 | bf.add key element |
bf.madd | 添加多个元素 | bf.madd key element [element…] |
bf.exists | 判断某个元素是否存在,返回1表示存在 | bf.exists key element |
bf.mexists | 判断多个元素是否存在,返回1表示存在 | bf.exists key lement [element…] |
bf.reserve | 设置布隆过滤器的错误率,key得是没有创建过的 | bf.reserve key 错误率 存储元素大小 |
错误率
- 该错误是指在判断元素是否存在的时候,如果返回0,则里面一定没有,如果返回1,不一定有
- 错误率越小,占用的空间就越大,200就是实际存储的值要远大于这个值准确率就会降低
四、缓存雪崩&缓存穿透
(一)缓存雪崩
定义
- 缓存雪崩是指在短时间内,有大量缓存同时过期,导致大量的请求查询数据库,从而对数据库造成了巨大的压力,严重情况下可能导致数据库宕机的情况叫做缓存雪崩。
缓存雪崩解决方案
- 1.随机化过期时间
- 为了避免缓存同时过期,可在设置缓存时添加随机时间,这样就可以极大的避免大量的缓存同时失效。
- 2.加锁排队
- 加锁排队可以起到缓冲的作用,防止大量的请求同时操作数据库,但它的缺点是增加了系统的响应时间,降低了系统的吞吐,牺牲了一部分用户体验。
(二)缓存穿透
定义
- 缓存穿透是指查询数据库和缓存都无数据,因为数据库查询无数据,出于容错考虑,不会将结果保存到缓存中,因此每次请求都会查询数据库,这种情况就叫做缓存穿透。
缓存穿透解决方案
- 使用过滤器
- 我们可以使用过滤器来减少对数据库的请求,例如使用我们前面所学的布隆过滤器。
- 缓存空结果
- 另一种方式是我们可以把每次从数据库查询的数据都保存到缓存中,为了提高前台用户的体验(解决长时间内查询不到任何信息的情况),我们可以将空结果的缓存时间设置的短一些,例如 3-5分钟。
(三)缓存击穿
定义
- 缓存击穿是短时间内大量用户访问一个key,即热点key,当热点key缓存失效的时候,就会有大量请求直接打在数据库上。
缓存穿透解决方案
- 加锁限流
- 限制访问客流。
- 设置热点key永不过期
- 热点key缓存一直存着,要更新的话也是在内部更新,不会过期