一、Reids

Redis原子性原理

1、Redis是单进程单线程的网络模型,用的是epoll,poll,select网络模型,这些网络模型都是单线程处理网络请求

2、Redis的单线程处理所有的客户端连接请求,命令读写请求。(有些任务比如rdb和aof等操作是fork子进程处理的,不会影响redis主线程处理客户端的命令

3、Redis提供的所有API操作,相对于服务端方面都是one by one执行的,命令是一个接着一个执行的,不存在并行执行的情况。

Redis 简介

Redis 是完全开源免费的,遵守 BSD 协议,是一个高性能的 key-value 数据库。

Redis 与其他 key - value 缓存产品有以下三个特点:

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

使用。

2.Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 listsetzsethash 等数据结

构的存储。

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

Redis 优势

1. 性能极高 – Redis 能读的速度是 110000 /s,写的速度是 81000 /s

2. 丰富的数据类型 – Redis 支持二进制案例的 Strings, Lists, Hashes, Sets Ordered S

ets 数据类型操作。

3. 原子 – Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个

操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI EXEC 指令包起来。

4. 丰富的特性 – Redis 还支持 publish/subscribe, 通知, key 过期等等特性。

Redis 与其他 key-value 存储有什么不同? 

1. Redis 有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进

化路径。Redis 的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。

2. Redis 运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内

存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的

复杂的数据结构,在内存中操作起来非常简单,这样 Redis 可以做很多内部复杂性很强的事情。

同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

 

Redis 数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

 

String(字符串)

string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。

string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。

string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

常用命令:

除了get、set、incr、decr mget等操作外,Redis还提供了下面一些操作:

获取字符串长度

往字符串append内容

设置和获取字符串的某一段内容

设置及获取字符串的某一位(bit)

批量设置一系列字符串的内容

应用场景:

String是最常用的一种数据类型,普通的key/value存储都可以归为此类,value其实不仅是String,

也可以是数字:比如想知道什么时候封锁一个IP地址(访问超过几次)。INCRBY命令让这些变得很容易,通过原子递增保持计数。

实现方式:

m,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。

Hash(哈希)

redis hash 是一个键值(key=>value)对集合。

redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

常用命令:

hget,hset,hgetall 等。

应用场景:

我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:

           用户ID,为查找的key,

           存储的value用户对象包含姓名name,年龄age,生日birthday 等信息,

   如果用普通的key/value结构来存储,主要有以下2种存储方式:

       第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,

           如:set u001 "李三,18,20010101"

           这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。

       第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,

           如:mset user:001:name "李三 "user:001:age18 user:001:birthday "20010101"

           虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。

    那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,

    并提供了直接存取这个Map成员的接口,

        如:hmset user:001 name "李三" age 18 birthday "20010101"   

            也就是说,Key仍然是用户ID,value是一个Map,这个Map的key是成员的属性名,value是属性值,

            这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过

            key(用户ID) + field(属性标签) 操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。

          这里同时需要注意,Redis提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部Map的成员很多,那么涉及到遍历整个内部Map的操作,由于Redis单线程模型的缘故,这个遍历操作可能会比较耗时,而另其它客户端的请求完全不响应,这点需要格外注意。

实例

DEL runoob 用于删除前面测试用过的 key,不然会报错:(error) WRONGTYPE Operation agai

实例中我们使用了 Redis HMSET, HGET 命令,HMSET 设置了两个 field=>value 对, HGET 获取对应 field 对应的 value

每个 hash 可以存储 232 -1 键值对(40多亿)。

赋值      hset   hash1   name  zhangsan  设置给定的key的value

          hmset  hash2  name  lisi   age  18   sex  nan 设置多个

取值      hget  hash1 name   获取存储在哈希表中指定字段的值

hmget  hash2  name  age  sex     获取多个

hgetall  hash2    获取所有的

删除      hdel  hash2  name   删除指定的字段

del  hash2  删除指定所有

      增加      hincrby   hash1 age   5

hexists hash1  age  查看哈希表 key 中,指定的字段是否存在。

 hlen   hash1   获取哈希表中字段的数量

 hkeys  hash1 获取所有哈希表中的字段

hvals  hash1  获取哈希表中所有值

 

List(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

实例常用命令:

    lpush,rpush,lpop,rpop,lrange,BLPOP(阻塞版)等。

 

应用场景:

    Redis list的应用场景非常多,也是Redis最重要的数据结构之一。

    我们可以轻松地实现最新消息排行等功能。

    Lists的另一个应用就是消息队列,可以利用Lists的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。

 

实现方式:

    Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

 

RPOPLPUSH source destination

 

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

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

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

    如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。

    一个典型的例子就是服务器的监控程序:它们需要在尽可能短的时间内,并行地检查一组网站,确保它们的可访问性。

    redis.lpush "downstream_ips", "192.168.0.10"

    redis.lpush "downstream_ips", "192.168.0.11"

    redis.lpush "downstream_ips", "192.168.0.12"

    redis.lpush "downstream_ips", "192.168.0.13"

    Then:

    next_ip = redis.rpoplpush "downstream_ips", "downstream_ips"

 

BLPOP

 

  假设现在有 job 、 command 和 request 三个列表,其中 job 不存在, command 和 request 都持有非空列表。考虑以下命令:

  BLPOP job command request 30  #阻塞30秒,0的话就是无限期阻塞,job列表为空,被跳过,紧接着command 列表的第一个元素被弹出。

  1) "command"                             # 弹出元素所属的列表

  2) "update system..."                    # 弹出元素所属的值

  为什么要阻塞版本的pop呢,主要是为了避免轮询。举个简单的例子如果我们用list来实现一个工作队列。执行任务的thread可以调用阻塞版本的pop去获取任务这样就可以避免轮询去检查是否有任务存在。当任务来时候工作线程可以立即返回,也可以避免轮询带来的延迟

 

