热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Redis——Redis五大数据类型——list,set和sorted_set(及应用场景)

Redis——Redis五大数据类型——list,set和sorted_set(及应用场景)-list数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分需要的存储

list
  • 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
  • 需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
  • list类型:保存多个数据,底层使用==双向链表存储结构==实现

  • 顺序表 查询数据的速度很快,但是从头到尾顺序不能变,想要从中间插入一个数据则很慢,增删操作慢
  • 链表 则插入和删除速度快,保留原有的物理顺序,在插入或者删除一个元素的时候,只需要改变指针指向即可。
  • 双向链表 有两个指针,一个指向前一个节点,一个后一个节点。

list 类型数据基本操作

  • 添加/修改数据

lpush key value1 [value2] ……

rpush key value1 [value2] ……

  • 获取数据

lrange key start stop

lindex key index llen key

  • 获取并移除数据

lpop key

rpop key

127.0.0.1:6379> lpush list1 one 
(integer) 1
127.0.0.1:6379> lpush list1 two
(integer) 2
127.0.0.1:6379> lpush list1 three
(integer) 3
127.0.0.1:6379> lrange list1 0 2
1) "three"
2) "two"
3) "one"

127.0.0.1:6379> rpush list2 one two three
(integer) 3
127.0.0.1:6379> lrange list2 0 2
1) "one"
2) "two"
3) "three"

127.0.0.1:6379> lrange list2 0 -1	# 和python的列表一样
1) "one"
2) "two"
3) "three"

127.0.0.1:6379> lpush list2 0		# 将一个值或多个值,插入到列表头部
(integer) 4
127.0.0.1:6379> rpush list2 4		# 将一个值或多个值,插入到列表尾部
(integer) 5
127.0.0.1:6379> lrange list2 0 -1
1) "0"
2) "one"
3) "two"
4) "three"
5) "4"

127.0.0.1:6379> lindex list2 0		# 通过下标获取list中的某一个值
"one"
127.0.0.1:6379> lindex list2 2
"three"
127.0.0.1:6379> llen list1		# 返回列表的长度
(integer) 3

127.0.0.1:6379> lpop list2		# 移除列表的第一个元素
"0"
127.0.0.1:6379> rpop list2		# 移除列表的最后一个元素
"4"
127.0.0.1:6379> lrange list2 0 -1
1) "one"
2) "two"
3) "three"

list 类型数据扩展操作

  • 规定时间内获取并移除数据

blpop key1 [key2] timeout

brpop key1 [key2] timeout brpoplpush source destination timeout

127.0.0.1:6379> lpush list5 a b
(integer) 2
127.0.0.1:6379> lpop list5
"b"
127.0.0.1:6379> lpop list5
"a"
127.0.0.1:6379> lpop list5
(nil)
127.0.0.1:6379> blpop list5 10
(nil)
(10.10s)

127.0.0.1:6379> lpush list5 d
(integer) 1
127.0.0.1:6379> blpop list5 10
1) "list5"
2) "d"
(5.73s)

127.0.0.1:6379> rpush list5 e
(integer) 1
127.0.0.1:6379> lrange list5 0 -1
1) "e"
127.0.0.1:6379> brpop list5 5
1) "list5"
2) "e"
127.0.0.1:6379> lrange list5 0 -1
(empty array)

  • 剪切数据

ltrim key start stop

127.0.0.1:6379> rpush mylist a b c d
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> ltrim mylist 1 2	# 通过下标截取指定的长度 这个list已经被改变了
OK
127.0.0.1:6379> lrange mylist 0 -1	# 只剩下截取后的元素
1) "b"
2) "c"
  • 移除列表的最后一个元素,并将其添加到新的列表

rpoplpush key key2

127.0.0.1:6379> rpush mylist1 a b c d
(integer) 4
127.0.0.1:6379> lrange mylist1 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> rpoplpush mylist1 mylist2	# # 移除列表的最后一个元素,并将其移动到新的列表
"d"
127.0.0.1:6379> lrange mylist1 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> lrange mylist2 0 -1		# # 查看目标列表中,确实存在该值
1) "d"

  • 将列表中指定下标的值替换为另外一个值,更新操作

lset key 下标 new value

