redis的实际运用

key设计原则

  1. 把表名转换为key前缀 如, tag:
  2. 第2段放置用于区分区key的字段–对应mysql中的主键的列名,如userid
  3. 第3段放置主键值,如2,3,4…, a , b ,c
  4. 第4段,写要存储的列名

深入学习Redis之redis的实际运用_Redis应用案例

#分布式集群中 对user:userid:9 进行hash保证同key在一个节点中
set user:userid:9:username lisi
set user:userid:9:password 111111
set user:userid:9:email lisi@163.com

#获取其所有字段
keys user:userid:9*

2 注意:
在关系型数据中,除主键外,还有可能其他列也步骤查询,
如上表中, username 也是极频繁查询的,往往这种列也是加了索引的.

key-value没有唯一索引和主键索引
redis不能通过非key查询 只能对要查询的字段进行数据冗余 (类似与关联表)
转换到k-v数据中,则也要相应的生成一条按照该列为主的key-value
Set user:username:lisi:uid 9 (这里username为key)

这样,我们可以根据username:lisi:uid ,查出userid=9, (过渡查询 获取id)
再查user:9:password/email … (再根据id 获取所有数据)

Redis数据库的应用

场景一:标签归类
如果使用mysql数据库,这样会涉及大量的连接查询
换成key-value存储

#key-value可以实现一对多的关系

set book:5:title 'PHP圣经'
set book:6:title 'ruby实战'
set book:7:title 'mysql运难'
set book:8:title ‘ruby server’

#标签使用kv 来存储
sadd tag:PHP 5
sadd tag:WEB 5 6
sadd tag:database 7
sadd tag:ruby 6 8
sadd tag:SERVER 8

#查: 既有PHP,又有WEB的书
Sinter tag:PHP tag:WEB #查集合的交集

#查: 有PHP或有WEB标签的书
Sunin tag:PHP tag:WEB

#查:含有ruby,不含WEB标签的书
Sdiff tag:ruby tag:WEB #求差集

业务场景二 位图法统计活跃用户
有一亿用户,用户有频繁登录的,也有不经常登录的。
问题:
1.如何来记录用户的登录信息
2.如何查询活跃用户

一天的登录信息,用位代替一个用户,0表示未登录,1表示已登录

周一:0101 0001 1、3、7号用户登录了
周二:0110 0111
周三:0110 1001
周四:*****
使用setbit命令来实现位的与操作

周一
setbit mon 100000000 0 #初识值
setbit mon 1 1 #一号用户登录
setbit mon 3 1 #三号用户登录
setbit mon 7 1 #七号用户登录

周二
setbit thur 100000000 0 #初识值
setbit thur 2 1 #二号用户登录
setbit thur 3 1 #三号用户登录
setbit thur 6 1 #六号用户登录

bitop and mon thur 10010 0000 只有3号用户两天都登录了

业务场景三
关于王者荣耀战绩查询的实现(为什么会出现延时性的思考)
借助redis来实现存储和查询战绩信息

  1. 建立redis集群,master用来记录新的战绩记录,并使用aof来进行持久化
  2. clusters用来查询战绩信息,通过master传输的aof来进行同步
  3. master的aof传输可以使用aof重写功能,去掉中间过程
  4. 由于aof是有短暂间隔的所以战绩查询有一定延迟

业务场景四
仿微博(关注、发布动态)
关于用户登录(id name password)
关于用户key的设计(redis的key设计意义 等同于mysql表结构的设计)
用户登录

  • 首先根据username 获取userid
  • 再根据userid 获取password
#注册用户
set user:userid:1:username zhansan
set user:userid:1:password 111111
set user:username:zhangsan:userid 1
#查找
get user:username:zhangsan #获得id

发微博

incr global:postid 自增长postid
set post:postid:$postid:time timestamp #时间戳
set post:postid:$postid:userid 5 #userid
set post:postid:$postid:content 'this is my home' #微博内容

