redis

一. 简介

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。拥有丰富的支持主流语言的客户端,C、C++、Python、Erlang、R、C#、Java、PHP、Objective-C、Perl、Ruby、Scala、Go、JavaScript。

二. 特点

2.1 数据结构丰富

Redis 虽然也是键值对数据库,但是和 Memcached 不同的是,Redis 支持多种类型的数据结构,不仅可以是字符串,同时还提供散列(hashes)列表(lists)集合(sets)有序集合(sorted sets)等数据结构

通过选用不同的数据结构,用户可以使用 Redis 解决各式各样的问题。

数据库有两种,一种硬盘数据库,一种内存数据库

值储存在硬盘,典型的是 SQL 数据库

 

硬盘是把

在内存里面就存储一下索引,当硬盘数据库想访问硬盘的值时,它先在内存里面找到索引,然后在找值,问题是什么,在读取和写入硬盘的时候,如果读写比较多的时候,它会把硬盘 IO 堵死。

至于内存数据库,它会直接把值放到内存里面,内存数据库就直接把值取到,风一样的感觉,读写数据的时候都不会受到硬盘 IO 速度的限制,所以速度极快。

 

注意:传统的数据库在存储数据时,会直接写入磁盘中,这样的话数据完整性好,数据不容易丢失,但是由于每次都写入磁盘,受到硬盘IO速度限制,执行速度较慢

2.2 数据持久化

Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用

2.3 数据的备份

Redis支持数据的备份,即master-slave模式的数据备份。

三, redis的安装

  • 上传redis压缩包redis-3.2.9.tar.gz

  • 解压压缩包

    • tar -zxvf redis-3.2.9.tar.gz

  • 安装依赖

    • yum -y install gcc tcl

    • 前面安装MySQL时安装过,故这里不需要安装

  • make

  • make install

  • 修改 redis.config

    • bind 127.0.0.1 追加 本地IP

    • bind 127.0.0.1 192.168.61.220

  • 客户端安装的地址

    • cd /usr/local/bin

  • 启动

    • 进入 redis目录下执行 : redis-server redis.conf

    • 客户端连接:redis-cli