127.0.0.1:6379> exists list		# 判断这个列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 mao		# 如果不存在列表 我们去更新会报错
(error) ERR no such key
127.0.0.1:6379> lpush list mao
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "mao"
127.0.0.1:6379> lset list 0 zhu		# 如果存在,更新当前下标的值
OK
127.0.0.1:6379> lrange list 0 -1
1) "zhu"
127.0.0.1:6379> lset list 1 gou		# 如果不存在下标 我们去更新会报错
(error) ERR index out of range

  • 将某一个具体的value 插入到列表中某个元素的前面或者后面

insert key before/after value new-value

127.0.0.1:6379> rpush mylist 'hello'
(integer) 1
127.0.0.1:6379> rpush mylist 'world'
(integer) 2
127.0.0.1:6379> linsert mylist before 'world' 'niu'
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "niu"
3) "world"
127.0.0.1:6379> linsert mylist after 'world' 'zhu'
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "niu"
3) "world"
4) "zhu"

应用场景 微信朋友圈点赞,要求按照点赞顺序显示点赞好友信息,如果取消点赞,移除对应好友信息

解决方案

  • 移除指定数据

lrem key count value

  • redis 应用于具有操作先后顺序的数据控制
127.0.0.1:6379> rpush friend a b c d e		# 朋友圈点赞顺序 a b c d e
(integer) 5
127.0.0.1:6379> lrange friend 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
127.0.0.1:6379> lrem friend 1 d		# 移除d
(integer) 1
127.0.0.1:6379> lrange friend 0 -1
1) "a"
2) "b"
3) "c"
4) "e"
127.0.0.1:6379> rpush friend d		
(integer) 5
127.0.0.1:6379> lrange friend 0 -1
1) "a"
2) "b"
3) "c"
4) "e"
5) "d"

127.0.0.1:6379> lpush letter a b a c d a o a u e a
(integer) 11
127.0.0.1:6379> lrange letter 0 -1
 1) "a"
 2) "e"
 3) "u"
 4) "a"
 5) "o"
 6) "a"
 7) "d"
 8) "c"
 9) "a"
10) "b"
11) "a"
127.0.0.1:6379> lrem letter 3 a		# 删除前三个a
(integer) 3
127.0.0.1:6379> lrange letter 0 -1
1) "e"
2) "u"
3) "o"
4) "d"
5) "c"
6) "a"
7) "b"
8) "a"

list 类型数据操作注意事项

  • list中保存的数据都是string类型的,数据总容量是有限的,最多2^32- 1 个元素 (4294967295)。
  • list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作
  • 获取全部数据操作结束索引设置为-1
  • list可以对数据进行分页操作,通常第一页的信息来自于list,第2页及更多的信息通过数据库的形式加载

list 类型应用场景

  • twitter、新浪微博中个人用户的关注列表需要按照用户的关注顺序进行展示,粉丝列表需要将最近关注的粉丝列在前面
  • 新闻、资讯类网站如何将最新的新闻或资讯按照发生的时间顺序展示?
  • 企业运营过程中,系统将产生出大量的运营数据,如何保障多台服务器操作日志的统一顺序输出?

解决方案

  • 依赖list的数据具有顺序的特征对信息进行管理
  • 使用队列模型解决多路信息汇总合并的问题
  • 使用栈模型解决最新消息的问题
我们使用三个redis客户端

第一台服务器产生日志
127.0.0.1:6379> rpush logs a1..
(integer) 1
127.0.0.1:6379> rpush logs a1...
(integer) 3

第二台服务器产生日志
127.0.0.1:6379> rpush logs b1..
(integer) 2
127.0.0.1:6379> rpush logs b1...
(integer) 5

第三台服务器产生日志
127.0.0.1:6379> rpush logs c1..
(integer) 4
127.0.0.1:6379> rpush logs c1...
(integer) 6

日志顺序
127.0.0.1:6379> lrange logs 0 -1
1) "a1.."
2) "b1.."
3) "a1..."
4) "c1.."
5) "b1..."
6) "c1..."

set
  • 新的存储需求:存储大量的数据,在查询方面提供更高的效率
  • 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
  • set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的

set 类型数据的基本操作

  • 添加数据

sadd key member1 [member2]

  • 获取全部数据

smembers key

  • 删除数据

srem key member1 [member2]

