String:
Redis是基于键值对的NoSQL数据库,键都是字符串,值可以是String,Hash,List,Set,Zset(有序集合),Bitmap(位图),HyperLogLog,GEO(地理信息定位),Stream(流)等多种数据结构
String为Redis最基本的类型。一个key对应一个value,value是字符串类型,也可以是数字类型(自动识别,可以进行自增自减操作)
String类型是二进制安全的,也就意味着Redis的String类型可以存储任何数据 如JPG图片或者序列化对象,最大能存储512MB
SET key value [EX seconds] [PX] [NX|XX]
GET name
DEL
INCR(自增)点击视频次数
DECR
mset
mget
应用场景:
缓存,缓存用户信息,广告,文章等
计数器,点赞,商品库存,视频浏览器次数等
分布式锁(NX,XX)
Hash:
hash也叫散列类型,类似其它语言的Map,HashMap等,其本身也是一个键值对结构。提供了field(字段)和value(字段值)的映射
字段值只能为字符串类型,不支持散列类型,集合类型等其他类型。相当于一个key对应一个map
key:sys:user:1用:分隔
HSET key field value
HGET key field
HDEL
hmset
hgetall
hkeys key
hvals key
hlen key
没有value就没有key
用户场景:用来存储用户信息
List:
Redis的list(列表)是一种线性的有序结构,可以按照元素被推入列表中的顺序来存储元素,并且列表中的元素可以重复
你可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含2^32-1个元素,可以通过索引下标获取元素(-1,-2)
常用命令:
添加:
LPUSH key value [value…]
RPUSH key value [value…]
linsert numbers after “two” “six”
lrange key start stop lrange中的stop包含了自身
llen numbers
LPOP key
rpop key
lset numbers 0 six
应用场景:消息队列,先进先出
Set:
Set(集合)类型也是用来保存多个的字符串元素,但和列表类型不一样的是。集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素,
Redis除了支持集合内的增删改查,同时还支持多个集合取交集,并集,差集,合理地使用好集合类型,能在实际开发中解决实际问题
集合中的最大成员数为2^32-1
SADD key member [members]
smemebers user:1
srem user:1 go
没有直接修改元素的命令,如果修改需要先移除元素后添加元素,这是set的底层数据结构决定的
集合间操作:
1.求集合的交集,并集,差集
sinter user:1 user:2
sunion user:1 user:2
sdiff user:1 user:2 以第一个为标准
应用场景
1。给用户添加标签,共同好友
Sorted Set:
有序集合(sorted set)同时具有“有序”和“集合”两种性质,这种数据结构中每个元素都由一个成员和一个与成员相关联的分值(score)组成,其中成员以字符串方式存储,而分值以双精度浮点数格式存储,集合中的成员以分数从小到大的排序。
有序集合中的每一个成员都是独一无二的,同一个有序集合中不会出现重复的成员,但不同成员的分值却可以是相同的,而且分值除了可以是数字外还可以是两个特殊的字符串:"+inf","-inf"。这两个特殊的字符串分别表示:无穷大和无穷小
当两个或多个成员拥有相同的分值时,Redis将按照这些成员在字典序中的大小对其排列
集合中的最大的成员数为2^32-1
zest简称
常用命令:
ZADD KEY [NX|XX] [CH] [INCR] score member [score member …]
选项:
NX:member必须不存在才可以设置成功,用于添加
XX:member必须存在。才可以设置成功,用于更新
CH:返回此次操作后,有序集合元素和分数发生变化的个数
ICNR:对score做增加,相当于ZINCRBY
zadd country:ranking 1 “meiguo” 2 zhongguo 3 eluosi 4 riben 5 deguo
ZRANGE key start stop [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]
有序集合是按照分值排名的,ZRANGE是从低到高返回,ZREVRANGE则相反,是从高到低返回
WITHSCORES:同时返回成员的分数
参数start和stop都是基于0的索引,start和stop都是全包含的
zrange country:ranking 0 -1 withscores
ZREM key member [member …]
zrem country:ranking “deguo”
应用场景:
排行榜:比如歌曲排行榜,下载排行榜,购买排行榜等
HyperLogLog:
问题场景:
有一个功能需求,需要统计一个网站或者一个页面,每天大致有多少用户点击进入。同一个用户点击进入多次记作1次
假设就以用户的IP作为唯一表示,同一IP地址多次访问网址,只记作一次用户访问
->计数器+容器(HashMap,HashSet)
用容器来记录每次访问的IP地址
但这样就会导致IP的增多将会导致内存花费增多
1.存储一个IPV4格式的IP最多需要15个字节
2.网站规模不同,每天出现的唯一IP可能有数十万,数百万个 1000万-4.5G
长期统计就需要很多数据
HyperlLogLog是一个专门为了设计集合的基数而创建的概率算法
啥是基数?
基数就是某数据集去重后的数据数量。比如{1,2,3,4,4,5},这个数据集的基数集就是{1,2,3,4,5},基数(不重复元素的个数)就是5.
对于一个给定的集合,可以计算出这个集合的近似基数,并非集合的精准基数,它可能会比实际的基数小一点或大一点,但估算误差会处于一个合理的范围内
特点:
在Redis中每一个HyperLogLog只需要使用12KB内存空间就可以对2^64个元素进行计数,而算法的标准误差仅为0.81%
因此那些不需要知道准确基数,或者因为条件限制而无法计算出准确基数的程序,就可以把这个近似基数当作集合的基数来使用。
常用命令:
1.添加指定元素到Hyperloglog中
PFADD key elements [element]
根据给定元素是否进行过计数,PFADD命令可能返回0,也可能返回1
如果给定的所有元素都已经进行过计数,那么命令将返回0,表示Hyperloglog计算出的近似基数没有发生变化
如果给定的元素至少有一个没有进行过计数的元素,导致计算出的近似基数发生了变化,那么Hyperloglog命令返回1
pfadd mylog a
pfcount mylog
用pfcount命令获取Hyperloglog的近似基数,会去重
合并多个Hyperloglog
语法:pfmerge new_key key [key]
合并多个key,并将结果存储在新创建的new_key中,结果返回ok
pfmerge three one two
pfcount 命令传入多个命令时,内部调用了PFMERGR命令,然后进行了如下操作:
1 进行Hyperloglog合并,并将结果集存储到临时Hyperloglog中
对临时Hyperloglog执行pfcount命令,求出基数
删除临时Hyperloglog
将结果返回给客户端
因此当程序需要对多个Hyperloglog调用pfcount命令,并且这个调用需要重复执行时,可以考虑把这一调用替换成相应的pfcount命令调用:通过把并集的计算结果存储到指定的Hyperloglog中,而不是每次都重新计算并集程序,可以很大程度的减少不必要的合并计算。
GEO:
应用场景
你在玩游戏时,可能会用到【附近的人】这个功能来匹配附近玩家,订外卖时,系统会推荐你当前定位附近的商家,骑行共享单车时,系统会帮你搜素附近的单车和停车位置。那你知道这些地理位置在Redis中如何存储和计算搜索的嘛?
CEO就是Redis中专门存储和计算地理位置的数据结构GEO
GEO是Redis在3.2版本中新添加的特性,通过这一特性,用户可以将经纬度格式的地理坐标存储到Redis中,并对坐标执行距离计算,范围查找等操作
常用命令:
1.存储坐标
语法: GEOADD key longitude latitude member[longitude latitude member…]
longitude 经度;latitude 维度
该命令返回新添加到key中的坐标数量作为返回值。
当添加的坐标在集合中已存在时,就会用新坐标代替已有的旧坐标
2 geopos Beijing-U beida
Geohash是一种编码格式,这种格式可以将用户给定的经度和维度转化为单个Geohash值,也可以根据给定的Geohash还原出被转换的经度和维度
通过GEOADD的坐标会被转换成一个52位的Geohash值,查询时会根据Geohash还原经纬度,所以会存在小范围的误差
3.查询两个地理位置之间的直线距离
GEOdist key member1 member2 [unit]
unit为指定单位的参数:m表示单位米,km表示单位千米,mi表示单位英里,ft表示单位英尺 默认为米
GEODIST命令在计算距离时会假设地球为完美的球星,在极限的情况下,这一假设最大会造成0.5%的误差
4.查询指定半径范围内的其他位置
GEOradius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
以给定的经纬度为中心,从位置集合中找出位于中心点指定半径范围内的其他的位置
5.根据名称查找指定半径范围内的其他位置
语法: GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
georadiusbymember Beijing-U beida 2000 m withdist
6.获取指定位置的Geohash值
GEOHASH key member [member …]
Redis使用有序集合存储GEO数据,一个位置集合实际上是一个有序集合,当我们调用GEO命令对位置集合进行操作时,这些命令实际上是在操作一个有序集合
Bitmap:
Redis的位图是由多个二进制组成的数组,数组中的每个二进制都有与之对应的偏移量(也称索引),我们可以通过这些偏移量可以对位图中指定的一个或多个二进制位进行操作。默认为0
常用命令:
1.设置二进制位的值
SETBIT key offset value
SETBIT命令在对二进制进行设置后,将返回二进制被设置之前的旧值作为结果
位图的扩展:
当用户执行SETBIT命令对一个位图进行操作时,如果位图当前的大小无法满足用户想要执行的设置操作,那么Redis将对被设置的位图进行扩展
以字节为单位进行的,所以扩展后的位图包含的二进制数量可能会比用户的要求稍微多些
获取二进制位上的值:
get bit mybit
若超过偏移量默认为0;
3.统计被设置的二进制数量
BITCOUNT key [start end]
统计字符串被设置为1的二进制位数量
start end指的不是偏移量而是字节偏移量
Stream:
流(Stream)是Redis5.0版本中新增加的数据结构,也是该本版最重要的更新。
克服以往版本中用户采用LIst,SortedSet 和发布/订阅的三个功能,但这些不同的实现都有各自的缺陷
List 不能查找指定数据的元素,也不能进行范围查找
Sorted Set则缺少发布/订阅提供的弹出操作
发布/订阅虽能将消息传递给多个客户端,但消息”发送既忘“的策略会导致客户端丢失消息,所以它是无法实现消息的可靠传递
Redis的流则是专门实现消息队列应用的最佳场景
Stream是一个包含0个或多任意多个流元素的有序队列,队列中的每个元素都包含一个ID和任意多个键值对,这些元素会根据ID的大小在流中有序的进行排列
流元素的ID由毫秒时间和顺序编号两部分组成,毫秒时间和顺序编号都用64位非负整数表示,所以整个流的ID的总长为128位。并且Redis在接受流ID输入以及展示流ID的时候都会使用连字符-分割这两部分
常用命令:
1.添加新元素到流的末尾:
XADD key ID field string [field string …]
将一个带有指定ID以及包含指定键值对的元素追加到流的末尾。
如果ID是我们传入的,传入的ID大小一定要比流中已有最大的ID要大,否则Redis不允许填入会报错。
如果ID参数是字符*,Redis会自动生成唯一的ID。
如果同一时间内存入多条数据,ID的毫秒时间部分不变,顺序编号递增
xadd mystream * name wangwu age 30
2.访问流中的元素:
XRANGE KEY start end [COUNT count]
此命令传入start_id end_id,
xrange mystream - + count 2
消费者组
一条消息只能由一个消费者消息,消费完消息,会发送ACK消息确认
3.创建消费者组:
XGROUP 【CREATE key groupname id-or -
】
k
e
y
:
流
的
名
称
i
d
−
o
r
−
】 key:流的名称 id-or-
】key:流的名称id−or−:指从那个ID开始读取消息,可以具体的某个ID,也可以是从0开始0-0,可以额是
,
,
,表示使用stream中最新消息的ID。
xgroup create mystream mygroup 0-0
4.获取消费者组中的消息
XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] streams key [key…] ID [ID…]
这个ID有特殊的含义,表示读取从来没有分给别的消息者的消息
xreadgroup group mygroup mys streams mystream
5.将消息标记为”已处理“
当消息给消费者处理完一条消息后,他需要向Redis发送一条针对该消息的XACK命令。
当Redis接收到消费者发来的ACK消息后,会移除指定的消息,
综合起来,一条消费者组消息从出现到处理完毕,需要经历以下阶段:
首先,当一个生产者通过XADD命令向流中添加一条消息时,该消息就从原来的”不存在“状态转换为了”未递送“状态
然后,当一个消费者通过XREADGROUP 命令从流中读取一条消息时,该消息就从原来的”未递送“状态转换成”待处理“
最后,当消费者完成了对消息的处理,并通过XACK命令向服务器进行确认时,该消息就从原来的待处理转化为”已确认”
XACK key group ID [id …]
6.显示已读取但未ACK的消息
XPENDING key group [start end count] [consumer]
7.删除指定元素
XDEL key ID [ID…]
从流中删除任意多个ID对应的元素
8获取流包含的元素数量
XLEN key
xlen mystream
这里对基本的Redis数据结构和操作进行了总结