【学习笔记】Redis geohash介绍和持久化配置介绍

geohash介绍

⾃Redis 3.2开始,Redis基于geohash和有序集合提供了地理位置相关功能。Redis Geo模块包含了以下6个命令:
▶GEOADD: 将给定的位置对象(纬度、经度、名字)添加到指定的key;
▶GEOPOS: 从key⾥⾯返回所有给定位置对象的位置(经度和纬度);
▶GEODIST: 返回两个给定位置之间的距离;
▶GEOHASH: 返回⼀个或多个位置对象的Geohash表⽰;
▶GEORADIUS: 以给定的经纬度为中⼼,返回⽬标集合中与中⼼的距离不超过给定最⼤距离的所有位置对象;
▶GEORADIUSBYMEMBER: 以给定的位置对象为中⼼,返回与其距离不超过给定最⼤距离的所有位置对象。
其中,组合使⽤GEOADD和GEORADIUS可实现“附近的⼈”中“增”和“查”的基本功能。要实现微信中“附近的⼈”功能,可直接使⽤GEORADIUSBYMEMBER命令。其中“给定的位置对象”即为⽤⼾本⼈,搜索的对象为其他⽤⼾。不过本质
上,GEORADIUSBYMEMBER = GEOPOS + GEORADIUS,即先查找⽤⼾位置再通过该位置搜索附近满⾜位置相互距离条件的其他⽤⼾对象。
以下会从源码⻆度⼊⼿对GEOADD和GEORADIUS命令进⾏分析,剖析其算法原理

Redis geo操作中只包含了“增”和“查”的操作,并没有专⻔的“删除”命令。主要是因为Redis内部使⽤有序集合(zset)保存位置对象,可⽤zrem进⾏删除。
在Redis源码geo.c的⽂件注释中,只说明了该⽂件为GEOADD、GEORADIUSGEORADIUSBYMEMBER的实现⽂件(其实在也实现了另三个命令)。从侧⾯看出其他三个命令为辅助命令。

GEOADD

使⽤⽅式
GEOADD key longitude latitude member [longitude latitude member …]
将给定的位置对象(纬度、经度、名字)添加到指定的key。
其中,key为集合名称,member为该经纬度所对应的对象。在实际运⽤中,当所需存储的对象数量过多时,可通过设置多
key(如⼀个省⼀个key)的⽅式对对象集合变相做sharding,避免单集合数量过多。
成功插⼊后的返回值:
(integer) N
其中N为成功插⼊的个数。

通过源码分析可以看出Redis内部使⽤有序集合(zset)保存位置对象,有序集合中每个元素都是⼀个带位置的对象,元素的score值为其经纬度对应的52位的geohash值。
double类型精度为52位;
geohash是以base32的⽅式编码,52bits最⾼可存储10位geohash值,对应地理区域⼤⼩为0.60.6⽶的格⼦。换句话说经Redis geo转换过的位置理论上会有约0.31.414=0.424⽶的误差。(?)

简单总结下GEOADD命令都⼲了啥:
1、参数提取和校验;
2、将⼊参经纬度转换为52位的geohash值(score);
3、调⽤ZADD命令将member及其对应的score存⼊集合key中。

GEORADIUS

使⽤⽅式

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count] [STORE key] [STORedisT key]

以给定的经纬度为中⼼,返回⽬标集合中与中⼼的距离不超过给定最⼤距离的所有位置对象。
范围单位:m | km | ft | mi --> ⽶ | 千⽶ | 英尺 | 英⾥
额外外参数:

  • WITHDIST:在返回位置对象的同时,将位置对象与中⼼之间的距离也⼀并返回。距离的单位和⽤⼾给定的范围单位保持⼀致。
  • WITHCOORD:将位置对象的经度和维度也⼀并返回。
  • WITHHASH:以 52 位有符号整数的形式,返回位置对象经过原始 geohash 编码的有序集合分值。这个选项主要⽤于底层应⽤
    或者调试,实际中的作⽤并不⼤。
  • ASC|DESC:从近到远返回位置对象元素 | 从远到近返回位置对象元素。
  • COUNT count:选取前N个匹配位置对象元素。(不设置则返回所有元素) - STORE key:将返回结果的地理位置信息保存到
    指定key。
  • STORedisT key:将返回结果离中⼼点的距离保存到指定key。