四. redis的使用

  • 切换数据库

    • select + 数据库名 redis有十六个数据库,分别从0-15.默认是0数据库

  • 操作key

    • 查找所有符合给定模式 pattern 的 key

      • key pattern

    • 检查给定 key 是否存在

      • exists key

    • 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。

      • expire key seconds

    • 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。

      • move key 数据库名称

    • 以秒为单位,返回给定 key 的剩余生存时间

      • ttl key

    • 返回 key 所储存的值的类型。

      • type key

    • 删除给定的一个或多个 key 。不存在的 key 会被忽略。

      • DEL key [key ...]

  • string 操作

    • 字符串是一种最基本的Redis值类型。Redis字符串是二进制安全的,这意味着一个Redis字符串能包含任意类型的数据

    • SET key value [EX seconds] [PX milliseconds] [NX|XX]

      • EX 设置过期时间,秒,等同于SETEX key seconds value

      • PX 设置过期时间,毫秒,等同于PSETEX key milliseconds value

      • NX 键不存在,才能设置,等同于SETNX key value

      • XX 键存在时,才能设置

    • 返回 key 所关联的字符串值。如果 key 不存在那么返回特殊值 nil 。

      假如 key 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。

      • GET key

    • 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。

      • APPEND key value

    • 返回 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。

      • strlen key

    • 将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。

      • incr key

    • 将 key 所储存的值加上增量 increment 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。

      • incrby key increment

    • 将 key 中储存的数字值减一。

      • decr key

    • 将 key 所储存的值减去减量 decrement 。

      • decrby key decrement

    • 返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。负数偏移量表示从字符串最后开始计数, -1 表示最后一个字符, -2 表示倒数第二个,以此类推。

      • getrange key start end

    • 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。不存在的 key 当作空白字符串处理。

      • setrange key offset value

    • 将值 value 关联到 key ,并将 key 的生存时间设为 seconds

      如果 key 已经存在, SETEX 命令将覆写旧值。这个命令类似于以下两个命令:SET key value EXPIRE key seconds # 设置生存时间

      不同之处是, SETEX 是一个原子性(atomic)操作,关联值和设置生存时间两个动作会在同一时间内完成,该命令在 Redis 用作缓存时,非常实用

      • setex key seconds value

    • 将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。

      • setnx key value

    • 返回所有(一个或多个)给定 key 的值。如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。

      • mget key [key. key .......]

    • 同时设置一个或多个 key-value 对。如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX 命令:它只会在所有给定 key 都不存在的情况下进行设置操作

      • MSET key value [key value ...]

    • 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作。MSETNX 是原子性的,因此它可以用作设置多个不同 key 表示不同字段(field)的唯一性逻辑对象(unique logic object),所有字段要么全被设置,要么全不被设置。

      • MSETNX key value [key value ...]

  • list 操作

    • 将一个或多个值 value 插入到列表 key 的表头如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头: 比如说,对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。

      • lpush key value [value....]

    • 将一个或多个值 value 插入到列表 key 的表尾(最右边)。如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。

      • rpush key value [value....]

    • 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。

      • lrange key start stop

    • 移除并返回列表 key 的头元素

      • lpop key

    • 移除并返回列表 key 的尾元素。

      • rpop key

    • 返回列表 key 中,下标为 index 的元素。

      • LINDEX key index

    • 返回列表 key 的长度。如果 key 不存在,则 key 被解释为一个空列表,返回 0 .

      • llen key

    • 根据参数 count 的值,移除列表中与参数 value 相等的元素。

      count 的值可以是以下几种:

      count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。

      count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。

      count = 0 : 移除表中所有与 value 相等的值。

      • LREM key count value

    • 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

      举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。

      RPOPLPUSH source destination

      命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:

      将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。

      将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。

      举个例子,你有两个列表 source 和 destination , source 列表有元素 a, b, c , destination 列表有元素 x, y, z ,执行 RPOPLPUSH sourcedestination 之后, source 列表包含元素 a, b , destination 列表包含元素 c, x, y, z ,并且元素 c 会被返回给客户端。

      • LTRIM key start stop

  • set 操作

    • 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。假如 key 不存在,则创建一个只包含 member 元素作成员的集合。

      • sadd key member [member............]

    • 返回集合 key 中的所有成员。不存在的 key 被视为空集合。

      • smembers key

    • 判断 member 元素是否集合 key 的成员。

      • sismember key member

    • 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。

      • srem key member [member.............]

    • 移除并返回集合中的一个随机元素。如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 SRANDMEMBER 命令。

      • spop key

    • 将 member 元素从 source 集合移动到 destination 集合。

      SMOVE 是原子性操作。如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 0 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去。当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。当 source 或 destination 不是集合类型时,返回一个错误。

      • SMOVE source destination member

    • 求差集:从第一个key的集合中去除其他集合和自己的交集部分

      • SDIFF key [key ...]

    • 返回一个集合的全部成员,该集合是所有给定集合的交集。不存在的 key 被视为空集。当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。

      • SINTER key [key ...]

    • 返回一个集合的全部成员,该集合是所有给定集合的并集。不存在的 key 被视为空集。

      • SUNION key [key ...]

  • sorted set 操作

    • 返回有序集 key 中,指定区间内的成员。

      其中成员的位置按 score 值递增(从小到大)来排序。

      具有相同 score 值的成员按字典序(lexicographical order )来排列。

      如果你需要成员按 score 值递减(从大到小)来排列,请使用 ZREVRANGE 命令。

      下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。

      你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。

      超出范围的下标并不会引起错误。

      比如说,当 start 的值比有序集的最大下标还要大,或是 start > stop 时, ZRANGE 命令只是简单地返回一个空列表。

      另一方面,假如 stop 参数的值比有序集的最大下标还要大,那么 Redis 将 stop 当作最大下标来处理。

      可以通过使用 WITHSCORES 选项,来让成员和它的 score 值一并返回,返回列表以 value1,score1, ..., valueN,scoreN 的格式表示。

      • ZRANGE key start stop [WITHSCORES]

    • 返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。

    • 移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。

      • ZREM key member [member ...]

    • 移除有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员

      • ZREMRANGEBYSCORE key min max

    • 返回有序集 key 中,成员 member 的 score 值。

      • ZSCORE key member

    • 返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。

      • ZCOUNT key min max

    • 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。

      • ZRANK key member

  • hash操作

    • 将哈希表 key 中的域 field 的值设为 value

      • hset key field value

    • 返回哈希表 key 中给定域 field 的值。

      • hset key field

    • 同时将多个 field-value (域-值)对设置到哈希表 key 中。此命令会覆盖哈希表中已存在的域。

      • HMSET key field value [field value ...]

    • 返回哈希表 key 中,一个或多个给定域的值

      • HMGET key field [field ...]

    • 返回哈希表 key 中,所有的域和值。

      • HGETALL key

    • 返回哈希表 key 中的所有域。

      • HKEYS key

    • 返回哈希表 key 中所有域的值。

      • hvals key

    • 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。若域 field 已经存在,该操作无效。

      • hsetnx key field value

    • 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。

      • HDEL key field [field ...]

    • 为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数,相当于对给定域进行减法操作。

      • HINCRBY key field increment

