1.1 什么是redis
Redis是用C语言开发的一个开源的高性能 ( key-value ) ,它是一种NOSQL的数据库。
redis是单进程单线程的内存数据库, 所以说不存在线程安全问题
redis
支持10wQPS, 可以说性能非常优秀. 之所以单进程单线程性能还那么好, 是因为底层采用了[IO多路复用(NIO思想)]
1.2 redis数据类型
redis提供了五种数据类型:
string(字符串)
list(链表)
set(集合)
zset(有序集合)
hash(哈希类型)
记得有一次面试, 面试官特意问了zset数据类型的用法, 平时开发中很少用到zset数据类型, 但是zset经典的应用就是排序, 后面会介绍到.
1.3 redis和memcached的对比
- 持久化:
- redis可以用来做缓存, 也可以做存储, 支持aof和rdb两种持久化方式
- memecached只能做缓存, 没法持久化数据
- 数据结构:
- redis有丰富的数据类型: 五种常用的数据结构
- memcached一般就是字符串和对象
1.4 redis官网
- 官网地址: http://redis.io
- 中文官网地址: http://www.redis.cn
- 下载地址: http://download.redis.io/releases/
1.5 redis应用场景
- 内存数据库(登陆信息, 购物车信息, 用户浏览器记录)
- 缓存服务器(商品数据, 广告数据等等)(使用的最多)
- session共享
- 任务队列(秒杀, 抢购, 12306等)
- 分布式锁的实现
- 支持发布订阅的消息模式
- 应用排行榜(有序集合)
- 网站访问统计
- 数据过期处理
2. redis的多用模式
2.1 redis单机版
- 执行如下命令:
#第一步 安装C语言环境
yum install -y gcc-c++
yum install -y wget
# 第二步 下载源码包
wget http://download.redis.io/releases/redis-5.0.6.tar.gz
tar xzvf redis-5.0.6.tar.gz
# 第三步 编译安装
cd redis-5.0.6
make install prefix=/usr/local/redis-5.0.6
- 启动redis
cd redis-5.0.6./redis-server
如果出现如下的界面, 说明启动成功了:
- 守护进程启动
redis-5.0.6下面有一个配置文件redis.conf, 修改如下:
vim redis.conf
# 将`daemonize`由`no`改为`yes`
daemonize yes
# 默认绑定的是回环地址,默认不能被其他机器访问
# bind 127.0.0.1
# 是否开启保护模式,由yes该为
noprotected-mode no
启动
./redis-server redis.conf
- 后端启动关闭方式
./redis-cli shutdown
- redis的其他主要命令
- redis-benchmark: 性能测试工具
- redis-check-aof: 检查 AOF 日志
- redis-check-dump: 检查 RDB 日志
- redis-cli: 启动命令行客户端
- redis-sentinel: redis的哨兵服务, 在redis2.8+以后加入的
- Redis-server: 启动Redis服务
在redis的解压目录中, 有一个redis的配置文件
2.2 主从模式
1. 主从复制的作用
- 主从备份 防止主机宕机
- 读写分离,分担 master 的任务
- 任务分离,如从服分别分担备份工作与计算工作
2. redis主从复制的两种方式
3. redis主从服务通信的原理
4. 配置redis主从模式
如果主服务器上需要增加redis的密码, 增加如下配置:
requirepass xxxxxx
redis的主, 从的安装方式, 步骤都一样, 从的配置文件从主拷贝过来, 然后在从节点的配置文佳中加上如下配置:
slaveof localhost 6379
#如果主上有密码, 则从服务器上的配置文件需要增加以下配置:
masterauth xxxxxx
2.3 哨兵模式
redis的哨兵模式是建立在主从模式上的, 因为主从模式如果主发生故障, 我们的从并无法直接提升为主共我们使用, 所以有了哨兵模式, 简单的说, 哨兵模式就是增加的投票机制, 增加几台服务器作为哨兵节点, 即监控节点, 如果超过半数的哨兵即: 2 / n + 1的个数认为主挂了, 就会自动提升从服务器为主服务器, 并且, 哨兵是可以实时改动redis主从的配置文件的.而自己的配置文件是实时发生变化.
2.3.1 sentinel结构
2.3.2 sentinel功能
Sentinel实现如下功能:
(1)monitoring——redis实例是否正常运行。
(2)notification——通知application错误信息。
(3)failover——某个master死掉,选择一个slave升级为master,修改其他slave的slaveof关系,更新client连接。
(4)configurationprovider——client通过sentinel获取redis地址,并在failover时更新地址。
Redis 2.8及以上版本可用。
2.3.3 sentinel集群
很显然,只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后(sentinel本身也有单点问题,single-point-of-failure)整个集群系统将无法按照预期的方式运行。所以有必要将sentinel集群,这样有几个好处:
即使有一些sentinel进程宕掉了,依然可以进行redis集群的主备切换;
如果只有一个sentinel进程,如果这个进程运行出错,或者是网络堵塞,那么将无法实现redis集群的主备切换(单点问题);
如果有多个sentinel,redis的客户端可以随意地连接任意一个sentinel来获得关于redis集群中的信息。
最少建立3个sentinel节点(sentinel-26380.conf、sentinel-26381.conf、sentinel-26382.conf)的部署方法完全是一致的(端口不同).
2.3.4 配置sentinel
根据官网给出的配置文件如下:
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
# 监控其他集群
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
- 第一行配置指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 127.0.0.1 , 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)。不过要注意, 无论你设置要多少个 Sentinel 同意才能判断一个服务器失效, 一个 Sentinel 都需要获得系统中多数(majority) Sentinel 的支持, 才能发起一次自动故障迁移, 并预留一个给定的配置纪元 (configuration Epoch ,一个配置纪元就是一个新主服务器配置的版本号)。换句话说, 在只有少数(minority) Sentinel 进程正常运作的情况下, Sentinel 是不能执行自动故障迁移的。
- down-after-milliseconds 选项指定了 Sentinel 认为服务器已经断线所需的毫秒数。
如果服务器在给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(subjectively down,简称 SDOWN )。
不过只有一个 Sentinel 将服务器标记为主观下线并不一定会引起服务器的自动故障迁移:只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线(objectively down, 简称 ODOWN ), 这时自动故障迁移才会执行。
将服务器标记为客观下线所需的 Sentinel 数量由对主服务器的配置决定。
- parallel-syncs 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长。
如果从服务器被设置为允许使用过期数据集(参见对 redis.conf 文件中对 slave-serve-stale-data 选项的说明), 那么你可能不希望所有从服务器都在同一时间向新的主服务器发送同步请求, 因为尽管复制过程的绝大部分步骤都不会阻塞从服务器, 但从服务器在载入主服务器发来的 RDB 文件时, 仍然会造成从服务器在一段时间内不能处理命令请求:如果全部从服务器一起对新的主服务器进行同步, 那么就可能会造成所有从服务器在短时间内全部不可用的情况出现。
你可以通过将这个值设为 1 来保证每次只有一个从服务器处于不能处理命令请求的状态。
2.3.5 启动sentinel
线上一般是不同的机器, 我们这里使用的是一个机器的不同端口
./redis-sentinel sentinel-26380.conf &
./redis-sentinel sentinel-26381.conf ./redis-sentinel sentinel-26382.conf &
2.3.6 sentinel的工作原理
- 每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。
- 如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
- 当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线
- 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令
- 当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
- 若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
2.4 redis cluster
2.4.1 什么是redis cluster
Redis Cluster 是 Redis 的分布式解决方案,在 Redis 3.0 版本正式推出 的,有效解决了 Redis 分布式方面的需求。当遇到单机内存、并发、流 量等瓶颈时,可以采用 Cluster 架构达到负载均衡的目的。
redis-cluster的优势:
- 官方推荐,毋庸置疑。
- 去中心化,集群最大可增加1000个节点,性能随节点增加而线性扩展。
- 管理方便,后续可自行增加或摘除节点,移动分槽等等。
- 简单,易上手。
2.4.2数据分布理论与redis的数据分区
分布式数据库首要解决把整个数据集按照分区规则映射到多个节点 的问题,即把数据集划分到多个节点上,每个节点负责整个数据的一个 子集。常见的分区规则有哈希分区和顺序分区。Redis Cluster 采用哈希 分区规则。
虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把 所有的数据映射到一个固定范围内的整数集合,整数定义为槽(slot)。比如 Redis Cluster 槽的范围是 0 ~ 16383。槽是集群内数据管理和迁移 的基本单位。
Redis Cluster 采用虚拟槽分区,所有的键根据哈希函数映射到 0 ~16383,计算公式:slot = CRC16(key)&16383。每一个节点负责维护一部 分槽以及槽所映射的键值数据。
redis-cluster把所有的物理节点映射到[0-16383] 上,cluster 负责维护node <->slot <-> value
2.4.3 redis cluster的体系架构
我们以 6 个节点为例,来介绍 Redis Cluster 的体系架构。其中:三个为
master 节点,另外三个为 slave 节点。
2.4.4 redis cluster一致性保证(官网)
Redis 并不能保证数据的强一致性. 这意味着在实际中集群在特定的条件下可能会丢失写操作.
第一个原因是因为集群使用了异步复制. 写操作过程:
- 客户端向主节点B写入一条命令.
- 主节点B向客户端回复命令状态.
- 主节点将写操作复制给他的从节点 B1, B2 和 B3.
主节点对命令的复制工作发生在返回命令回复之后, 因为如果每次处理命令请求都需要等待复制操作完成的话, 那么主节点处理命令请求的速度将极大地降低 —— 我们必须在性能和一致性之间做出权衡。注意:Redis 集群可能会在将来提供同步写的方法。Redis 集群另外一种可能会丢失命令的情况是集群出现了网络分区, 并且一个客户端与至少包括一个主节点在内的少数实例被孤立。
举个例子 假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点, 其中 A 、B 、C 为主节点, A1 、B1 、C1 为A,B,C的从节点, 还有一个客户端 Z1 假设集群中发生网络分区,那么集群可能会分为两方,大部分的一方包含节点 A 、C 、A1 、B1 和 C1 ,小部分的一方则包含节点 B 和客户端 Z1 .
Z1仍然能够向主节点B中写入, 如果网络分区发生时间较短,那么集群将会继续正常运作,如果分区的时间足够让大部分的一方将B1选举为新的master,那么Z1写入B中的数据便丢失了.
注意, 在网络分裂出现期间, 客户端 Z1 可以向主节点 B 发送写命令的最大时间是有限制的, 这一时间限制称为节点超时时间(node timeout), 是 Redis 集群的一个重要的配置选项:
2.4.5 安装redis cluster
Redis cluster最少需要三台主服务器, 三台从服务器(自己做实验的话, 可以使用一台服务器, 不同的端口)
- 安装Ruby环境和Ruby Redis接口
由于创建和管理需要使用到 redis-trib 工具,该工具位于 Redis 源码的 src 文 件夹中,它是一个 Ruby 程序,这个程序通过向实例发送特殊命令来完成创建新 集群,检查集群,或者对集群进行重新分片(reshared)等工作,所以需要安装 Ruby环境和相应的 Redis 接口
下面是可以使用 yum 来安装 Ruby, 添加yum源, 然后yum安装
[media]
name=Red Hat Enterprise Linux 7.4 baseurl=file:///cdroom
enabled=1
gpgcheck=1
gpgkey=file:///cdroom/RPM-GPG-KEY-redhat-release
yum 安装配置:
yum -y install ruby ruby-devel ruby
gems rpm-buildgem install redis
如果在安装过程中出现ERROR: Error installing redis redis requires Ruby version >= 2.2.2.
请参考该博客地址, 讲的十分清楚: https://blog.csdn.net/chenxinchongcn/article/details/78666374
- 以6个节点为例, 安装和部署redis cluster
- 主节点: 6379, 6380, 6381
- 从节点: 6382, 6383, 6384
- 每个配置文件的地方都需要修改, 修改成端口所对应的
daemonize yes
#各个节点的端口不同
port 6379
#开启集群服务
cluster-enabled yes
#节点的配置文件名字, 需要更改成不同的端口
cluster-config-file nodes/nodes-6379.conf cluster-node-timeout 15000
# rdb 文件名字改成不同的端口
dbfilename dump6379.rdb
appendonly yes
#aof 文件名字改成不同的端口
appendfilename "appendonly6379.aof"
- 配置文件一共有6个
- redis6379.conf
- redis6380.conf
- redis6381.conf
- redis6382.conf
- redis6383.conf
- redis6384.conf
- 启动redis实例
bin/redis-server conf/redis6379.conf
bin/redis-server conf/redis6380.conf
bin/redis-server conf/redis6381.conf
bin/redis-server conf/redis6382.conf
bin/redis-server conf/redis6383.conf
bin/redis-server conf/redis6384.conf
查看redis的进程
ps -ef |grep redis
- 使用 redis-trib.rb 自动部署方式
bin/redis-trib.rb create --replicas 1 192.168.56.72:6379 192.168.56.72:6380 192.168.56.72:6381 192.168.56.72:6382 192.168.56.72:6383 192.168.56.72:6384
注意: –replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
开始配置集群
- 测试redis cluster
- 使用客户端登陆:
bin/redis-cli -c -p 6379
可以使用cluster nodes 命令查看集群中的节点
2.4.6 维护节点
1. 添加主节点
- 在终端打开一个新的标签页.
- 进入cluster-test 目录.
- 创建并进入 7006文件夹.
- 和其他节点一样,创建redis.conf文件,需要将端口号改成7006.
- 最后启动节点 ../redis-server ./redis.conf
- 如果正常的话,节点会正确的启动.
bin/redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:6379
redis 127.0.0.1:7006> cluster nodes
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:6380 master - 0 1385543178575 0 connected 5960-10921
3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:6383 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385543179583 0 connected
f093c80dde814da99c5cf72a7dd01590792b783b :0 myself,master - 0 0 0 connected
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:6381 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543178072 3 connected
a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:6382 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385543178575 0 connected
97a3a64667477371c4479320d683e4c8db5858b1 127.0.0.1:6379 master - 0 1385543179080 0 connected 0-5959 10922-11422
3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:6384 master - 0 1385543177568 3 connected 11423-16383
新节点现在已经连接上了集群, 成为集群的一份子, 并且可以对客户端的命令请求进行转向了, 但是和其他主节点相比, 新节点还有两点区别:
a. 新节点没有包含任何数据, 因为它没有包含任何哈希槽.
b. 尽管新节点没有包含任何哈希槽, 但它仍然是一个主节点, 所以在集群需要将某个从节点升级为新的主节点时, 这个新节点不会被选中。
2. has槽重新分配(数据迁移)
a. 先连接集群上任意一个节点
bin/redis-cli --cluster reshard 127.0.0.1:6379
b. 输入要分配的槽数量
bin/redis-trib.rb reshard 127.0.0.1:6379
#有个提示输入1-16384, 属于多少, 代表分配多少个槽
c. 输入要接收槽的节点id
通过cluster nodes 查看7006的节点id为: 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0
输入到提示信息中
d. 输入源节点id
- 输入源节点id, 槽将从源节点中拿, 分配后的槽在源及诶单中就不存在了, 输入all, 就是把所有源节点中获取槽, 输入done取消分配
3. 添加从节点
./redis-trib.rb add-node --slave 127.0.0.1:7006 127.0.0.1:6379
4. 删除节点
bin/redis-trib del-node 127.0.0.1:6379 `<node-id>`
#可以通过cluster nodes 查看
node-idcluster nodes