redis实用知识点总结
1.Redis
nosql为解决大数据下的多重种类的数据带来的挑战,尤其是大规模的数据时。
特点:
- 性能高;
- 丰富的数据类型String、 List、 Hash、 Set、 Ordered Set;
- 原子性 支持事务 Muti exec指令;
- publish/subscribe特性。
redis 单个key 可存512M, 支持丰富数据类型,单线程 原子性,可持久化,支持集群 可支持16个库,可做消息队列
企业开发:做数据库 缓存 消息中间件
2.安装:
`sudo apt-get install redis-server`
3.配置文件
cd /etc/redis/redis.conf
分配内存空间建议不超过1G 建议256M-512M
必须要修改的参数:
- daemonize no 修改为 daemonize yes 是否做后台守护进程 后台运行
- bind 127.0.0.1 注释掉
- requirepass 设置密码 //如 requirepass redis-password
进入到redis-cli 中config get config_setting_name
来获取配置参数, config set config_setting_name new_config_value
修改参数
远程连接:
redis-cli -h IP地址 -p 端口 -a 密码
4.redis关闭
- 查询pid,
ps -ef | grep -i redis
kill -9 pid
(此方式是非正常关闭容易丢失数据) - 正常关闭(数据会做持久化)
./bin/redis-cli shutdown
5.Redis命令
- del key //key存在时 删除key
- dump key //序列化给定key 返回序列化的值
- exists key //检查key是否存在
- expire key seconds //设置key过期时间,设置有效期1.设置秒,2.lru算法设置
- ttl key //查看过期时间秒 -1为永久有效,-2无效
- pttl key //查看 毫秒
- persist key //永久有效
- keys [*|?] //查看key
- rename key new_key //修改key名
- move key db //当前库的key 移动到指定的数据库中
- type key //key类型
expire key seconds应用场景:
- 限时优惠活动信息
- 网站数据缓存 定时更新的数据,积分排行榜
- 手机验证码
- 限制网站访问频率
key命名规范:
- key不要太长,尽量不超过1024字节
- key也不要太短,会可读性太低
- 在一个项目中,key最好统一命名模式,如user:123:password , (居然是冒号也可以!)
6.String
是一个key和一个value 组成,String类型是二进制安全,可包含任何数据,如图片jpg 序列化对象。
一个键对大存储512M
二进制安全,在传输数据时,保证二进制数据的信息安全,不被篡改 破译等,如果被攻击,能够及时检测出来。
二进制安全特点:
- 编码解码发生在客户端,执行效率高
- 不需要频繁的编解码,不会出现乱码
命令:
- set key value //key 区分大小写
- get key
- setnx key value //只有在key 不存在的时候 设置值 !!!解决分布式锁的方案之一
- getset key value //设置key,并返回key的旧值,当key不存在 返回nil
- strlen key //返回字符串长度
- del key //删除,若存在返回值得数字类型
- incr key //自增
- decr key //自减
- incrby key 增量值 //在原有数字上加上指定增量值
- decrby key 减量值
场景:
- String通常保存单个字符串或json字符串
- 二进制安全,可以完全把图片内容保存作为字符串
- 计数器 (常规计数:微博数 粉丝数)
7.Hash
Hash是string类型的field和value的映射表,特别适合存储对象。每个hash可存储2的32次方-1个键值对(40多亿),
相比于json,该类型数据占有很少的磁盘空间。
命令:
- hset key field value
- hget key field //取单个
- hmget key field[field] //取多个field的值
- hlen key //获取字段数量
- hdel key field
- hgetall key //获取所有
- hsetnx key field value //field不存在时,设置哈希表字段的值
- hincrby key field increment //key中指定field的整数据值加上increment
- hincrbyfloat key field increment // 加上浮点数增量
- hexists key field //查看key中,指定字段field是否存在
场景:
1.适合存储一个对象(如用户信息对象数据),接近关系型数据结构的对象,类似于HashMap结构
8.List
list列表是简单的字符串列表,按照顺序排序,从列表的左或右添加
命令:
- lpush key value1
[value2]
//左侧 (开头)插入 - rpush key value1
[value2]
- lpushx key value //插入头部,列表不在 操作无效
- rpushx key value
- llen key //列表长度
- lindex key index //索引获取列表元素,0索引为第一个元素
- lrange key start stop //获取列表指定范围内的元素 如lrange l1 0 -1 取所有的列表值
- lpop key //移除列表开头(左侧)一个元素
- rpop key
- blpop key1
[key2]
timeout //移除第一个元素,若没有会阻塞列表,直到超时或移除元素为止 - ltrim key start stop //对列表修剪,保留指定区域(start->stop索引范围)的值
- lset key index value //修改指定索引值
- linsert key before
|
alter value //指定值前或后插入值 - rpoplpush source destination //移除列表最后一个元素 并将该列表添加到另一个列表并返回
- brpoplpush source destination timeout //从列表中弹出一个值,插入另外一个列表中并返回它,如果没有则等待超时或发现可弹出元素为止。
场景:
- 数据量大的集合数据删减
列表显示数据关注列表,粉丝列表,留言评价 分页 热点新闻等,其中分页 可以对前端发送的请求来截取list列表中
相应的一段数据,达到分页的目的!!!又如每个博文评论 可以单独存在list中
ps:分页((pageNum-1)pageSize,pageSizepageNum-1) - 任务队列
list来实现一个消息队列,而且可以确保先后顺序。
rpoplpush source destination 示例案例:订单系统的下单流程,用户系统登录注册短信等
订单下单流程:
完成付款后:
淘宝的后台 生成一个 队列 订单ID
A --- B
1.商家出货
2.快递发件
3.A --> A.airpot
4.A.airpot --> B.airpot
5.B.airpot --> B
6.B --> recipient
list : 1-->2 --> 3--> 4--> 5-->6
使用rpoplpush 每当快递到一个地方触发一次操作,把最左列表值添加到另一个列表队列中 表示已执行的位置。
商品评价
9.Set
是String类型的无序集合,集合成员具有唯一性,没有重复值。其添加 查找 删除复杂度O(1)
命令:
- sadd key member1[member2]
- scard key //获取集合成员数
- smembers key //返回集合中所有成员
- sismember key member //判断member元素是否是集合的成员 验证是否存在
- srandmember key [count] //返回集合中一个 或多个随机数
- srem key member1[member2] //删除
- spop key [count] //移除并返回集合中一个随机元素
- smove source destination member //将member从source移到destination集合
- sdiff key1 key2 //差集
- sinter key1 key2 //交集
- sunion key1 key2 //并集
场景:
- 共同关注,共同喜好,共同好友等
- 利用唯一性,统计所有访问网站的所有独立IP
10.ZSet
有序集合,是string类型元素集合,元素唯一性
命令:
- zadd key score1 memeber1[score2 member2]
- zcard key
- zcount key min max //计算有序集合中指定区间分数的成员数
- zrank key member //返回有序集合中指定成员的索引
- zrange key start stop[withscores] //通过索引区间返回有序集合指定区间的成员(低到高)
- zrevrange key start stop[whithscore] //返回有序集合通过索引指定区间内的成员 分数从高到低
- del key //移除
- zrem key member[member] //移除有序集合中的若干个成员
- zremrangebyrank key start stop //移除有序集合中指定排名区间的所有成员(第一名是0)由低到高排序
- zremrangebyscore key min max //移除有序集合中给定的分数区间的所有成员
场景:
- 排行榜
- 如twitter public timeline 以发表时间作为score来存储,获取时间是自动按时间排序的
- 班级成绩排名,score是考试分数,集合元素是学生学号,这个有序集合可以排序
- 带权重的队列,如普通消息score为1 重要消息score为2 优先任务执行顺序
11.发布订阅
pub/sub是一种消息通信模式,redis客户端可以订阅任意数量的频道。
命令:
- subscribe channel[channel…] //订阅一个 多个频道的信息
- psubscribe pattern[pattern…] //订阅一个或多个符合给定模式的频道
- publish channel message //将信息发布到指定的频道
- unsubscribe [channel [channel…]] //指定退订的频道
- punsubscribe [pattern[pattern…]] //退订所给定模式的频道
12.redis多数据库
数据库由一个整数索引标识,而不是一个数据库名称,默认连接数据库0
redis配置文件,database 16 //(从0开始1 2 …15)
命令:
- select 数据库 //数据库切换
- move key 名称 数据库 //移动数据 当前key移动到另个库
- flushdb //清除当前数据库的所有key
- flushall //清除整个redis的数据库所有key
13.事务
Redis事务可以一次执行多个命令
批量操作在发送exec命令前,被放入队列缓存。
收到exec命令后 进入事务执行,事务中任意命令执行失败,其余命令依然被执行,
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
- redis会将一个事务中所有命令序列化,然后按顺序执行
- 执行中不会被其他命令插入,不许出现加塞行为
事务的错误处理:队列中的某个命令出现了报告错误,执行时整个的所有队列都被取消。
命令:
- multi 开始事务
- exec 触发事务 一并执行所有命令
- discard 取消事务
- watch key[key…] //监视一个 多个key,当执行事务前key被其他命令改动,则事务将被打断。
- unwatch key
场景:
- 一组命令同时执行或都不执行
- 一组命令执行过程不被其他命令插入 ,如商品秒杀,转账
redis淘汰策略
6种策略
14.持久化
数据存放于:
- 内存:高效,断电内存数据丢失
- 硬盘:读写慢于内存,断电不会丢失
RDB
存放在dump.rdb 文件中,是redis默认的持久化机制,相当于快照,保存的是一种状态,几十G数据对应几KB快照
- 优点:快照保存数据几块,还原极快,适用于灾难备份
- 缺点:小内存机器不适合使用,RDB机制符合条件就会快照
- 条件:redis.conf 修改SNAPSHOTTING 的save 配置
AOF
append-only file:aof 比快照方式更好的持久化 每收到写命令,会追加到appendonly.aof ,
当redis重启,重新执行此文件,重建整个数据库的内容。
但这方式会导致持久化文件 会越变越大.
15.redis缓存与数据库一致性
-
实时同步
强一致性要求高的时候,采用实时同步。即查询缓存查询不到 再从DB查询,保存到缓存;更新缓存时,
先更新数据库,再将缓存的设置过期(建议不要去更新缓存内容,应该设置缓存过期)缓存穿透:
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,
这将导致,这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。解决方法:持久层查询不到就缓存空结果,查询时先判断缓存中是否exists(key), 如果有直接返回空,没有则查询后返回
注意insert时需要清除查询的key,否则即使DB中有值也查询不到(当然也可以设置空缓存的过期时间)缓存雪崩:
如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。
这个没有完美解决办法,但可以分析用户行为,尽量让失效点均匀分布。大多数系统设计者考虑用加锁或队列的方式
保证缓存的单线程写,从而避免失效时大量的并发请求落到底层存储系统上。1.加锁排队,限流–限流算法:1计数、2滑动窗口、3.令牌桶Token Bucket、4漏桶leaky Bucket
在缓存失效后,通过加锁或队列来控制读数据库写缓存的线程数量。如对某个key只允许一个线程查询数据和写缓存,其他线程等待热点key:
某个key访问非常频繁,当key失效的时候有大量线程来构建缓存,导致负载增加,系统崩溃。解决方法:
- 使用锁,分布式锁
- 缓存过期时间不设置,而是设置在key对应的value里面,如果检测到存的时间过期则异步更新缓存
- 在value设置一个比过期时间t0小的过期时间值t1,当t1过期的时候,延长t1并做更新缓存操作
- 设置标签缓存,标签缓存设置过期时间,标签缓存过期后,需异步更新实际缓存!!
-
异步队列
对并发程度较高的,可采用异步队列的方式同步,可采用kafka等消息中间件处理消息生产和消费。 -
阿里的同步工具canal
canal模拟mysql slave和master的同步机制,监控DB bitlog日志更新来触发缓存的更新,使用时具有局限性。
16.高并发
可能问题:
一般项目中,只用一台redis是不行的 原因:
- 结构上,单个redis会发生单点故障,一台redis处理所有请求 压力大
- 容量上,单个redis服务器,容量有限,单台redis最大内存不应该超过20G
高可用:
减少停工时间,保持服务器高度可用
高并发:
通过设计保证系统能够同时并行处理很多请求
高并发指标:响应时间,吞吐量(单位时间内处理的请求数量),每秒查询率QPS(每秒请求数),并发用户(同时承载正常用户数,在线人数)等
提高并发能力:
- 垂直扩展
增强单机硬件性能 如cpu 内存 SSD
提升单剂架构性能 如cache减少IO,异步增加吞吐量 - 水平扩展(终极解决方案)
只是增加服务器数量,但架构各层怎么水平设计扩展是难点
17.主从复制
应用场景:电子商务网上的商品,一次上传 无数次浏览(多读少写)
redis服务可有多个slaves复制同步, master–(slave1,slave2…), master节点处理写请求,slave处理读请求
修改配置redis.conf
变回主库: slaveof on one
//不是任何从
变回从库: slaveof ip port
18.Redis Cluster 集群
在大流量访问下提供稳定的业务,集群化是存储的必然形态,集群是水平扩展形式。
redis cluster集群至少需要3个master+3个slave才能建立集群。
特点:
- redis节点彼此互联,二进制协议传输
- 节点fail是通过半数节点检测失效才生效
- 客户端与redis直连