127.0.0.1:6379> sadd myset xiaotian		# set集合中添加元素
(integer) 1
127.0.0.1:6379> sadd myset lovexiaotian
(integer) 1
127.0.0.1:6379> sadd myset maomao
(integer) 1
127.0.0.1:6379> smembers myset		# 查看指定set的所有值
1) "maomao"
2) "xiaotian"
3) "lovexiaotian"
127.0.0.1:6379> srem myset maomao
(integer) 1
127.0.0.1:6379> smembers myset
1) "xiaotian"
2) "lovexiaotian"
  • 获取集合数据总量

scard key

  • 判断集合中是否包含指定数据

sismember key member

127.0.0.1:6379> scard myset
(integer) 2
127.0.0.1:6379> sismember myset xiaotian	# 判断某一个值是不是在set集合中
(integer) 1
127.0.0.1:6379> sismember myset zhuzhu
(integer) 0

业务场景 每位用户首次使用微博时会设置3项爱好的内容,但是后期为了增加用户的活跃度、兴趣点,必须让用户对其他信息类别逐渐产生兴趣,增加客户留存度,如何实现?

业务分析

  • 系统分析出各个分类的最新或最热点信息条目并组织成set集合
  • 随机挑选其中部分信息
  • 配合用户关注信息分类中的热点信息组织成展示的全信息集合

解决方案

  • 随机获取集合中指定数量的数据

srandmember key [count]

  • 随机获取集合中的某个数据并将该数据移出集合

spop key [count]

127.0.0.1:6379> sadd news youxi		# set集合中添加元素
(integer) 1
127.0.0.1:6379> sadd news tiyu
(integer) 1
127.0.0.1:6379> sadd news yule
(integer) 1
127.0.0.1:6379> sadd news kexue
(integer) 1
127.0.0.1:6379> srandmember news 1		# 随机抽选出一个元素
1) "yule"
127.0.0.1:6379> srandmember news 1
1) "youxi"
127.0.0.1:6379> srandmember news 1
1) "kexue"
127.0.0.1:6379> scard news
(integer) 4
127.0.0.1:6379> srandmember news 3		# # 随机抽选出指定个数的元素
1) "kexue"
2) "tiyu"
3) "yule"
127.0.0.1:6379> srandmember news 3
1) "youxi"
2) "kexue"
3) "yule"
127.0.0.1:6379> spop news		# 随机删除一些set合集中的元素
"kexue"
127.0.0.1:6379> smembers news
1) "youxi"
2) "tiyu"
3) "yule"
127.0.0.1:6379> spop news 2		# 随机指定个数的set合集中的元素
1) "tiyu"
2) "youxi"
127.0.0.1:6379> smembers news
1) "yule"

  • redis 应用于随机推荐类信息检索,例如热点歌单推荐,热点新闻推荐,热卖旅游线路,应用APP推荐,up主推荐等

业务场景

  • 脉脉为了促进用户间的交流,保障业务成单率的提升,需要让每位用户拥有大量的好友,事实上职场新人不具有更多的职场好友,如何快速为用户积累更多的好友?
  • 新浪微博为了增加用户热度,提高用户留存性,需要微博用户在关注更多的人,以此获得更多的信息或热门话题,如何提高用户关注他人的总量?
  • QQ新用户入网年龄越来越低,这些用户的朋友圈交际圈非常小,往往集中在一所学校甚至一个班级中,如何帮助用户快速积累好友用户带来更多的活跃度?
  • 微信公众号是微信信息流通的渠道之一,增加用户关注的公众号成为提高用户活跃度的一种方式,如何帮助用户积累更多关注的公众号?
  • 美团外卖为了提升成单量,必须帮助用户挖掘美食需求,如何推荐给用户最适合自己的美食?

解决方案

  • 求两个集合的交、并、差集

    sinter key1 [key2]

sunion key1 [key2] sdiff key1 [key2]

  • 求两个集合的交、并、差集并存储到指定集合中

    sinterstore destination key1 [key2]

sunionstore destination key1 [key2] sdiffstore destination key1 [key2]

  • 将指定数据从原始集合中移动到目标集合中

    smove source destination member