由于 STORE 和 STORedisT 两个选项的存在,GEORADIUS 和 GEORADIUSBYMEMBER 命令在技术上会被标记为写⼊命令,从⽽只会查询(写⼊)主实例,QPS过⾼时容易造成主实例读写压⼒过⼤。为解决这个问题,在 Redis 3.2.10 和 Redis 4.0.0 中,分别新增了 GEORADIUS_RO 和 GEORADIUSBYMEMBER_RO两个只读命令。
不过,在实际开发中笔者发现 在java package Redis.clients.jedis.params.geo 的 GeoRadiusParam 参数类中并不包含STORE 和 STORedisT 两个参数选项,在调⽤georadius时是否真的只查询了主实例,还是进⾏了只读封装。
成功查询后的返回值:
不带WITH限定,返回⼀个member list,如:
[“member1”,“member2”,“member3”]
带WITH限定,member list中每个member也是⼀个嵌套list,如:
[
[“member1”, distance1, [longitude1, latitude1]]
[“member2”, distance2, [longitude2, latitude2]]
]

⼩结
抛开众多可选参数不谈,简单总结下GEORADIUS命令是怎么利⽤geohash获取⽬标位置对象的:
1、参数提取和校验;
2、利⽤中⼼点和输⼊半径计算待查区域范围。这个范围参数包括满⾜条件的最⾼的geohash⽹格等级(精度) 以及 对应的能够覆盖⽬标区域的九宫格位置;(后续会有详细说明)
3、对九宫格进⾏遍历,根据每个geohash⽹格的范围框选出位置对象。进⼀步找出与中⼼点距离⼩于输⼊半径的对象,进⾏返回。
直接描述不太好理解,我们通过如下两张图在对算法进⾏简单的演⽰:
在这里插入图片描述
令左图的中⼼为搜索中⼼,绿⾊圆形区域为⽬标区域,所有点为待搜索的位置对象,红⾊点则为满⾜条件的位置对象。
在实际搜索时,⾸先会根据搜索半径计算geohash⽹格等级(即右图中⽹格⼤⼩等级),并确定九宫格位置(即红⾊九宫格位置信息);再依次查找计算九宫格中的点(蓝点和红点)与中⼼点的距离,最终筛选出距离范围内的点(红点)。

如何通过geohash⽹格的范围框选出元素对象?效率如何?
⾸先在每个geohash⽹格中的geohash值都是连续的,有固定范围。所以只要找出有序集合中,处在该范围的位置对象即可。以下是有序集合的跳表数据结构:
在这里插入图片描述
其拥有类似⼆叉查找树的查询效率,操作平均时间复杂性为O(log(N))。
且最底层的所有元素都以链表的形式按序排列。
所以在查询时,只要找到集合中处在⽬标geohash⽹格中的第⼀个值,后续依次对⽐即可,不⽤多次查找。九宫格不能⼀起查,要⼀个个遍历的原因也在于九宫格各⽹格对应的geohash值不具有连续性。只有连续了,查询效率才会⾼,不然要多做许多距离运算。

持久化的方式