列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。

两端添加    lpush   mylist     a   b    c   将一个或多个元素插入到列表头部

rpush   mylist     a   b    c   将一个或多个元素插入到列表尾部

查看        lrange  mylist     0   3       获取列表指定范围内的元素

                             开始  结束     结束-1 为全部

两端弹出   lpop    mylsit    移除并获取列表的第一个值

           rpop    mylsit    移除并获取列表的最后一个值

获取列表个数  llen  mylist    获取列表的长度

仅当存在时才插入 lpushx   mylist    q  mylist存在的时候,将p插入到头部

仅当存在时才插入 rpushx   mylist    q  mylist存在的时候,将p插入到尾部

删除             lrem    mylist    2   a

在指定元素前【后】插入元素  linsert  mylist before[after] b   11;   b之后(之前)插入元素

Rpoplpush  mylist     mylist2   从一个列表中弹出一个值压入到另一个列表中

Set(集合)

Redis的Set是string类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

实例

常用命令:

    sadd,srem,spop,sdiff ,smembers,sunion 等。

 

应用场景:

    Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

    比如在微博应用中,每个人的好友存在一个集合(set)中,这样求两个人的共同好友的操作,可能就只需要用求交集命令即可。

    Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实

 

实现方式:

    set 的内部实现是一个 value永远为nullHashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因.

添加     sadd   myset     a   b   c

删除     srem   myset  a   b

查看   smembers  myset

是否存在 sismember  myset  a   myseta是否存在

差集     sdiff      myset1   myset2    

交集     sinter  myset1    myset2

并集   sunion   myset      myset2

长度   scard   myset   

随机返回成员    srandmemberset   myset

差集存入变量  sdiffstore     myset1    myset2  myset3   myset2myset3中的相差的值存入myset1

交集存入变量  sinterstore     myset1    myset2  myset3   myset2myset3中的交集的值存入myset1

并集存入变量  sunionstore    myset1    myset2  myset3   myset2myset3中的并差的值存入myset1

跟踪唯一,访问博客的ip地址存入到set

注意:以上实例中 rabitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。

集合中最大的成员数为 232 - 1(4294967295, 每个集合可存储40多亿个成员)。

zset(sorted set:有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

添加    Zadd  mysort    70 张三    80 李四  90王五

取值   zcore  myset     张三

       Zcard  mysort   成员数量

删除  zrem   mysort   张三  李四

Zrevrand  mysort   0  4  按照范围删除

Zremrangbyscore  mysort   80  100 删除80100之间的分数

范围查找  zrang  mysort  0  -1全部的内容

Zrem  mysort    0  -1 全部

Zrang  mysort   0   -1 withscores   元素对应的分数

Zrangbyscore  mysort  1  100 withscores

zincrby   mysort    3  list   list+3

Zcount   mysort   80   90  统计80 90之间有多少

 

持久化连接

Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为全持久化模式”) 

由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOFappend only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。

二者的区别

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储

二者优缺点

RDB存在哪些优势呢?

1). 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。

2). 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。

3). 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。

4). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

RDB又存在哪些劣势呢?

1). 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。

2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。

AOF的优势有哪些呢?

1). 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。

2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。

3). 如果日志过大,Redis可以自动启用rewrite机制。即Redisappend模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。

4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。

AOF的劣势有哪些呢?

1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。

常用配置

RDB持久化配置

Redis会将数据集的快照dumpdump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:

save 900 1           #900(15分钟)之后,如果至少有1key发生变化,则dump内存快照。

save 300 10         #300(5分钟)之后,如果至少有10key发生变化,则dump内存快照。

save 60 10000      #60(1分钟)之后,如果至少有10000key发生变化,则dump内存快照

 

AOF持久化配置

 

Redis的配置文件中存在三种同步方式,它们分别是:

appendfsync always     #每次有数据修改发生时都会写入AOF文件。选择这个

appendfsync everysec  #每秒钟同步一次,该策略为AOF的缺省策略。

appendfsync no          #从不同步。高效但是数据不会被持久化。

 

Redis 事务

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

  1. 批量操作在发送 EXEC 命令前被放入队列缓存。
  2. 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  3. 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:

1.开始事务。

2.命令入队。

3.执行事务。

指令:

开启事务:multi  exec  discard  