127.0.0.1:6379> sadd user1 mao		# 添加用户1的朋友
(integer) 1
127.0.0.1:6379> sadd user1 zhu
(integer) 1
127.0.0.1:6379> sadd user1 niu
(integer) 1
127.0.0.1:6379> sadd user2 zhu		# 添加用户2的朋友
(integer) 1
127.0.0.1:6379> sadd user2 gou
(integer) 1
127.0.0.1:6379> sinter user1 user2		# 共同朋友 交集
1) "zhu"
127.0.0.1:6379> sunion user1 user2		# 并集
1) "mao"
2) "gou"
3) "niu"
4) "zhu"
127.0.0.1:6379> sdiff user1 user2	# 差集
1) "mao"	
2) "niu"
127.0.0.1:6379> sdiff user2 user1	# 差集
1) "gou"
127.0.0.1:6379> sinterstore user3 user1 user2	# 将用户1和用户2的交集存入用户3
(integer) 1
127.0.0.1:6379> smembers user3
1) "zhu"
127.0.0.1:6379> sunionstore user4 user1 user2	# 将用户1和用户2的并集存入用户4
(integer) 4
127.0.0.1:6379> smembers user4
1) "mao"
2) "gou"
3) "niu"
4) "zhu"
127.0.0.1:6379> sdiffstore user5 user1 user2	# 将用户1和用户2的差集存入用户5
(integer) 2
127.0.0.1:6379> smembers user5
1) "mao"
2) "niu"
127.0.0.1:6379> smove user2 user1 gou	# 将user2的元素移动到user1里
(integer) 1
127.0.0.1:6379> smembers user1
1) "mao"
2) "gou"
3) "niu"
4) "zhu"
127.0.0.1:6379> smembers user2
1) "zhu"

  • redis 应用于同类信息的关联搜索,二度关联搜索,深度关联搜索
  • 显示共同关注(一度)
  • 显示共同好友(一度)
  • 由用户A出发,获取到好友用户B的好友信息列表(一度)
  • 由用户A出发,获取到好友用户B的购物清单列表(二度)
  • 由用户A出发,获取到好友用户B的游戏充值列表(二度)

set 类型数据操作的注意事项

  • set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份
  • set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间

set 类型应用场景

业务场景1

集团公司共具有12000名员工,内部OA系统中具有700多个角色,3000多个业务操作,23000多种数据,每位员工具有一个或多个角色,如何快速进行业务操作的权限校验?

解决方案

  • 依赖set集合数据不重复的特征,依赖set集合hash存储结构特征完成数据过滤与快速查询
  • 根据用户id获取用户所有角色
  • 根据用户所有角色获取用户==所有操作权限==放入set集合
  • 根据用户所有角色获取用户==所有数据全选==放入set合计
127.0.0.1:6379> sadd rid:001 getall getById		# 添加角色权限
(integer) 2
127.0.0.1:6379> sadd rid:002 getCount getall insert
(integer) 3
127.0.0.1:6379> sunionstore uid:007 rid:001 rid:002		# 将uid为007的员工权限合并
(integer) 4
127.0.0.1:6379> smembers uid:007
1) "insert"
2) "getById"
3) "getCount"
4) "getall"
127.0.0.1:6379> sismember uid:007 insert
(integer) 1

  • redis 应用于同类型不重复数据的合并操作

业务场景2

  • 公司对旗下新的网站做推广,统计网站的PV(访问量),UV(独立访客),IP(独立IP)。
  • PV:网站被访问次数,可通过刷新页面提高访问量
  • UV:网站被不同用户访问的次数,可通过COOKIE统计访问量,相同用户切换IP地址,UV不变
  • IP:网站被不同IP地址访问的总次数,可通过IP地址统计访问量,相同IP不同用户访问,IP不变

解决方案

  • 利用set集合的数据去重特征,记录各种访问数据
  • 建立string类型数据,利用incr统计日访问量(PV)
  • 建立set模型,记录不同COOKIE数量(UV)
  • 建立set模型,记录不同IP数量(IP)
127.0.0.1:6379> sadd ips 192.168.188.10		# 一个独立ip访问
(integer) 1
127.0.0.1:6379> sadd ips 192.168.188.20		# 第二个独立ip访问
(integer) 1
127.0.0.1:6379> sadd ips 192.168.188.10		# 相同的ip访问则不增加
(integer) 0
127.0.0.1:6379> scard ips
(integer) 2
  • redis 应用于同类型数据的快速去重

业务场景3

  • 黑名单
    • 资讯类信息类网站追求高访问量,但是由于其信息的价值,往往容易被不法分子利用,通过爬虫技术,

