redis的八大特性
速度快、持久化、多种数据结构、支持多种编辑语言,功能丰富、简单、主从复制、高可用和分布式
速度快
10万 QPS
内存操作
C语言编写
单线程,一个时刻只能执行一条命令
多路IO复用模型
数据结构
string hash list set zset
BitMaps:位图
HyperLogLog:超小内存唯一值计数
GEO:地理信息定位
功能丰富
发布订阅
Lua脚本
事务
pipeline(可以统一执行查询的命令)
redis典型应用场景
缓存系统、计数器、消息队列系统、排行榜、社交网络
redis常用配置
# daemonize
是否是守护进程(no|yes),默认是no,建议yes
# port
redis对外端口号
# logfile
redis系统日志
# dir
redis工作目录
redis的命令
通用命令
keys:查询所有的key
dbsize:key的数量
exists key 判断key是否存在
del key [key...]
expire key seconds
type key
string
set get del
incr key # key自增1,如果key不存在,自增后get(key) = 1
decr key # key自减1,如果key不存在,自增后get(key) = -1
incrby key k # key自增1,如果key不存在,自增后get(key) = k
decrby key k # key自减1,如果key不存在,自增后get(key) = -k
# 应用场景:计数器
set key value # 不管key是否存在,都设置
setnx key value # key不存在,才设置
set key value xx # key存在,才设置
慢查询
1.默认值
config get slowlog-max-len = 128
config get slowlog-log-slower-than = 1000
2.修改配置文件重启
3.动态配置
config set slow-max-len 1000
config set slowlog-log-slower-than 1000
# 慢查询指令
1.slowlog get [n]:获取慢查询队列
2.slowlog len:获取慢查询队列长度
3.slowlog reset:清空慢查询队列
# 运维校验
1.slowlog-max-len不要设置过大,默认10ms,通常设置1ms
2.slowlog-log-slower-than不要设置过小,通常设置1000左右
3.理解命令生命周期
4.定期持久化慢查询
生命周期
pipline
# 流水线
pipline把n个命令打包起来,传输到服务端(只需要传输一次),服务端按顺序执行命令,然后把结果打包起来依次返回
# 两点注意
1.redis的命令时间是微秒级别的
2.pipline每次条数要控制(网络)
# 使用建议
1.注意每次pipline携带数据量
2.pipline每次只能作用在一个redis节点上
3.M操作与pipline区别
发布订阅
# 发布者(publisher)
# 频道(channel)
# 订阅者(subscriber)
# API
publish
subscribe
unsubscribe
其他
Bitmap
把字符串的每个字母转成二进制了
set name zs
getbit name 0 # 获取索引0上的值,
setbit name 1 1 # 设置索引为1上的值为1,只能设为0或1
# 使用经验
1.type=string,最大512MB
2.注意setbit时的偏移量,可能有较大耗时
3.位图不是绝对好
HyperLogLog
1.基于HyperLogLog算法:极小空间完成独立数量统计
2.本质还是字符串
# 三个命令
1.pfadd key element [element...]:向HyperLogLog添加元素,里面的元素都是唯一的
2.pfcount key [key...]:计算HyperLogLog的独立总数
3.pfmerge destkey sourcekey [sourcekey ...]:合并多个HyperLogLog
# 使用场景,统计总数
# 缺点:有错误率,官方给的是0.81%
GEO
GEO(地理信息定位):存储经纬度,计算两地距离,范围计算等
# 添加城市的经纬度
geoadd key longitude latitude member
# 例如
geoadd cities:locations 116.28 39.22 beijing # 存储北京的经纬度
geoadd cities:locations 117.12 39.08 tianjin
# 取出城市的经纬度
geopos key member [member ...]
geopos cities:locations tianjin
# 获取两个地理位置的距离
geodist key member1 member2 [unit]
# unit:m(米)、km(千米)、mi(英里)、ft(尺)
持久化
RDB
# 触发持久化的,三种机制,手动执行命令
save(同步),会阻塞
bgsave(异步),开启一个子进程去调用fork函数,去执行拷贝,拷贝好之后新文件替换掉老文件
自动
# 通过配置
save 60 1000 # 在60秒内,变了1000次数据,就执行bgsave
AOF
# 持久化的三种策略
always:不丢失数,但IO开销较大,一般的sata盘之后几百TPS
everysec:每秒一次fsync,缺点,丢一秒数据(一般采用这种方式)
no:不用管,缺点,不可控
# AOF重写
比AOF原生好,可以把过期的数据去掉,把多条命令可以合为一条
作用·:减少硬盘占用量,加速恢复速度
# AOF重写实现两种方式
bgrewriteaof
AOF重写配置
RDB和AOF的比较
子进程开销和优化
1.CPU:
开销:RDB和AOF文件生成,属于CPU密集型
优化:不做CPU绑定,不和CPU密集型部署
2.内存:
开销:fork内存开销,copy-on-write
优化:echo never > /sys/kernel/mm/transparent_hugepage/enabled
3.硬盘:
开销:AOF和RDB文件写入,可以结合iostat,iotop分析
硬盘优化
1.不要和高硬盘负载服务部署一起:存储服务,消息队列等
2.no-appendfsync-on-rewrite = yes
3.根据写入量决定磁盘类型:例如ssd
主从复制
主从复制的简单总结
1.一个master可以有多个slave
2.一个slave只能有一个master
3.数据流向是单向的,master到slave
实现主从复制
# 命令实现-主从复制
slaveof 127.0.0.1 6379 # 6379为主
# 命令实现-取消复制
slaveof no one
# 修改配置
slaveof ip port # 绑定的ip是主,本身为从
slave-read-only yes
主:用来写
从:用来读,不能用来写,会报错
故障处理
# slave宕机
这个好说,直接在弄一个从的绑到主上
# master宕机
把从的slave,改为master(slaveof no one),把其他从的在绑定到该主
开发与运维中的问题
读写分离
1.读写分离:读流量分摊到从节点
2.可能遇到问题:
复制数据延迟
读到过期数据
从节点故障
主从配置不一致
1.例如maxmemory不一致:丢失数据
2.例如数据结构优化参数(例如hash-max-ziplist-entries):内存不一致
规避全量复制
1.第一次全量复制
第一次不可避免
小主节点、低峰
2.节点运行ID不匹配
主节点重启(运行ID变化)
故障转移,例如哨兵或集群
3.复制积压缓冲区不足
网络中断,部分复制无法满足
增大复制缓冲区配置rel_backlog_size,网络“增强”
规避复制风暴
1.单主节点复制风暴:
问题:主节点重启,多从节点复制
解决:更换复制拓扑
2.单机器复制风暴
机器宕机后,大量全量复制
主节点分散多机器
Redis Sentienl[哨兵]
在原主从复制基础上
Redis Sentienl故障转移
1.多个sentinel发现并确认master有问题
2.选举出一个sentinel作为领导
3.选出一个slave作为master
4.通知其余slave成为新的master的slave
5.通知客户端主从变化
6.等待老的master复制成为新master的slave
Redis Sentienl的配置
port 26379
daemonize yes
dir "/tmp/redis-4.0.7/data"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
# 启动
redis-sentinel sentinel.conf
客户端连接
# 现在就不是直连redis-server了,而是连接redis-sentienl(这样可以自动实现故障转移,实现高可用)
遍历sentinel节点集合,获取一个可用的sentinel节点,会返回一个master地址,实际连的就是master
客户端接入流程
1.sentinel地址集合:获取一个可用的sentinel节点,会返回一个master地址
2.masterName:校验该master是否是真的master节点
3.不是代理模式,是直接连接的master
内部有三个定时任务
1.每10秒每个sentinel对master和slave执行info
发现slave节点
确认主从关系
2.每2秒每个sentinel通过master节点的channel交换信息(pub/sub)
通过__sentinel__:hello频道交互
交互对节点的“看法”和自身信息
3.每1秒每个sentinel对其他sentinel和redis执行ping
心跳检测,失败判定依据
主观下线和客观下线
sentinel monitor <masterName> <ip> <port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds <masterName> <timeout>
sentinel down-after-milliseconds mymaster 30000
主观下线:每个sentinel节点对Redis节点失败的“偏见”
客观下线:所有sentinel节点对Redis节点失败“达成共识”(超过quorum个统一)
sentinel is-master-down-byaddr
领导者选举
原因:只有一个sentinel节点完成故障转移
选举:通过sentinel is-master-down-by-addr命令都希望成为领导者
1.每个做主观下线的sentinel节点向其他sentinel节点发送命令,要求将它设置为领导者
2.收到命令的sentinel节点如果没有同意通过其他sentinel节点发送的命令,那么将同意该请求,否则拒绝
3.如果该sentinel节点发现自己的票数已经超过sentinel集合半数且超过quorum,那么它将成为领导者
4.如果此过程有多个sentinel节点成为领导者。那么将等待一段时间重新进场选举
故障转移(sentinel领导者节点完成)
1.从slave节点中选出一个“合适的”节点作为新的master节点
2.对上面的slave节点执行slave no one命令让其成功为master节点
3.向剩余的slave节点发送命令,让它们成为新master节点的slave节点,复制规则和parallel-syncs参数有关
4.更新对原来master节点配置为slave,并保持对其“关注”,当其恢复后命令它取复制新的master节点
# 选择“合适的”slave节点
1.选择slave-priority(slave节点优先级)最高的slave节点,如果存在则返回,不存在则继续
2.选择复制偏移量最大的slave节点(复制的最完整),如果存在则返回,不存在则继续
3.选择runID最小的slave节点
总结
1.Redis Sentinel是redis的高可用实现方案:
故障发现、故障自动转移、配置中心、客户端通知
2.Redis Sentinel从Reids2.8版本开始才正式生产可用,之前版本生产不可用
3.尽可能在不用物理机上部署Redis Sentinel所有节点
4.Reids Sentinel中的Sentinel节点个数应该为大于等于3,且最好为奇数
5.Redis Sentinel中的数据节点与普通数据节点没有区别
6.客户端初始化时连接的是Sentinel节点集合,不再是具体的Redis节点,但Sentinel只是配置中心不是代理
7.Redis Sentinel通过三个定时任务实现了Sentinel节点对于主节点、从节点、其余Sentinel节点的监控
8.Redis Sentinel在对节点做失败判定时分为主观下线和客观下线
9.看懂Redis Sentinel故障转移日志对于Redis Sentinel以及问题排查非常有帮助
10.Redis Sentinel实现读写分离高可用可以依赖Sentinel节点的消息通知,获取Redis数据节点的状态变化