[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BURxYWOm-1631241512733)(C:\Users\Administrator\Desktop\新建文件夹\redis-white.png)]
Redis
关系型数据库
Oracle,MySQL,SqlServer,DB2
非关系型数据库
NoSQL只是一种理论,泛指非关系型数据库
Redis:特点键值对存储,主要使用一个哈希表,用key和lvaue形式存储数据,redis是主要代表
HBase:列存储数据库,这部分数据库通常是用来应对分布式存储的海量数据,键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的
MongoDb:文档型数据库,可以看作是键值数据库的升级版,允许之间嵌套键值,效率也比键值数据库查询效率高
Neo4j:图形数据库,图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API
非关系型数据库特点
1.数据模型比较简单.(主要)
2.需要灵活性更强的应用系统
3.对数据库性能要求较高(主要)
4.不需要高度的数据一致性(主要)
5.对于给定key,比较容易映射复杂值的环境.
与关系型数据区分
https://blog.csdn.net/aaronthon/article/details/81714528
关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织
优点:
1、易于维护:都是使用表结构,格式一致;
2、使用方便:SQL语言通用,可用于复杂查询;
3、复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。
缺点:
1、读写性能比较差,尤其是海量数据的高效率读写;
2、固定的表结构,灵活度稍欠;
3、高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。
-----------------------------------------------------------------------------------------
非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。
优点:
1、格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
2、速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;
3、高扩展性;
4、成本低:nosql数据库部署简单,基本都是开源软件。
缺点:
1、不提供sql支持,学习和使用成本较高;
2、无事务处理;
3、数据结构相对复杂,复杂查询方面稍欠。
Redis
面试:redis定位是缓存, 提高数据读写速度, 减轻对数据库存储与访问压力
什么是redis
是以key-value形式存储的非关系型数据库
优点:
对数据高并发读写(直接在内存中进行读写的)
对海量数据的高效率存储和访问
对数据的可扩展和高可用性,
单线程操作,每个操作都是i原子操作,没有并发相关问题
redis6之前是单线程操作的,之后就是多线程了
缺点:redis(ACID处理非常简单),无法做太复杂的关系数据模型,
优势:性能极高,支持超过10w次每秒的读写频率
数据类型丰富:String,list,set,hash,ordered sets
Redis,所有操作都是原子性的,同时还支持对几个操作合并的原子性执行
谁在用redis
比较著名的公司有:
github、blizzard、stackoverflow、flickr
国内
新浪微博(全球最大的redis集群)
2200+亿 commands/day 5000亿Read/day 500亿Write/day
18TB+ Memory
500+ Servers in 6 IDC 2000+instances
淘宝
腾讯微博
redis在线入门 : http://try.redis.io/
redis 中文资料站: http://www.redis.cn/
https://www.runoob.com/redis/redis-tutorial.html
redis安装
傻瓜式安装,下一步,下一步就可以了
Redis默认端口是: 6379
安装好后会自动启动服务器,并且没有密码
进入到安装目录下,使用cmd命令行运行redis-cli.exe程序,出现下面界面表示安装成功
一般项目中设计缓存操作,首选考虑方案:redis
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TWdtjGxd-1631241512735)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210909093715602.png)]
Redis命令格式
类型命令 key 参数数据
set name dafei
String类型命令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zI2cRHlh-1631241512737)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210909193114621.png)]
set key value 存入键值对
get key 根据键取出值
incr key 把值递增1
decr key 把值递减1
del key 根据键删取键值对
setex key timeout value 存入键值对,timeout表示失效时间,单位s
ttl key 可以查询当前key剩多长时间,-1表示永久,-2表示失效
setnx key value 如果key存在,不做操作,否则添加
incrby key num -> 偏移值
mset k1 v1 k2 v2 … -> 批量存入键值对
mget k1 k2 … -> 批量取出键值
append key ‘value’ -> 原值后拼接新内容
setnx key value -> 存入键值对,键存在时不存入
setex key timeout value -> 存入键值对,timeout表示失效时间,单位s
ttl ->可以查询出当前的key还剩余多长时间过期
setrange key index value -> 修改键对应的值,index表示开始的索引位置
应用场景:
计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,同时数据可以异步落地到其他的数据源
共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上,在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息都直接从redis中集中获取。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CxrPKGAb-1631241512739)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210909104533924.png)]
hash类型
Hash类型是String类型的field和value的映射表.或者说是一个String集合.它特别适合存储对象,相比较而言,讲一个对象存储在Hash类型里要比存储在String类型里占用更少的内存空间,并方便存储整个对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V4o7X8sY-1631241512741)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210909194635665.png)]
Mp<String,Map<String,?>> map
hset key hashkey hashvalue ->存入一个hash对象
hget key hashkey ->根据hash对象键去取值
hexists key hashkey ->判断hash对象是含有某个键
hdel key hashkey -> 根据hashkey删除hash对象键值对
hincrby key hashkey 递增值 -> 递增hashkey对应的值
hlen key -> 获取hash对象键的数量
hkeys key -> 获取hash对象的所有键
hvals key -> 获取hash对象的所有值
hgetall key -> 获取hash对象的所有数据
同样有hsetnx,其作用跟用法和setnx一样
应用场景:
共享session:
key:user_token
value:
class User{
private String userame;
private String password;
private int age;
}
user("dafei", "666", 18)
-------------------------------------
方案1: 将user对象转换json格式字符串存redis 【侧重于查, 改非常麻烦】
key value
----------------------------------------------
user_token : "{name:dafei, age:19, password:666}"
方案2: 将user对象转换hash对象存redis【侧重于改,查询相对麻烦】
key value
---------------------------------------------
user_token : {
name:ddafei
age 19
password: 666
}
list类型
Redis中的List类似Java中的queue,也可以当做List来用.
List类型是一个链表结构的集合,其主要功能有push,pop,获取元素等.更详细的说,List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,list的设计非常简单精巧,即可以作为栈,又可以作为队列.满足绝大多数需求.
Map<String, List>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VAuvBpXi-1631241512742)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210909200915505.png)]
rpush key value ->往列表右边添加数据
lrange key start end ->范围显示列表数据,全显示则设置0 -1
lpush key value ->往列表左边添加数据
lpop key -> 弹出列表最左边的数据
rpop key ->弹出列表最右边的数据
llen key -> 获取列表长度
linsert key before/after refVal newVal -> 参考值之前/后插入数据
lset key index value -> 根据索引修改数据
lrem key count value -> 在列表中按照个数删除数据
ltrim key start end -> 范围截取列表
lindex key index -> 根据索引取列表中数据
应用场景
1.用户收藏文章列表:
xxxx_user_articles:uid [aid1, aid2, aid3…]
set类型
Set集合是string类型的无序集合,set是通过hashtable实现的,对集合我们可以取交集,并集,差集.
sadd key value ->往set 集合中添加元素
smembers key ->列出set集合中的元素
srem key value ->删除set集合中的元素
spop key count ->随机弹出集合中的元素
sdiff key1 key2 -> 返回key1中特有元素(差集)
sdiffstore var key1 key2 -> 返回key1中特有元素存入另一个set集合
sinter key1 key2 -> 返回两个set集合的交集
sinterstore var key1 key2 -> 返回两个set集合的交集存入另一个set集合
sunion key1 key2 -> 返回两个set集合的并集
sunionstore var key1 key2 -> 返回两个set集合的并集存入另一个set集合
smove key1 key2 value -> 把key1中的某元素移入key2中
scard key -> 返回set集合中元素个数
sismember key value -> 判断集合是否包含某个值
srandmember key count -> 随机获取set集合中元素
应用场景
1,去重;
2,抽奖;
1,准备一个抽奖池:sadd luckydraw 1 2 3 4 5 6 7 8 9 10 11 12 13
2,抽3个三等奖:spop luckydraw 3
3,抽2个二等奖:spop luckydraw 2
4,抽1个二等奖:spop luckydraw 1
sorted-set类型(有序集合)
zadd key score column ->存入分数和名称,key表示类别,score表示的是分数,colume表示用户
zincrby key score column ->偏移名称对应的分数 ,给相应的用户加上相应的分数
zrange key start end ->按照分数升序输出名称
zrevrange key start end ->按照分数降序输出名称
zrank key name ->升序返回排名
zrevrank key name ->降序返回排名
zcard key ->返回元素个数
zrangebyscore key min max [withscores] -> 按照分数范围升序输出名称
zrevrangebyscore key max min [withscores] -> 按照分数范围降序输出名称
zrem key name -> 删除名称和分数
zremrangebyscore key min max [withscores] -> 根据分数范围删除元素
zremrangebyrank key start end -> 根据排名删除元素
zcount key min max -> 按照分数范围统计个数
应用场景
排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面:
按照时间、按照播放量、按照获得的赞数等。
总结
2: 如果确定使用redis, 此时需要考虑使用哪个数据类型 【偏redis原生数据结构】
1>如果要排序选用zset
2>如果数据是多个且允许重复选用list
3>如果数据是多个且不允许重复选用set
4>剩下的使用string
hash —> 转换成json格式
{
key1:value1
key2:value2 ------> “{key1:value1, key2:value2}”
}
JSON.toJsonString(map)
----------------------------------------------------------------------------
有些公司约定: 所有的redis的key跟value都使用字符串(排除使用zset场景) 【偏redis String类型json结构】
1>如果要排序选用zset
2>剩下的使用string
优点: java操作中如果使用各种类型: list set 其他的 操作redis时需要明确指定的泛型, 麻烦
所以有些公司统一规范, 统一使用字符串, 减少泛型操作
Listlist = …
Set set = …
Map<String, Object> map = …
List list = redis对象.getList
Set set =redis对象.getSet
Map<Object, Object> map = redis对象.getMap
3:怎么设计 key 与 value值
key的设计
1:唯一性
2:可读性
设计keyvalue 缓存用户收藏文章列表
key value
article_favor_list:uid1 [1,2,3,4]
article_favor:uid2 [1,2,3,4]
3:灵活性
4:时效性
value值
根据需求决定
redis进阶
redis高级命令
返回满足的所有键 keys * (可以模糊查询)
exists 是否存在指定key
expire 设置某个key的过期时间.使用ttl查看剩余时间
persist 取消过期时间
flushdb 清空当前数据库,flushall清空所有数据库
select 选择数据库 数据库为0到15(一共16个数据库) 默认进入的是0数据库
move [key] [数据库下标] 讲当前数据中的key转移到其他数据库中
randomkey 随机返回数据库里的一个key
rename重命名key
echo 打印名
dbsize 查看数据库的key数量
info 获取数据库信息
config get 实时传储收到的请求(返回相关的配置信息)
config get * 返回所有配置
redis安全性
因为redis速度非常快,所以在一台比较好的服务器下,一个外部用户在一秒内可以进行15w次的密码尝试,这意味你需要设定非常强大的密码来方式暴力破解.
vi编辑redis.conf文件,找到下面进行保存修改
requirepass [密码]
重启服务器 pkill redis-server
再次进入127.0.01:6379>keys *
(error)NOAUTH Authentication required.
会发现没有权限进行查询auth [密码]
输入密码则成功进入
每次进入的时候都需要输入免密,还有种简单的方式:
redis-cli -a [密码]
redis事务
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
- 批量操作在发送 EXEC 命令前被放入队列缓存。
- 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
- 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:
-
开始事务。
-
命令入队。
-
执行事务。
-
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
redis持久性机制
Redis是一个支持持久化的内存数据库,也就是说redis需要将内存中的数据同步到硬盘来保持持久化
两种持久化方式:
RDB方式:
1.snapshotting(快照)默认方式.将内存中以快照的方式写入到二进制文件中.默认为dump.rdb.可以配置设置自动做快照持久化方式.我们可以配置redis在n秒内如果超过m个key就修改自动做快照.
Snapshotting设置:
save 900 1 #900秒内如果超过1个Key被修改则发起快照保存
save 300 10 #300秒内如果超过10个key被修改,则发起快照保存
save 60 10000
AOF方式
2.append-only file (缩写aof)的方式,由于快照方式是在一定时间间隔做一次,所以可能发生reids意外down的情况就会丢失最后一次快照后的所有修改的数据.aof比快照方式有更好的持久化性,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到命令中,当redis重新启动时会重新执行文件中保存的写命令来在内存中重建这个数据库的内容.这个文件在bin目录下:appendonly.aof
aof不是立即写到硬盘中,可以通过配置文件修改强制写到硬盘中.
aof设置:
appendonly yes //启动aof持久化方式有三种修改方式
#appendfsync always//收到命令就立即写到磁盘,效率最慢.但是能保证完全的持久化
#appendfsync everysec//每秒写入磁盘一次,在性能和持久化方面做了很好的折中
#appendfsync no //完全以依赖os 性能最好,持久化没保证
Redis内存淘汰机制及过期Key处理
Redis内存淘汰机制
Redis内存淘汰机制是指当内存使用达到上限(可通过maxmemory配置,0为不限制,即服务器内存上限),根据一定的算法来决定淘汰掉哪些数据,以保证新数据的存入。
常见的内存淘汰机制分为四大类:
1. LRU:LRU是Least recently used,最近最少使用的意思,简单的理解就是从数据库中删除最近最少访问的数据,该算法认为,你长期不用的数据,那么被再次访问的概率也就很小了,淘汰的数据为最长时间没有被使用,仅与时间相关。
2. LFU:LFU是Least Frequently Used,最不经常使用的意思,简单的理解就是淘汰一段时间内,使用次数最少的数据,这个与频次和时间相关。
3. TTL:Redis中,有的数据是设置了过期时间的,而设置了过期时间的这部分数据,就是该算法要解决的对象。如果你快过期了,不好意思,我内存现在不够了,反正你也要退休了,提前送你一程,把你干掉吧。
4. 随机淘汰:生死有命,富贵在天,是否被干掉,全凭天意了。
通过maxmemroy-policy可以配置具体的淘汰机制,看了网上很多文章说只有6种,其实有8种,可以看Redis5.0的配置文件,上面有说明:
1. volatile-lru -> 找出已经设置过期时间的数据集,将最近最少使用(被访问到)的数据干掉。
2. volatile-ttl -> 找出已经设置过期时间的数据集,将即将过期的数据干掉。
3. volatile-random -> 找出已经设置过期时间的数据集,进行无差别攻击,随机干掉数据。
4. volatile-lfu -> 找出已经设置过期时间的数据集,将一段时间内,使用次数最少的数据干掉。
5. allkeys-lru ->与第1个差不多,数据集从设置过期时间数据变为全体数据。
6. allkeys-lfu -> 与第4个差不多,数据集从设置过期时间数据变为全体数据。
7. allkeys-random -> 与第3个差不多,数据集从设置过期时间数据变为全体数据。
8. no-enviction -> 什么都不干,报错,告诉你内存不足,这样的好处是可以保证数据不丢失,这也是系统默认的淘汰策略。
Redis过期Key清除策略
Redis中大家会对存入的数据设置过期时间,那么这些数据如果过期了,Redis是怎么样把他们消灭掉的呢?我们一起来探讨一下。下面介绍三种清除策略:
惰性删除:当访问Key时,才去判断它是否过期,如果过期,直接干掉。这种方式对CPU很友好,但是一个key如果长期不用,一直存在内存里,会造成内存浪费。
定时删除:设置键的过期时间的同时,创建一个定时器,当到达过期时间点,立即执行对Key的删除操作,这种方式最不友好。
定期删除:隔一段时间,对数据进行一次检查,删除里面的过期Key,至于要删除多少过期Key,检查多少数据,则由算法决定。举个例子方便大家理解:Redis每秒随机取100个数据进行过期检查,删除检查数据中所有已经过期的Key,如果过期的Key占比大于总数的25%,也就是超过25个,再重复上述检查操作。
为全体数据。
6. allkeys-lfu -> 与第4个差不多,数据集从设置过期时间数据变为全体数据。
7. allkeys-random -> 与第3个差不多,数据集从设置过期时间数据变为全体数据。
8. no-enviction -> 什么都不干,报错,告诉你内存不足,这样的好处是可以保证数据不丢失,这也是系统默认的淘汰策略。
Redis过期Key清除策略
Redis中大家会对存入的数据设置过期时间,那么这些数据如果过期了,Redis是怎么样把他们消灭掉的呢?我们一起来探讨一下。下面介绍三种清除策略:
惰性删除:当访问Key时,才去判断它是否过期,如果过期,直接干掉。这种方式对CPU很友好,但是一个key如果长期不用,一直存在内存里,会造成内存浪费。
定时删除:设置键的过期时间的同时,创建一个定时器,当到达过期时间点,立即执行对Key的删除操作,这种方式最不友好。
定期删除:隔一段时间,对数据进行一次检查,删除里面的过期Key,至于要删除多少过期Key,检查多少数据,则由算法决定。举个例子方便大家理解:Redis每秒随机取100个数据进行过期检查,删除检查数据中所有已经过期的Key,如果过期的Key占比大于总数的25%,也就是超过25个,再重复上述检查操作。
Redis服务器实际使用的是惰性删除和定期删除两种策略:通过配合使用这两种删除策略,可以很好地在合理使用CPU和避免浪费内存之间取得平衡。