Redis 基础

Redis 是一款开源的、高性能的键-值存储。它常被称作是一款数据结构服务器、缓存服务器

Rredis 属于非关系型数据库和 Memcached 类似,Redis 也是一种 key-value 型存储系统

支持的主要数据类型为:字符串(strings)类型、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)

  • Redis支持多种数据类型,适应更多的场景需求。
  • 支持发布订阅,管道
  • 设置 TTL 存活时间,到期自动删除
  • 可以执行 lua 脚本
  • 提供了简单的事务功能, 能在一定程度上保证事务特性
  • 提供了流水线(Pipeline) 功能, 这样客户端能将一批命令一次性传到 Redis, 减少了网络的开销
  • 可以使用内存做持久化
  • 可以将数据复制到任意数量的从服务器
  • 基于内存的访问,非阻塞I/O,Redis 使用事件驱动模型 epoll 多路复用实现,连接、读写、关闭都转换为事件不在网络I/O上浪费过多的时间
  • 单线程避免的高并发的时候,多线程有锁的问题和线程切换的 CPU 开销的问题
  • 使用C语言编写,更好的发挥服务器性能,并且代码简洁,性能高

REDIS 持久化概念

Redis是一种高级key-value数据库。数据可以持久化,而且支持的数据类型很丰富。有字符串,链表,集 合和有序集合。支持在服务器端计算集合的并,交和补集(difference)等,还支持多种排序功能。所以Redis也可以被看成是一个数据结构服务器,由于 Redis 的数据都存放在内存中,如果没有配置持久化,redis 重启后数据就全丢失了,于是需要开启 redis 的持久化功能,将数据保存到磁 盘上,当 redis 重启后,可以从磁盘中恢复数据

redis 提供两种方式进行持久化,一种是 RDB 持久化(原理是将 Reids 在内存中的数据库记录定时 dump到磁盘上的RDB持久化),另外一种是 AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)

RDB 持久化

当 Redis 需要做持久化时,Redis 会 fork 一个子进程,子进程将数据写到磁盘上一个临时 RDB 文件中。当子进程完成写临时文件后,将原来的 RDB 替换掉,这样的好处就是可以 copy-on-write,Redis默认情况下,是快照 RDB 的持久化方式,将内存中的数据以快照的方式写入二进制文件中,默认的文件名是 dump.rdb 。当然我们也可以手动执行 save 或者 bgsave(异步)做快照

1
2
3
4
5
6
7
8
9
# 默认配置文件开启rdb

save 900 1 
save 300 10
save 60 10000

# 900秒之内,如果超过1个key被修改,则发起快照保存;
# 300秒内,如果超过10个key被修改,则发起快照保存;
# 1分钟之内,如果1万个key被修改,则发起快照保存;

优点: 这种文件非常适合用于进行备份: 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。RDB 非常适用于灾难恢复(disaster recovery)

缺点: 如果你需要尽量避免在服务器故障时丢失数据,那么 RDB 不适合你。 虽然 Redis 允许你设置不同的保存点(save point)来控制保存 RDB 文件的频率, 但是, 因为RDB 文件需要保存整个数据集的状态, 所以它并不是一个轻松的操作。 因此你可能会至少 5 分钟才保存一次 RDB 文件。 在这种情况下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据

AOF 持久化

使用 AOF 做持久化,每一个写命令都通过write函数追加到 appendonly.aof 中,配置方式:启动 AOF 持久化的方式

1
2
3
4
5
# redis.conf 配置

appendfsync yes   
appendfsync always     #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec   #每秒钟同步一次,该策略为AOF的缺省策略。

AOF 就可以做到全程持久化,只需要在配置文件中开启(默认是no),appendonly yes开启 AOF 之后,Redis 每执行一个修改数据的命令,都会把它添加到 AOF 文件中,当 Redis 重启时,将会读取 AOF 文件进行“重放”以恢复到 Redis 关闭前的最后时刻

优点: 使用 AOF 持久化会让 Redis 变得非常耐久(much more durable):你可以设置不同的 fsync 策略,比如无 fsync ,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。 AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。

缺点: 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)

Redis官网下载地址

Redis 安装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
wget http://download.redis.io/releases/redis-5.0.4.tar.gz

tar xf redis-5.0.4.tar.gz

cd redis-5.0.4

make

cd ..
mv redis-5.0.4 /usr/local/redis