五. redis持久化

Redis 提供了多种不同级别的持久化方式:

RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。

·AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。

·Redis 还可以同时使用 AOF 持久化和 RDB 持久化。 在这种情况下, 当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存在.

5.1 RDB

Rdb:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的 snapshot 快照,它恢复时就是将快照文件直接读到内存里。

Redis 会单独的创建(fork) 一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程结束了,再用这个临时文件替换上次持久化的文件。整个过程中,主进程是不进行任何 IO 操作,这就确保了极高的性能,如果需要进行大规模的数据恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方法要比 AOF 方式更加的高效。RDB 的缺点是最后一次持久化后的数据可能丢失。

Fork 的作用是复制一个与当前进程一样的进程,新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程

Rdb 保存的是 dump.rdb 文件

 

RDB save 操作

Rdb 是整个内存的压缩的 snapshot,RDB 的数据结构,可以配置符合快照触发条件,默认的是 1 分钟内改动 1 万次,或者 5 分钟改动 10 次,或者是 15 分钟改动一次;

Save 禁用:如果想禁用 RDB 持久化的策略,只要不设置任何 save 指令,或者是给 save 传入一个空字符串参数也可以。

 

save 指令:即刻保存操作对象

5.1.1 如何触发RDB快照

Save:save 时只管保存,其他不管,全部阻塞。

Bgsave:redis 会在后台进行快照操作,快照操作的同时还可以响应客户端的请求,可以通过 lastsave 命令获取最后一次成功执行快照的时间。

5.1.2 如何停止

静态停止:将配置文件里的RDB 保存规则改为 save “”

动态停止 :

 

5.2 AOF

以日志的形式俩记录每个写操作,将 redis 执行过的所有写指令记录下来(读操作不记录)。只许追加文件但不可以改写文件,redis 启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次一完成数据恢复工作。

======APPEND ONLY MODE=====

开启 aof :appendonly yes (默认是 no)

 

 

5.2.1 Aof策略

Appendfsync 参数:

Always 同步持久化 每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性较好。

Everysec: 出厂默认推荐,异步操作,每秒记录,日过一秒宕机,有数据丢失

No:从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。

5.2.2 Rewrite

概念:AOF 采用文件追加方式,文件会越来越来大为避免出现此种情况,新增了重写机制,aof 文件的大小超过所设定的阈值时,redis 就会自动 aof 文件的内容压缩,值保留可以恢复数据的最小指令集,可以使用命令 bgrewirteaof。

重写原理:aof 文件持续增长而大时,会 fork 出一条新进程来将文件重写(也就是先写临时文件最后再 rename),遍历新进程的内存中的数据,每条记录有一条 set 语句,重写 aof 文件的操作,并没有读取旧的的 aof 文件,而是将整个内存的数据库内容用命令的方式重写了一个新的 aof 文件,这点和快照有点类似。

触发机制:redis 会记录上次重写的 aof 的大小,默认的配置当 aof 文件大小为上次 rewrite 后大小的一倍且文件大于 64M 触发。

 

no-appendfsync-on-rewrite no : 重写时是否可以运用 Appendfsync 用默认 no 即可,保证数据安全

auto-aof-rewrite-percentage 倍数 设置基准值

auto-aof-rewrite-min-size 设置基准值大小

5.2.3 AOF优点

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

AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。

Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。

AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

5.2.4 AOF缺点

对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。

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

5.2.5 备份Redis 数据

一定要备份你的数据库!

磁盘故障, 节点失效, 诸如此类的问题都可能让你的数据消失不见, 不进行备份是非常危险的。

Redis 对于数据备份是非常友好的, 因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的 RDB 文件。

这也就是说, 无论何时, 复制 RDB 文件都是绝对安全的。

建议:

创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。

确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。

至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。

六. redis的主从复制

6.1 主从复制的理解

  • 一个主服务器可以有多个从服务器

  • 从服务器也可以拥有自己的从服务器,多个服务器的从服务器之间构成图状结构

  • 复制功能不会阻塞主服务器.也就是说当多个从服务器在同步数据的时候,主服务器还可以继续处理命令

  • 复制功能也不会阻塞从服务器,也就是说从服务器在进行数据同步的同时,也可以运用旧的数据进行处理命令查询,但是在从服务器删除旧版本数据集并载入新版本数据集的那段时间内, 连接请求会被阻塞。

6.2 从服务器的配置

  • 只要在配置文件中增加以下

    • slaveof 192.168.61.220 6379

  • 调用slaveof命令

    • slaveof 192.168.61.220 6379

