1、Redis 数据类型
1.1、数据类型的介绍
- Redis数据类型(5种常用)
- string – String
- hash – HashMap
- list – LinkedList
- set – HashSet
- sorted_set --TreeSet - redis数据存储格式
- redis自身是一个Map,其中所有的数据都是采用key:value的形式存储
- 数据类型指的是存储的数据的类型,也就是value部分的类型,key部分永远都是字符串
1.1.1 String类型
- 存储的数据:单个数据,最简单的数据存储类型,也是最常用的数据存储类型
- 存储数据的格式:一个存储空间保存一个数据
- 存储内容:通常使用字符串,如果字符串以整数的形式展示,可以作为数字操作使用
- String类型的数据的基本操作
- 添加/修改数据
set key value
- 获取数据
get key
- 删除数据
del key
- 添加/修改多个数据
mset key1 value1 key2 value2...
- 获取多个数据
mget key1 key2...
- 获取数据字符个数(字符串长度)
strlen key
- 追加信息到原始信息后部(如果原始信息存在就追加,否则新建)
append key value
- 添加/修改数据
- String类型数据的扩展操作
- 设置数值数据增加指定范围的值
incr key incrby key increment incrbyfloat key increment
- 设置数值数据减少指定范围的值
decr key decrby key increment
- String 作为数值操作
- String在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算
- redis所有的操作都是原子性的,采用单线程处理所有业务,命令时一个一个执行的,因此无需考虑并发带来的数据影响
- 注意:按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis数值上限,将报错。
9223372036854775807(java中long类型数据最大值,Long.MAX_VALUE)
- 设置数据具有指定的生命周期
setex key seconds value psetex key milliseconds value
- 设置数值数据增加指定范围的值
- String 类型数据操作的注意事项
- 数据操作不成功的反馈与数据正常操作之间的差异
- 数据未获取到:(nil)等同于null
- 数据最大存储量:512MB
- 数值计算最大范围(java中的long的最大值):9223372036854775807
- key的设置约定
- 数据库中的热点数据key命名惯例
表名:主键名:主键值:字段名
eg:order: id: 123456: name
- 数据库中的热点数据key命名惯例
1.1.2 hash类型
- 新的存储需求:对一系列存储的数据进行编组,方便管理,典型的应用存储对象信息
- 需要的存储结构:一个存储空间保存多个键值对数据
- hash类型:底层使用哈希表结构实现数据存储
- hash存储结构优化
- 如果field数量较少,存储结构优化为类数组结构
- 如果field数量较多,存储结构使用HashMap结构
- hash存储结构优化
- 基本操作
- 添加/修改数据
hset key field value
- 获取数据
hget key field hgetall key
- 删除数据
hdel key field1 [field2]
- 添加/修改多个数据
hmset key field1 value1 field2 value2
- 获取多个数据
hmget key field1 field2
- 获取哈希表中字段的数量
hlen key
- 获取哈希表中是否存在指定的字段
hexists key field
- 添加/修改数据
- 扩展操作
- 获取哈希表中所有的字段名或字段值
hkeys key hvals key
- 设置指定字段的数值数据增加指定范围的值
hincrby key field increment hincrbyfloat key field increment
- 设置属性前检验当前是否存在该field,存在则不做操作,不存在则设置
hsetnx key field value
- 获取哈希表中所有的字段名或字段值
- 注意事项
- hash类型下的value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对的值为(nil)
- 每个hash可以存储232-1个键值对
- hash类型十分贴近对象的存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用
- hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率会很低,有可能成为数据访问瓶颈
1.1.3 list类型
- 数据存储需求:存储多个数据,并对数据的进入存储空间的顺序进行区分
- 需要的存储机构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
- list类型:保存多个数据,底层使用双向链表存储结构实现
- 基本操作
- 添加/修改数据,左进右进
lpush key value1 [value2] ... rpush key value1 [value2] ...
- 获取数据(stop可设置-1,代表最后一个的索引)
lrange key start stop lindex key index llen key
- 获取并移除数据
lpop key rpop key
- 添加/修改数据,左进右进
- 扩展操作
- 规定时间内获取并移除数据
blpop key1 [key2] timeout brpop key2 [key2] timeout
- 移除指定数据
lrem key count value
- 规定时间内获取并移除数据
- 注意事项
- list中保存的数据都是string类型的,数据总容量是有限的,最多 232-1个元素(4294967295)
- list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作
- 获取全部数据操作结束索引设置为-1
- list可以对数据进行分页操作,通常第一页的信息来自与list,第2页及跟多的信息通过数据库的形式加载
1.1.4 set类型
- 新的存储需求:存储大量的数据,在查询方面提供更高的效率
- 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
- set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
- 基本操作
- 添加数据
sadd key member1 [member2]
- 获取全部数据
smembers key
- 删除数据
srem key member1 [member2]
- 获取集合数据总量
scard key
- 判断集合中是否包含指定数据
sismember key member
- 添加数据
- 拓展操作
- 随机获取集合中指定数量的数据
srandmember key [count]
- 随机获取集合中的某个数据并将该数据移出集合
spop key
- 求两个集合的交、并、差集
sinter key1 [key2] sunion key1 [key2] sdiff key1 [key2]
- 求两个集合的交、并、差集并存储到指定集合中
sinterstore desination key1 [key2] sunionstore destination key1 [key2] sdiffstore destination key1 [key2]
- 将指定数据从原始集合中移动到目标集合中
smove source destination member
- 随机获取集合中指定数量的数据
- 注意事项
- set类型不允许数据重复,如果添加的数据在set中已经存在,将只保留一份
- set虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
1.1.5 sorted_set类型
- 新的存储需求:数据排序有利于数据的有效展示,不要提供一种可以根据自身特征进行排序的方式
- 需要的存储结构:新的存储模型,可以保存可排序的数据
- sorted_set类型:在set的存储结构基础上添加可排序字段
- 基本操作
- 添加数据
zadd key score1 member1 [scored2 member2]
- 获取全部数据
zrange key start stop [WITHSCORES] zrevrange key start stop [WITHSCORES]
- 删除数据
zrem key member [member ... ]
- 按条件获取数据
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 ...]
- 获取数据对应的索引(排名)
zrank key member zrevrank key member
- score值获取与修改
zscore key member zincrby key increment member
- 获取当前时间
time
- 添加数据
- 注意事项
- score 保存的数据存储空间是64位,如果是整数范围是-9007199254740992~9007199254740992
- score保存的数据也可以是一个双精度的double值,基于双精度浮点数的特征,可能会丢失精度,使用时候要慎重
- sorted_set底层存储还是基于set结构的,因此数据不能重复,如果重复添加相同的数据,score值将被反复覆盖,保留最后一次修改的结果
1.2 通用命令
1.2.1 key通用命令
- key特征
- key是一个字符串,通过key获取redis中保存的数据
- 基本操作
- 删除指定key
del key
- 获取key是否存在
exists key
- 获取key的类型
type key
- 删除指定key
- 扩展操作
- 为指定key设置有效期
expire key seconds pexpire key milliseconds expireat key timestamp pexpireat key milliseconds-timestamp
- 获取key的有效时间
ttl key pttl key // 返回毫秒数
- 切换key从时效性转为永久性
persist key
- 查询key
keys pattern
查询模式规则:
* : 匹配任意数量的任意符号
?: 匹配一个任意符号
[]: 匹配其中一个指定符号
- 其他操作
- 为key改名
rename key new key renamenx key newkey // 如果新名称不存在才能改
- 对所有key排序
sort key [desc]
- 其他key通用操作
```help @generic ``
1.2.1 数据库通用操作
- redis为每个服务提供由16个数据库,编号从0到15
- 每个数据库之间的数据相互独立
- 基本操作
- 切换数据库
select index
- 其他操作
quit ping echo message
- 数据移动
move key db
- 数据清楚
dbsize flushdb flushall
- 切换数据库
2、Jedis
2.1、Jedis简介
基于链接池获取连接
- JedisPool: Jedis提供的连接池技术
- poolConfig:连接池配置对象
- host:redis服务地址
- port:redis服务端口号
public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port) { this(poolConfig, host, port, 2000, (String)null, 0, (String)null); }
3、Redis持久化
3.1、持久化简介
- 什么是持久化?
利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化 - 为什么要进行持久化?
防止数据的意外丢失,确保数据安全性 - 持久化过程保存什么
- 将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据(RDB)
- 将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程(AOF)
3.2、RDB
RDB (Redis DataBase)
- 1、命令:
save
作用:手动执行一次保存操作- RDB启动方式
- 用户:redis操作者
- 时间:即使(随时进行)
- 操作:保存数据
- save 指令相关配置
- dbfilename dump.rdb
- 说明:设置本地数据库文件名,默认值为dump.rdb
- 经验:通常设置为dump-端口号.rdb
- dir
- 说明:设置存储.rdb文件的路径
- 经验:通常设置成存储空间较大的目录中,目录名称data
- rdbcompression yes
- 说明:设置存储至本地数据库时是否压缩数据,默认为yes,采用LZF压缩
- 经验:通常默认为开启状态,如果设置为no,可以节省CPU运行时间,但会使存储空间变大(巨大)
- rdbchecksum yes
- 说明:设置是否进行RDB文件格式校验,该校验过程在写文件和读文件过程均进行
- 经验:通常默认为开启状态,如果设置为no,可以节约读写性过程约10%时间消耗,但是存储一定的数据损坏风险
- dbfilename dump.rdb
- save指令工作原理
注意:由于redis为单线程执行,save指令的执行会阻塞当前redis服务器,知道当前RDB过程完成为止,有可能造成长时间阻塞,线上环境不建议使用
- RDB启动方式
- 2、命令
bgsave
作用:手动启动后台保存操作,但不是立即执行- 相关配置
其他配置同save配置 - stop-writes-on-bgsave-error yess
- 说明:后台存储过程中如果出现错误现象,是否停止保存操作
- 经验:通常默认为开启状态
- bgsave指令工作原理
发送指令=》 调用fork函数,生成子进程=》生成rdb文件
注意:bgsave指令是针对save阻塞问题做的优化,redis内部所有涉及到RDB操作都建议采用bgsave的方式,save命令可以放弃使用
- 相关配置
- 3、自动执行
- 3、RDB启动方式
- 用户:redis服务器发起指令(基于条件)
- 时间:满足条件
- 操作:保存数据
- 配置
save second changes
作用:满足限定时间范围内key的变化数量达到指定数量即进行持久化
参数- second:监控时间范围(单位s)
- changes:监控key的变化量
- 位置
在conf文件中进行配置 - 范例
save 900 1 save 300 10 save 60 10000
- 配置原理
注意:
save配置要根据实际业务情况进行配置,频度过高或过低都会出现性能问题,结果可能是灾难性的
save配置中对于second与changes设置通常具有互补对应关系,尽量不要设置成包含性关系
save配置中对于启动后执行的是bgsave操作
- 3、RDB启动方式
- 4、特殊启动形式
- 全量赋值
- 服务器运行过程中重启
debug reload
- 关闭服务器时指定保存数据
shutdown save
- RDB三种方式对比
方式 save指令 bgsave指令 读写 同步 异步 阻塞客户端指令 是 否 额外内存消耗 否 是 启动新进程 否 是 - RDB优缺点
- 优点
- RDB是一个紧凑压缩的二进制文件,存储效率极高
- RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
- RDB恢复数据的速度要比AOF块很多
- 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中国,用于灾难恢复
- 缺点
- RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大可能丢失数据
- bgsave指令每次运行要fork操作创建子进程,要牺牲掉一些性能
- Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象
- 优点
3.2、AOF
RDB存储的弊端
1、存储数据量大,效率较低
基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低
2、大数据量下的IO性能较低
3、基于fork创建子进程,内存产生额外消耗
4、宕机带来的数据丢失风险
- AOF概念
- AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的。与RDB相比可以简单描述为改记录数据产生的过程
- AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式
- AOF写数据三种策略(appendfsync)
- always(每次)
每次写入操作均同步到AOF文件中,数据零误差,性能较低,不建议使用 - everysec(每秒)
每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高,建议使用,也是默认配置
在系统突然宕机的情况下丢失1秒内的数据 - no(系统控制)
由操作系统控制每次同步到AOF文件的周期,整体过程不可控
- always(每次)
- AOF功能开启
- 配置
appendonly yes | no
作用:是否开启AOF持久化功能,默认为不开启状态 - 配置
appeendfsync always | everysec | no
作用:AOF写数据策略 - 配置
appendfilename filename
作用:AOF持久化文件名,默认文件名appendonly.aof,建议配置为appendonly-端口号.aof - 配置
dir
作用:AOF持久化文件保存路径,与RDB持久化文件保持一致
- 配置
- AOF重写
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。AOF文件重写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是对同一个数据的若干条命令执行结果转化成最终结果数据对应的指令进行记录。- 重写作用
- 降低磁盘占用量,提高磁盘利用率
- 提高持久化效率,降低持久化写时间,提高IO性能
- 降低数据恢复复用时,提高数据恢复效率
- 重写规则
- 进程内已超时的数据不再写入文件
- 忽略无效指令,重写时使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令,如 del key1、hdel key2,srem key3、set key4 1111、set key4 222等
- 对同一数据的多条写命令合并成为一条命令
如lpush list1 a、lpush list1 b、lpush list1 c、可以转化为lpush list1 a b c。
为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素
- 重写方式
调用fork函数生成子进程,重写aof文件- 手动重写
bgrewriteaof
- 自动重写
- 自动重写触发条件设置(任意满足即触发)
auto-aof-rewrite-min-size size auto-aof-rewrite-percentage percentage
- 自动重写触发对比参数(运行指令info Persistence获取具体信息)
aof_current_size aof_base_size
- 自动重写触发条件
aof_current_size > auto-aof-rewrite-min-size ( aof_current_size - aof_base_size ) / aof_base_size >= auto-aof-rewrite-percentage
- 手动重写
- 重写作用
4、事务
- 事务简介
redis执行指令过程中,多条连续执行的指令被干扰,打断,插队
redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。当执行时,一次性按照添加顺序依次执行,中间不会被打断或者干扰。
一个队列中,一次性、顺序性、排他性的执行一系列命令 - 事务基本操作
- 开启事务
multi
作用:设定事务的开启位置,此指令执行后,后续的所有指令均加到事务中 - 执行事务
exec
作用:设定事务的介绍位置,同时执行事务。与multi成对出现,成对使用
注意:加入事务的命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行 - 取消事务
discard
作用:终止当前事务的定义,发生在multi之后,exec之前
- 开启事务
- 事务的工作流程
- 事务的注意事项
已经执行完毕的命令对应的数据不会自动回滚,需要程序员自己在代码中实现回滚- 语法错误
指命令书写格式有误
处理结果:如果定义的事务中所包含的命令存在语法错误,整体事务中的所有命令均不会执行。包括那些语法正确的命令。 - 运行错误
指命令 格式正确,但是无法正确的执行。例如对list进行incr操作
处理结果:能够正确运行的命令会执行,运行错误的命令不会被执行
- 语法错误
- 锁
- 基于特定条件的事务执行–锁
- 对key添加监视锁,在执行exec前如果key发生了变化,终止事务执行
watch key1 [key2 ...]
- 取消对所有key的监视
unwatch
- 对key添加监视锁,在执行exec前如果key发生了变化,终止事务执行
- 基于特定条件的事务执行–分布式锁
- 使用setnx设置一个公共锁
setnx lock-key value
利用setnx命令的返回值特征,有值则返回设置失效,无值则返回设置成功- 对于返回设置成功的,拥有控制权,进行下一步的具体业务操作
- 对于返回设置失败的, 不具有控制权,配对或等待
- 操作完毕通过del操作释放锁
注意:上述解决方案是一种设计概念,依赖规范保障,具有风险性
- 使用setnx设置一个公共锁
- 基于特定条件的事务执行–分布式锁改良
setnx成功之后,立即使用expire设置锁失效- 使用expire为锁key添加时间限定,到时不释放,放弃锁
由于操作通常都是微秒或毫秒级,因此该锁定时间不宜设置过大。具体时间需要业务测试后确认。expire lock-key second pexpire lock-key millisecond
- 例如:持有锁的操作最长执行时间127ms,最短执行时间7ms
- 测试百万次最长执行时间对应命令的最大耗时,测试百万次网络平均延时
- 锁时间设定推荐:最大耗时 * 120% + 平均网络延迟*110%
- 如果业务最大耗时<<网络平均延时,通常为2个数量级,取其中单个耗时较长即可
- 基于特定条件的事务执行–锁
5、Redis删除策略
5.1、过期数据
Redis是一种内存级数据库,所有数据均放在内存中,内存中的数据可以通过TTL指令获取其状态
- 数据状态
- XX:具有失效性的数据
- -1:永久有效的数据
- -2:已经过期的数据或被删除的数据或未定义的数据
- 数据删除策略
- 1、定时删除
- 2、惰性删除
- 3、定期删除
5.2、数据删除策略
- 时效性数据的存储结构
- expire、expireat、pexpire、pexpireat设置key过期时间
- 数据删除策略的目标
- 在内存占用与CPU占用之间寻找一种平衡,顾此失彼都会造成整体redis性能的下降、甚至引发服务器宕机或内存泄漏
- 定时删除
- 创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
- 优点:节约内存, 到时就删除,快速释放掉不必要的内存占用
- 确定:CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量
- 总结:用处理器性能高换取存储空间(拿时间换空间)
- 惰性删除
- 数据到达过期时间,不做处理。等下次访问该数据时
- 如果未过期,返回数据
- 发现已过期,删除,返回不存在(expirelfNeeded())
- 优点:节约CPU性能,发现必须删除的时候才删除
- 确定:内存压力很大,出现长期占用内存的数据
- 总结:用存储空间换取处理器性能
- 数据到达过期时间,不做处理。等下次访问该数据时
- 定期删除
- Redis启动服务器初始化时,读取配置server.hz的值,默认为10
- 每秒钟执行server.hz次serverCron()(轮寻)=> databasesCron()(轮询expires数据)=> activeExpireCycle()
- activeExpireCycle()对每个expires[*]逐一检测,每次执行250ms/server.hz
- 对某个expires[*]检测时,随机挑选W个key检测
- 如果key超时,删除key
- 如果一轮中删除的key的数量>W*25%,循环该过程
- 如果一轮中删除的key的数量<=W25%,检查下一个expires[],0-15循环
- W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值
- 参数current_db用于记录activeExpireCycle()进入哪个expires[*]执行
- 如果activeExpireCycle()执行时间到期,下次从current_db继续向下执行
- 特点:
- 周期性轮叙redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度
- 特点1:CPU性能占用设置有峰值,检测频度可自定义设置
- 特点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
- 总结:周期性抽查存储空间(随机抽查,重点抽查)
- 删除策略对标
- 定时删除: - 节约内存,无占用 - 部分时段占用CPU资源,频度高 - 拿时间换空间
- 惰性删除: - 内存占用严重 - 延时执行,CPU利用率高 - 那空间换时间,默认使用(同定期删除同时使用)
- 定期删除: - 内存定期随机清理 - 每秒花费固定的CPU资源维护内存 - 随机抽查,重点抽查,也默认使用
5.3、逐出算法
Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存不满足新加入数据的最低要求,redis要临时删除一些数据未当前指令清理存储空间。清理数据的策略为逐出算法
注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息
(error) OOM command not allowed when used memory>'maxmemory'
- 影响数据逐出的相关配置
- 最大可使用内存
maxmemory
占用物理内存的比例,默认值为0,表示不限制。生产环境中根据需求设定,通常设置在50%以上。 - 每次选取待删除数据的个数
maxmemory-samples
选取数据时并不会全库扫描,导致严重的性能消耗,降低读写性能。因此采用随机获取数据的方式作为待检测删除数据 - 删除策略
maxmemory-policy volatile-lru
达到最大内存后的,对被挑选出来的数据进行删除的策略- 检测易失数据(可能会过期的数据集server.db[i].expires)
- volatile-lru:挑选最近最少使用的数据淘汰(last recently used)
- volatile-lfu:挑选最近使用次数最少的数据淘汰(least frequently used)
- volatile-ttl:挑选将要过期的数据淘汰
- volatile-random:任意选择数据淘汰
- 检测全库数据(所有数据集server.db[i].dict)
- allkeys-lru:挑选最近最少使用的数据淘汰
- allkeys-lfu:挑选最近使用次数最少的数据淘汰
- allkeys-random:任意选择数据淘汰
- 放弃数据驱逐
- no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),会引发错误OOM(out of memory)
- 最大可使用内存
- 数据逐出策略配置依据
- 使用INFO命令输出监控信息,查询缓存hit和miss的次数,根据业务需求调优Redis配置
6、Redis.conf配置
6.1、服务器基础配置
- 服务端设定
- 设置服务器以守护进程的方式运行
daemonize yes | no
- 绑定主机地址
bind 127.0.0.1
- 设置服务器端口号
port 6379
- 设置数据库数量
databases 16
- 设置服务器以守护进程的方式运行
- 日志配置
- 设置服务器以指定日志记录级别
loglevel debug | verbose | notice | warning
- 日志记录文件名
logfile 端口号.log
注意:日志级别开发期设置为verbose即可,生产环境中配置为notice,简化日志输出量,降低写日志IO的频度
- 设置服务器以指定日志记录级别
- 客户端配置
- 设置同一时间最大客户端连接数,默认无限制。当客户端连接到达上限,redis会关闭新的连接
maxclients 0
- 客户端闲置等待最大时长,达到最大值后关闭连接。如需关闭该功能,设置为0
timeout 300 // 单位秒/s
- 设置同一时间最大客户端连接数,默认无限制。当客户端连接到达上限,redis会关闭新的连接
- 多服务器快捷配置
- 导入并加载指定配置文件信息,用于快速创建redis公共配置较多的redis实例配置文件,便于维护
include /path/server-端口号.conf
- 导入并加载指定配置文件信息,用于快速创建redis公共配置较多的redis实例配置文件,便于维护
7、Redis高级数据类型
7.1、Bitmaps
数据统计
- 基础操作
- 获取指定key对应偏移量上的bit值
getbit key offset
- 设置指定key对应偏移量上的bit值,value只能是1或0
setbit key offset value
- 对指定key按位进行交、并、非、异或操作,并将结果保存到destKey中
bitop op destkey key1 [key2...]
op可选下列运算方式- and:交
- or:并
- not:非
- xor:异或
- 统计指定key中1的数量
bit count key [start end]
- 获取指定key对应偏移量上的bit值
7.2、HyperLogLog
数据基数统
- 基础操作
- 添加数据
pfadd key element [element]
- 统计数据
pfcount key [key...]
- 合并数据
pfmerge destkey sourcekey [sourcekey ...]
- 添加数据
- 相关说明
- 用于进行基数统计,不是集合,不保存数据,只记录数量而不是具体数据
- 核心是基数估算算法,最终数值存在一定误差
- 误差范围:基数估计的结果是一个带有0.81%标准错误的近似值
- 耗空间极小,每个hyperloglog key占用了12k的内存用于标记基数
- pfadd命令不是一次性分配12k内存使用,会随着基数的增加内存逐渐增大
- pfmerge命令合并后占用的存储空间为12k,无论合并之前数据量多少
7.3、GEO
地理位置计算,经纬度距离计算,不算高度差
- 基本操作
- 添加坐标点
geoadd key longitude latitude member [longitude latitude member...]
- 获取坐标点
geopos key member [member...]
- 计算坐标点距离
geodist key member1 member2 [unit]
- 根据坐标求范围内的数据
georadius key longitude latitude radius m | km | ft | mi [withcoord] [withdist] [count count]
- 根据点求范围内数据
georadiusbymember key member radius m | km | ft |mi [withcoord] [withdist] [withhash] [count count]
- 根据指定点对应的坐标hash值
geohash key member [member ...]
- 添加坐标点
8、Redis复制
8.1、简介
业界高可用性目标5个9,即99.999%,即服务器年宕机时长低于315秒,约等于5.25分钟
- 单机redis的风险与问题
- 问题1.机器故障
- 现象:硬盘故障,系统崩溃
- 本质:数据丢失,很可能对业务造成灾难性打击
- 结论:基本上会放弃使用redis
- 问题2.容量瓶颈
- 现象:内存不足,从16G升级到64G,从64G升级到128G,无限升级内存
- 本质:穷,硬件条件跟不上
- 结论:放弃使用redis
- 结论:为了避免单点redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服务器上,连接在一起,并保证数据是同步的。即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现redis的高可用,同时实现数据冗余备份
- 问题1.机器故障
- 多台服务器连接方案
- 提供数据方:master
- 主服务器,主节点,主库(连接该服务器的为主客户端)
- 接收数据房:slave
- 从服务器,从节点,从库(连接该服务器的为从客户端)
- 需要解决的问题:数据同步
- 核心工作:master的数据复制到slave中
- 提供数据方:master
- 主从复制
主从复制即将master中的数据即时、有效的复制到slave中
特征:一个master可以拥有多个slave,一个slave只对应一个master
职责:- master:
- 写数据
- 执行写操作,将出现变化的数据自动同步到slave
- 读数据(可忽略)
- slave
- 读数据
- 写数据(禁止)
- 作用
- 读写分离:master写,slave读,提供服务器的读写负载能力
- 负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
- 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
- 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
- 高可用基石:基于主从复制,构建哨兵模式与集群,实现redis的高可用方案
- master:
8.2、主从复制工作流程
- 总述
- 主从复制过程大体可以分为3个阶段
- 阶段一:建立连接阶段(即准备阶段)
- 阶段二:数据同步阶段
- 阶段三:命令传播阶段
- 主从复制过程大体可以分为3个阶段
8.2.1、阶段一:建立连接阶段
建立slave到master的连接,使master能够识别slave,并保存slave端口号
步骤一:设置master的地址和端口,保存master信息
步骤二:建立socket连接
步骤三:发送ping命令
步骤四:身份验证
步骤五:发送slave端口信息
至此,主从连接成功
状态:
salve:保存master的地址和端口
master:保存slave的端口
总体:之间创建了连接的socket
- 主从连接(slave连接master)
- 方式一:客户端发送命令
slaveof <masterip> <masterport>
- 方式二:启动服务器参数
redis-server --slaveof <masterip> <masterport>
- 方式三:服务器配置
slaveof <masterip> <masterport>
- slave系统信息
- master_link_down_since_seconds
- masterhost
- masterport
- master系统信息
- slave_listening_port(多个)
- 方式一:客户端发送命令
- 主从断开连接
- 客户端发送命令
slaveof no one
- 客户端发送命令
- 授权访问
- master配置文件设置密码
requirepass <password>
- master 客户端发送命令设置密码
config set requirepass <password> config get requirepass
- slave客户端发送命令设置密码
auth <password>
- slave配置文件设置密码
masterauth <password>
- 启动客户端设置密码
redis-cli -a <password>
- master配置文件设置密码
8.2.2、阶段二:数据同步阶段
在slave初次连接master后,复制master中的所有数据到slave
将slave的数据库状态更新成master当前的数据库状态
- 数据同步阶段工作流程
步骤1:请求同步数据
步骤2:创建RDB同步数据
步骤3:恢复RDB同步数据
步骤4:请求部分同步数据
步骤5:恢复部分同步数据
至此,数据同步工作完成
状态:
slave:具有master端全部数据,包含RDB过程接收的数据
master:保存slave当前数据同步的位置
总体:之间完成了数据克隆 - 数据同步阶段master说明
- 如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行
- 复制缓冲区大小设定不合理,会导致数据溢出。如进行全量赋值周期太长,进行部分复制时发现数据已经存在丢失的情况,必须进行第二次全量赋值,至始slave陷入死循环状态
repl-back-log-size 1mb
- master单机内存占用主机内存的比例不应过大,建议使用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间数据延迟较大,数据一致性变差,应谨慎选择
8.2.3、阶段三:命令传播阶段
当master数据库状态被修改后,导致主从 服务器数据库状态不一致,此时需要让主从数据同步到一致的状态,同步的动作称为命令传播
master将接收到的数据变更命令发送给slave,slave接收命令后执行命令
- 命令传播阶段的部分复制
- 命令传播阶段出现了断网现象
- 网络闪断闪连 忽略
- 短时间网络终端 部分复制
- 长时间网络终端 全量复制
- 部分复制的三个核心要素
- 服务器的运行ID(run id)
- 主服务器的复制积压缓冲区
- 主从服务器的复制偏移量
- 命令传播阶段出现了断网现象
- 服务器运行ID(runid)
- 概念
服务器运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行ID - 组成
运行ID由40位字符组成,是一个随机的十六进制字符
例如:fdc9ff13b9fdc9ff13b9fdc9ff13b9fdc9ff13b9 - 作用
运行ID被用于在服务器间进行传输,识别身份
如果想两次操作均对同一台服务器进行,必须每次操作携带对应的运行ID,用于对方识别 - 实现方式
运行ID在每台服务器启动时自动生成的,master在首次连接slave时,会将自己的运行ID发送给slave,slave保存此ID,通过info server命令,可以查看节点的runid。
- 概念
- 复制缓冲区
- 概念:复制缓冲区,又名复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区
- 复制缓冲区默认数据存储空间大小是1M,由于存储空间大小是固定的,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列
- 由来:每台服务器启动时,如果开启有AOF或被连接称为master节点,即创建复制缓冲区
- 作用:用于保存master收到的所有指令(仅影响数据变更的指令,例如set,select)
- 数据来源:当master接受到主客户端的指令时,除了将指令执行,会将该指令存储到缓冲区中
- 工作原理
- 组成
- 偏移量
- 字节值
- 工作原理
- 通过offset区分不同的slave当前数据传播的差异
- master记录已发送的信息对应的offset
- slave记录已接收的信息对应的offset
- 组成
- 主从服务器复制偏移量(offset)
- 概念:一个数字,描述复制缓冲区中的指令字节位置
- 分类:
- master复制偏移量:记录发送给所有slave的指令字节对应的位置(多个)
- slave复制偏移量:记录slave接收master发送过来的指令字节对应的位置(一个)
- 数据来源:
- master端:发送一次记录一次
- slave端:接受一次记录一次
- 作用:同步信息,对比master与slave的差异,当slave短线后,恢复数据使用
- 心跳机制
- 进入命令传播阶段时候,master与slave间需要进行信息交换,使用心跳机制进行维护,实现双方连接保持在线
- master心跳:
- 指令:PING
- 周期:由repl-ping-slave-period决定,默认10秒
- 作用:判断slave是否在线
- 查询:INFO replication 获取slave最后一次连接时间间隔,lag项维持在0或1视为正常
- slave心跳任务
- 指令:REPLCONF ACK {offset}
- 周期:1秒
- 作用1:汇报slave自己的复制偏移量,获取最新的数据变更指令
- 作用2:判断master是否在线
- 注意事项
- 当slave多数掉线,或延迟过高时,master为保障数据稳定性,将拒绝所有信息同步操作
slave数量少于2个,或者所有slave的延迟都大于等于10秒时,强制关闭master写功能,停止数据同步min-slaves-to-write 2 min-slaves-max-lag 8
- slave数量由slave发送REPLCONF ACK命令做确认
- slave延迟由slave发送REPLCONF ACK命令做确认
- 概念:复制缓冲区,又名复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区
8.3、主从复制工作流程(完整)
8.3、主从复制常见流程
9、哨兵模式
9.1、哨兵简介
哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。
- 作用
- 监控:不断的检查master和slave是否正常运行。master存活检测、master与slave运行情况检测
- 通知(提醒):当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知
- 自动故障转移:断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的服务器地址
-注意:哨兵也是一台redis服务器,只是不提供数据服务,通常哨兵配置数量为单数
9.2、启用哨兵模式
启动哨兵
redis-sentinel sentinel.conf
9.3、哨兵工作原理
-
主从切换
- 哨兵在进行主从切换过程中经历三个阶段
- 监控
- 通知
- 故障转移
- 哨兵在进行主从切换过程中经历三个阶段
-
阶段一:监控阶段
- 用于同步各个节点的状态信息
- 获取master的状态
- master属性
- runid
- role:master
- 各个slave的详细信息
- master属性
- 获取所有slave的状态(根据master中的slave信息)
- slave属性
- runid
- role:slave
- master_host、master_port
- offset
- …
- slave属性
-
阶段二:通知阶段
-
阶段三:故障转移阶段
-
服务器列表中挑选备选master
- 在线的
- 响应慢的
- 与原master断开时间久的
- 优先原则
- 优先级
- offset
- runid
-
发送指令(sentinel)
- 向新的master发送slaveof no one
- 向其他slave发送slaveof 新master IP 端口
-
总结
- 监控
- 同步信息
- 通知
- 保持联通
- 故障转移
- 发现问题
- 竞选负责人
- 优选新master
- 新master上任,其他slave切换master,原master作为slave故障恢复后连接
- 监控
10、集群
11、解决翻案
11.1、缓存预热
11.2、缓存雪崩