1.持久化的⼏种⽅式
Redis 持久化拥有以下三种⽅式:
快照⽅式(RDB, Redis DataBase)将某⼀个时刻的内存数据,以⼆进制的⽅式写⼊磁盘;
⽂件追加⽅式(AOF, Append Only File),记录所有的操作命令,并以⽂本的形式追加到⽂件中;
混合持久化⽅式,Redis 4.0 之后新增的⽅式,混合持久化是结合了 RDB 和 AOF 的优点,在写⼊的时候,先把当前的数据以RDB 的形式写⼊⽂件的开头,再将后续的操作命令以 AOF 的格式存⼊⽂件,这样既能保证 Redis 重启时的速度,⼜能简单数据丢失的⻛险。
因为每种持久化⽅案,都有特定的使⽤场景,让我们先从 RDB 持久化说起吧。
2.RDB简介
RDB(Redis DataBase)是将某⼀个时刻的内存快照(Snapshot),以⼆进制的⽅式写⼊磁盘的过程。
3.持久化触发
RDB 的持久化触发⽅式有两类:⼀类是⼿动触发,另⼀类是⾃动触发。
1)⼿动触发
⼿动触发持久化的操作有两个: save 和 bgsave ,它们主要区别体现在:是否阻塞 Redis 主线程的执⾏。
① save 命令
在客⼾端中执⾏ save 命令,就会触发 Redis 的持久化,但同时也是使 Redis 处于阻塞状态,直到 RDB 持久化完成,才会响应其他客⼾端发来的命令,所以在⽣产环境⼀定要慎⽤。
save 命令使⽤如下:
在这里插入图片描述
从图⽚可以看出,当执⾏完 save 命令之后,持久化⽂件 dump.rdb 的修改时间就变了,这就表⽰ save 成功的触发了 RDB 持久化。save 命令执⾏流程,如下图所⽰:
在这里插入图片描述
② bgsave 命令
bgsave(background save)既后台保存的意思, 它和 save 命令最⼤的区别就是 bgsave 会 fork() ⼀个⼦进程来执⾏持久化,整个过程中只有在 fork() ⼦进程时有短暂的阻塞,当⼦进程被创建之后,Redis 的主进程就可以响应其他客⼾端的请求了,相对于整个流程都阻塞的 save 命令来说,显然 bgsave 命令更适合我们使⽤。bgsave 命令使⽤,如下图所⽰:
在这里插入图片描述
2)⾃动触发
说完了 RDB 的⼿动触发⽅式,下⾯来看如何⾃动触发 RDB 持久化?RDB ⾃动持久化主要来源于以下⼏种情况。
① save m n
save m
n 是指在 m 秒内,如果有 n 个键发⽣改变,则⾃动触发持久化。参数 m 和 n 可以在 Redis 的配置⽂件中找到,例如,
save601 则表明在 60 秒内,⾄少有⼀个键发⽣改变,就会触发 RDB 持久化。⾃动触发持久化,本质是 Redis 通过判断,如果满⾜设置的触发条件,⾃动执⾏⼀次 bgsave 命令。注意:当设置多个 save m n 命令时,满⾜任意⼀个条件都会触发持久化。例如,我们设置了以下两个 save m n 命令:
save 60 10
save 600 1
当 60s 内如果有 10 次 Redis 键值发⽣改变,就会触发持久化;如果 60s 内 Redis 的键值改变次数少于 10 次,那么 Redis 就会判断600s 内,Redis 的键值是否⾄少被修改了⼀次,如果满⾜则会触发持久化。
② flushall
flushall 命令⽤于清空 Redis 数据库,在⽣产环境下⼀定慎⽤,当 Redis 执⾏了 flushall 命令之后,则会触发⾃动持久化,把 RDB⽂件清空.
③ 主从同步触发
在 Redis 主从复制中,当从节点执⾏全量复制操作时,主节点会执⾏ bgsave 命令,并将 RDB ⽂件发送给从节点,该过程会⾃动触发 Redis 持久化。

配置说明

bgsave 失败之后,是否停⽌持久化数据到磁盘,yes 表⽰停⽌持久化,no 表⽰忽略错误继续写⽂件。

stop-writes-on-bgsave-error yes

RDB ⽂件压缩

rdbcompression yes

写⼊⽂件和读取⽂件时是否开启 RDB ⽂件检查,检查是否有⽆损坏,如果在启动是检查发现损坏,则停⽌启动。

rdbchecksum yes

RDB ⽂件名

dbfilename
dump
.rdb

# RDB ⽂件压缩

rdbcompression yes

# 写⼊⽂件和读取⽂件时是否开启 RDB ⽂件检查,检查是否有⽆损坏,如果在启动是检查发现损坏,则停⽌启动。

rdbchecksum yes