快速获取信息,个别特种行业网站信息通过爬虫获取分析后,可以转换成商业机密进行出售。例如第三方火车票、机票、酒店刷票代购软件,电商刷评论、刷好评。 + 同时爬虫带来的伪流量也会给经营者带来错觉,产生错误的决策,有效避免网站被爬虫反复爬取成为每个网站都要考虑的基本问题。在基于技术层面区分出爬虫用户后,需要将此类用户进行有效的屏蔽,这就是==黑名单==的典型应用。 + ps:不是说爬虫一定做摧毁性的工作,有些小型网站需要爬虫为其带来一些流量。

  • 白名单
    • 对于安全性更高的应用访问,仅仅靠黑名单是不能解决安全问题的,此时需要设定可访问的用户群体,依赖白名单做更为苛刻的访问验证

解决方案

  • 基于经营战略设定问题用户发现、鉴别规则
  • 周期性更新满足规则的用户黑名单,加入set集合
  • 用户行为信息达到后与黑名单进行比对,确认行为去向
  • 黑名单过滤IP地址:应用于开放游客访问权限的信息源
  • 黑名单过滤设备信息:应用于限定访问设备的信息源
  • 黑名单过滤用户:应用于基于访问权限的信息源

sorted_set
  • 新的存储需求:数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式
  • 需要的存储结构:新的存储模型,可以保存可排序的数据
  • sorted_set类型:在set的存储结构基础上添加可排序字段

sorted_set 类型数据的基本操作

  • 添加数据

    zadd key score1 member1 [score2 member2]

  • 获取全部数据

    zrange key start stop [WITHSCORES]

zrevrange key start stop [WITHSCORES]

  • 删除数据

    zrem key member [member ...]

127.0.0.1:6379> zadd scores 100 maomao 60 xiaotian 94 zhuzhu 47 pancheng	# 添加四个学生和成绩
(integer) 4
127.0.0.1:6379> zrange scores 0 -1		# 获取全部数据从小到大
1) "pancheng"
2) "xiaotian"
3) "zhuzhu"
4) "maomao"

127.0.0.1:6379> zrange scores 0 -1 withscores	# withscores 可以获取姓名和成绩
1) "pancheng"
2) "47"
3) "xiaotian"
4) "60"
5) "zhuzhu"
6) "94"
7) "maomao"
8) "100"
127.0.0.1:6379> zrevrange scores 0 -1 withscores	# 反转 从大到小排序
1) "maomao"
2) "100"
3) "zhuzhu"
4) "94"
5) "xiaotian"
6) "60"
7) "pancheng"
8) "47"
127.0.0.1:6379> zrem scores pancheng	# 删除数据
(integer) 1
127.0.0.1:6379> zrevrange scores 0 -1 withscores
1) "maomao"
2) "100"
3) "zhuzhu"
4) "94"
5) "xiaotian"
6) "60"
  • 按条件获取数据

    zrangebyscore key min max [WITHSCORES] [LIMIT]

zrevrangebyscore key max min [WITHSCORES]

  • 条件删除数据

    zremrangebyrank key start stop

zremrangebyscore key min max

127.0.0.1:6379> zrangebyscore scores 50 100 withscores	# 从小到大
1) "xiaotian"
2) "60"
3) "pancheng"
4) "88"
5) "zhuzhu"
6) "94"
7) "maomao"
8) "100"

127.0.0.1:6379> zrevrangebyscore scores 100 50 withscores		# 从大到小
1) "maomao"
2) "100"
3) "zhuzhu"
4) "94"
5) "pancheng"
6) "88"
7) "xiaotian"
8) "60"

127.0.0.1:6379> zrange scores 0 -1 withscores
1) "xiaotian"
2) "60"
3) "pancheng"
4) "88"
5) "zhuzhu"
6) "94"
7) "maomao"
8) "100"
127.0.0.1:6379> zremrangebyrank scores 0 1		# 根据下标删除
(integer) 2
127.0.0.1:6379> zrange scores 0 -1 withscores
1) "zhuzhu"
2) "94"
3) "maomao"
4) "100"