echo 'PATH=$PATH':/usr/local/redis/src/ >> /etc/profile
source /etc/profile
# 启动redis-server
redis-server 

# 方法一:后台启动,redis自带日志
nohup redis-server /usr/local/redis/redis.conf &>/dev/null &

#方法二:修改配置文件/user/local/redis/redis.cof中 daemonize no 改为yes
redis-server /usr/local/redis/redis.conf

Redis-cluster 集群

redis-cluster

redis cluster是去中心化的,集群中的每个节点都是平等的关系,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃。

这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 创建集群目录
mkdir /usr/local/redis/cluster
mkdir /usr/local/redis/cluster/700{0,1,2,3,4,5}

cp /usr/local/redis/redis.conf //usr/local/redis/cluster/700{0,1,2,3,4,5}

# 修改7000-7005六个文件配置文件redis.conf
port 7000-7005
bind 192.168.11.114  # 连入主机IP,不修改外部无法炼乳你得redis缓存服务器
daemonize yes  # 开启守护进程,后台运行
pidfile /var/run/redis_7000-7005.pid  
cluster-enabled yes  # 开启集群模式
启动集群实列

redis-server 7001-7005/redis.conf

1
2
3
4
5
6
7
[[email protected] cluster]# ps -ef |grep redis
root      21772      1  0 13:12 ?        00:00:00 redis-server 127.0.0.1:7000 [cluster]
root      21778      1  0 13:13 ?        00:00:00 redis-server 127.0.0.1:7001 [cluster]
root      21783      1  0 13:13 ?        00:00:00 redis-server 127.0.0.1:7002 [cluster]
root      21788      1  0 13:13 ?        00:00:00 redis-server 127.0.0.1:7003 [cluster]
root      21793      1  0 13:13 ?        00:00:00 redis-server 127.0.0.1:7004 [cluster]
root      21798      1  0 13:13 ?        00:00:00 redis-server 127.0.0.1:7005 [cluster]

redis5.0之后不需要用ruby安装集群,redis3-4之下需要安装ruby来启动集群

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
[[email protected] cluster]# redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460          # 主节点
Master[1] -> Slots 5461 - 10922         # 主节点
Master[2] -> Slots 10923 - 16383        # 主节点
Adding replica 127.0.0.1:7004 to 127.0.0.1:7000    # 主节点对应的从节点
Adding replica 127.0.0.1:7005 to 127.0.0.1:7001    # 主节点对应的从节点
Adding replica 127.0.0.1:7003 to 127.0.0.1:7002    # 主节点对应的从节点
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 78a010d898d25e8ed8476d0e5eb143fa8517065b 127.0.0.1:7000  
   slots:[0-5460] (5461 slots) master                    # 主节点分配的hash槽
M: 199a014f4af2455b5f388d3fdbc8eeac09920010 127.0.0.1:7001 
   slots:[5461-10922] (5462 slots) master                # 主节点分配的hash槽
M: d6a81ed6f4eff088e851c29fb22a61c1d2a53c72 127.0.0.1:7002  
   slots:[10923-16383] (5461 slots) master               # 主节点分配的hash槽
S: 2bc6eb1e70a483d6baf3278120c51692b88f52ff 127.0.0.1:7003
   replicates 78a010d898d25e8ed8476d0e5eb143fa8517065b    # 从节点没有hash槽    
S: af465d24c5233e92ceedb2d70a011186e58c7289 127.0.0.1:7004
   replicates 199a014f4af2455b5f388d3fdbc8eeac09920010
S: bbd243415e85e3e4f4525a1fc6ea787324c2b2f8 127.0.0.1:7005
   replicates d6a81ed6f4eff088e851c29fb22a61c1d2a53c72
Can I set the above configuration? (type 'yes' to accept): yes   # 需要手动输入yes,服从这种主从分配,也可以通过配置文件指定slave
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 127.0.0.1:7000)   # 以下是详细的主从节点分布
M: 78a010d898d25e8ed8476d0e5eb143fa8517065b 127.0.0.1:7000
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 2bc6eb1e70a483d6baf3278120c51692b88f52ff 127.0.0.1:7003
   slots: (0 slots) slave
   replicates 78a010d898d25e8ed8476d0e5eb143fa8517065b
