Redis
2021-12-23 14:51:53 0 举报
AI智能生成
登录查看完整内容
redis学习笔记
作者其他创作
大纲/内容
优势:1.处理高并发,大批量数据的能力强。2.支持分布式集群,负载均衡,性能高。3.内存级数据库,查询速度快。4.存储格式多,支持key-value形式,文档形式,图片形式。5.没有多表连接查询机制和限制,扩展性高。
缺点:1.不支持sql工业的标准。2.没有join等复杂的连接操作。3.事务处理能力弱。4.没有完整性约束,对于复杂业务场景支持较差。
优点:1.通过事务处理保持数据的一致性。2.数据更新的开销很小。3.可以进行Join等复杂查询。
缺点:1.数据独写必须经过sql解析,大量数据,高并发下独写性能不足。2.为保证数据一致性,需要加锁,影响并发操作。3.无法适应非结构化存储。4.扩展困难
Redis是一种运行速度很快,并发能力很强,并且运行再内存上的Nosql数据库
介绍
缓存
在使用传统的关系型关系数据库,来做这个功能,非常麻烦而使用Redis的SortSet(有序集合)数据解构能够简单的搞定。
排行榜
利用Redis中原子性的自增操作,我们可以统计类似用户点赞数,用户访问数等。这类操作如果使用Mysql,频繁独写会嗲来相当大的压力,限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击嗲来不必要的压力。
计算器/限速器
利用集合的一些命令,比如求交集,并集,差集等。可以方便搞定一些共同好友,共同爱好之类的功能。
好友关系
除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制,比如:到货通知,右键发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全可以用List来完成异步解耦。
简单消息队列
以jsp为例,默认Session是保护在服务器的文件中,如果是集群服务同一个用户过来可能落在不同的机器上,这就会导致用户频繁登录;采用Redis保存Session后,无论落在哪台机器上都能够获取到对应的Session信息。
Session共享
使用场景
1.Redis和Memcache都是内存数据库,不过memcache还可用户缓存其他东西,例如图片,视频等。
3.虚拟内存-Redis当物理内存用完时,可以将一些很久没有用到的value交换到磁盘。
4.存储数据安全 -Memcache挂掉后,数据没了(没有持久化机制);redis可以定期把偶从你到磁盘(持久化)
5.灾难恢复-Memche挂掉后,数据不可恢复,Redis数据丢失后,可以通过RBD或AOF恢复。
Redis和Memcache
1.Redis和MongoDB并不是竞争关系,更多的是一直哦弄个协作共存的关系。
2.MongoDB本质上还是硬盘数据库,在复杂查询时,仍然会有大量的资源消耗,而且在处理负载逻辑时,仍然要不可避免地进行多次查询。
3.这时就需要redis或Memcache这样的内存数据库来作中间层进行缓存和加速。
4.比如在某些复杂的页面的场景中,整个也i按的内容如果都从MongoDB中查询,可能要十几个查询语句,耗时很长。如果需求允许,则可以把整个页面的对象缓存至Redis中,定期更新。这样MongoDB和Redis就能很好地协作起来
Redis和MongoDB
Redis/Memcache/MongoDB对比
所有节点在同一时间的数据完全一致,这就是分布式的一致性。
C(Consistency):强一致性
服务一直可用,而且要是正常的响应时间。
A(Availability):高可用性
即分布式系统在遇到某节点或网络分区故障时,仍然能够对外提供满足一致性或可用性的服务。
P(Partition tolerance):分区容错性
CAP原理
分区是常态,不可避免,三者不可共存。
一致性高,可用性低。
一致性低,可用性高。
可用性和一致性是一对冤家
CA:单点集群,满足一致性,可用性的系统,通常在可拓展性上不太强。
CP:满足一致性,分区容错性的系统,通常性能不是特别高。
AP:满足可用性,分区容错性的系统,通常一致性要求低一些
三大类原则
CAP总结
分布式数据库
原子性是指事务是一个不可再分割的工作单位,事务中操作要么都发生,要么都不发生。
A:原子性
一致性是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。这就说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。
C:一致性
多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。
I:独立性
持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库中,并不会被回滚。
D:持久性
ACID原理
传统的关系数据库
数据库
已配置文件方式启动:redis-server/opt/redis-5.0.4/redis.conf
进入redis:redis-cli
单实例关系:redis-cli shutdown
性能测试:redis-benchmark(ctrl+C停止)
系统
保存key数据:set key china
返回字符长度
往key中追加数据(abc):append key abc
key自增1(++):incr key
key自减1(--):decr key
key自增3(+=3):incrby key 3
key自减(-=2):decrby key 3
加减操作(必须是数字类型)
nil:已过期
添加key键值v1时同时设置5秒的生命周期:setex key 5 v
0:添加失败,数据已存在
1:添加成功,数据不存在
添加key键值v1时同时设置5秒的生命周期(判断是否存在,防止被覆盖):setnx key 5 v
添加数据的并添加生命周期
add
移动键到几号库:move key db
update
清空当前数据库:flushdb
清空所有数据库:fluashall
删除数据key:del key
delete
获取key数据:get key
切换数据库:select 16 (切换16号数据库)
数据库数量:dbsize(默认16个数据库)
查询所有键: keys *
查询k开头:keys k*
查询e结尾:keys *e
查询包含k键:keys *k*
查询k开头,后匹配一个字符:keys k?
查询k开头,后匹配两个字符:keys k??
第二个字母可能是a或者e:keys r[ae]dis
模糊查询
存在:(integer) 1
不存在:(integer) 0
判断看key是否存在:exists key
永不过期:-1
已过期:-2
查看key键过期时间:ttl key
为key键设置过期时间(倒计时):expire key 秒
查看key键的数据类型:type key
查询key键值长度:strlen key
查询key全部值:getrange key 0 -1
查询key的值,返回时下标0~下标3(包含0和3),共返回4个字符:getrange key 0 3
替换key的值,从下标1开始提供为xxx:setrange key 1 xxx
查询范围
select
一次添加多条数据:mset k1 v1 k2 v2 k3 v3
一次获取多条数据:mget k1 k2
0:添加失败,已存在
1:添加成功
先get后set:getset key v1
多功能操作
String
从左往右(上-下):lpush list1 1 2 3 4
从右往左(下-上):rpush list1 1 2 3 4
从左边进入,在list1中的2元素之前插入java:linsert list1 before 2 java
插入某个元素之前
从左边进入,在list1中的2元素之后插入redis:linsert list1 after 2 redis
插入某元素之后
插入元素(指定某个元素之前/之后)
改变某个下标的值(将list1中下标为0的元素修改成x):lset list1 0 x
移除左(上)边第一个元素:lpop list1
移除右(下)边第一个元素:rpop list 1
删除n个value(从list1中移除2个3):lrem list1 2 3
查询指定下标返回数据(0开始,-1结尾):lrange list1 0 -1
查询集合长度:llen list01
获取指定范围的值(获取list1中下标3~6的值):ltrim list1 3 6
从一个集合搞一个元素到另一个集合中(右出一个,左进一个):rpop lpush list01 list02
List
返回插入元素数量
添加元素(自动排除重复元素):sadd set1 1 2 2 3 5
移动元素:将key1某个值赋值给key2:smove set1 set2 3
删除成功:1
删除集合中元素:srem key value
随机移除:spop set1
查询集合:smembers set1
存在:1
不存在:0
判断元素是否存在:sismember set1 2
获取集合中元素的个数:scard set1
随机获取元素:srandmembers set1
随机获取n个元素:srandmember set1 3
set1和set2共同存在的元素:sinter set1 set2
交集:sinter
将set1和set2中所有元素合并起来(去除重复的):sunion set1 set2
并集:sunion
在set1中存在,在set2中不存在:sdiff set1 set2
在set2中存在,在set1中不存在:sdiff set2 set1
差集:sdiff
数据集合类
Set
添加(添加user,值为id=1001):hset user id 1001
添加学生student,属性一堆:hmset student id 101 name tom age 22
添加失败:0 已存在
添加成功: 1 属性不存在可以添加
添加的时候先判断是否存在:hset student age 18
自增整数2:hincrby student age 2
自增整数
自增小数5.5:hincrbyfloat user money 3.5
自增小数
删除属性(删除学生年龄属性):hdel student age
获取属性信息(获取学生姓名):hget student name
获取所有属性信息(获取学上全部信息)包括值:hgetall student
查询元素的属性个数(查询学生属性个数):hgetall student
判断元素是否存在某个属性(student是否存在name属性):hexists student name
获取属性的所有key不包括值(获取student所有的属性名):hkeys student
获取属性的所有值(获取student所有属性的值(内容)):hvals student
Hash
添加:zadd zset01 10 vip1 20 vip2 30 vip3 40 vip4 50 vip5
删除(删除vip5):zrem zset01 vip5
查询数据:zrange zset01 0 -1
带着分数查询数据:zrange zset01 0 -1 withscores
20<=score<=40:zrangebyscore zset01 20 40
模糊查询:zrangebyscore
查询集合长度: zcard
范围内元素个数(分数在20~40之间,共有几个元素):zcount zset01 20 30
查询元素下标(vip3在集合中的下标(从上向下)):zrank zset01 vip3
通过值获得分数:zscore zset01 vip2
逆序找下标:zrevrank zset01 vip3
逆序查询:zrevrange
逆序范围查找:zrevrangebyscore
Zset
常用命令
1.在指定的时间间隔内,将内存中的数据集的快照写入磁盘2.默认保存在/usr/local/bin中,文件名dump.rdb
简介
每次关机时,redis会自动将数据备份到一个文件中:/usr/local/bin/dump.rdb
自动备份
每次操作完成,执行命令save就会立刻备份
手动备份
stop-writes-on-bgsave-error:进水口和出水口,出水口发生故障与否yes:当后台被封时候发生错误,前台停止写入no:不管是否故障,继续写入
rdbcompression:对于存到到磁盘中的快照,是否启动LZF压缩算法。一般都会启动。yes:启动 no:不启动
rdbchecksum:在存储快照后,是否启动CRC64算法进行校验注意:开启后,大约增加10%左右的CPU消耗
dbfilename:快照备份文件名字
dir:快照备份问价能保存目录,默认为当前目录
RDB相关配置
优点:适合大规模数据恢复,对数据完整性和一致性要求不高。
缺点:一定间隔备份一次,意外宕机,就是去最后一次快照的所有修改。
优缺点
RDB
以日志的形式记录每个写操作
将redis执行过的指令全部记录下来(读操作不记录)
只许追加文件,不可以改写文件
redis在启动指出会读取该文件从头到为执行一遍,这样来重构数据
修改redis.conf总配置文件:appendonly yesappendfilename appendonly.aof
注意点:1.文件中最后一句要删除,否则数据恢复不了2.编辑这个文件,最后要:wq!强制执行
开启AOF
appendonly:开启aof模式
appendfilename:aof的文件名字,最好别改!
appendfsync:追写策略always:每次数据变更,就会立刻记录到磁盘,性能较差,但数据完整性好everysec:默认设置,异步操作,每秒记录,如果一秒当家,会有数据丢失no:不追写
AOF采用文件追加的方式,文件会越来越大,为了解决这个问题,增加了重写机制,redis会自动记录上一次AOF文件的大小,当AOF文件大小达到预先设定的大小时,redis就会启动AOF文件进行内容压缩,只保留可以恢复数据的最小指令集合
no-appendfsync-on-rewrite:重写时是否运用Appendfsync追写策略;用默认no即可,保证数据安全性。
AOF相关配置
AOF
只用作后备用途,建议15分钟备份一次就行
1.在最恶劣的情况下,也只丢失不超过2秒的数据,数据完整性比较高,但代价太大,会带来持续的IO
2.对硬盘的大小要求也高,默认64mb,太小了,企业级最少5G以上
总结
持久化
Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份slave接收到数据文件后,存盘,并加载到内存中;
全量复制
Slave初始化后,开始正常工作时主服务器发生的写操作同步到从服务器的过程;
增量复制
Redis主从同步策略:主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。
当然,如果有需要,slave在任何时候都可以发起全量同步。
redis策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
补充
复制原理
所有命令都会按照顺序执行,事务在执行过程中,不会被其他客户端送来的命令打断。
隔离性
队列中的命令没有提交之前都不会被实际执行,不存在\"事务中查询要看到事务里的更新,事务外查询不能看\"的问题
没有隔离级别
如果一个命令失败,但是别的命令肯会执行成功,没有回滚
不保证原子性
三特性
可以理解成关系型事务中的begin
multi
可以理解成关系型事务中的commit
exec
可以理解成关系型事务中的rollback
discard
监控
watch
取消watch命令对所有key的操作
unwatch
一旦执行了exec命令,那么之前加的所有监控自动失效
publish(发布)
subscribe(订阅)
发布订阅
事务命令(三步走)
事务
Redisson就是用于在Java程序中操作Redis的库,它使得我们可以在程序中轻松地使用Redis。
Redisson在java.util中常用接口的基础上,为我们提供了一系列具有分布式特性的工具类。
Redisson
zookeeper的特点就是高可靠性
redis特点就是高性能
分布式锁方案比较
实现分布式锁
主机挂了,没有主机
一主二仆
继承关系,选出新主机
血脉相传
手动选择主机
谋权篡位
主从复制(读写分离:主机写,从机读)
redis集群的策略
当主机宕机后,可以通过sentinel.conf配置文件,投票选出新主机
由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求
Sentinel是Redis的高可用性解决方案
所有写的操作都是在master上完成的
然后再同步到slave上,所以两台机器之间会有延迟
当系统很繁忙的时候,延迟问题会加重
slave机器数量增加,问题也会加重
缺点
哨兵模式
JedisPool
redis的连接池技术
查询(双层检测锁)
redisson秒杀
redis实际项目中如何使用缓存(使用场景)
因为redis是单线程,所以命令也就具备原子性,使用setnx命令实现锁,保存-v,如果k不存在,保存(当前线程加锁),执行完成后,删除k表示释放锁,如果k已存在,阻塞线程执行,表示有锁。
因为redis是基于内存的操作,CPU不是Redis的评级,Redis的评级最有可能是机器内存的大小或者带宽。既然单线程容易实现,而且CPU不会成为评级,那就顺理成章地采用单线程的方案了。
Redis是纯内存数据库,一般都是见到那的存取操作,线程占用的时间很多,时间的花费主要集中在IO上。所以读取速度快。
Redis使用的是非阻塞IO多路复用,使用了单线程轮询描述,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。
官方答案
redis是单线程的吗 那他是怎么支持高并发请求的?
在高并发下,大量的缓存key在同一事件失效,导致大量的请求落到数据库上。例:活动系统里面同时进行着非常多的活动,但是在某个时间点,所有的活动缓存全部过期。
概念
缓存数据的过期事件设置随机,防止同一事件大量数据过期现象发生。
如果缓存数据库是分布式部署,将热点数据君君分布在不同得缓存数据库中
设置热点数据永远不过期
解决方案
redis缓存雪崩
是指查询一个一定不存在的数据,缓存没有命中,数据库也查询不到。这将导致每次查询都到数据库中查询,会增加数据库的压力。
1. 在接口做校验2. 存null值(缓存击穿加锁)3. 布隆过滤器拦截: 将所有可能的查询key 先映射到布隆过滤器中,查询时先判断key是否存在布隆过滤器中,存在才继续向下执行,如果不存在,则直接返回。布隆过滤器将值进行多次哈希bit存储,布隆过滤器说某个元素在,可能会被误判。布隆过滤器说某个元素不在,那么一定不在。
redis缓存穿透
对一些设置了过期时间的key,如果这些key在某个时间点高并发的情况下,是一些非常热点的数据如果这个key在大量请求时,刚好过期,那么查询的任务会落到数据库上,这称之为缓存击穿。
采用加锁的方法
redis缓存击穿
相关问题
Redis
0 条评论
回复 删除
下一页