127.0.0.1:6379> zrange scores 0 -1 withscores
1) "xiaotian"
2) "66"
3) "pancheng"
4) "88"
5) "zhuzhu"
6) "94"
7) "maomao"
8) "100"
127.0.0.1:6379> zremrangebyscore scores 70 90	# 根据条件来删除
(integer) 1
127.0.0.1:6379> zrange scores 0 -1 withscores
1) "xiaotian"
2) "66"
3) "zhuzhu"
4) "94"
5) "maomao"
6) "100"

==注意:==

  • min与max用于限定搜索查询的条件
  • start与stop用于限定查询范围,作用于索引,表示开始和结束索引
  • offset与count用于限定查询范围,作用于查询结果,表示开始位置和数据总量
  • 获取集合数据总量

    zcard key

zcount key min max

  • 集合交、并操作

    zinterstore destination numkeys key [key ...]

zunionstore destination numkeys key [key ...]

127.0.0.1:6379> zadd s1 50 aa 60 bb 70 cc
(integer) 3
127.0.0.1:6379> zadd s2 60 aa 40 bb 90 dd
(integer) 3
127.0.0.1:6379> zadd s3 70 aa 20 bb 100 dd
(integer) 3
127.0.0.1:6379> zinterstore ss 3 s1 s2 s3
(integer) 2
127.0.0.1:6379> zrange ss 0 -1 withscores
1) "bb"
2) "120"
3) "aa"
4) "180"
127.0.0.1:6379> zinterstore sss 3 s1 s2 s3 aggregate max		# 求最大值
(integer) 2
127.0.0.1:6379> zrange sss 0 -1 withscores
1) "bb"
2) "60"
3) "aa"
4) "70"

sorted_set 类型数据的扩展操作

业务场景

  • 各类资源网站TOP10(电影,歌曲,文档,电商,游戏等)
  • 游戏活跃度统计
  • 游戏好友亲密度

业务分析

  • 为所有参与排名的资源建立排序依据

解决方案

  • 获取数据对应的索引(排名)

    zrank key member

zrevrank key member

  • score值获取与修改

    zscore key member

zincrby key increment member

127.0.0.1:6379> zadd music 800 suis 750 ikura 700 aca	# 三个歌手的播放量
(integer) 3
127.0.0.1:6379> zrank music suis	# 从小到大的排名
(integer) 2
127.0.0.1:6379> zrank music aca
(integer) 0
127.0.0.1:6379> zrank music ikura
(integer) 1
127.0.0.1:6379> zrevrank music suis		# 从大到小查看排名
(integer) 0
127.0.0.1:6379> zscore music aca		# 获取播放量
"700"
127.0.0.1:6379> zincrby music 10 aca	# 增加
"710"

  • redis 应用于计数器组合排序功能对应的排名

sorted_set 类型数据操作的注意事项

  • score保存的数据存储空间是64位,如果是整数范围是-9007199254740992~9007199254740992
  • score保存的数据也可以是一个==双精度的double值==,基于双精度浮点数的特征,可能会丢失精度,使用时

候要慎重

  • sorted_set 底层存储还是基于==set结构==的,因此数据==不能重复==,如果重复添加相同的数据,score值将被反

复==覆盖==,保留最后一次修改的结果

127.0.0.1:6379> zadd test1 11 aa
(integer) 1
127.0.0.1:6379> zrange test1 0 -1 withscores
1) "aa"
2) "11"
127.0.0.1:6379> zadd test1 22 aa
(integer) 0		# 返回失败 但是数值仍然改变
127.0.0.1:6379> zrange test1 0 -1 withscores
1) "aa"
2) "22"
127.0.0.1:6379> zadd test1 33 aa
(integer) 0
127.0.0.1:6379> zrange test1 0 -1 withscores
1) "aa"
2) "33"

sorted_set 类型应用场景

应用场景1

  • 基础服务+增值服务类网站会设定各位会员的试用,让用户充分体验会员优势。例如观影试用VIP、游戏

VIP体验、云盘下载体验VIP、数据查看体验VIP。当VIP体验到期后,如果有效管理此类信息。即便对于正式VIP用户也存在对应的管理方式。

  • 网站会定期开启投票、讨论,限时进行,逾期作废。如何有效管理此类过期信息。

