学习源码是一个由浅入深,再到逐渐简化的过程,即所谓“把书读厚,把书读薄”的过程。
”昨夜西风凋碧树。独上高楼,望尽天涯路”,我们先从Redis的特性、用途及数据类型这几个方面介绍下Redis,对其有个总体上的认知。
定义(关键词):C语言、开源、key-value、NoSQL、基于内存
特点:
用途:
数据类型 | 底层数据结构 | 常用命令 | 应用场景 | 备注 |
---|---|---|---|---|
String | int, embstr, raw | set, mset, get, append, setbit ... | 【字符串】万物皆可String | 字符串,二进制安全 |
Hash | ht, ziplist | hget, hset, hegetall, hkeys, hexists ... | 【存储对象】操作用户属性 | 散列,键值对集合,map |
List | linkedlist, ziplist | lpush/lpop, rpush/rpop, lrange ... | 【增删快】最新消息排行;【按序】消息队列 | 列表,双向链表 |
Set | intset, ht | sadd, spop, sinter, sunion, sdiff ... | 【支持交/并/差集】共同好友;【不重复】统计访问网站IP | 集合,不重复 |
ZSet | ziplist, skipklist | zadd, zrange, zrem, zcard, zrank ... | 【有序】排行榜;【score】带权重的消息队列、延时队列 | 有序集合,按score排序 |
Stream | listpack, rax | xadd, xrange, xrevrange, xgroup, xread ... | 【消息队列】IRC / 实时聊天系统, IoT数据采集 | 类似于日志的数据结构,本质是一个消息队列 |
数据类型 | 依赖的数据结构 | 常用命令 | 应用场景 | 备注 |
---|---|---|---|---|
Bitmap | String | setbit, getbit, bitop, bitcount, bitpos | 活跃用户数统计; 统计某一天的用户登陆数量 | 存储与对象ID关联的节省空间并且高性能的布尔信息 |
Hyperloglog | String | pfadd, pfcount, pfmerge | 基数统计; 统计每日访问IP数/页面UV 数/在线用户数等 | bitmap的升级版;概率算法,不直接存储数据集合本身,概率统计方法预估基数值 |
Geo | ZSet | geoadd, geohash, geopos, geodist, georadius | 基于位置的服务(LBS) | Redis3.2以后版本 |
注意:
bitmap不是实际的数据类型是string类型上的一组面向bit操作的集合。
由于string是二进制安全的,并且它们的最大长度是512m,所以bitmap能最大设置2^32个不同的bit。
8 *1024*1024* 512 = 2^32 = 4294967296 = 40+ 亿
优点:
存储信息时可以节省大量的空间。例如在一个系统中,不同的用户被一个增长的用户ID表示。40亿(2^32=4*1024*1024*1024≈40亿
)用户只需要512M内存就能记住某种信息,例如用户是否登录过。
操作:
使用场景:
hyperLogLog是bitmap的升级版。本质上是一种概率算法,不直接存储数据集合本身,而是通过一定的概率统计方法预估基数值。这种方法可以大大节省内存,同时保证误差控制在一定范围内。
被编码成Redis字符串。因此可以通过调用GET命令序列化一个Hyperloglog(HLL),也可以通过调用SET命令将其反序列化到redis服务器。HLL的API类似使用SETS数据结构做相同的任务,SETS结构中,通过SADD命令把每一个观察的元素添加到一个SET集合,用SCARD命令检查SET集合中元素的数量,集合里的元素都是唯一的,已经存在的元素不会被重复添加。
而使用HLL时并不是真正添加项到HLL中(这一点和SETS结构差异很大),因为HLL的数据结构只包含一个不包含实际元素的状态。
操作:
使用场景:
底层数据类型:zset
Redis的GEO特性在 Redis3.2版本中推出,这个功能可以将用户给定的地理位置(经度和纬度)信息储存起来,并对这些信息进行操作。
GEO相关命令只有6个:
使用场景:
GEO类型的底层数据结构是用Zset实现的。
例如,存储车辆/店铺的经纬度信息时,元素是车辆/店铺ID,元素的权重Sore是本应是经纬度信息,但Sore应该是float类型,因此,需要对一组经纬度进行编码(即GeoHash编码)。
简要步骤:
Step 1:将经度/纬度进行二分拆解,得到二叉树结构,并进行0/1编码,再通过N位bit进行存储(N越大,精度越高);
Step 2:将经度和纬度的N位bit进行交叉组合,得到GeoHash值。
GeoHash编码的基本原理是“二分区间,区间编码”,先对经度和纬度分别编码,再将经纬度各自的编码组合成一个最终编码。简单来说,GeoHash将一个空间分割成一个个小方块,我们可以通过查询给定经纬度所在方格周围的4个或者8个方格,以此进行“周边查找”。【GeoHash值相近,并不一定位置相近,故需计算邻居节点,以提高LBS精度】
注意:
在项目开发中,会看到将一个Redis单独划分出来,用于经纬度的计算。如果数据量过亿,就需要对 Geo 数据进行拆分,按国家/省/市拆分,甚至按区拆分,以降低单个 zset 集合的大小。
【原因:在一个地图应用中,数据可能会有百万千万条,如果使用Geo,位置信息将全部放在一个 zset 集合中。在 Redis 的集群环境中,集合 可能会从一个节点迁移到另一个节点,如果单个 key 的数据过大,会导致集群的迁移出现卡顿等问题,影响线上服务的正常运行。所以,建议 Geo 的数据使用单独的 Redis 实例部署。】
实例:
# 新增
127.0.0.1:6379> geoadd city 114.06667 22.61667 "shenzhen" 119.30000 26.08333 "fuzhou"
(integer) 2
# zset类型
127.0.0.1:6379> TYPE city
zset
# 标准Geohash值,可以在http://geohash.org/使用。
127.0.0.1:6379> geohash city shenzhen fuzhou
1) "ws10ethzdh0"
2) "wssu6srd7k0"
# 获取key的经纬度
127.0.0.1:6379> geopos city shenzhen fuzhou
1) 1) "114.06667023897171021"
2) "22.61666928352524764"
2) 1) "119.29999798536300659"
2) "26.08332883679719316"
# 计算距离
127.0.0.1:6379> geodist city shenzhen fuzhou km
"655.5342"
# 计算范围
127.0.0.1:6379> georadius city 116 15 1000 km
1) "shenzhen"
127.0.0.1:6379> georadius city 116 15 2000 km
1) "shenzhen"
2) "fuzhou"
127.0.0.1:6379> georadius city 116 15 2000 km asc
1) "shenzhen"
2) "fuzhou"
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。