Redis入门
概念
-
高性能的NOSQL系列的非关系数据库
- 缓存机制的数据库
-
数据之间没有关系
-
数据存在内存中
-
下载安装
-
命令操作
数据结构
redis存储的是键值对的方式
key是键值对 value有五种数据类型
String
字符串类型 string string
String类型是二进制安全的,意思是 redis 的 string 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象。
- 存储
set key value
- 获取
get key
- 删除
del key
实战场景
1.缓存: 经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力。
2.计数器:redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源。
3.session:常见方案spring session + redis实现session共享
Hash:map
哈希类型 hash :map格式
是一个Mapmap,指值本身又是一种键值对结构,如 value={{field1,value1},......fieldN,valueN}}
-
存储
hset key field value
-
获取
hget key field
:获取指定的值hgetall key
:获取所有值 -
删除
hdel key field
实战场景
1.缓存: 能直观,相比string更节省空间,的维护缓存信息,如用户信息,视频信息等。
List:linkedlist
列表 list: linkedlist
List 说白了就是链表(redis 使用双端链表实现的 List),是有序的,value可以重复,可以通过下标取出对应的value值,左右两边都能进行插入和删除数据。
- 添加
lpush key value
: 将元素将入列表左边rpush key value
: 将元素加入列表右边
- 查询
lrange key start end
: 范围获取
- 删除
lpop key
:删除列表最左边的元素,并将元素返回rpop key
:删除列表最右边的元素 ,并将元素返回
实战场景
1.timeline:例如微博的时间轴,有人发布微博,用lpush加入时间轴,展示新的列表信息。
Set
集合类型 set: 不允许重复元素
集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中
1. 不允许有重复的元素,
2.集合中的元素是无序的,不能通过索引下标获取元素,
3.支持集合间的操作,可以取多个集合取交集、并集、差集。
- 存储 :
sadd key vlaue
- 获取:
smembers key
: 获取set所有元素 - 删除 :
srem key value
: 删除set集合中某个元素
实战场景
1.标签(tag),给用户添加标签,或者用户给消息添加标签,这样有同一标签或者类似标签的可以给推荐关注的事或者关注的人。
2.点赞,或点踩,收藏等,可以放到set中实现
Sortedset:zset
有序集合sortedset :不允许重复元素,且元素有顺序按照给定的score 分数排序(就和一个班里的同学学号不能重复,但考试成绩可以相同)。
-
存储 :
zadd key score value
-
获取 :
zrange key start end
-
删除 :
zren key value
-
通用命令
keys *
查询所有键type key
: 获取键对应的value类型del key
:删除指定的key value
实战场景
1.排行榜:有序集合经典使用场景。例如小说视频等网站需要对用户上传的小说视频做排行榜,榜单可以按照用户关注数,更新时间,字数等打分,做排行。
持久化操作
-
RDB:默认的方式,不需要配置,默认就是使用这种机制
-
在redis.Windows.conf文件中编辑
save 900 1
- 十五分钟后如果有一个key更新就持久化
save 300 10
- 5分钟后,如果有十个key更新就持久化
save 60 10000
- 1分钟后如果有一万个key更新就持久化
-
启用配置需要重启redis服务器,在redis路径cmd启动
redis.server.exe redis.windows.conf
-
-
AOF:日志记录的方式,可以记录每条命令的操作,可以每一次命令操作后,持久化数据
- 编辑redis.windows.conf文件
appendonly no (关闭aof) --> appendonly yes (开启aof)
appendfsync everysec
: 每隔一秒进行一次持久化appendfsync always
: 每次操作都进行持久化appendfsync no
:不进行持久化
- 编辑redis.windows.conf文件
-
使用java操作redis
优缺点
RDB操作用save持久化会造成redis阻塞,redis不能处理其他命令
RDB使用bgsave可以异步进行快照操作,同时可以响应客户端的请求,通过创建子进程fork,持久化通过子进程完成
RDB通过配置方式去保存快照数据
AOF通过命令方式,每当一条命令过来就保存在aof文件中
Jedis
-
导包
-
创建Jedis对象,传入参数
("IP地址",端口号)默认是localhost 6379
-
redis有的方法,jedis也有
-
方法
jedis.setex(key,second ,value)
存储知道过期时间的key value
-
使用JedisPool工具类
-
/** * 加载配置文件,配置连接池的参数 * 提供获取连接的方法 */ private static JedisPool jedisPool; //获取配置文件信息 static { InputStream stream = JedisPoolUtil.class.getClassLoader().getResourceAsStream("jedis.properties"); //创建properties的对象读取文件 Properties pro = new Properties(); try { pro.load(stream); } catch (IOException e) { e.printStackTrace(); } //获取数据,设置到JedisPoolConfig中 JedisPoolConfig Config = new JedisPoolConfig(); Config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal"))); Config.setMaxTotal(Integer.parseInt(pro.getProperty("maxIdle"))); //初始化JedisPool jedisPool = new JedisPool(Config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port"))); } public static Jedis getJedis() { return jedisPool.getResource(); }
注意
- 使用redis缓存一些不经常发生变化的数据.
- 数据库的数据一旦发生改变,则需要更新缓存
- 数据库的表的执行,增删改查的操作,需要及时更新redis缓存数据情况,再次存入
- 数据库的数据一旦发生改变,则需要更新缓存
Redis高级
Redis的数据特征
删除策略
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态
-
xx:具有时效性的数据
-
-1 :永久有效的数据
-
-2 :已经过期的数据或被删除的数据或未定义的数据
定时删除
- 创建一个定时器,当key设置有效过期时间.且过期时间到达时,定时器任务立即执行删除操作
- 优点:节约内存,到时就删除,快速释放不必要的内存占用
- 缺点:CPU压力大,无论CPU此刻负载多高,均占用CPU,会影响redis服务器响应的时间和指令的吞吐量
- 总结:用处理器性能换存储空间(用空间换时间)
惰性删除
- 数据过期不做处理,等待下一次访问数据时候删除
- 访问数据之前
(get name)
会执行一个expireIfNeeded()
判断数据是否过期 - 过期就删除,返回不存在
- 未过期就返回数据
- 访问数据之前
- 优点:节约CPU性能,发现必须删除的时候才删除
- 缺点:占用内存空间大,内存压力很大,出现长期占用内存的数据
- 总结:用存储空间换取处理器性能(用时间换空间)
定期删除
-
Redis启动服务器初始化时,读取配置server.hz的值,默认为10
-
每秒钟执行server.hz次serverCron()-------->databasesCron()--------->activeExpireCycle()
-
**activeExpireCycle()**对每个expires[*]逐一进行检测,每次执行耗时:250ms/server.hz
-
对某个expires[*]检测时,随机挑选W个key检测
如果key超时,删除key
如果一轮中删除的key的数量>W*25%,循环该过程
如果一轮中删除的key的数量≤W*25%,检查下一个expires[*],0-15循环
W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值
-
参数current_db用于记录activeExpireCycle() 进入哪个expires[*] 执行
-
如果activeExpireCycle()执行时间到期,下次从current_db继续向下执行
总的来说:定期删除就是周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度
- 特点1:CPU性能占用设置有峰值,检测频度可自定义设置
- 特点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
- 总结:周期性抽查存储空间(随机抽查,重点抽查)
淘汰策略
影响数据淘汰的相关配置
-
最大可使用内存 默认值是0 不限制
maxmemory ?mb
-
每次选取待删除的数据个数,采取随机获取数据的方式
maxmemory-sample count
-
对数据进行删除的选择策略
maxmemory-policy policy
Policy
- 检测易失数据(可能会过期的数据集server.db[i].expires )
- LRU:least recently used 最近最少使用的 长时间不用的
- LFU:least frequently used 最近不常用的 一段时间之内访问时间最少的
- volatile-lru:挑选最近最少使用的数据淘汰
- volatile-lfu:挑选最近使用次数最少的数据淘汰
- volatile-ttl:挑选将要过期的数据淘汰
- volatile-random:任意选择数据淘汰
- 检测全库数据(所有数据集server.db[i].dict )
- allkeys-lru:挑选最近最少使用的数据淘汰
- allkeys-lfu:挑选最近时间次数最少的数据淘汰
- allkeys-random:任意选择数据淘汰
- 放弃数据驱逐
- no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),会引发错误OOM(out of memory)
缓存问题
-
穿透
访问某个redis中不存在的值达到穿透 redis的效果 压力直达服务器
-
雪崩
某个时间点key大批量过期导致访问并发直接压在服务器上
-
击穿
某个key不断的扛着并发 到了过期时间后 并发直接打在服务器上
集群方案
主从复制Replication
读写分离 一台主节点 几台从节点 通过 slaveof ip 地址 端口号连接redis数据库,主节点可读可写 从节点只能读不能写
通过修改redis配置文件中配置
slaveof no one 断开连接
shut down关闭服务器
工作流程(三个阶段)
建立连接
数据同步
全量复制/部分复制
-
发送指令psync2
-
master执行bgsave保存数据
-
当slave和master建立socket连接之后创建命令缓存区
-
生成RDB文件,通过socket发送slave
-
接收RDB,清空数据,执行RDB文件恢复进程
-
发送命令告知RDB恢复已经完成
-
发送复制缓冲区信息
-
接收信息 执行bgrewriteaof,恢复数据
数据同步阶段slave说明
-
如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行
-
复制缓冲区大小设定不合理,会导致数据溢出。如进行全量复制周期太长,进行部分复制时发现数据已
经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态。repl-backlog-size ?mb
-
master单机内存占用主机内存的比例不应过大,建议使用50%-70%的内存,留下30%-50%的内存用于执
行bgsave命令和创建复制缓冲区
心
数据同步阶段slave说明
-
为避免slave进行全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭此期间的对外服务
slave-serve-stale-data yes| no
-
数据同步阶段,master发送给slave信息可以理解master是slave的一个客户端,主动向slave发送
命令 -
多个slave同时对master请求数据同步,master发送的RDB文件增多,会对带宽造成巨大冲击,如果
master带宽不足,因此数据同步需要根据业务需求,适量错峰 -
slave过多时,建议调整拓扑结构,由一主多从结构变为树状结构,中间的节点既是master,也是
slave。注意使用树状结构时,由于层级深度,导致深度越高的slave与最顶层master间数据同步延迟
较大,数据一致性变差,应谨慎选择
命令传播和复制缓冲区工作原理
- master接受到的命令发送给slave进行同步
命令传播的出现断网现象
- 网络闪断 忽略
- 短时间网络中断 部分复制
- 三个核心要素
info server /info
查看- 服务器的运行id
- 主服务器的复制积压缓冲区
- 主从服务器的复制偏移量
- 三个核心要素
- 长时间网络中断 全量复制
主从复制配置方式
心跳机制
哨兵sentinel
-
高可用(HA)介绍
高可用是分布式系统架构设计中必须考虑的因素,通过架构设计减少系统不能提供服务的时间,保证高可用通常遵循下面几点:
- 单点是系统高可用的最大敌人,应该尽量在系统设计的过程中尽量避免单点
- 通过架构设计而保障系统的高可用.其核心准则是:冗余
- 实现故障自动转移
-
哨兵sentinel介绍
-
sentinel(哨兵)是用于监控redis集群中Master状态的工具,其本身也是一个独立运行的进程,是Redis 的高可用解决方案,sentinel哨兵模式已经被集成在redis2.4之后的版本中。
-
sentinel可以监视一个或者多个redis master服务,以及这些master服务的所有从服务;当某个master服务下线时,自动将该master下的某个从服务升级为master服务替代已下线的master服务继续处理请求,并且其余从节点开始从新的主节点复制数据。
-
在redis安装完成后,会有一个redis-sentinel的文件,这就是启动senkinel的脚本文件,同时还有一个sentinel.conf文件,这个是sentinel的配置文件。
-
配置sentinel哨兵
#外部可以访问 bind 0.8.8.0 #设置哨兵监听的主服务器信息,最后一个数字是投票哨兵的数量,一般是除以二向上取整 sentinel monitor mymaster 127.8.8.1 6379 1 #设置判断宕机时长,该设置是否进行主从切换 sentinel down-after-milliseconds mymaster 1008e #奢姿故障切换最大时长 sentinel failover-timeout mymaster 6e8ee #设置主从切换后,同时进行数据同步的slave数量 sentinel parallel-syncs mymaster 1
-
哨兵的工作原理
监控
sentinel之间发布订阅互通信息,监控master和slave运行状态
通知
故障转移
主观下线
任意一台的sentinel监控到master下线后记录该master状态消息sdown
客观下线
一半以上的sentinel再次发送消息给master确认是否下线,下线后记录odown
cluster集群结构搭建
Cluster配置
是否启用cluster,加入cluster节点
cluster-enabled yes| no
cluster配置文件名,该文件属于自动生成,仅用于快速查找文件并查询文件内容
cluster-config-file filename
节点服务响应超时时间,用于判定该节点是否下线或切换为从节点
cluster-node-timeout milliseconds
master连接的slave最小数量
cluster-migration-barrier min_slave_number
Cluster命令
redis-cli命令
添加master到当前集群中,连接时可以指定任意现有节点地址与端口
redis-cli --cluster add-node new-master-host:new-master-port now-host:now-port
添加slave
redis-cli --cluster add-node new-slave-host:new-slave-port
master-host:master-port --cluster-slave --cluster-master-id masterid
删除节点,如果删除的节点是master,必须保障其中没有槽slot
redis-cli --cluster del-node del-slave-host:del-slave-port del-slave-id
重新分槽,分槽是从具有槽的master中划分一部分给其他master,过程中不创建新的槽
redis-cli --cluster reshard new-master-host:new-master:port --oluster-from src-master-idl,src-master-id2,src-master-idn --cluster-to target-master-id --cluster-slots slots
- 将需要参与分槽的所有masterid不分先后顺序添加到参数中,使用,分隔
- 指定目标得到的槽的数量,所有的槽将平均从每个来源的master处获取
重新分配槽,从具有槽的master中分配指定数量的槽到另一个master中,常用于清空指定master中的槽
redis-cli --cluster reshard src-master-host:src-master-port --cluster-from src-master-id --cluster-to target-master-id --cluster-slots slots --cluster-yes