解决方案

  • 对于基于时间线限定的任务处理,将处理时间记录为score值,利用排序功能区分处理的先后顺序

  • 记录下一个要处理的时间,当到期后处理对应任务,移除redis中的记录,并记录下一个要处理的时间

  • 当新任务加入时,判定并更新当前下一个要处理的任务时间

  • 为提升sorted_set的性能,通常将任务根据特征存储成若干个sorted_set。例如1小时内,1天内,周内,月内,季内,年度等,操作时逐级提升,将即将操作的若干个任务纳入到1小时内处理的队列中

  • 获取当前系统时间

    time

127.0.0.1:6379> zadd ts 1509802345 uid:001 1509802390 uid:002 151038284 uid:003
(integer) 3
127.0.0.1:6379> zrange ts 0 -1 withscores
1) "uid:003"
2) "151038284"
3) "uid:001"
4) "1509802345"
5) "uid:002"
6) "1509802390"
127.0.0.1:6379> zrem ts uid:003
(integer) 1
127.0.0.1:6379> zrange ts 0 -1 withscores
1) "uid:001"
2) "1509802345"
3) "uid:002"
4) "1509802390"
127.0.0.1:6379> zadd ts 1510382841 uid:003
(integer) 1
127.0.0.1:6379> zrange ts 0 -1 withscores
1) "uid:001"
2) "1509802345"
3) "uid:002"
4) "1509802390"
5) "uid:003"
6) "1510382841"
127.0.0.1:6379> time		# 时间戳
1) "1618647056"
2) "262066"
127.0.0.1:6379> time
1) "1618647057"
2) "779953"
127.0.0.1:6379> time
1) "1618647059"
2) "242339"
  • redis 应用于定时任务执行顺序管理或任务过期管理

应用场景2

  • 任务/消息权重设定应用

当任务或者消息待处理,形成了任务队列或消息队列时,对于高优先级的任务要保障对其优先处理,如何实现任务权重管理。

解决方案

  • 对于带有权重的任务,优先处理权重高的任务,采用score记录权重即可多条件任务权重设定
  • 如果权重条件过多时,需要对排序score值进行处理,保障score值能够兼容2条件或者多条件,例如外贸订单优先于国内订单,总裁订单优先于员工订单,经理订单优先于员工订单
  • 因score长度受限,需要对数据进行截断处理,尤其是时间设置为小时或分钟级即可(折算后)
  • 先设定订单类别,后设定订单发起角色类别,整体score长度必须是统一的,不足位补0。第一排序规则首位不得是0
    • 例如外贸101,国内102,经理004,员工008。
    • 员工下的外贸单score值为101008(优先)
    • 经理下的国内单score值为102004
127.0.0.1:6379> zadd order 102004 order:id:1
(integer) 1
127.0.0.1:6379> zadd order 101008 order:id:2
(integer) 1
127.0.0.1:6379> zrevrange order 0 -1 withscores	# 订单优先级
1) "order:id:1"
2) "102004"
3) "order:id:2"
4) "101008"
127.0.0.1:6379> zrange order 0 -1
1) "order:id:2"
2) "order:id:1"
  • redis 应用于即时任务/消息队列执行管理

数据类型实践案例

实践案例1

业务场景 人工智能领域的语义识别与自动对话将是未来服务业机器人应答呼叫体系中的重要技术,百度自研用户评价语义识别服务,免费开放给企业试用,同时训练百度自己的模型。现对试用用户的使用行为进行限速,限制每个用户每分钟最多发起10次调用

解决方案

  • 设计计数器,记录调用次数,用于控制业务执行次数。以用户id作为key,使用次数作为value
  • 在调用前获取次数,判断是否超过限定次数
    • 不超过次数的情况下,每次调用计数+1
    • 业务调用失败,计数-1
  • 为计数器设置生命周期为指定周期,例如1秒/分钟,自动清空周期内使用次数

到达10就进行限制

127.0.0.1:6379> get uid:00415
(nil)
127.0.0.1:6379> setex uid:00415 60 1
OK
127.0.0.1:6379> get uid:00415
"1"
127.0.0.1:6379> incr uid:00415
(integer) 2
127.0.0.1:6379> incr uid:00415
(integer) 3
127.0.0.1:6379> get uid:00415
"3"
127.0.0.1:6379> incrby uid:00415 7
(integer) 10
127.0.0.1:6379> get uid:00415
(nil)

