Redis是C语言开发的一个高性能键值对(key -value) 内存数据库,能够用做数据库,缓存和消息中间件等。html
Redis是C语言开发的一个高性能键值对(key -value) 内存数据库,能够用做数据库,缓存和消息中间件等。
做为内存数据库,它的性能很是优秀,数据存储在内存当中,读写速度很是快,支持并发10W QPS(每秒查询次数),单进程单线程,是线程安全的,采用IO多路复用机制。java
丰富的数据类型,支持字符串,散列,列表,集合,有序集合等,支持数据持久化。能够将内存中数据保存在磁盘中,重启时加载。node
主从复制,哨兵,高可用,可用做分布式锁。能够做为消息中间件使用,支持发布订阅。web
和Java的数据结构类比:redis
Redis | Java |
---|---|
string | String |
hash | HashMap |
list | LinkedList |
set | HashSet |
sorted set | TreeSet |
string是最基本的数据类型,跟 mencached 同样的类型,也是二进制安全的,能够包含任何数据算法
如:jpg图片或者序列化的对象。最大能存储512MB。数据库
特性json
最大能存储容量: 512MB 数值计算最大范围: Java中long的最大值 2^32-1 数据未获取到: 为nil至关于null 表示运行结果是否成功: integer 0 -> false 失败 integer 1 -> true 成功 表示运行结果值: integer 3 -> 3条 integer 1 -> 1条
关系型数据库数据在Redis中 key 热点数据命名惯例:数组
大部分数据都是从数据库来的:因此 通常的命名规范都会是:key[表名:主键名:主键值:字段名] value[xxxx] 表名 :主键名 :主键值 :字段名 order :id : 11111 : name equip :id : 11111 : type news :id : 11111 : title
用法:缓存
单个操做set get 多个操做加前缀mset mget (Multiple多个)
根据发送时长和执行时长来判断用单指令仍是多指令
// 添加/修改 set key value // 获取 get key // 删除 1成功,0失败 del key // 添加/修改多个 mset key1 value1 key2 value2 .... // 获取多个 mget key1 key2 .... // 获取value的数据字符长度 strlen key // 追加信息到值后面(存在就追加,不然新增) append key value
大型企业级应用中,分表操做是基本操做,使用多张表存储同类型数据,可是对应的主键ID必须保证统一性,不能重复。
oracle数据库具备sequence设定,能够解决,可是MySQL没有相似机制。
利用Redis 生成ID,主要利用Redis是单线程,因此也能够用来生成惟一ID,当使用的是Redis集群的时候,好比集群中有5台Redis,初始化每台Redis的值为1,2,3,4,5,设置步长为5,而且肯定一个不随机的负载均衡策略,可以保证有序惟一。
优势:不依赖数据库,灵活,且性能相对于数据库有必定提升,使用Redis集群策略还能排除单点故障问题,ID自然有序。
缺点:须要引入Redis这个新组件,开发配置工做量大
//设置数值数据增长指定范围的值,若是incr传的负数,会变成减,若是decr传整数,变成加 //每次+1,key+=1 incr key //每次+指定的值,key+=increment incrby ket increment //每次增长指定小数的值 incrbufloat ket increment //设置数值数据减小指定范围的值 //每次减一,key-=1 decr key //每次减指定的值,key-=increment decrby key increment
注意事项:
string在Redis内部为字符串存储,当它进行操做的时候会转类型为数字,若是含有其余非数字字符,则会报错.
超出数值上限也会报错,好比用Java语言的long类型
基本类型:long 二进制位数:64 包装类:java.lang.Long 最小值:Long.MIN_VALUE=-9223372036854775808 (-2的63次方) 最大值:Long.MAX_VALUE=9223372036854775807 (2的63次方-1)
另外一篇介绍常见的惟一ID生成方案,数据库自增/UUID/snowflake雪花算法/zookeeper/MongoDB的objectId
Redis 控制数据的生命周期,经过数据是否失效控制业务行为,适用于所具备时效性限定控制的操做。
微信投票:每四小时只能投一票。
电商热门商品推荐:热门商品不能一直处于热门期,每种商品热门期维持3天,3天后自动取消热门。
热点新闻,新闻网站会出现热点新闻,最大特征是时效性,因此如何控制热点新闻的时效性。
设置数据具备指定的生命周期:
// 设置N秒时间,N秒后失效删除掉数据 setex key seconds values // 设置N毫秒时间,N毫秒后失效删除掉数据 psetex key milliseconds value
Redis 应用于各类结构型和非结构型高热度数据访问加速
例如微博大V主页显示的粉丝数与微博数量,每一个用户访问到其主页都会有这几个数据
Redis 存储格式
// set 用户:id:id号:粉丝 粉丝数 set user:id:11111:fans 20 // set 用户:id:id号:博客 博客数 set user:id:11111:blogs 20 // set 用户:id:id号:关注 关注数 set user:id:11111:focus 20
// set 用户:id:id号 JSON set user:id:11111 {ID:11111,NAME:大V,fans:20,blogs:20,focus:30}
对于第一种,能够随时利用incr key进行数据更新,
而第二种须要全取出来才能够更新(取数据方便,更新数据麻烦),不过对于这种而言,上面举例的粉丝数多几个少几个用户也不会特别去关注,只需设定刷新策略,来选择用哪一种方式去实现。
hash 是一个string类型的key-field-value 映射表,特别适合用来存储对象,和单个string类型不一样的是,hash能够对信息的每一个属性字段进行单独存储,而string类型则须要对用户对象进行序列化保存,而且以字符串存储整个序列化数据(整存整取)对象类的数据存储若是有比较频繁的更新需求操做会显得笨重,而hash能够进行整存零取,从而节约网络流量,不过内存占用也会相对比string大。
新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
须要的存储结构:一个存储空间保存多个键值对数据
hash类型:底层使用哈希表结构实现数据存储
特性
hash存储结构优化:
hash 类型下的value 只能存储字符串,不容许存储其余数据类型,不存在嵌套现象,若是数据未获取到,则返回nil(NULL)
每一个hash能够存储2^32-1个键值对
hash类型十分贴近对象的数据存储形式,而且能够灵活添加删除对象属性。可是hash设计初衷不是为了存储大量对象而设计的,因此不能滥用,更不能够将hash做为对象列表使用。
hgettall 操做能够获取所有属性,若是内部field过多,遍历总体数据效率就会很低,有可能成为数据访问瓶颈。
命名惯例
用法
// 单个 hset key field value // 多个 hmset key field1 value1 field2 value2..
// 单个 hget key field // 多个 hmget key field1 field2..
hgettall key
hdel key field1
hlen key
hexists key field 1存在 0不存在
// 获取全部的field名 hkeys key // 获去全部的field-value值 hvals key
// 增长指定的数值 hincrby key field increment // 增长指定小数的值 ingcrbyfolat field increment
hsetnx key field value
电商网站购物车设计与实现
一、初步设计:
二、改进设计:
上述的设计仅仅在缓存里设置了商品ID和数量,可是一个完整的购物车是除了商品ID和数量以外,还显示必定量的商品信息(标题、介绍、类型之类),按照初步设计来的话,要显示商品信息还得去数据库查,这就形成了数据库压力增大,并无提升效率,因此商品信息也该缓存起来。
解决:
将每条购物车中的商品记录保存成两条field
field1专用于保存购买数量:
field2专用于保存商品信息:
问题:若是多个用户添加同一件商品到购物车,那么每一个购物车都会保存一份一样的商品信息,因此,须要将商品信息独立出来存储,作一个独立的Hash,减小没必要要的开支。又回到了以前保存的商品ID-数量这一个设计上面。
解决:
用到了 hsetnx key field value 命令, 若是 key 对应的 field 的没有值,则不添加,不然插入新的 field
上述 string 操做所存储的用户热点信息为例
将
// set 用户:id:id号:粉丝 粉丝数 set user:id:11111:fans 20 // set 用户:id:id号:博客 博客数 set user:id:11111:blogs 20 // set 用户:id:id号:关注 关注数 set user:id:11111:focus 20
和
// set 用户:id:id号 JSON set user:id:11111 {ID:11111,NAME:大V,fans:20,blogs:20,focus:30}
graph LR user:id:11111-->JSON
改为利用hash存储:
双十一活动日,销售手机充值卡的商家对移动、联通、电信的30元、50元、100元商品退出抢购活动,每种商品抢购上线100张。
tips : redis 应用于抢购,限购类,限量发放优惠卷,激活码等业务的数据存储设计。
对比string 和 hash
一、列表对象保存的全部字符串元素的长度都小于64字节 二、列表对象保存的元素数量小于512个
特性:
list中保存的数据都是string类型的,数据总容量是有限的,最多2^32-1个元素
list具备索引的概念,可是操做数据时一般以队列的形式进行入队出队操做,或者以栈的形式进行入栈出栈操做。(左右操做)
获取所有数据结束索引设置为-1
list能够对数据进行分页操做,一般第一页的信息来自于list,第二页以及更多的信息再经过数据库查询加载,这样能够避免数据库压力过大,提升查询速度,由于通常首先看到的是第一页,后面的页数信息也不必定去看。
技术方案都不会只用一种去解决问题的,都是混合式方案,经过某种技术去解决其中一个点,可能得到的提高也是很大的。
用list比较合适去解决:
举例:使用list结构实现栈和队列。
栈后进先出用lpush+blpop ,
队列先进先出用 lpush+brpop,可应对多客户端消费一个队列。
使用:
r: right右 --> rpush右边插入
l:left左 --> lpush左边插入
lpush key value1 [value2].....lpush key 0 -1 0表明首个元素,-1表示倒数第一个,因此用0 -1能够查所有的元素 lpush key value1 [value2].....
lrange key start stop // 第几位开始-第几位结束 lindex key index // list第几个 llen key // list长度
lpop key rpop key
blpop key1 [key2] timeout //block 阻塞版本的移除,根据timeout等n秒,再获取数据有数据则取,没有则nil
// 在某个key列表移除count个 value元素 lrem key count value
微信朋友圈点赞,要求按照点赞顺序显示点赞好友信息。
将这条朋友圈信息做为Key,点赞列表做为value,每个新人点赞都将用rpush 加到value里面,当用户想取消点赞的时候,该怎么办呢?
由于用户位置在过一段时间后,不必定会是在最后,对于这种状况能够用到上面的移除指定数据 lrem 命令lrem list 1 xxx
根据上面的例子:redis 可应用于具备操做前后顺序的数据控制 ,例如消息队列,数据队列,均可以用list来模拟
(用在数据库里的话就是与最新添加的数据按照时间倒序显示差很少 order by time DESC)
我的用户的关注列表须要按照用户的关注顺序进行展现,粉丝列表须要将最近的粉丝列在前面
新闻资讯类的网站将最新新闻资讯按照时间顺序展现
集群服务器日志统一顺序输出,将全部集群服务器日志都打到Redis缓存服务器上,再有其余服务器在缓存上读取日志。
list能存储大量数据,并且它还有存储顺序,能用对应的索引访问,看上去是很是好的存储方式,可是list的底层内部存储结构是一个链表结构。 咱们知道链表结构的存储效率是很低的,对于这么一个能存储大量数据的,可是读取速度慢的结构,就不合适用了,须要引入一种新的存储结构set
新的存储需求:存储大量的数据,在查询方面提供更高的效率
须要的存储结构:可以保存大量的数据,高校的内部存储机制,便于查询
set类型:与hash存储结构彻底相同,仅存储键(key,field)值,不存储值(value = nil),而且值不容许重复(field自然不容许重复,重复就覆盖了以前的)也就是只利用key-field这部分来存储数据
集合中最大的成员数为 每一个集合可存储40多亿个成员)。
value 的空间没法使用,由于开发人员已经决定使用Set这一类型做为存储结构,那么它能调用的API已经规定了,不能跨结构使用
结构对比:
hash类型:
set类型:value 为空
基本操做:
添加数据
// 类型不容许重复,若是添加数据在set中存在,将保留一份,后续数据添加失败 sadd key member1 [member2]
获取所有数据
smembers key
删除数据
srem key member1 [member2]
获取集合数据总量
scard key
判断集合中是否包含指定数据
sismember key member
随机获取集合中指定数量的数据
srandmember key [count]
随机获取集合中的某个数据并将该数据移除集合
spop key [count]
Redis 用于随机推荐类信息检索,例如热点歌单推荐,热点新闻推荐,热卖旅游线路,应用APP推荐,博主大V推荐
共同好友,可能认识的人,微博XX也关注了它
经过下列指令来获取A ∪ B, A ∩ B
,A - B
用于同类信息的关联搜索:显示共同关注/显示共同好友
求两个集合的交、并、差集
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
OA系统员工有一个或者多个角色,每一种角色对应多种不一样业务权限,须要快速的进行业务权限校验
依赖set集合数据不重复的特性,依赖sset集合hash存储结构特征完成数据过滤与快速查询
根据用户ID获取用户全部角色
根据用户全部角色获取用户全部操做权限放入set集合
根据用户全部角色获取用户全部数据入set集合
这里有两种方式来验证权限:
//查询 用户id:01业务的全部权限 smembers userid:01
//判断userid:01集合中是否包含insert这个指定数据 sismember userid:01 insert
对比上面1和2两种方式,咱们使用Redis来提供基础数据仍是提供校验结果?
第一种是将数据和业务逻辑分离开来,redis只提供数据,业务校验在业务层将结果遍历处理
第二种是将业务校验放在数据提供方进行校验,直接将结果返回
如今流行数据-业务分离,数据是纯粹提供基础数据,可是业务逻辑处理仍是在代码里,可是第二种的处理方式是,Redis不只仅提供了基础数据,并且还将这部分业务校验逻辑一并处理,这种方式的业务耦合度会比较高(按照分层思想,咱们不该该将业务逻辑处理放到数据提供层去
),比较推荐第一种作法,该分的仍是得分,避免之后扩展业务逻辑的没必要要的麻烦
利用 Redis 的Set集合的数据去重特性,记录各类访问数据
网站数据统计,公司网站推广,须要统计网站的PV(访问量),UV(独立访问量),IP(独立IP)。
PV:网站被访问次数,可经过刷新页面提升访问量
这种刷新就加一的数据,能够直接用string类型存储,利用它的incr命令来统计日访问量(PV)
UV:网站被不一样用户访问的次数,可经过cookie统计访问量,相同用户切换IP地址,UV不变
创建set模型,记录不一样cookie数量(UV)利用scard统计
IP:网站被不一样IP地址访问的总次数,可经过IP地址统计访问量,相同IP不一样用户访问,IP不变
创建set模型,记录不一样IP数量(IP)利用scard统计
利用 Redis 的Set集合的数据去重特性,记录各类访问数据
基于Redis制做网站黑名单,过滤IP地址、设备信息、用户信息等
创建set模型,记录不一样名单信息,提供给业务逻辑层进行访问权限断定
数据排序有利于数据的有效展现,须要提供一种能够根据自身特征进行排序的方式
Redis 有序集合和集合同样也是string类型元素的集合,且不容许重复的成员。
在set的存储结构基础上作改变,不一样的是每一个元素都会关联一个 double/整数 类型的分数。redis正是经过分数来为集合中的成员进行从小到大的排序。若是为整数类型则为64位。
有序集合的成员是惟一的,但分数(score)却能够重复。
集合是经过哈希表实现的,因此添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 2^32 - 1 (4294967295, 每一个集合可存储40多亿个成员)。
set类型:value 为空
sorted_set类型:value 为空,多加一个score,用来作排序用
用法
添加数据
//添加KEY 排序为score1 值为member1 zadd key score1 member1 [score2 member2]
获取所有数据
zrange key start stop // 获取key里面的数据 0 -1 【WITHSCORES为可选,加上能够显示出每一个值对应排序的分数】 zrange key start stop [WITHSCORES] //翻转获取,倒叙-由大到小,默认由小到大排序 zrevrange key start stop [WITHSCORES]
删除数据
zrem key member [member...]
按条件获取数据
// min与max用于限定搜索查询的条件 // start与stop用于限定查询范围,做用于索引,表示开始和结束索引 // offset与count用于限定查询范围,做用于查询结果,表示开始位置和数据总量 zrangebyscore key min max [WITHSCORES] [LIMIT] zrevrangebyscore key max min [WITHSCORES]
条件删除数据
zremrangebyrank key start stop zremrangebyscore key min max
获取集合数据总量
zcard key zcount key min max
集合交、并操做
zinterstore destination numkeys key [key ...] zunionstore destination numkeys key [key ...]
利用 Redis 的sorted_set集合的数据排序特性实现各种榜单,应用于计数器组合排序功能对应的排名
各种投票、网站排名、活跃度统计榜单(百度热榜),游戏亲密度(如王者荣耀的)等等。。。
获取数据对应的索引(排名)
zrank key member zrevrank key member
score值获取与修改
zscore key member zincrby key increment member
利用 Redis 应用于定时任务执行顺序管理或任务过时管理
各种VIP体验、开启投票、讨论,限时进行,逾期做废等会过时的信息
对于基于时间线限定的任务处理,将处理时间记录为score值,利用排序功能区分处理的前后顺序
记录下一个要处理的时间,当到期后处理对应任务,移除redis中的记录,并记录下一个要处理的时间
当新任务加入时,断定并更新当前下一个要处理的任务时间
为提高sorted_set的性能,一般将任务根据特征存储成若干个sorted_set。例如1小时内,1天内,周内, 月内,季内,年度等,操做时逐级提高,将即将操做的若干个任务归入到1小时内处理的队列中
应用于即时任务/消息队列执行管理
任务/消息权重设定应用 当任务或者消息待处理,造成了任务队列或消息队列时,对于高优先级的任务要保障对其优先处理,如 何实现任务权重管理。
对于带有权重的任务,优先处理权重高的任务,采用score记录权重便可