Multi  开启事务

exec执行

discard 回滚

Redis缓存穿透和缓存雪崩以及解决方案

 

缓存穿透

缓存穿透是指查询一个一定不存在的数据,由于缓存不命中,接着查询数据库也无法查询出结果,因此也不会写入到缓存中,这将会导致每个查询都会去请求数据库,造成缓存穿透;

解决方案

布隆过滤

对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;

缓存空对象

当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;

但是这种方法会存在两个问题:

如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;

即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

比较

 

缓存雪崩

缓存雪崩是指,由于缓存层承载着大量请求,有效的保护了存储层,但是如果缓存层由于某些原因整体不能提供服务,于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

解决方案

保证缓存层服务高可用性

即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,比如 Redis Sentinel 和 Redis Cluster 都实现了高可用。

依赖隔离组件为后端限流并降级

在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

数据预热

可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

缓存并发

缓存并发是指,高并发场景下同时大量查询过期的key值、最后查询数据库将缓存结果回写到缓存、造成数据库压力过大

分布式锁

在缓存更新或者过期的情况下,先获取锁,在进行更新或者从数据库中获取数据后,再释放锁,需要一定的时间等待,就可以从缓存中继续获取数据。

Redis高并发的问题

Redis缓存的高性能有目共睹,应用的场景也是非常广泛,但是在高并发的场景下,也会出现问题:缓存击穿、缓存雪崩、缓存和数据一致性,以及今天要谈到的缓存并发竞争。

这里的并发指的是多个redis的client同时set key引起的并发问题。

2.出现并发设置Key的原因

Redis是一种单线程机制的nosql数据库,基于key-value,数据可持久化落盘。由于单线程所以Redis本身并没有锁的概念,多个客户端连接并不存在竞争关系,但是利用jedis等客户端对Redis进行并发访问时会出现问题。

比如:同时有多个子系统去set一个key。这个时候要注意什么呢?

3.举一个例子

多客户端同时并发写一个key,一个key的值是1,本来按顺序修改为2,3,4,最后是4,但是顺序变成了4,3,2,最后变成了2

如何解决redis的并发竞争key问题呢?下面给到2个Redis并发竞争的解决方案。

第一种方案:分布式锁+时间戳

1.整体技术方案

这种情况,主要是准备一个分布式锁,大家去抢锁,抢到锁就做set操作。

加锁的目的实际上就是把并行读写改成串行读写的方式,从而来避免资源竞争。

2.Redis分布式锁的实现

主要用到的redis函数是setnx()

SETNX实现分布式锁

利用SETNX非常简单地实现分布式锁。例如:某客户端要获得一个名字youzhi的锁,客户端使用下面的命令进行获取:

SETNX lock.youzhi<current Unix time + lock timeout + 1>

如返回1,则该客户端获得锁,把lock.youzhi的键值设置为时间值表示该键已被锁定,该客户端最后可以通过DEL lock.foo来释放该锁。

如返回0,表明该锁已被其他客户端取得,这时我们可以先返回或进行重试等对方完成或等待锁超时。

3.时间戳

由于上面举的例子,要求key的操作需要顺序执行,所以需要保存一个时间戳判断set顺序。

系统A key 1 {ValueA 7:00}

系统B key 1 { ValueB 7:05}

假设系统B先抢到锁,将key1设置为{ValueB 7:05}。接下来系统A抢到锁,发现自己的key1的时间戳早于缓存中的时间戳(7:00<7:05),那就不做set操作了。

4.什么是分布式锁

因为传统的加锁的做法(如java的synchronized和Lock)这里没用,只适合单点。因为这是分布式环境,需要的是分布式锁。

当然,分布式锁可以基于很多种方式实现,比如zookeeper、redis等,不管哪种方式实现,基本原理是不变的:用一个状态值表示锁,对锁的占用和释放通过状态值来标识。

第二种方案:利用消息队列

在并发量过大的情况下,可以通过消息中间件进行处理,把并行读写进行串行化。

Redis.set操作放在队列中使其串行化,必须的一个一个执行。

这种方式在一些高并发的场景中算是一种通用的解决方案。

Redis的哨兵机制 或者心跳机制 模式 原理详解

Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器,该系统执行以下三个任务:
监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送    通知。

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

  哨兵(sentinel) 是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossipprotocols)来接收关于Master是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master。
      每个哨兵(sentinel) 会向其它哨兵(sentinel)、master、slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的”主观认为宕机” Subjective Down,简称sdown).
“哨兵群”中的多数sentinel,都报告某一master没响应,系统才认为该master"彻底死亡"(即:客观上的真正down机,Objective Down,简称odown),通过一定的vote算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置。
      虽然哨兵(sentinel) 释出为一个单独的可执行文件 redis-sentinel ,但实际上它只是一个运行在特殊模式下的 Redis 服务器,你可以在启动一个普通 Redis 服务器时通过给定 --sentinel 选项来启动哨兵(sentinel)。

 

 

 

posted on 2020-03-31 17:11  forve  阅读(174)  评论(0)    收藏  举报