解决方案改良

  • 取消最大值的判定,利用incr操作超过最大值抛出异常的形式替代每次判断是否大于最大值
  • 判断是否为nil,
    • 如果是,设置为Max-次数
    • 如果不是,计数+1
    • 业务调用失败,计数-1
  • 遇到异常即+操作超过上限,视为使用达到上限

127.0.0.1:6379> get uid:00415
(nil)
127.0.0.1:6379> setex uid:00415 60 9223372036854775797
OK
127.0.0.1:6379> get uid:00415	# 设定一个最大值-10的值
"9223372036854775797"
127.0.0.1:6379> incr uid:00415
(integer) 9223372036854775798
127.0.0.1:6379> incrby uid:00415 9
(integer) 9223372036854775807
127.0.0.1:6379> incr uid:00415		# 再次增加 发现数值超范围了	然后告诉用户超次了
(error) ERR increment or decrement would overflow

实践案例2

业务场景 使用微信的过程中,当微信接收消息后,会默认将最近接收的消息置顶,当多个好友及关注的订阅号同时发送消息时,该排序会不停的进行交替。同时还可以将重要的会话设置为置顶。一旦用户离线后,再次打开微信时,消息该按照什么样的顺序显示?

解决方案

  • 依赖list的数据具有顺序的特征对消息进行管理,将list结构作为栈使用
  • 对置顶与普通会话分别创建独立的list分别管理
  • 当某个list中接收到用户消息后,将消息发送方的id从list的一侧加入list(此处设定左侧)
  • 多个相同id发出的消息反复入栈会出现问题,在入栈之前无论是否具有当前id对应的消息,先删除对应id
  • 推送消息时先推送置顶会话list,再推送普通会话list,推送完成的list清除所有数据
  • 消息的数量,也就是微信用户对话数量采用计数器的思想另行记录,伴随list操作同步更新
127.0.0.1:6379> lrem 100 1 200
(integer) 0
127.0.0.1:6379> lpush 100 200
(integer) 1
127.0.0.1:6379> lrem 100 1 300
(integer) 0
127.0.0.1:6379> lpush 100 300
(integer) 2
127.0.0.1:6379> lrem 100 1 400
(integer) 0
127.0.0.1:6379> lpush 100 400
(integer) 3
127.0.0.1:6379> lrem 100 1 200
(integer) 1
127.0.0.1:6379> lpush 100 200
(integer) 3
127.0.0.1:6379> lrem 100 1 300
(integer) 1
127.0.0.1:6379> lpush 100 300
(integer) 3
127.0.0.1:6379> lrange 100 0 -1		# 最后接收消息的顺序
1) "300"
2) "200"
3) "400"
  • redis 应用于基于时间顺序的数据操作,而不关注具体时间

推荐阅读
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 006_Redis的List数据类型
    1.List类型是一个链表结构的集合,主要功能有push,pop,获取元素等。List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,List的设 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • 这是一个愚蠢的问题,但我只是对此感到好奇.假设我在Pythonshell,我有一些我查询的数据库对象.我做:db.query(的queryString)该查询在0xffdf842c ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
  • Explain如何助力SQL语句的优化及其分析方法
    本文介绍了Explain如何助力SQL语句的优化以及分析方法。Explain是一个数据库SQL语句的模拟器,通过对SQL语句的模拟返回一个性能分析表,从而帮助工程师了解程序运行缓慢的原因。文章还介绍了Explain运行方法以及如何分析Explain表格中各个字段的含义。MySQL 5.5开始支持Explain功能,但仅限于select语句,而MySQL 5.7逐渐支持对update、delete和insert语句的模拟和分析。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 企业数据应用挑战及元数据管理的重要性
    本文主要介绍了企业在日常经营管理过程中面临的数据应用挑战,包括数据找不到、数据读不懂、数据不可信等问题。针对这些挑战,通过元数据管理可以实现数据的可见、可懂、可用,帮助业务快速获取所需数据。文章提出了“灵魂”三问——元数据是什么、有什么用、又该怎么管,强调了元数据管理在企业数据治理中的基础和前提作用。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • 2016 linux发行版排行_灵越7590 安装 linux (manjarognome)
    RT之前做了一次灵越7590黑苹果炒作业的文章,希望能够分享给更多不想折腾的人。kawauso:教你如何给灵越7590黑苹果抄作业​zhuanlan.z ... [详细]
author-avatar
jinnee5921_866
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有