S: af465d24c5233e92ceedb2d70a011186e58c7289 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 199a014f4af2455b5f388d3fdbc8eeac09920010
S: bbd243415e85e3e4f4525a1fc6ea787324c2b2f8 127.0.0.1:7005
   slots: (0 slots) slave
   replicates d6a81ed6f4eff088e851c29fb22a61c1d2a53c72
M: 199a014f4af2455b5f388d3fdbc8eeac09920010 127.0.0.1:7001
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: d6a81ed6f4eff088e851c29fb22a61c1d2a53c72 127.0.0.1:7002
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
测试集群
查看集群node节点信息
1
2
3
4
5
6
7
[[email protected] cluster]# redis-cli -c -h 127.0.0.1 -p 7003 cluster nodes
af465d24c5233e92ceedb2d70a011186e58c7289 127.0.0.1:[email protected] slave 199a014f4af2455b5f388d3fdbc8eeac09920010 0 1555053804000 5 connected
78a010d898d25e8ed8476d0e5eb143fa8517065b 127.0.0.1:[email protected] master - 0 1555053803414 1 connected 0-5460
199a014f4af2455b5f388d3fdbc8eeac09920010 127.0.0.1:[email protected] master - 0 1555053803000 2 connected 5461-10922
d6a81ed6f4eff088e851c29fb22a61c1d2a53c72 127.0.0.1:[email protected] master - 0 1555053804421 3 connected 10923-16383
bbd243415e85e3e4f4525a1fc6ea787324c2b2f8 127.0.0.1:[email protected] slave d6a81ed6f4eff088e851c29fb22a61c1d2a53c72 0 1555053803000 6 connected
2bc6eb1e70a483d6baf3278120c51692b88f52ff 127.0.0.1:[email protected] myself,slave 78a010d898d25e8ed8476d0e5eb143fa8517065b 0 1555053803000 4 connected
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[[email protected] cluster]# redis-cli -c -p 7000
127.0.0.1:7000> set name zw
-> Redirected to slot [5798] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get name
"zw"
127.0.0.1:7001> quit

[[email protected] cluster]# redis-cli -c -p 7003
127.0.0.1:7003> get name
-> Redirected to slot [5798] located at 127.0.0.1:7001
"zw"
127.0.0.1:7001> quit

停止 7000实列 master查看是否还能get到name

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[[email protected] cluster]# redis-cli -c -h 127.0.0.1 -p 7003 cluster nodes
af465d24c5233e92ceedb2d70a011186e58c7289 127.0.0.1:[email protected] slave 199a014f4af2455b5f388d3fdbc8eeac09920010 0 1555054991175 5 connected
78a010d898d25e8ed8476d0e5eb143fa8517065b 127.0.0.1:[email protected] master,fail - 1555054687543 1555054686036 1 disconnected
199a014f4af2455b5f388d3fdbc8eeac09920010 127.0.0.1:[email protected] master - 0 1555054991000 2 connected 5461-10922
d6a81ed6f4eff088e851c29fb22a61c1d2a53c72 127.0.0.1:[email protected] master - 0 1555054992181 3 connected 10923-16383
bbd243415e85e3e4f4525a1fc6ea787324c2b2f8 127.0.0.1:[email protected] slave d6a81ed6f4eff088e851c29fb22a61c1d2a53c72 0 1555054991000 6 connected
2bc6eb1e70a483d6baf3278120c51692b88f52ff 127.0.0.1:[email protected] myself,master - 0 1555054990000 8 connected 0-5460

[[email protected] cluster]# redis-cli -c -p 7004
127.0.0.1:7004> get name
-> Redirected to slot [5798] located at 127.0.0.1:7001
"zw"
127.0.0.1:7001> exit

可以发现 7003 已经替换成新的master了 必须要3个或以上的主节点,否则在创建集群时会失败,并且当存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了

telnet IP 端口 info cluster info 打印集群的信息 cluster nodes 列出集群当前已知的所有节点(node),以及这些节点的相关信息

Redis 集群总结

redis cluster在设计的时候,就考虑到了去中心化、去中间件,也就是说,集群中的每个节点都是平等关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。 Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个 slot,当我们 set 一个 key 时,会用CRC16算法来取模得到所属的 slot,然后将这个 key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。所以我们在测试的时候看到 set 和 get 的时候,直接跳转到了7000端口的节点。 Redis 集群会把数据存在一个 master 节点,然后在这个 master 和其对应的 salve 之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的 master 节点获取数据。只有当一个 master 挂掉之后,才会启动一个对应的 salve 节点,充当 master 。