其中⽐较重要的参数如下列表:
① save 参数
它是⽤来配置触发 RDB 持久化条件的参数,满⾜保存条件时将会把数据持久化到硬盘。默认配置说明如下:
save 900 1:表⽰ 900 秒内如果⾄少有 1 个 key 值变化,则把数据持久化到硬盘;
save 300 10:表⽰ 300 秒内如果⾄少有 10 个 key 值变化,则把数据持久化到硬盘;
save 60 10000:表⽰ 60 秒内如果⾄少有 10000 个 key 值变化,则把数据持久化到硬盘。
② rdbcompression 参数
它的默认值是 yes 表⽰开启 RDB ⽂件压缩,Redis 会采⽤ LZF 算法进⾏压缩。如果不想消耗 CPU 性能来进⾏⽂件压缩的话,可以
设置为关闭此功能,这样的缺点是需要更多的磁盘空间来保存⽂件。
③ rdbchecksum 参数
它的默认值为 yes 表⽰写⼊⽂件和读取⽂件时是否开启 RDB ⽂件检查,检查是否有⽆损坏,如果在启动是检查发现损坏,则停⽌启动。

5.配置查询
Redis 中可以使⽤命令查询当前配置参数。查询命令的格式为: configgetxxx ,例如,想要获取 RDB ⽂件的存储名称设置,可以
使⽤ configgetdbfilename ,执⾏效果如下图所⽰:
在这里插入图片描述

6.配置设置
设置 RDB 的配置,可以通过以下两种⽅式:

⼿动修改 Redis 配置⽂件;
使⽤命令⾏设置,例如,使⽤ configsetdir"/usr/data" 就是⽤于修改 RDB 的存储⽬录。

注意:⼿动修改 Redis 配置⽂件的⽅式是全局⽣效的,即重启 Redis 服务器设置参数也不会丢失,⽽使⽤命令修改的⽅式,在Redis 重启之后就会丢失。但⼿动修改 Redis 配置⽂件,想要⽴即⽣效需要重启 Redis 服务器,⽽命令的⽅式则不需要重启 Redis
服务器。
7.RDB ⽂件恢复
当 Redis 服务器启动时,如果 Redis 根⽬录存在 RDB ⽂件 dump.rdb,Redis 就会⾃动加载 RDB ⽂件恢复持久化数据。如果根⽬录没有 dump.rdb ⽂件,请先将 dump.rdb ⽂件移动到 Redis 的根⽬录。
验证 RDB ⽂件是否被加载
Redis 在启动时有⽇志信息,会显⽰是否加载了 RDB ⽂件,我们执⾏ Redis 启动命令:
redis.conf src/redis-server ,如下图所
⽰:
在这里插入图片描述
8.RDB 优缺点
1)RDB 优点
RDB 的内容为⼆进制的数据,占⽤内存更⼩,更紧凑,更适合做为备份⽂件;
RDB 对灾难恢复⾮常有⽤,它是⼀个紧凑的⽂件,可以更快的传输到远程服务器进⾏ Redis 服务恢复;
RDB 可以更⼤程度的提⾼ Redis 的运⾏速度,因为每次持久化时 Redis 主进程都会 fork() ⼀个⼦进程,进⾏数据持久化到磁盘,Redis 主进程并不会执⾏磁盘 I/O 等操作;与 AOF 格式的⽂件相⽐,RDB ⽂件可以更快的重启。

2)RDB 缺点
因为 RDB 只能保存某个时间间隔的数据,如果中途 Redis 服务被意外终⽌了,则会丢失⼀段时间内的 Redis 数据;

RDB 需要经常 fork() 才能使⽤⼦进程将其持久化在磁盘上。如果数据集很⼤,fork() 可能很耗时,并且如果数据集很⼤且CPU 性能不佳,则可能导致 Redis 停⽌为客⼾端服务⼏毫秒甚⾄⼀秒钟。

9.禁⽤持久化
禁⽤持久化可以提⾼ Redis 的执⾏效率,如果对数据丢失不敏感的情况下,可以在连接客⼾端的情况下,执⾏

config set save "" 

命令即可禁⽤ Redis 的持久化

Guess you like

Origin blog.csdn.net/qq_41358574/article/details/121726212