6.3 只读从服务器

  • 只读模式由 redis.conf 文件中的 slave-read-only 选项控制, 也可以通过 CONFIG SET 命令来开启或关闭这个模式。

  • · 只读从服务器会拒绝执行任何写命令, 所以不会出现因为操作失误而将数据不小心写入到了从服务器的情况。

  • 如果主服务器通过 requirepass 选项设置了密码, 那么为了让从服务器的同步操作可以顺利进行, 我们也必须为从服务器进行相应的身份验证设置。

    对于一个正在运行的服务器, 可以使用客户端输入以下命令:

    config set masterauth <password>

    要永久地设置这个密码, 那么可以将它加入到配置文件中:

    masterauth <password>

七. redis的哨兵模式

redis的sentinel系统用于管理多个服务器,该系统执行三个任务

  • 监控:sentinel会不断的检查你的主服务器和从服务器是否正常运行

  • 提醒:当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

  • 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程, 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

  • 配置sentinel

    • 进入redis目录下找到sentinel.conf文件

    • 删除 并新建文件夹加入

      • sentinel monitor mymaster 192.168.78.101 6379 2
        sentinel down-after-milliseconds mymaster 30000
        sentinel failover-timeout mymaster 180000
        sentinel parallel-syncs mymaster 1
        protected-mode no
    • 第一行配置指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 127.0.0.1 , 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)。

      不过要注意, 无论你设置要多少个 Sentinel 同意才能判断一个服务器失效, 一个 Sentinel 都需要获得系统中多数(majority) Sentinel 的支持, 才能发起一次自动故障迁移。换句话说, 在只有少数(minority) Sentinel 进程正常运作的情况下, Sentinel 是不能执行自动故障迁移的。

      其他选项的基本格式如下:

      sentinel <选项的名字> <主服务器的名字> <选项的值>

      各个选项的功能如下:

      l down-after-milliseconds 选项指定了 Sentinel 认为服务器已经断线所需的毫秒数。如果服务器在给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(subjectively down,简称 SDOWN )。不过只有一个 Sentinel 将服务器标记为主观下线并不一定会引起服务器的自动故障迁移: 只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线,这时自动故障迁移才会执行。将服务器标记为客观下线所需的 Sentinel 数量由对主服务器的配置决定。

      parallel-syncs 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长。如果从服务器被设置为允许使用过期数据集(参见对 redis.conf 文件中对 slave-serve-stale-data 选项的说明), 那么你可能不希望所有从服务器都在同一时间向新的主服务器发送同步请求, 因为尽管复制过程的绝大部分步骤都不会阻塞从服务器, 但从服务器在载入主服务器发来的 RDB 文件时, 仍然会造成从服务器在一段时间内不能处理命令请求: 如果全部从服务器一起对新的主服务器进行同步, 那么就可能会造成所有从服务器在短时间内全部不可用的情况出现。你可以通过将这个值设为 1 来保证每次只有一个从服务器处于不能处理命令请求的状态。

八, 集群搭建

1.1 集群数据共享

Redis 集群使用数据分片(sharding)而非一致性哈希来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和

集群中的每个节点负责处理一部分哈希槽。 举个例子, 一个集群可以有三个哈希槽, 其中:

l 节点 A 负责处理 0 号至 5500 号哈希槽。

l 节点 B 负责处理 5501 号至 11000 号哈希槽。

l 节点 C 负责处理 11001 号至 16384 号哈希槽。

这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。 比如说:

l 如果用户将新节点 D 添加到集群中, 那么集群只需要将节点 A 、B 、 C 中的某些槽移动到节点 D 就可以了。

l 与此类似, 如果用户要从集群中移除节点 A , 那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C , 然后再移除空白(不包含任何哈希槽)的节点 A 就可以了。

因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞, 所以无论是添加新节点还是移除已存在节点, 又或者改变某个节点包含的哈希槽数量, 都不会造成集群下线。

1.2 集群的主从复制

为了使得集群在一部分节点下线或者无法与集群的大多数节点进行通讯的情况下, 仍然可以正常运作, Redis 集群对节点使用了主从复制功能: 集群中的每个节点都有1个至N个复制品,其中一个复制品为主节点, 而其余的 N-1 个复制品为从节点。

在之前列举的节点 A 、B 、C 的例子中, 如果节点 B 下线了, 那么集群将无法正常运行, 因为集群找不到节点来处理5501号至11000号的哈希槽。

另一方面, 假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1 , 那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B , 继续处理 5501 号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。

不过如果节点 B 和 B1 都下线的话, Redis 集群还是会停止运作。