粉丝关系(关注关系)
我的关注( 集合 following )
我的粉丝( 集合 followed )
使用2个集合用于统计关注和分数数量

#关注用户
#第一步判断 改用户id在不在我的 我的关注集合当中
ismember following:userid myid

#添加关注
sadd following:myid 1 #添加1到我的关注
#这样时为了可以查看粉丝的微博
sadd follower:1 myid #添加将我添加到1的粉丝

#取消关注
srem following:myid 1 #添加1到我的关注
#这样时为了可以查看粉丝的微博
srem follower:1 myid #添加将我添加到1的粉丝

#查看我的粉丝
smembers followed:id
scard followed:id #我的粉丝数量
#查看我的关注
smembers following:id
scard following:id #我的关注数量

增强cookie安全性(保证用户名及密码的安全性)

  • 通过cookie保存密码的用户信息登录时 可以通过生成随机数作为用户令牌 并保存到redis服务器
  • 用户免密登录时 获取用户令牌并与数据库进行对比 拦截非法用户访问
  • 注销用户时 清空redis中的用户令牌

使用哈希数据存储微博
使用hash能够实现 key一对多

post:postid 这种拼接的方式 保证了key的唯一性
#设定元素
hset post:postid name lisi
hset post:postid aga q0
hmset post:postid name wang age 10 #同时设置多个属性

推送微博 VS 拉取微博

  • 推送微博的模式 如果一个人有大量的粉丝,这样存在大规模的lpush recivepost:userid postid
    并且一次推送要一次遍历千万个粉丝
  • 有些用户时长期不在线 但微博本身是有时效性的 使用推送模式存在大量的推送行为没有实际意义。
  • 使用用户登录拉取关注人的最新微博 最符合实际的业务需求

微博获取(通过主动拉取的)
通过链表 获取我的关注的人的微博
获取我的关注id smembers following:useid
根据 mystarid获取postid pullpost
使用sort 能够起到类似于mysql join(连接查询的作用)

#限制链表大小
ltrim pullpost:userid

#根据我的关注userid 获取postid后 导入到pullpost:userid链表中
lpush pullpost:userid postid

#获取微博的详情
hmset post:postid

问: 上次我拉取了 A->5,67,三条微博, 下次刷新home.php, 从>7的微博开始拉取
解决: 拉取时,设定一个lastpull时间点, 下次拉取时,取>lastpull的微博
JAVA VO (post集合,lastpullTime) 下一次获取只获取晚于该时间的微博。

问: 有很多关注人,如何取?
解决: 循环自己的关注列表,逐个取他们的新微博。

问: 取出来之后放在哪儿?
答: pull:$userid的链接里

问: 如果个人中心,只有前1000条
答: ltrim,只取前1000条

问: 如果我关注 A,B两人, 从2人中,各取3条最新信息,这3+3条信息, 从时间上,是交错的, 如何按时间排序?
我们发布时, 是发布的hash结构, 发布时间作为一个属性存在hash,不能按时间来排序.
解决方案:
同步时,取微博后,记录本次取的微博的最大id,
下次同步时,只取比最大id更大的微博。

结合Java的来实现最新的50条微博

  • 使用一个链表 存放微博的id
  • redis只使用存储频繁使用的数据,冷数据应存储到mysql数据库中
    将一个用户的最新20条数据存储到redis,其他的存储到mysql数据库当中。
  • 应用首先会在redis读取数据,如果没读取到,就会到mysql中获取
#限制链表大小
ltrim pullpost:userid 50

#在java中 按照id从小到大排序 并以链表的形式进行存取
lpush pullpost:userid postid

#下一次拉取最新的微博
#获取第一个数据的元素 获取其id
#在mysql中获取id大于该值的新微博
#进一个的同时弹出一个 lpush 从最左出插入
lpush pullpost:userid postid

深入学习Redis之redis的实际运用_Redis应用_02