1、NoSQL简介
- NoSQL:Not Only SQL
Key Value / Tuple Store:DynamoDB, redis
Wide Column Store / Column Families:列式数据库, hbase
Document Store:文档数据库,mongodb,Elastic
Graph Databases:图式数据库,Neo4j
Multimodel Databases:
Object Databases:
Time Series / Streaming Databases:时间序列存储
mysql是关系型数据库,是属于SQL而不是NoSQL - ACID:原子性、一致性、隔离性、持久性,事物性存储必须满足ACID
- 特性:数据量大、数据变化非常快(数据增长快、流量分布变化大、数据间耦合结构变化快)、数据源很多
- CAP、BASE
CAP:
Consistency、Availablity、Partition tolerence分区容错性
C:多个数据节点上的数据一致;
A:用户发出请求后的有限时间范围内返回结果;
P:network partition,网络发生分区后,服务是否依然可用;
CAP理论:一个分布式系统不可能同时满足C、A、P三个特性,最多可同时满足其中两者;对于分布式系统满足分区容错性几乎是必须的。
AP:
C:弱一致性;
CP:
BASE:BA,S,E,基于CAP演化而来
BA:Basically Available,基本可用;
S:Soft state,软状态/柔性事务,即状态可以在一个时间窗口内是不同步的;
E:Eventually consistency,最终一致性;
2、Redis介绍
- REmote DIctionary Server:远程字典服务器或数据结构服务器,k/v,数据结构;
内存存储:in-memroy,键和值都在内存中存储
持久化:为了保证数据的持久化,redis会将内存中的数据以快照或AOF的方式存储到磁盘上
主从(sentinel)
Cluster(shard) - 程序环境:
安装:yum install redis 在epel源里
配置文件:/etc/redis.conf
主程序:/usr/bin/redis-server
端口:6379/tcp
客户端:/usr/bin/redis-cli
Unit File:/usr/lib/systemd/system/redis.service
数据目录:/var/lib/redis - redis:k/v
key:直接ASCII字符串;
value:strings(字符串), lists(数组), hashes(含有子健和值), sets(集合), sorted sets(有序集合), bitmaps(位图), hyperloglogs,geo(基于位置经纬度做搜索) - 客户端redis-cli命令:
Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
-h HOST
-p PORT
-a PASSWORD
-n DBID ---redis也有数据库,用数字表示,默认有0-15号数据库,共16个,可以在配置文件中修改数据库的数量 - 与Connection相关命令:
help @connection
AUTH---输入密码进行认证
ECHO
PING ---ping服务器是否存活,如果是好的会回应pang
QUIT ---客户端退出连接
SELECT dbid ---切换数据库 - 清空数据库:
FLUSHDB:清空当前数据库;
FLUSHALL:清空所有数据库;
3、Redis数据结构举例
1、安装、启动、客户端连接和切库
[root@centos7 .ssh]#redis-cli -h 172.18.21.107 -p 6379 ---可以连接到本机的某个地址和端口
172.18.21.107:6379> quit
[root@centos7 .ssh]#redis-cli ---不加默认连接到本机的127.0.0.1地址的6379端口
127.0.0.1:6379> select 0 ---默认连接后进入的是0号数据库
OK
127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]> select 1 ---可以进行切库
OK
2、字符串string数据结构
127.0.0.1:6379[1]> help @string ---可以查看帮助
127.0.0.1:6379[1]> set mykey 'hello redis' ---增加一个键和值
OK
127.0.0.1:6379[1]> get mykey ---获取键和值
"hello redis"
127.0.0.1:6379[1]> append mykey ' ,how old are you' ---在存在的键的后面追加值
(integer) 28
127.0.0.1:6379[1]> get mykey
"hello redis ,how old are you"
127.0.0.1:6379[1]> strlen mykey ---查看面mykey键的值的长度
(integer) 28
127.0.0.1:6379[1]> set mykey 'hi redis' EX 100 ---修改键的值,并设定过期时间为100s
OK
127.0.0.1:6379[1]> get mykey
"hi redis"
127.0.0.1:6379[1]> set mykey 'hello' NX ---如果mykey 这个键不存在才创建,存在就不创建出现nil
(nil)
127.0.0.1:6379[1]> set mykey 'hello' XX ---如果存在这个键才修改
OK
127.0.0.1:6379[1]> get mykey
"hello"
127.0.0.1:6379[1]> set mykeytwo value EX 100 XX ---XX表示如果存在才创建,不存在就不创建
(nil)
127.0.0.1:6379[1]> set count 0 ---创建一个键值为整数
OK
127.0.0.1:6379[1]> incr count ---自增
(integer) 1
127.0.0.1:6379[1]> incrby count 2
(integer) 3
127.0.0.1:6379[1]> incrby count 2 ---以多少进行自增
(integer) 5
127.0.0.1:6379[1]> decr count
(integer) 4
127.0.0.1:6379[1]> decrby count 2 ---以多少进行自减
(integer) 2
127.0.0.1:6379[1]> del count ---删除键
(integer) 1
127.0.0.1:6379[1]> get count
(nil)
3、数组list数据结构
127.0.0.1:6379[1]> help @list
127.0.0.1:6379[1]> lpush weekdays sat ---在weekdays数组中增加一个元素为sat,并且是左侧入站,rpush表示右侧入站,也就是在数组中加入元素的时候是从左侧加还是从右侧加入的
(integer) 1
127.0.0.1:6379[1]> lpush weekdays fri
(integer) 2
127.0.0.1:6379[1]> lpush weekdays thu ---数组的名字是键,数组中的元素是值
(integer) 3
127.0.0.1:6379[1]> lindex weekdays 0 ---查看数组的索引为0的元素
"thu"
127.0.0.1:6379[1]> lindex weekdays 1
"fri"
127.0.0.1:6379[1]> lindex weekdays 3
(nil)
127.0.0.1:6379[1]> lindex weekdays 2
"sat"
127.0.0.1:6379[1]> lpush weekdays tue
(integer) 4
127.0.0.1:6379[1]> linsert weekdays after tue wed ---在tue元素之后插入wed元素
(integer) 5
127.0.0.1:6379[1]> lrange weekdays 0 4 ---查看数组的索引下标为0-4的元素
1) "tue"
2) "wed"
3) "thu"
4) "fri"
5) "sat"
127.0.0.1:6379[1]> rpop weekdays ---从右侧出站
"sat"
127.0.0.1:6379[1]> lrange weekdays 0 4 ---查看一下上面的元素已经没有了
1) "tue"
2) "wed"
3) "thu"
4) "fri"
127.0.0.1:6379[1]> lrem weekdays 2 wed ---从中间删除某个元素
(integer) 1
127.0.0.1:6379[1]> lrange weekdays 0 4
1) "tue"
2) "thu"
3) "fri"
127.0.0.1:6379[1]> llen weekdays ---查看数组中元素的个数
(integer) 3
127.0.0.1:6379[1]> lpush weekdays sun
(integer) 4
127.0.0.1:6379[1]> lrange weekdays 0 4
1) "sun"
2) "tue"
3) "thu"
4) "fri"
127.0.0.1:6379[1]> lindex weekdays 0
"sun"
127.0.0.1:6379[1]> lindex weekdays 1
"tue"
127.0.0.1:6379[1]> lindex weekdays 2
"thu"
127.0.0.1:6379[1]> lindex weekdays 3
"fri"
127.0.0.1:6379[1]> lindex weekdays 4
(nil)
3、hash数据结构
127.0.0.1:6379[1]> help @hash
127.0.0.1:6379[1]> HMSET member name jerry age 17 gender female ---member为键,name、age、gender为它的子健,jerry、17、female为子健的值
OK
127.0.0.1:6379[1]> hkeys member ---查看所有的子健
1) "name"
2) "age"
3) "gender"
127.0.0.1:6379[1]> HVALS member ---查看所有子健的值
1) "jerry"
2) "17"
3) "female"
127.0.0.1:6379[1]> HSTRLEN member name ---查看name子健的值的长度
(integer) 5
127.0.0.1:6379[1]> HSTRLEN member age
(integer) 2
127.0.0.1:6379[1]> HGETALL member ---查看所有子健和值
1) "name"
2) "jerry"
3) "age"
4) "17"
5) "gender"
6) "female"
127.0.0.1:6379[1]> HDEL member gender ---删除某个子健
(integer) 1
127.0.0.1:6379[1]> HGETALL member
1) "name"
2) "jerry"
3) "age"
4) "17"
4、集合set数据结构
127.0.0.1:6379[1]> help @set
127.0.0.1:6379[1]> SADD animals elephant wolf tiger monkey fox dog cat ---添加一个集合
(integer) 7
127.0.0.1:6379[1]> SADD jiaqin pig dog chiken duck fish
(integer) 5
127.0.0.1:6379[1]> SMEMBERS animals ---查看集合中的成员
1) "monkey"
2) "tiger"
3) "cat"
4) "elephant"
5) "fox"
6) "dog"
7) "wolf"
127.0.0.1:6379[1]> SMEMBERS jiaqin
1) "pig"
2) "chiken"
3) "duck"
4) "dog"
5) "fish"
127.0.0.1:6379[1]> SCARD animals ---查看集合中成员的数量
(integer) 7
127.0.0.1:6379[1]> SPOP animals ---随机的扇出一个成员
"monkey"
127.0.0.1:6379[1]> SREM jiaqin fish ---删除某个集合中的指定成员
(integer) 1
127.0.0.1:6379[1]> SINTER animals jiaqin ---求交集
1) "dog"
127.0.0.1:6379[1]> SDIFF animals jiaqin ---求差集,表示animals中有而jiaqin中没有的成员
1) "wolf"
2) "cat"
3) "fox"
4) "elephant"
5) "tiger"
127.0.0.1:6379[1]> SDIFF jiaqin animals ---和上面的正好相反
1) "pig"
2) "chiken"
3) "duck"
127.0.0.1:6379[1]> SUNION animals jiaqin ---求并集
1) "cat"
2) "chiken"
3) "elephant"
4) "fox"
5) "duck"
6) "dog"
7) "wolf"
8) "tiger"
9) "pig"
5、有序集合sorted_set数据结构
127.0.0.1:6379[1]> help @sorted_set
127.0.0.1:6379[1]> ZADD name 1 tom 3 jerry 9 obama 7 trump 4 bush ---添加键和值,name是键,后面名字是值,数字是给值打的分数,根据这个分数才能进行排序,变成有序集合
(integer) 5
127.0.0.1:6379[1]> ZSCORE name trump ---查找trump的分数
"7"
127.0.0.1:6379[1]> ZRANK name trump ---查找trump的索引,索引是按照分数从低到高进行排序的,从0开始
(integer) 3
127.0.0.1:6379[1]> ZRANK name tom
(integer) 0
127.0.0.1:6379[1]> ZRANK name jerry
(integer) 1
127.0.0.1:6379[1]> ZRANK name obama
(integer) 4
127.0.0.1:6379[1]> ZRANGE name 1 3 根据索引进行查找
1) "jerry"
2) "bush"
3) "trump"
127.0.0.1:6379[1]> ZRANGEBYSCORE name 3 10 ---根据分数进行查找
1) "jerry"
2) "bush"
3) "trump"
4) "obama"
6、发布订阅队列pubsub数据结构
127.0.0.1:6379[1]> help @pubsub
127.0.0.1:6379[1]> PUBLISH ops 'rhel 8.0 is coming'
(integer) 0 ---发布一个频道为ops,内容为rhel 8.0 is coming
复制打开另外一个终端
[root@centos7 app]#redis-cli
127.0.0.1:6379> SUBSCRIBE ops ---在另外一个终端订阅这个频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "ops"
3) (integer) 1
在第一终端的ops频道再发布一个消息
127.0.0.1:6379[1]> PUBLISH ops 'good morning'
(integer) 1
在另外一个终端可以看到这个消息,因为这个终端订阅了这个频道,所有订阅了这个频道的终端都可以看到这个消息
1) "message"
2) "ops"
3) "good morning"
4、配置和使用redis
vim /etc/redis.conf
- 通用配置项:
daemonize:设置为no,如果设置为yes以守护进程的方式运行就不受systemd的控制了,设置成no时以systmectl启动时会以守护进程的方式运行
supervised:一般设置为no,意思是受不受upstart(centos6)和systemd(centos7)的监督,这一项设置成yes和no都可以,因为即使受他们的监督,redis运行出问题了也不会将结果反馈给他们
loglevel, pidfile, logfile,
databases:设定数据库数量,默认为16个,每个数据库的名字均为整数,从0开始编号,默认操作的数据库为0;
切换数据库的方法:
SELECT
- 网络配置项:
bind IP ---bind 0.0.0.0表示监听在本机的所有ip
port PORT
protected-mode ---表示启动保护模式,当bind后面没有写ip地址并且配置文件中没有设置连接到redis主机的密码时会启动保护模式,用户连接的时候将会失败
tcp-backlog ---tcp的后援队列长度
unixsocket
timeout:在客户端空闲几秒钟后关闭连接
- 安全配置:
requirepass ---设置连接到redis服务器的密码
[root@centos7 .ssh]#systemctl restart redis
[root@centos7 .ssh]#redis-cli
127.0.0.1:6379> KEYS * ---连入后如果不输入密码是看不到数据库的
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH centos ---输入密码后可以看到了
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> KEYS *
1) "member"
2) "mykey"
3) "name"
4) "jiaqin"
5) "weekdays"
6) "animals"
[root@centos7 .ssh]#redis-cli -a centos ---也可以连接的时候直接指明密码
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> KEYS *
1) "member"
2) "mykey"
3) "name"
4) "jiaqin"
5) "weekdays"
6) "animals"
rename-command ---
对config命令进行重命名,客户端连接到redis后,使用config命令
可以改变redis在运行时的服务特性,这个命令比较危险,最好别
人不知道这个命令叫什么,但在AOF或Replication环境中,为了
管理方便,使从服务器也知道这个命令的名字,不建议重命名
- Limits相关的配置:
maxclients:最大并发连接数,默认是1000
maxmemory :最大内存,单位是字节
maxmemory-policy noeviction:定义淘汰策略,默认是noeviction表示不淘汰,当内存空间被占满时,不允许写数据,会返回错误信息
一般volatile-ttl策略比较好,表示当内存空间要满了时,会淘汰马上要到期的键
淘汰策略:volatile-lru, allkeys-lru, volatile-random, allkeys-random, volatile-ttl, noeviction
maxmemory-samples 5:淘汰算法运行时的采样样本数,样本数越多越精确,但出于性能考虑设置成5就可以了
- SlowLog相关的配置:
slowlog-log-slower-than 10000 单位是微秒;查询时间超过10毫秒的就认为是慢查询,就记录到慢查询日志中
slowlog-max-len 128:设置慢查询日志最多记录多少条记录;
- ADVANCED配置:
hash-max-ziplist-entries 512:一个hash内部最多能容纳多少个子健
hash-max-ziplist-value 64:每个子健的值最大不能超过多少个字节
list-max-ziplist-size -2:每个子健的值允许占的最大空间;
client-output-buffer-limit normal 0 0 0 正常客户端
client-output-buffer-limit slave 256mb 64mb 60 从服务器的客户端
client-output-buffer-limit pubsub 32mb 8mb 60 连接到队列服务器的客户端
redis的数据先存到内存缓冲区,客户端连接时通过内存缓冲不区
输出给客户端,以上三项是用来定义发送给客户端的缓冲区的大
小, 比如:256mb 64mb 60分别表示硬限制、软限制和软限制
的宽限期
- 配置参数可运行时修改
127.0.0.1:6379> INFO ----服务器状态信息查看,分为多个段
127.0.0.1:6379> INFO memory
127.0.0.1:6379> INFO replication ---只查看某个段
127.0.0.1:6379> INFO stats
127.0.0.1:6379> CONFIG RESETSTAT ----重新计数
127.0.0.1:6379> CONFIG GET requirepass ---可以查看密码
1) "requirepass"
2) "centos"
127.0.0.1:6379> CONFIG GET maxclients
1) "maxclients"
2) "10000"
127.0.0.1:6379> CONFIG SET maxclients 10200 ---修改最大并发连接
OK
127.0.0.1:6379> CONFIG GET maxclients
1) "maxclients"
2) "10200"
127.0.0.1:6379> CONFIG REWRITE ---写到配置文件里
OK
vim /etc/redis.conf
maxclients 10200 ---发现配置文件里已经修改,运用config set
可以修改运行时的参数并写到配置文件里,所以说config这个命令
很危险,不能让别人知道。
- 查看客户端的连接
127.0.0.1:6379> CLIENT list ---查看有几个客户端连接到本机
id=3 addr=127.0.0.1:45178 fd=5 name= age=613 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
id=4 addr=127.0.0.1:45180 fd=6 name= age=3 idle=3 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=command
127.0.0.1:6379> CLIENT SETNAME n1 ---给客户端命名
OK
127.0.0.1:6379> CLIENT list
id=3 addr=127.0.0.1:45178 fd=5 name=n1 age=628 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
id=4 addr=127.0.0.1:45180 fd=6 name= age=18 idle=18 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=command
127.0.0.1:6379[1]> CLIENT KILL id 4 ---杀死某个客户端
(integer) 1
127.0.0.1:6379[1]> CLIENT list ---发现id为4的客户端没有了
id=3 addr=127.0.0.1:45178 fd=5 name=n1 age=725 idle=0 flags=N db=1 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
5、redis的持久化
- RDB:snapshotting, 二进制格式;按事先定制的策略,周期性地将数据从内存同步至磁盘;数据文件默认为dump.rdb;
客户端显式使用SAVE或BGSAVE命令来手动启动快照保存机制;
SAVE:同步,即在主线程中保存快照,此时会阻塞所有客户端请求;不会丢失数据
BGSAVE:异步;backgroud,启动一个子进程去保存快照并在后台运行,不会阻塞客户端的请求,但有可能丢失数据,因为同步的时候客户端可能正在写数据
[root@centos7 ~]#cd /var/lib/redis/
[root@centos7 redis]#ls
dump.rdb
- AOF:Append Only File, fsync(aof文件重写)
记录每次写操作至指定的文件尾部实现的持久化;当redis重启时,可通过重新执行文件中的命令在内存中重建出数据库;相当于mysql的二进制日志,可以进行时间点还原
BGREWRITEAOF:AOF文件重写;
不会读取正在使用AOF文件,而是通过将内存中的数据以命令的方式保存至临时文件中,完成之后替换原来的AOF文件; - RDB相关的配置:
*save
save 900 1
save 300 10
save 60 10000
表示:三个策略满足其中任意一个均会触发SNAPSHOTTING操作;900s内至少有一个key有变化,300s内至少有10个key有变化,60s内至少有1W个key发生变化;
stop-writes-on-bgsave-error yes
持久功能,也就是保存到磁盘操作出现错误时,是否禁止新的写入操作请求;
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb:指定rdb文件名
dir /var/lib/redis:rdb文件的存储路径
- AOF相关的配置
appendonly no ---如果改成yes表示启用AOF持久化功能,RDB和AOF持久化功能可以同时启用是没有问题的
[root@centos7 redis]#ls /var/lib/redis/ ---启用之后会发现数据目录有两个文件了
appendonly.aof dump.rdb
appendfilename "appendonly.aof"
appendfsync :AOF重写有以下三种模式
no:redis不执行主动同步操作,而是由操作系统自行决定;
everysec:每秒一次; 默认
always:每语句一次;
no-appendfsync-on-rewrite no:是否在执行aof重写期间开启一个后端的子进程,默认为no,表示启用;但如果重写的模式为no,则不建议开启,因为不知道什么时候会重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
上述两个条件同时满足时,方会触发重写AOF;与上次aof文件大小相比,其增长量超过100%,且大小不少于64MB;
aof-load-truncated yes :AOF开启时要不要重新清理一下aof文件
注意:持久机制本身不能取代备份;应该制订备份策略,对redis库定期备份;
RDB与AOF同时启用:
(1) BGSAVE和BGREWRITEAOF不会同时进行;
(2) Redis服务器启动时用持久化的数据文件恢复数据,会优先使用AOF;
6、redis的主从复制
特点:一个Master可以有多个slave主机,支持链式复制;
Master以非阻塞方式同步数据至slave主机;
配置slave节点:
redis-cli> SLAVEOF
redis-cli> CONFIG SET masterauth
配置参数:
slaveof :指明主节点redis监听的ip地址和端口号,只在从上设置
masterauth:指明主节点的密码,只在从节点的设置
slave-serve-stale-data yes:是否可以用过期的数据响应客户端的请求
slave-read-only yes:从节点只允许读操作
repl-diskless-sync no :要不要启用无磁盘的复制,新的从节点或某较长时间未能与主节点进行同步的从节点重新与主节点通信,需要做“full synchronization",此时其同步方式有两种style:
Disk-backend:主节点新创建快照文件于磁盘中,而后将其发送给从节点;
Diskless:主节点新创建快照后直接通过网络套接字文件发送给从节点;为了实现并行复制,通常需要在复制启动前延迟一个时间段;
repl-diskless-sync-delay 5 :发送快照时是否延迟发送
repl-ping-slave-period 10 主节点多长时间探测一下从节点是否存活
repl-timeout 60:主从复制的超时时长
repl-disable-tcp-nodelay no :发送tcp响应时是否延迟
repl-backlog-size 1mb从服务器后援队列的大小
slave-priority 100:复制集群中,主节点故障时,sentinel应用场景中的主节点选举时使用的优先级;数字越小优先级越高,但0表示不参与选举;
min-slaves-to-write 3:主节点仅允许其能够通信的从节点数量大于等于此处的值时接受写操作;
min-slaves-max-lag 10:从节点延迟时长超出此处指定的时长时,主节点会拒绝写入操作;
示例
1、同步所有节点的时间
2、在node2上的设置
vim /etc/redis.conf
bind 0.0.0.0
requirepass centos ---设置客户端连接本节点的密码
slaveof 172.18.21.107 6379 ---指明主的地址和端口
masterauth centos ---指明主的密码
systemctl start redis
redis-cli -a centos
127.0.0.1:6379[1]> INFO replication ---查看一下主从复制的相关信息,发现角色是从
测试
在主节点node1上创建一个键和值
127.0.0.1:6379[1]> set mykey 'hello redis'
在从节点node2上
127.0.0.1:6379[1]> get mykey ---可以看到,说明主从复制成功
"hello redis"
3、在node3上采用config命令在运行时创建主从复制
vim /etc/redis.conf
bind 0.0.0.0
requirepass centos
systemctl start redis
ss -nlt
[root@node3 ~]#redis-cli -a centos ---连接到此服务器
127.0.0.1:6379> CONFIG GET slaveof
1) "slaveof"
2) ""
127.0.0.1:6379> slaveof 172.18.21.107 6379 ---指明主节点的ip和端口
OK
127.0.0.1:6379> CONFIG GET slaveof
1) "slaveof"
2) "172.18.21.107 6379"
127.0.0.1:6379> CONFIG set masterauth centos ---指明主节点的密码
OK
127.0.0.1:6379> CONFIG GET masterauth
1) "masterauth"
2) "centos"
127.0.0.1:6379> CONFIG REWRITE ---写到配置文件里
OK
[root@node3 ~]#tail -n 3 /etc/redis.conf ---发现已经追加到配置文件的最后
# Generated by CONFIG REWRITE
slaveof 172.18.21.107 6379
masterauth "centos"
127.0.0.1:6379> INFO replication
# Replication
role:slave ---角色已经变成从
master_host:172.18.21.107
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:1704
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> KEYS * ---可以看到前面创建的键
1) "mykey"
127.0.0.1:6379[1]> get mykey
"hello slave 2"
7、redis的故障转移
redis的故障转移通过sentinel完成:主要完成三个功能:监控、通知、自动故障转移,主节点荡机了,会自动提升一个从节点为新的主节点
选举机制:流言协议、投票协议
流言协议:不能主观的判断某一个节点不可用,而是问其他节点能不能找到主节点,如果其他的也找不到主几点才证明主节点真的荡机了
投票协议:with quorum > total/2,without quorum <=total/2,quorum表示sentinel集群的quorum机制,比如有三个sentinel节点,至少有2个节点同时判定主节点故障时,才认为其真的故障,才会进行故障转移
配置参数
sentinel monitor :监控的主节点的名字、ip地址、端口、法定人数
sentinel auth-pass :监控的主节点的名字和密码
表示sentinel集群的quorum机制,即至少有quorum个sentinel节点同时判定主节点故障时,才认为其真的故障;
s_down: subjectively down ---主观判断其故障
o_down: objectively down ----客观判断其故障
sentinel down-after-milliseconds :监控到指定的集群的主节点异常状态持续多久方才将标记为“故障”;单位是毫秒
sentinel parallel-syncs :指在failover故障转移过程中,能够被sentinel并行配置的从节点的数量;
sentinel failover-timeout :sentinel必须在此指定的时长内完成故障转移操作,否则,将视为故障转移操作失败;
sentinel notification-script :通知脚本,此脚本被自动传递多个参数;
示例:本实验是在6主从复制的基础上完成的
1、在node1节点上的设置
vim /etc/redis-sentinel.conf
bind 0.0.0.0 ---注意一定要加上监听的ip地址,不然会启动保护模式,此行配置文件中没有,需要后加上
sentinel monitor mymaster 172.18.21.107 6379 2 ---只监控主节点就可以,给主节点起个名字叫mymaster
sentinel auth-pass mymaster centos ---监控的主节点的名字和密码
sentinel down-after-milliseconds mymaster 5000 ---主节点故障5秒后标记为故障状态
sentinel parallel-syncs mymaster 3 ---故障转移过程中能够被sentinel并行配置的从节点的数量是3
sentinel failover-timeout mymaster 60000 ---故障转移时间超过1分钟认为失败
将此配置拷贝到node2和node3节点上
scp /etc/redis-sentinel.conf node2:/etc/
scp /etc/redis-sentinel.conf node3:/etc/
2、在三个节点上都启动redis-sentinel
systemctl start redis-sentinel.service
ss -nlt ---发现26379端口已经打开
3、在node1上连接到redis-sentinel
redis-cli -h 172.18.21.107 -p 26379
172.18.21.107:26379> sentinel masters ---查看主节点的信息
172.18.21.107:26379> sentinel slaves mymaster -=--查看从节点的信息,查看从节点时要指明查看哪个主节点的从节点,后面要加上mymaster,指明主节点的名字
4、测试
停止node1节点的redis服务
systemctl stop redis
redis-cli -h 172.18.21.107 -p 26379
172.18.21.107:26379> sentinel masters ---查看主节点发现主节
点变成了node3,这里因为没有设置优先级,所以会根据ip地址自
动提升一个从为主节点,可以通过修改配置文件中slave-priority
100来设置优先级,数字越小优先级越高
172.18.21.107:26379> sentinel slaves mymaster ---从节点变成node1和node2,并且node1的状态为 "s_down,slave,disconnected"主观故障
5、恢复node1节点,使其成为正常工作的从节点
在node1上的操作
vim /etc/redis.conf
slaveof 172.18.21.7 6379
masterauth centos
repl-diskless-sync no ---将此项改为no,如果前面当主的时候改成了Diskless或者Disk-backend
systemctl start redis
6、测试
redis-cli -h 172.18.21.107 -p 26379
172.18.21.107:26379> sentinel masters
172.18.21.107:26379> sentinel slaves mymaste ---查看到node1为slave,而不是"s_down,slave,disconnected"
备注:
SENTINEL failover ---手动触发故障转移 failover故障转移
SENTINEL get-master-addr-by-name
172.18.21.107:26379> SENTINEL get-master-addr-by-name mymaster ---可以获得主的地址和端口
1) "172.18.21.7"
2) "6379"
8、redis集群
redis集群会在所有redis节点上分配很多个槽,一共16384个槽,范围是0-16383,每个节点上分配一定数量的槽,当客户端创建 一个键和值时,会对键进行哈希计算,将计算的结果对16384取模,也会生成0-16383之间的数字,这个数字和哪个节点上的哪个槽位对上,此键就必须创建在这个节点上,因此需要客户端的人工智能,也就是客户端在创建一个键时如果和某个节点的某个槽位对上,就必须在这个节点上创建这个键,redis集群是将数据分别存储在不同的redis节点的槽位上,每个节点的数据只是一部分。
集群相关的配置:
cluster-enabled 是否开启集群配置
cluster-config-file 集群节点集群信息配置文件,每个节点都有一个,由redis生成和更新
cluster-node-timeout 集群节点互连超时的阈值,单位毫秒
cluster-slave-validity-factor 集群服务中每个节点也应该有从节点来避免单点,这就需要设置故障转移,进行故障转移时,salve会 申请成为master。有时slave会和master失联很久导致数据较旧,这样的slave不应该成为master。这个配置是用来设置失联多久的从节点不能提升为主节点
cluster-require-full-coverage yes:如果任何一个节点故障了,并且没有设置从节点,导致槽不完整了,还能否接受客户端的请求,此配置是要求有完整的槽才能接受请求,因此设置为yes
配置过程:
(1) 设置配置文件,启用集群功能;
(2) 启动redis后为每个节点分配slots;
CLUSTER ADDSLOTS
注意:每个slot要独立创建;可用范围是0-16383,共16384个
(3) 设定集群成员关系;
CLUSTE MEET
示例:设置redis的三个集群服务,此实验没有设置从节点,三个节点都是主节点
1、在node1上的设置
vim /etc/redis.conf
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
cluster-require-full-coverage yes
scp /etc/redis.conf node2:/etc
scp /etc/redis.conf node1:/etc
min-slaves-to-write 0 ----在这里要注意要把这一项改为0,或者注释掉,此项是定义主节点有几个从节点时才允许写,此实验没有从节点
2、重新启动所有节点的redis服务
systemctl restart redis
3、给每个节点分配槽位,在node1上设置
[root@node1 ~]#echo $[16384/3] ---一般都是平均分配
5461
[root@node1 ~]#echo $[5461*2]
10922
[root@node1 ~]#redis-cli -a centos cluster addslots {0..5461}
OK
[root@node1 ~]#redis-cli -a centos -h 172.18.21.100 cluster addslots {5462..10922}
OK
[root@node1 ~]#redis-cli -a centos -h 172.18.21.7 cluster addslots {10923..16383}
OK
[root@node1 ~]#redis-cli -a centos
127.0.0.1:6379> CLUSTER INFO
cluster_state:fail ---可以看到此时的状态还是失败的
cluster_slots_assigned:5463 ---槽位已经分配成功了
cluster_slots_ok:5463
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:1
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0
4、让集群内的成员会面
127.0.0.1:6379> CLUSTER MEET 172.18.21.100 6379
OK
127.0.0.1:6379> CLUSTER MEET 172.18.21.7 6379
OK
127.0.0.1:6379> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384 ---见面之后发现槽位一共是16384个了
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:3
cluster_current_epoch:2
cluster_my_epoch:1
cluster_stats_messages_sent:25
cluster_stats_messages_received:23
5、测试
在node1上的操作
[root@node1 ~]#redis-cli -a centos
127.0.0.1:6379> set test1key hi
OK
127.0.0.1:6379> get test1key
"hi"
127.0.0.1:6379> set testkey2 hello ---告诉我们要到node3节点上设置才可以,因为对testkey2这个键进行哈希计算后,对16384取模会落到node3节点的槽上
(error) MOVED 14758 172.18.21.7:6379
127.0.0.1:6379>
在node3节点上的操作
[root@node3 ~]#redis-cli -a centos
127.0.0.1:6379> set testkey2 hello ---在node3节点上就可以设置了
OK
127.0.0.1:6379> get testkey2
"hello"
127.0.0.1:6379> set testkey3 sayhello
(error) MOVED 10631 172.18.21.100:6379
在node2节点上的操作
[root@node2 .ssh]#redis-cli -a centos
127.0.0.1:6379> set testkey3 sayhello
OK