1.3, 集群的一致性

Redis 集群不保证数据的强一致性(strong consistency): 在特定条件下, Redis 集群可能会丢失已经被执行过的写命令。

使用异步复制是 Redis 集群可能会丢失写命令的其中一个原因。 考虑以下这个写命令的例子:

l 客户端向主节点 B 发送一条写命令。

l 主节点 B 执行写命令,并向客户端返回命令回复。

l 主节点 B 将刚刚执行的写命令复制给它的从节点 B1 、 B2 和 B3 。

如你所见, 主节点对命令的复制工作发生在返回命令回复之后, 因为如果每次处理命令请求都需要等待复制操作完成的话, 那么主节点处理命令请求的速度将极大地降低 —— 我们必须在性能和一致性之间做出权衡。

Redis 集群另外一种可能会丢失命令的情况是, 集群出现网络分裂(network partition), 并且一个客户端与至少包括一个主节点在内的少数(minority)实例被孤立。

举个例子, 假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点, 其中 A 、B 、C 为主节点, 而 A1 、B1 、C1 分别为三个主节点的从节点, 另外还有一个客户端 Z1 。

假设集群中发生网络分裂, 那么集群可能会分裂为两方, 大多数(majority)的一方包含节点 A 、C 、A1 、B1 和 C1 , 而少数(minority)的一方则包含节点 B 和客户端 Z1 。

在网络分裂期间, 主节点 B 仍然会接受 Z1 发送的写命令:

l 如果网络分裂出现的时间很短, 那么集群会继续正常运行;

l 但是, 如果网络分裂出现的时间足够长, 使得大多数一方将从节点 B1 设置为新的主节点, 并使用 B1 来代替原来的主节点 B , 那么 Z1 发送给主节点 B 的写命令将丢失。

注意, 在网络分裂出现期间, 客户端 Z1 可以向主节点 B 发送写命令的最大时间是有限制的, 这一时间限制称为节点超时时间(node timeout), 是 Redis 集群的一个重要的配置选项:

l 对于大多数一方来说, 如果一个主节点未能在节点超时时间所设定的时限内重新联系上集群, 那么集群会将这个主节点视为下线, 并使用从节点来代替这个主节点继续工作。

对于少数一方, 如果一个主节点未能在节点超时时间所设定的时限内重新联系上集群, 那么它将停止处理写命令, 并向客户端报告错误。

1.4 集群搭建

集群规划:3个主节点,3个从节点。

配置文件:

port 7000

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

daemonize yes

protected-mode no

文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为 nodes.conf.

首先准备三台机器,计划每台机器运行两个redis实例,集群一共运行6个实例。在每台机器上创建个redis-cluster的目录,创建两个以端口号为名字的子目录, 稍后我们在将每个目录中运行一个 Redis 实例。

mkdir cluster-test

cd cluster-test

mkdir 7000 7001

在文件夹 7000 和7001 中, 各创建一个 redis.conf 文件, 文件的内容可以使用上面的示例配置文件, 但记得将配置中的端口号从 7000 改为与文件夹名字相同的号码。

在每台机器的7000和7001文件夹下,使用redis-server redis.conf启动实例

现在我们已经有了六个正在运行中的 Redis 实例, 接下来我们需要使用这些实例来创建集群, 并为每个节点编写配置文件。

通过使用 Redis 集群命令行工具 redis-trib , 编写节点配置文件的工作可以非常容易地完成: redis-trib 位于 Redis 源码的 src 文件夹中, 它是一个 Ruby 程序, 这个程序通过向实例发送特殊命令来完成创建新集群, 检查集群, 或者对集群进行重新分片(reshared)等工作。

安装ruby相关的程序:

1.yum install ruby

2.yum install rubygems

3.gem install redis-3.2.1.gem

安装完之后用执行以下命令来创建集群:

./redis-trib.rb create --replicas 1 192.168.61.220:7000 192.168.61.220:7001

192.168.61.221:7000 192.168.61.221:7001 192.168.61.222:7000 192.168.61.222:7001

命令的意义如下:

给定 redis-trib.rb 程序的命令是 create , 这表示我们希望创建一个新的集群。

选项 --replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。

之后跟着的其他参数则是实例的地址列表, 我们希望程序使用这些地址所指示的实例来创建新集群。

简单来说, 以上命令的意思就是让 redis-trib 程序创建一个包含三个主节点和三个从节点的集群。

创建完之后必须用 redis-cli –c –p 7000来链接集群,要不然连接的是默认端口(6379)

posted @ 2019-12-30 13:54  数据阮小白  阅读(90)  评论(0编辑  收藏  举报