知识目录
- 1.Redis开篇
- 2.Redis数据类型
- 3.字符串增删改查
- 4.Hash增删改查
- 5.列表增删改查
- 6.集合增删改查
- 7.有序集合增删改查
- 8.Redis-发布订阅
- 9.Redis-数据持久化
- 10.Node如何操作redis
- 11.Redis主从复制
- 12.Redis-分片集群
1.Redis开篇
1.什么是Redis?
- Remote Dictionary Server(远程字典服务器)
- Redis是一个’开源的’使用’C语言’编写的数据库
- Redis和MongoDB一样是NoSQL类型的数据库
不同的是MongoDB存储的是文档, 而Redis存储的是键值对(Key-Value)
2.Redis特点
- 速度快
- Redis默认情况下将数据存储在内存中
- 读取速度能达到10万次/s左右, 写入能到到8万次/秒左右
- 支持数据的持久化
- Redis默认情况下将数据存储在内存中
- 但是也可以将内存中的数据保存到磁盘中
- 支持多种数据结构
- Redis是通过key-value形式存储数据的
- value不仅支持常见的字符串类型,整型以外
- 同时还提供了list, set ,zset, hash等数据结构的存储
- 定制性强
- Redis虽然强大, 但是它是开源免费的
- Redis第一个版本代码在23000行左右
- Redis当前版本代码在50000行左右
- 支持分布式
- 和MongoDB一样, Redis是支持主从复制, 支持分布式存储的
3.Redis场景应用场景
- 缓存系统
- 由于Redis是将数据存储在内存中的, 所以我们可以使用Redis来实现内存缓存
- 对于经常会被查询,但是不经常被修改或者删除的数据, 存储到Redis中
- 排行榜
- 由于Redis支持集合(Set)和有序集合(Sorted Set)
所以使得我们在实现排行榜的时候变的非常简单
- 计数器
- 由于Redis提供了incr/decr指令, 使得我们在实现计数器时非常简单
- 转发数/评论数/播放数/访问数/… …
- 存储社交关系
- 由于Redis支持存储集合类型数据, 由于社交关系不会经常发生改变
所以很多社交网站会使用Redis来存储社交关系
- 消息队列系统
- Redis天生支持发布订阅模式, 所以天生就是实现消息队列系统的材料
4.Redis下载和安装
https://github.com/MicrosoftArchive/redis/releases
redis.windows.conf: 配置文件,将redis作为普通软件使用的配置,命令行关闭则redis关闭
redis.windows-service.conf:配置文件,将redis作为系统服务的配置,用以区别开两种不同的使用方式
1.配置文件修改
redis.windows-service.conf
- 绑定IP
bind 127.0.0.1 - 绑定端口号
port 6379 - 数据库文件
dbfilename dump.rdb - 数据文件存储路径
dir ./ - 默认数据库
databases 16(默认创建16个数据库,0-15) - 日志文件
logfile “server_log.txt” - 主从复制(类似于双机备份)
slaveof
http://www.runoob.com/redis/redis-conf.html
在cmd中输入:redis-cli -h 127.0.0.1 -p 6379即可进入redis数据库
clear清屏
2.Redis数据类型
3.字符串增删改查
1.默认数据库
默认情况下Redis给我们创建了16个数据库(0~15),
如果使用的时候没有明确的选中使用哪个数据库, 那么默认使用第0个
2.切换数据库
select 1
3.字符串类型-增删改查
redisdoc.com 所有语法文档
- 新增
set key value
set name Andy - 查询
get key
get name - 修改
set key value
如果key已经存在就是修改 - 删除
del key
del name
4.字符串类型-高级操作
set key value (key不存在就新增, 存在就覆盖)
setnx key value (只有key不存在才新增)
set key value xx (只有key存在才更新)
5.字符串类型-批量处理
- 批量添加值
mset key value key value
mset name lnj age 98 score 100 - 批量查询值
mget key key key
mget name age score
6.字符串类型-其它操作
- 设置新值返回旧值
getset key newValue - 给旧值追加数据
append key value - 计算value字符串长度
strlen key
注意点: 中文问题(编码不同长度不同) - 获取指定下标范围的值
getrange key start end - 从指定下标开始设置字符串的值
setrange key offset value
7.字符串类型-自增自减操作
- incr
- 作用: 给指定key的对应的Value自增1, 如果key不存在会自动新增, 并从0开始自增1
- 格式: incr key
- decr
- 作用: 给指定key的对应的Value自减1, 如果key不存在会自动新增, 并从0开始自减1
- 格式: decr key
- incrby
- 作用: 给指定key的对应的Value增加指定值, 如果key不存在会自动新增, 并从0开始增加
- 格式: incrby key number
- decrby
- 作用: 给指定key的对应的Value减少指定的值, 如果key不存在会自动新增, 并从0开始减少
- 格式: decrby key number
- incrbyfloat
- 作用: 给指定key的对应的Value增加指定值, 如果key不存在会自动新增, 并从0开始增加
- 格式: incrbyfloat key float
8.通用命令
- 查询当前数据库中所有的key
keys * - 清空当前数据库(开发操作)
flushdb - 清空所有数据库(离职操作)
flushall
注意点:由于Redis是单线程的, 而以上操作都是非常耗时的, 所以不推荐在企业开发中使用 - 计算当前数据库key的总数
dbsize
注意点: dbsize并不是通过遍历统计得到当前数据库key的总数, 而是每次操作时内部会自动统计,所以dbsize并不是一个耗时的操作, 我们可以在企业开发中大胆的使用 - 查看value数据类型
type key - 判断指定key是否存在
exists key
注意点: 如果存在返回1, 如果不存在返回0 - 设置key过期时间
expire key seconds
注意点: 如果没有添加过期时间就是添加
如果已经添加过了过期时间就是修改 - 查看key过期时间
ttl key - 取消key过期时间
persist key
注意点: 如果key不存在或者已经被删除会返回-2,如果key存在并且过期时间已经被删除会返回-1
4.Hash增删改查
1.Redis-Hash类型-增删改查
Redis的Value除了可以存储普通的字符串类型以外, 还可以存储Hash类型
Hash类型就相当于在JS中的对象, 可以把整个对象当做一个Value存储起来
- 增加
hset key field value
hset user name it666
hset user age 34 - 查询
hget key field
hget user name - 修改
如果字段不存在就是新增, 如果字段存在就是修改
hset key field value
hset user name it666 - 删除
- 删除指定的字段
hdel key field
hdel user name - 删除对应key所有的数据
del key
del user
2.Redis-Hash类型-高级操作
- 批量新增
hmset key field1 value1 field2 value2
hmset user name lnj age 34 score 100 - 批量查询
hmget key field1 field2 field3
hmget user name age score - 工具指令
hlen key 返回key存储的hash表中有多少条数据
hlen user
hexists key field 判断指定的key存储的Hash中是否有指定的字段
hexists user name 返回1表示存在
hexists user gender 返回0表示不存在
3.Redis-Hash类型-其它操作
- 查询所有field
hkeys key
hkeys user - 查询所有value
hvals key
hvals user - 查询所有的field和value
hgetall key
hgetall user
注意点:由于Redis是单线程的, 而以上操作都是非常耗时的, 所以不推荐在企业开发中使用
5.列表增删改查
1.Redis-List类型-增删改查
Redis的Value除了可以存储字符串和Hash类型以外, 还可以存储List类型
List类型就相当于JavaScript中的数组, 可以把整个数组当做一个Value存储起来
注意点: List是有序的
- 增加
- 从第二个Value开始添加到前一个的左边
- lpush key value1 value2 value3
- lpush arr1 aa bb cc -> cc bb aa
- 从第二个Value开始添加到前一个的右边
- rpush key value1 value2 value3
- rpush arr2 aa bb cc -> aa bb cc
- 查询
- 查询指定范围数据
- lrange key startIndex endIndex
- 索引从0开始, endIndex等于-1表示取到最后
- 查询指定索引数据
- lindex key index
- 从前往后索引从0开始, 从后往前索引从-1开始
- 修改
lset key index value
注意 index从0开始 - 删除
- lpop删除左边元素
lpop key - rpop删除右边元素
rpop key - lrem删除指定个数的指定元素(remove)
lrem key count value - count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count
- count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值
- count = 0 : 移除表中所有与 value 相等的值
- ltrim按照索引剪切列表
ltrim key start end(对原有的列表进行剪切)
2.Redis-List类型-其它操作
- 追加数据
lpush key value1,value2,… - 22 11 aa bb
rpush key value1,value2,… - 22 11 aa bb 11 22
- 插入数据
linsert key before|after oldValue newValue - 获取列表长度
llen key
3.列表实现简单数据结构
- 栈结构(水桶) - 先进后出
lpush + lpop - 队列结构(水管) - 先进先出
lpush + rpop - 所以在企业开发中, 如果需要需要’先进后出’或者’先进先出’的数据
我们就可以将这些数据存储到Redis的列表中
6.集合增删改查
1.Redis-Set类型操作-增删改查
集合就是一堆无序的数据, Redis可以把一堆无序的数据当做Value存储起来
注意点: 集合中不能出现重复的数据
- 新增
sadd key value1, [value2, …] - 查询
- 返回集合中所有元素
- smembers key
- 注意点:由于Redis是单线程的, 而以上操作都是非常耗时的, 所以当元素比较多时需要慎用
- 返回集合中N个元素
- srandmember key [count]
- 删除
- 随机删除N个元素
- spop key
- 删除集合中的指定元素
- srem key value1, [value2, …]
修改就是删除加新增
2.Redis-Set类型操作-其它操作
- 追加元素
- sadd: key不存在就新增, 存在就追加
- sadd: 追加的元素不存在就追加, 追加的元素存在会自动忽略
- 统计集合中元素个数
- scard key
- 判断集合中是否有指定元素
- sismember key member
Redis中的集合是支持集合间的操作的, 也就是求交集,并集和差集
- 交集
- sinter key [key, …]
- {1, 2, 3} ∩ {2, 3, 4} = {2, 3}
- 并集
- sunion key [key, …]
- {1, 2, 3} ∪ {2, 3, 4} = {1, 2, 3, 4}
- 差集
- sdiff key [key, …]
- {1, 2, 3} - {2, 3, 4} = {1}
- {2, 3, 4} - {1, 2, 3} = {4}
3.Redis-Set类型操作-应用场景
- 抽奖
- srandmember key [count] 随机取出
- 绑定标签
- sadd key value1, [value2, …]
- 社交关系
- sinter key [key, …] 例如:微博共同关注的好友
- sunion key [key, …]
- sdiff key [key, …]
7.有序集合增删改查
1.什么是ZSet?
ZSet是有序集合, Redis可以把一堆通过权重排序的数据当做一个Value存储起来
2.Redis-ZSet类型操作-增删改查
- 新增
zadd key 权重 value 权重 value - 查询
- 查询指定排名范围内的数据
zrange key start end - 查询指定权重范围内的数据
zrangebyscore key 权重 权重 - 查询指定元素权重
zscore key element - 查询指定权重范围内元素个数
zcount key minscore maxscore - 查询集合中元素个数
zcard key - 删除
- 删除指定元素
zrem key value - 删除指定排名范围元素
zremrangbyrank key start end - 删除指定权重范围元素
zremrangbyscore key minscore maxscore
3.Redis-ZSet类型-其它操作
- 增加或减少元素权重
- zincrby key score element
- 从高到低的操作
- zrevrange
- zrev…
2.Redis-ZSet类型-应用场景
- 存储排行榜数据
8.Redis-发布订阅
1.什么是发布订阅?
在发布订阅中有三个角色: 发布者(publisher)/订阅者(subscriber)/频道(channel)
只要发布者将消息发送到对应的频道中, 那么所有的订阅者都能收到这个消息, 这个就是Redis的发布订阅
现实生活中的发布订阅:
'张三和李四’去’商店’买鞋, 但是最近炒鞋的人比较多, 要买的鞋子已经卖完了
于是商店老板就让张三和李四先加粉丝群, 到货了会在群里通知
这里的商店老板就是发布者
这里的粉丝群就是频道
这里的张三李四就是订阅者
只要张三和李四加了粉丝群, 只要老板在粉丝群里发送消息, 那么张三和李四就能收到老板发送的消息
- 订阅频道
- subscribe channel [channel …]
- 发布消息
- publish channel message
- 退订频道
- unsubscribe [channel [channel …]]
9.Redis-数据持久化
1.Redis数据持久化
- 默认情况下Redis是将数据保存在内存中的, 保存在内存中的数据有一个特点, 那就是机器重启之后数据就会丢失
- 所以为了避免服务器重启死机等问题发生的时候, Redis中保存的数据丢失, Redis提供了数据持久化功能
2.什么是数据持久化
- 数据持久化就是将内存中的数据写入到磁盘中
- Redis和大部分主流数据库(MySQL/MongoDB/…)一样, 支持RDB和AOF持久化
3.RDB(快照)
将内存中所有内容写入到一个文件中
4.触发生成RDB三种机制
- 手动执行save命令
- 同步执行(会阻塞线程)
- 如果已经存在旧的RDB文件, 会利用新的覆盖旧的
- 手动执行bgsave命令
- 异步执行
- 如果已经存在旧的RDB文件, 会利用新的覆盖旧的
- 通过配置文件自动生成
- 通过配置文件指定自动生成条件, 一旦满足条件就会自动执行bgsave生成RDB文件
dir ./ #RDB文件保存的路径
dbfilename dump.rdb #RDB文件的名称
#save 900 1 #自动生成条件
#save 300 10
#save 60 10000
stop-writes-on-bgsave-error yes #bgsave发生错误是否停止写入
rdbcompression yes #是否采用压缩模式写入
rdbchecksum yes #是否对生成的RDB文件进行校验
- 自动生成弊端
- 无法控制生成的频率, 如果频率过高会导致性能消耗较大
- 推荐配置
dir /rdbdiskpath #由于备份是比较占用磁盘空的, 所以推荐使用一个比较大的磁盘路径
dbfilename dump-${prot}.rdb #由于一台服务器上可能部署多个Redis, 所以可以给RDB文件添加端口号作为区分
stop-writes-on-bgsave-error yes #bgsave发生错误是否停止写入
rdbcompression yes #是否采用压缩模式写入
rdbchecksum yes #是否对生成的RDB文件进行校验
5.RDB存在的问题
- 不可控、数据丢失
- 服务器宕机之前的数据, 如果未写入RDB文件就会丢失
示例: set name lnj
save or bgsave or 自动保存
set name zs
set name ls
set name ww
宕机
- 耗时、耗性能
- RDB是一次性把内存中所有的内容写入到磁盘中, 是一个比较重的操作
如果需要写入的数据比较多, 那么就比较耗时 - RDB每次都是把内存中的所有内容全部写入到磁盘中,
哪怕内存中的数据已经写入过了也会再次完整写入,
重复写入相同的数据, 也比较浪费I/O资源 - 如果通过save命令写入, 会阻塞后续命令执行
如果是通过bgsave写入, 不会阻塞后续命令执行,
会开启子进程去专门负责写入, 但是开启子进程会消耗内存空间 - … …
6.AOF(日志)
将每一条操作Redis的指令都写入到文件中
7.触发生成AOF三种机制
- always
- 每条命令都写入一条命令到文件中
- 优点: 不会丢失数据
- 缺点: 磁盘I/O消耗较大
- everysec(默认配置)
- 每隔1秒写入一次, 也就是先收集1秒钟的命令, 然后再一次性写入到文件中
- 优点: 磁盘I/O消耗相对较小
- 缺点: 可能丢失1秒数据
- no
- 让操作系统决定什么时候写入, 操作系统想什么时候写入就什么时候写入
- 不可控, 可能丢失大量数据
8.AOF文件重写
- 随着时间的推移AOF文件会越来越大
- 文件越来越大带来的问题就是-磁盘消耗越来越大
- 文件越来越大带来的问题就是-写入速度会越来越慢
- 文件越来越大带来的问题就是-恢复的时间越来越慢
- … …
- 所以AOF提供了重写的机制
- 我们可以对AOF文件中保存的内容进行优化
- 从而降低文件的体积
- 从而提升文件的恢复速度
- 在AOF的重写机制中
- 可以将自动去除冗余命令
- 可以自动删除没有用的命令
- … …
- 例如:
- 优化前: set name lnj; set name zs; set name ls;
- 优化后: set name ls;
- 优化前: incr count; incr count; incr count; incr count;
- 优化后: set count 4;
- 优化前: expire name 3
- 优化后: 3秒后由于数据已经被删除, 所以这条命令不用保存
- … …
9.触发AOF重写两种机制
- bgrewriteaof命令
- 开启一个新的子进程, 根据内存中的数据生成命令写入到AOF文件中
- 配置文件设置
auto-aof-rewrite-min-size 200mb #AOF文件体积达到多大时进行重写
auto-aof-rewrite-percentage 100 #对比上一次重写后, 增长了百分之多少再次进行重写
例如上一次重写后大小是100MB, 如果设置为50, 那么下一次就是增长0.5倍(150M)之后再重写
例如上一次重写后大小是100MB, 如果设置为100, 那么下一次就是增长两倍(200M)之后再重写 - AOF推荐配置
appendonly yes #是否使用AOF
appendfilename “appendonly-${prot}.aof” #AOF文件名称
appendfsync everysec #写入命令的同步机制
dir /rdbdiskpath #保存AOF文件路径
auto-aof-rewrite-min-size 64mb #AOF文件重写体积
auto-aof-rewrite-percentage 100 #AOF文件增长率
no-appendfsync-on-rewrite yes #AOF重写时是否正常写入当前操作的命令
如果非常追求数据的安全性,那么no-appendfsync-on-rewrite no
如果追求性能,那么no-appendfsync-on-rewrite yes
10.RDB和AOF对比
- AOF优先级高于RDB
- 如果Redis服务器同时开启了RDB和AOF, 那么宕机重启之后会优先从AOF中恢复数据
- RDB体积小于AOF
- 由于RDB在备份的时候会对数据进行压缩, 而AOF是逐条保存命令, 所以RDB体积比AOF小
- RDB恢复速度比AOF恢复速度快
- 由于AOF是通过逐条执行命令的方式恢复数据, 而RDB是通过加载预先保存的数据恢复数据
所以RDB的恢复速度比AOF快
- AOF数据安全性高于RDB
- 由于AOF可以逐条写入命令, 而RDB只能定期备份数据, 所以AOF数据安全性高于RDB
- 所以综上所述, 两者各有所长, 两者不是替代关系而是互补关系
10.Node如何操作redis
首先需要安装一个库
npm install redis
//app.js
//1.引入redis库
const redis = require('redis');
//2.利用redis库连接到redis服务器
const client = redis.createClient('6379','127.0.0.1');//参数为port和host
//3.监听连接成功还是失败
client.on('error',function(error){
console.log(error);
});
//4.通过连接的对象client来操作redis(与操作redis的命令一致)
client.set('name','Andy',redis.print);//redis.print是操作后的提示,如:OK
client.get('name',(err,val)=>{
if(err){
console.log(err);
return;
}
console.log(val);
})
11.Redis主从复制
1.Redis高可用性
- 如果所有用户都从同一台Redis服务器上读写数据
那么如果这台Redis服务器宕机了, 用户就不能进行读写了 - 如果我们有多台Redis服务器, 并且每台服务器中存储的内容都相同
那么即使有一台服务器宕机了, 用户还可以继续使用其它的服务器 - 以上这种特点, 我们就称之为’高可用性’
2.Redis数据安全性
- 如果所有数据都保存在同一台Redis服务器上
那么如果这台Redis服务器坏了, 那么很有可能会导致数据丢失 - 如果我们有多台Redis服务器, 并且每台服务器中存储的内容都相同
那么即使有一台服务器坏了, 也不会导致数据丢失
因为我们还有其它保存了相同内容的服务器 - 以上这种特点, 我们就称之为’数据的安全性’
3.Redis数据分流
- 如果所有用户都从同一台Redis服务器上读写数据
那么由于服务器的性能限制和网络传输速度的限制
如果同一时刻用户量较多时, 服务器负荷增大, 数据处理速度变慢的问题 - 如果我们有多台Redis服务器, 如果我们把请求分流到不同的服务器
那么就可以降低了服务器压力, 加快数据处理速度
并且如果我们将多台服务器安装到不同的区域, 还可以采用就近原则访问
还可以进一步提升用户的访问速度 - 以上这种特点, 我们就称之为’数据分流’
4.Redis主从复制
- 主从复制就是使用多台保存了相同内容的Redis服务器来组成一个数据库集群
这个数据库集群中的每一台Redis服务我们称之为一个节点
5.Redis主从复制特点
- 主从复制中必须有一个主节点
- 主节点主要负责写入数据和读取
- 主从复制中除了主节点以外的节点我们称之为’从节点’
- 副节点默认情况下只能读取数据, 不能写入数据
- 副节点主要负责从主节点不断复制数据
- 和MongoDB不同的是,Redis中的主从复制, 主节点挂掉后不会自动选举
如果需要自动选举需要借助Redis Sentinel来实现
6.主从复制原理
6.1初始化同步(全量复制)
- 给一个从节点添加主节点之后, 从节点会给主节点发送全量复制请求
- 主节点收到全量复制请求, 会执行bgsave生成RDB文件
- 主节点生成完RDB文件, 会将RDB文件发送给从节点
- 主节点在生成和发送RDB过程中, 如果还收到了其它的命令
Redis会存储到缓冲区中 - 当RDB文件发送完毕之后, 会将缓冲区中的缓存的命令发送给从节点
- 从节点收到RDB文件,收到缓冲区命令后, 会先清空自身保存的数据
然后加载RDB文件中的内容, 然后执行收到的其它命令
6.2后续同步
- 主节点每执行一个写命令就会向从节点发送相同的写命令
从节点接收到主节点发送过来的命令, 就执行对应的命令
以实现和主节点同步
7.主从复制存在的问题
- 主从复制有效的解决了Redis’数据安全性’和’数据分流的问题’
但是Redis主从复制并没有解决’高可用性’的问题 - 在标准的主从复制中只有主节点可以读写数据, 从节点只能读取数据
所以一旦主节点宕机了, 那么用户就不能继续写入数据了 - 也就是说在Redis的主从复制中, 主节点宕机了, 系统是不会自动重新选举一个主节点出来的
8.Redis-Sentinel
- Redis-Sentinel是一个用来监控主从结构中每个节点的状态
- 我们可以给Redis-Sentinel添加多个Sentinel节点, 让这些节点来监控主从结构的状态
- 一旦发现主节点挂掉了, 再让这些Sentinel节点帮我们重新从从节点中选举出一个主节点
9.Redis-Sentinel是如何做到高可用的?
- Redis-Sentinel有三个定时任务
- 一个用于获取主从关系,发现新节点
- 一个用于交换信息,投票选出新主服务器
- 一个用于监听节点是否可用
- 每10秒每个sentinel节点对master节点和slave节点执行info操作
- 确定主从关系
- 发现子节点
- 每2秒每个sentinel节点通过master节点的channel(sentinel:hello)交换信息
- 目的就是为故障判断,信息交互提供通道
- 每1秒每个sentintel节点对master节点和slave节点以及其余的sentinel节点执行ping操作
- 心跳检测节点是否发生故障
10.Redis-Sentinel选举规则
- 第一个发现主节点挂掉的Sentinel会发起选举, 这个Sentinel我们称之为候选Sentinel
- 候选Sentinel会给其它Sentinel发送消息, 其它Sentinel默认都会投出同意票
- 只有其它Sentinel已经投过票才会投出反对票
- 当同意的票数过半时, 候选Sentinel就变成了领导者
- 领导Sentinel会依次给所有子节点发送slaveof no one指令, 让所有子节点脱离原来的主节点
- 所有节点脱离关系后
- 领导Sentinel会优先选择优先级高的节点作为主节点(slave-priority配置)
- 如果没有节点设置优先级, 那么会自动选择数据最完整的节点作为主节点
- 如果节点保存的数据都一样, 那么会自动选择进程ID最小的节点作为主节点
- 重新设置完主节点后, 再让剩余节点与这个节点建立关系
11.主观下线和客观下线
主观下线: 一个Sentinel节点认为主节点下线
客观下线: 多个Sentinel节点认为主节点下线
12.Redis-Sentinel搭建
12.1首先搭建一个主从结构
12.2然后搭建一个奇数个Sentinel节点的Sentinel
12.3修改Sentinel配置文件(sentinel.conf)
port 26380 # 当前Sentinel服务运行的端口
sentinel monitor mymaster 127.0.0.1 6380 2 # 主服务器名称 主服务器地址 主服务器端口,客观下线票数
sentinel down-after-milliseconds mymaster 10000 # 主观下线时间
sentinel parallel-syncs mymaster 1 # 故障转移之后,从节点是串行还是并行同步数据
sentinel failover-timeout mymaster 20000 # 故障转移超时时间
daemonize yes #以守护进程方式运行
12.4注册sentinel服务
redis-server.exe --service-install sentinel.conf --sentinel --service-name Sentinel26380
redis-server.exe --service-install sentinel.conf --sentinel --service-name Sentinel26381
redis-server.exe --service-install sentinel.conf --sentinel --service-name Sentinel26382
12.5测试Redis-Sentinel
info replication
13.NodeJS访问Redis-Sentinel
- 使用Redis-Sentinel之后, 由于主节点可能发生变化, 所以我们不能直接操作主节点
只有Redis-Sentinel最清楚当前的主节点是谁, 所以我们应该通过Redis-Sentinel来操作主节点
https://www.npmjs.com/package/redis-sentinel
12.Redis-分片集群
1.已经解决的问题
主从复制+Redis-Sentinel解决了’高可用性’、‘数据安全性’、'数据分流’的问题
但是由于在主从复制中每台服务器保存的都是相同的内容, 所以还没有解决服务器的容量问题
2.如何解决服务器容量问题?
通过Redis Cluster来解决
3.什么是Redis Cluster?
- Redis Cluster可以将数据库中的数据拆分成多份, 分布式的保存到多台电脑上
- 分布式存储就是将一份完整的数据拆分成多份小的数据存储到不同的服务器上
- 既然需要将一份完整的数据拆分成多份小的数据, 那么首先我们需要关注如何拆分
4.分布式存储中常见的分片规则
4.1顺序分片
|--------------|
| 1~100 |
|--------------|
|--------------| |--------------| |--------------|
| 1 ~ 33 | | 34~66 | | 67~100 |
|--------------| |--------------| |--------------|
特点:
1.支持顺序访问
2.键值和业务相关
3.可能会出现数据倾斜
4.2哈希分片 redis采用的就是hash分片
|--------------|
| 1 ~ 100 |
|--------------|
hash(key)%3
|--------------| |--------------| |--------------|
| 3,6,9…99 | | 1,4,7…100 | | 2,5,8…98 |
|--------------| |--------------| |--------------|
特点:
1.数据分散度高,不容易出现数据倾斜
2.支持批量操作
3.不支持顺序访问
4.键值和业务无关(真正存储的是hash值)
5.三种常见的哈希分片
- 节点取余
- 一致性哈希
- 虚拟槽哈希
5.1.节点取余
- hash(key)%N
|--------------|
| 1~100 |
|--------------|
hash(key)%3
|--------------| |--------------| |--------------|
| 3,6,9…99 | | 1,4,7…100 | | 2,5,8…98 |
|--------------| |--------------| |--------------|
|--------------|
| 1~100 |
|--------------|
hash(key)%4
|--------------| |--------------| |--------------| |--------------|
| 4,8,…100 | | 1,5…97 | | 2,6…98 | | 3,7…99 |
|--------------| |--------------| |--------------| |--------------|
- 节点取余存在的问题
数据迁移量较大
例如: 1~10, 3个节点
第0个节点: 3, 6, 9
第1个节点: 1, 4, 7, 10
第2个节点: 2, 5, 8
增加一台服务器后:
第0个节点: 4, 8
第1个节点: 1, 5, 9
第2个节点: 2, 6, 10
第3个节点: 3, 7
- 节点取余推荐扩容方式:翻倍扩容
例如: 1~10, 3个节点
第0个节点: 3, 6, 9
第1个节点: 1, 4, 7, 10
第2个节点: 2, 5, 8
增加一倍:
第0个节点: 6
第1个节点: 1 7
第2个节点: 2 8
第3个节点: 3 9
第4个节点: 4 10
第5个节点: 5
5.2一致性哈希
- 一致性Hash算法将整个哈希值的空间组织成一个0~2(32)次方的虚拟的圆环
- 然后再求出分片服务器的Hash值, 根据分片服务器的Hash值将服务器配置到虚拟的圆环对应的位置
- 然后再求出需要保存数据键的Hash值, 根据求出的值在虚拟的圆环顺时针方向上存入对应的分片服务器中
- 如果保存数据键的Hash值超过2(32)次方,就会保存到第一台分片服务器上
如何扩容
推荐的方式是:翻倍扩容,这样有利于负载均衡
5.3虚拟槽哈希(redis采用的是这种方式)
- Redis Cluster采用的是’虚拟槽哈希’的方式来分片
- 在Redis Cluster中一共有0~16383个虚拟槽, 我们可以把这些槽分配给对应的分片服务器
- 在存储数据的时候通过 slot = CRC16(key) & 16383 计算出对应数据键的槽值,
然后将该值保存到对应槽的分片服务器上
如何扩容
将原本已经分配好的槽分一些给新的redis服务器,而且将以前槽所保存的数据一并分配给新的服务器,可以均分,这样就可以达到负载均衡啦!
6.Redis Cluster完整结构
- 在Redis Cluster必须至少有6台服务器(可多不可少)
- 在Redis Cluster每一台分片服务器都必须是一个主从结构
- 在Redis Cluster中每一台主分片服务器都是可读可写的
- 由于每个分片都是主从复制结构, 所以就保证了数据的’安全性’和’可分流性’
- 但是Redis Cluster的’高可用性’并不依赖于Redis Sentinel,
在Redis Cluster中它自己实现了Redis Sentinel高可用相关功能 - 由于每一台主分片服务器都是可读可写的,
所以为了保证数据能够正确的写入到对应槽值的服务器中
为了保证能够正确的从对应的服务器中取出对应槽的数据
所有主分片服务器之间都是互通的(也就是知道其它分片服务器的存储,和保存槽的范围) - 在设置或获取数据时
- 如果当前访问的分片服务器中保存了对应的数据, 就直接返回对应的数据
- 如果当前访问的分片服务器中没有保存对应的数据, 由于分片服务器之间是相互通讯了
那么就会返回保存对应数据的那台分片服务器的地址给用户,
用户可以根据返回的地址到对应的分片服务器上获取对应的数据