zoukankan      html  css  js  c++  java
  • Redis

    第1章 Redis介绍

    1.1Redis是什么

    Redis是一种基于键值对的NoSQL数据库,与很多键值对数据库不同,redis中的值可以有string,hash,list,set,zset,geo等多种数据结构和算法组成.
    因为Redis会将所有的数据都放在内存中,所以他的读写性能非常惊人.
    不仅如此,Redis还可以将内存中的数据利用快照和日志的形式保存到硬盘上
    Redis还提供了键过期,发布订阅,事务,流水线等附加功能.
    

    第2章 Redis的重要特性

    1.1速度快

    Redis所有的数据都存放在内存中
    Redis使用C语言实现
    Redis使用单线程架构
    

    1.2基于键值对的数据结构服务器

    5种数据结构:
    字符串
    哈希
    列表
    集合
    有序集合
    

    1.3丰富的功能

    提供了键过期功能,可以实现缓存
    提供了发布订阅功能,可以实现消息系统
    提供了pipeline功能,客户端可以将一批命令一次性传到Redis,减少了网络开
    

    1.4 简单稳定

    源码很少,3.0版本以后5万行左右.
    使用单线程模型法,使得Redis服务端处理模型变得简单.
    不依赖操作系统的中的类库
    

    1.5客户端语言多

    java,PHP,python,C,C++,Nodejs等
    

    1.6持久化

    2种持久化方案
    1.RDB
    2.AOF
    

    1.7 高可用和分布式

    1.哨兵
    2.集群
    

    第3章 企业缓存产品介绍

    1.1Memcached

    优点:高性能读写、单一数据类型、支持客户端式分布式集群、一致性hash、多核结构、多线程读写性能高。
    缺点:无持久化、节点故障可能出现缓存穿透、分布式需要客户端实现、跨机房数据同步困难、架构扩容复杂度高
    

    1.2 Redis

    优点:
    高性能读写、多数据类型支持、数据持久化、高可用架构、支持自定义虚拟内存、支持分布式分片集群、单线程读写性能极高
    缺点:多线程读写较Memcached慢
    新浪、京东、直播类平台、网页游戏 
    memcache与redis在读写性能的对比
    memcached 适合,多用户访问,每个用户少量的rw
    redis        适合,少用户访问,每个用户大量rw  
    

    1.3 Tair

    优点:高性能读写、支持三种存储引擎(ddb、rdb、ldb)、支持高可用、支持分布式分片集群、支撑了几乎所有淘宝业务的缓存。
    缺点:单机情况下,读写性能较其他两种产品较慢
    

    第4章 Redis应用场景

    1.1 缓存-键过期时间

    缓存session会话
    例如:登录一个网站,登陆以后记录用户名和密码。过几天以后在登录需要重新登录需要在输入用户名和密码
    缓存用户信息,找不到再去mysql查,查到然后回写到redis
    说明:这里不会把MySQL所有的数据写入redis,只会把热点数据写入到redis
    优惠券例子:
    一般优惠卷都有一个时间限制,这个功能就是用redis的键过期时间来实现的
    

    1.2 排行榜-列表&有序集合

    热度排名排行榜
    发布时间排行榜
    

    1.3计数器应用-天然支持计数器

    帖子浏览数
    视频播放次数
    商品浏览数
    

    1.4社交网络-集合

    踩/赞,粉丝,共同好友/喜好,推送,打标签
    案例:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。
    Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,
    对上面的所有集合操作,还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中
    

    1.5消息队列系统-发布订阅

    配合 elk 实现日志收集
    

    第5章 Redis安装部署

    1.1 目录规划

    ##软件目录
    /data
    ##Redis数据目录
    /data/redis_6379
    ##Redis配置文件、日志文件、pid文件目录
    /data/6379/{conf,log,pid}
    

    1.2 第一个里程:创建相应的目录

    mkdir /data/
    mkdir /data/redis_6379
    mkdir  /data/6379/{conf,log,pid} -p
    

    1.3 第二个里程:上传软件并解压

    上传至 /data
    tar xf redis-3.2.12.tar.gz
    mv redis-3.2.12 redis
    

    1.4 第三个里程:编写环境变量

    vim /etc/profile 
    export PATH=/data/redis/src:$PATH
    source /etc/profile 
    

    1.5 第四个里程:安装依赖包

    yum -y install gcc automake autoconf libtool make
    cd /data/redis
    make && make install
    

    1.6 第五个里程:启动并测试

    启动:
    redis-server & 
    连接测试:
    redis-cli 
    127.0.0.1:6379> set num 10
    OK
    127.0.0.1:6379> get num
    10
    

    第6章 配置文件说明

    [root@redis01 ~]# cat /data/6379/conf/redis.conf 
    ### 以守护进程模式启动
    daemonize yes
    ### 绑定的主机地址
    bind 10.0.1.51 127.0.0.1
    ### 监听端口
    port 6379
    ### pid文件和log文件的保存地址
    pidfile /data/6379/pid/redis_6379.pid
    logfile /data/6379/log/redis_6379.log
    ### 设置数据库的数量,默认数据库为0
    databases 16
    ### 指定本地持久化文件的文件名,默认是dump.rdb
    dbfilename redis_6379.rdb
    ### 本地数据库的目录
    dir /data/redis_6379
    ###密码
    requirepass 123
    masterauth 123
    ###是否打开 aof 日志功能
    appendonly yes
    ###每1个命令,都立即同步到 aof
    appendfsync always
    

    第7章 启动====关闭服务

    1.1 启动服务

    redis-server /data/6379/conf/redis.conf
    

    1.2 关闭服务

    redis-cli shutdown
    

    第8章 Redis基本操作命令

    1.1 全局命令

    Redis有5种数据结构,它们是键值对中的值,对于键来说有一些通用的命令

    1.1.1查看所有的键

    keys *
    说明:生产中禁止使用此命令
    

    1.2.2 查看键的总数

    Dbsize 
    # dbsize 命令在计算键总数时不会遍历所有键,而是直接获取Redis内置的键总数变量
    

    1.2.3 检查键是否存在

    Exists key
    # 如果键存在则返回1,不存在则返回0
    

    1.2.4 删除键

    Del key [key …]
    说明:通用命令,无论值是什么数据结构类型,del命令都可以将其删除.
    

    1.2.5 设置键过期时间

    EXPIRE k1 100
    # Redis支持对键添加过期时间,当超过过期时间后,会自动删除键.
    # 通过ttl命令观察键的剩余时间      ===ping的时候后面的那个时间可以看到这个命令
    

    1.2.6 取消过期时间

    PERSIST k1
    状态码:
    0: 表示这个key不存在
    1: 表示这个key存在,并且设置过期时间成功
    

    1.2.7 查看key是否过期

    TTL k1
    状态码:
    -1 :这个key存在,并且永不过期
    -2 :这个key不存在
    N  :这个key存在,并且在N秒后过期	
    过期后的key直接会被删除
    

    1.2.8 查看键的数据类型

    Type key
    

    第9章 各数据类型的应用场景

    1.1 string(字符串)

    应用场景
    session 共享
    常规计数:微博数,粉丝数,订阅、礼物
    key:value
    ----------
    (1)
     set name zhangsan  
    (2)
     MSET id 101 name zhangsan age 20 gender m
     等价于以下操作:
     SET id 101 
     set name zhangsan 
     set age 20 
     set gender m
    (3)计数器
    每点一次关注,都执行以下命令一次
    127.0.0.1:6379> incr num
    显示粉丝数量:
    127.0.0.1:6379> get num
    暗箱操作:
    127.0.0.1:6379> INCRBY num 10000
    (integer) 10006
    127.0.0.1:6379> get num
    "10006"
    127.0.0.1:6379> DECRBY num 10000
    (integer) 6
    127.0.0.1:6379> get num
    "6"
    详细的例子:------------------------------------
    增
    set mykey "test"                为键设置新值,并覆盖原有值
    getset mycounter 0              设置值,取值同时进行
    setex mykey 10 "hello"          设置指定 Key 的过期时间为10秒,在存活时间可以获取value
    setnx mykey "hello"             若该键不存在,则为键设置新值
    mset key3  "zyx"  key4 "xyz"    批量设置键
    删
    del mykey                        删除已有键
    改
    append mykey "hello"            若该键并不存在,返回当前 Value 的长度
                                    该键已经存在,返回追加后 Value的长度
    incr mykey                      值增加1,若该key不存在,创建key,初始值设为0,增加后结果为1
    decrby  mykey  5                值减少5
    setrange mykey 20 dd            把第21和22个字节,替换为dd, 超过value长度,自动补0
    查  
    exists mykey                    判断该键是否存在,存在返回 1,否则返回0
    get mykey                       获取Key对应的value
    strlen mykey                    获取指定 Key 的字符长度
    ttl mykey                       查看一下指定 Key 的剩余存活时间(秒数)
    getrange mykey 1 20             获取第2到第20个字节,若20超过value长度,则截取第2个和后面所有的
    mget key3 key4                  批量获取键
    

    1.2 hash类型(字典类型)

    应用场景:
    存储部分变更的数据,如用户信息等。
    最接近mysql表结构的一种类型
    主要是可以做数据库缓存。
    存数据:
    hmset stu  id 101 name zhangsan age 20 gender m
    hmset stu1 id 102 name zhangsan1 age 21 gender f
    取数据:
    HMGET stu id name age gender
    HMGET stu1 id name age gender
    select concat("hmset city_",id," id ",id," name ",name," countrycode ",countrycode," district ",district," population ",population) from city limit 10 into outfile '/tmp/hmset.txt'
    ---------------------更多的例子
    增
    hset myhash field1 "s"    
    若字段field1不存在,创建该键及与其关联的Hashes, Hashes中,key为field1 ,并设value为s ,若存在会覆盖原value
    hsetnx myhash field1 s    
    若字段field1不存在,创建该键及与其关联的Hashes, Hashes中,key为field1 ,并设value为s, 若字段field1存在,则无效
    hmset myhash field1 "hello" field2 "world       一次性设置多个字段
    删
    hdel myhash field1                      删除 myhash 键中字段名为 field1 的字段
    del myhash                              删除键
    改  
    hincrby myhash field 1                  给field的值加1
    查
    hget myhash field1                      获取键值为 myhash,字段为 field1 的值
    hlen myhash                             获取myhash键的字段数量
    hexists myhash field1                   判断 myhash 键中是否存在字段名为 field1 的字段
    hmget myhash field1 field2 field3       一次性获取多个字段
    hgetall myhash                          返回 myhash 键的所有字段及其值
    hkeys myhash                            获取myhash 键中所有字段的名字
    hvals myhash                            获取 myhash 键中所有字段的值
    

    1.3 LIST(列表)

    应用场景
    消息队列系统
    比如sina微博
    在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。
    但是做了限制不能超过5000个ID,因此获取ID的函数会一直询问Redis。
    只有在start/count参数超出了这个范围的时候,才需要去访问数据库。
    系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。
    SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,
    而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
    微信朋友圈:
    127.0.0.1:6379> LPUSH wechat "today is nice day !"
    127.0.0.1:6379> LPUSH wechat "today is bad day !"
    127.0.0.1:6379> LPUSH wechat "today is good  day !"
    127.0.0.1:6379> LPUSH wechat "today is rainy  day !"
    127.0.0.1:6379> LPUSH wechat "today is friday !"
    [5,4,3,2,1]
     0 1 2 3 4 
    [e,d,c,b,a]
    0 1 2 3  4
    127.0.0.1:6379> lrange wechat  0 0
    1) "today is friday !"
    127.0.0.1:6379> lrange wechat  0 1
    1) "today is friday !"
    2) "today is rainy  day !"
    127.0.0.1:6379> lrange wechat  0 2
    1) "today is friday !"
    2) "today is rainy  day !"
    3) "today is good  day !"
    127.0.0.1:6379> lrange wechat  0 3
    127.0.0.1:6379> lrange wechat  -2 -1
    1) "today is bad day !"
    2) "today is nice day !"
    -----------------
    增 
    lpush mykey a b             若key不存在,创建该键及与其关联的List,依次插入a ,b, 若List类型的key存在,则插入                             value中
    lpushx mykey2 e             若key不存在,此命令无效, 若key存在,则插入value中
    linsert mykey before a a1   在 a 的前面插入新元素 a1
    linsert mykey after e e2    在e 的后面插入新元素 e2
    rpush mykey a b             在链表尾部先插入b,在插入a
    rpushx mykey e              若key存在,在尾部插入e, 若key不存在,则无效
    rpoplpush mykey mykey2      将mykey的尾部元素弹出,再插入到mykey2 的头部(原子性的操作)
    删
    del mykey                   删除已有键 
    lrem mykey 2 a              从头部开始找,按先后顺序,值为a的元素,删除数量为2个,若存在第3个,则不删除
    ltrim mykey 0 2             从头开始,索引为0,1,2的3个元素,其余全部删除
    改
    lset mykey 1 e              从头开始, 将索引为1的元素值,设置为新值 e,若索引越界,则返回错误信息
    rpoplpush mykey mykey       将 mykey 中的尾部元素移到其头部
    查
    lrange mykey 0 -1           取链表中的全部元素,其中0表示第一个元素,-1表示最后一个元素。
    lrange mykey 0 2            从头开始,取索引为0,1,2的元素
    lrange mykey 0 0            从头开始,取第一个元素,从第0个开始,到第0个结束
    lpop mykey                  获取头部元素,并且弹出头部元素,出栈
    lindex mykey 6              从头开始,获取索引为6的元素 若下标越界,则返回nil 
    

    1.4 SET 集合类型(join union)

    应用场景:
    案例:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。
    Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,
    对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
    127.0.0.1:6379> sadd lxl pg1 jnl baoqiang gsy alexsb
    (integer) 5
    127.0.0.1:6379> sadd jnl baoqiang ms bbh yf wxg
    (integer) 5
    127.0.0.1:6379> SUNION lx jnl
    1) "baoqiang"
    2) "yf"
    3) "bbh"
    4) "ms"
    5) "wxg"
    127.0.0.1:6379> SUNION lxl  jnl
    1) "gsy"
    2) "yf"
    3) "alexsb"
    4) "bbh"
    5) "jnl"
    6) "pg1"
    7) "baoqiang"
    8) "ms"
    9) "wxg"
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> SINTER lxl jnl
    1) "baoqiang"
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> SDIFF jnl lxl
    1) "wxg"
    2) "yf"
    3) "bbh"
    4) "ms"
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> 
    127.0.0.1:6379> SDIFF lxl jnl
    1) "jnl"
    2) "pg1"
    3) "gsy"
    4) "alexsb"
    增
    sadd myset a b c  
    若key不存在,创建该键及与其关联的set,依次插入a ,b,若key存在,则插入value中,若a 在myset中已经存在,则插入了 d 和 e 两个新成员。
    删
    spop myset                                  尾部的b被移出,事实上b并不是之前插入的第一个或最后一个成员
    srem myset a d f                            若f不存在, 移出 a、d ,并返回2
    改
    smove myset myset2 a                        将a从 myset 移到 myset2,
    查
    sismember myset a                           判断 a 是否已经存在,返回值为 1 表示存在。
    smembers myset                              查看set中的内容
    scard myset                                 获取Set 集合中元素的数量
    srandmember myset                           随机的返回某一成员
    sdiff myset1 myset2 myset3                  1和2得到一个结果,拿这个集合和3比较,获得每个独有的值
    sdiffstore diffkey myset myset2 myset3      3个集和比较,获取独有的元素,并存入diffkey 关联的Set中
    sinter myset myset2 myset3                  获得3个集合中都有的元素
    sinterstore interkey myset myset2 myset3    把交集存入interkey 关联的Set中
    sunion myset myset2 myset3                  获取3个集合中的成员的并集
    sunionstore unionkey myset myset2 myset3    把并集存入unionkey 关联的Set中
    

    1.5 SortedSet(有序集合)

    应用场景:
    排行榜应用,取TOP N操作
    这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,
    这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,
    每次只需要执行一条ZADD命令即可。
    127.0.0.1:6379> zadd topN 0 smlt 0 fskl 0 fshkl 0 lzlsfs 0 wdhbx 0 wxg 
    (integer) 6
    127.0.0.1:6379> ZINCRBY topN 100000 smlt
    "100000"
    127.0.0.1:6379> ZINCRBY topN 10000 fskl
    "10000"
    127.0.0.1:6379> ZINCRBY topN 1000000 fshkl
    "1000000"
    127.0.0.1:6379> ZINCRBY topN 100 lzlsfs
    "100"
    127.0.0.1:6379> ZINCRBY topN 10 wdhbx
    "10"
    127.0.0.1:6379> ZINCRBY topN 100000000 wxg
    "100000000"
    127.0.0.1:6379> ZREVRANGE topN 0 2 
    1) "wxg"
    2) "fshkl"
    3) "smlt"
    127.0.0.1:6379> ZREVRANGE topN 0 2 withscores
    1) "wxg"
    2) "100000000"
    3) "fshkl"
    4) "1000000"
    5) "smlt"
    6) "100000"
    127.0.0.1:6379> 
    增
    zadd myzset 2 "two" 3 "three"       添加两个分数分别是 2 和 3 的两个成员
    删
    zrem myzset one two                 删除多个成员变量,返回删除的数量
    改
    zincrby myzset 2 one                将成员 one 的分数增加 2,并返回该成员更新后的分数
    查 
    zrange myzset 0 -1 WITHSCORES       返回所有成员和分数,不加WITHSCORES,只返回成员
    zrank myzset one                    获取成员one在Sorted-Set中的位置索引值。0表示第一个位置
    zcard myzset                        获取 myzset 键中成员的数量
    zcount myzset 1 2                   获取分数满足表达式 1 <= score <= 2 的成员的数量
    zscore myzset three                 获取成员 three 的分数
    zrangebyscore myzset  1 2               获取分数满足表达式 1 < score <= 2 的成员
    #-inf 表示第一个成员,+inf最后一个成员
    #limit限制关键字
    #2  3  是索引号
    zrangebyscore myzset -inf +inf limit 2 3  返回索引是2和3的成员
    zremrangebyscore myzset 1 2               删除分数 1<= score <= 2 的成员,并返回实际删除的数量
    zremrangebyrank myzset 0 1                删除位置索引满足表达式 0 <= rank <= 1 的成员
    zrevrange myzset 0 -1 WITHSCORES          按位置索引从高到低,获取所有成员和分数
    #原始成员:位置索引从小到大
          one  0  
          two  1
    #执行顺序:把索引反转
          位置索引:从大到小
          one 1
          two 0
    #输出结果: two  
           one
    zrevrange myzset 1 3                     获取位置索引,为1,2,3的成员
    #相反的顺序:从高到低的顺序
    zrevrangebyscore myzset 3 0              获取分数 3>=score>=0的成员并以相反的顺序输出
    zrevrangebyscore myzset 4 0 limit 1 2    获取索引是1和2的成员,并反转位置索引
    

    第10章 在线修查看和修改配置

    CONFIG GET *
    CONFIG GET requirepass
    CONFIG SET requirepass 123
    说明:redis 支持多次tab键,在线修改的参数,及时生效,但是重启以后,如果配置文件没有修改,还是以配置文件为主,所以,可以在线修改以后,在修改配置文件
    

    第11章 Redis持久化的2种方式

    1.1 RDB 持久化优缺点

    可以在指定的时间间隔内生成数据集的 时间点快照(point-in-time snapshot)。
    优点:速度快,适合于用做备份,主从复制也是基于RDB持久化功能实现的。
    缺点:会有数据丢失
    =====================
    rdb持久化核心配置参数
    vim /data/6379/redis.conf
    dir /data/6379
    dbfilename dump.rdb
    save 900 1      #900秒(15分钟)内有1个更改
    save 300 10     #300秒(5分钟)内有10个更改
    save 60 10000   #60秒内有10000个更改  
    

    1.2 AOF持久化优缺点

    记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 
    AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。
    优点:可以最大程度保证数据不丢
    缺点:日志记录量级比较大
    ========
    AOF持久化配置参数
    appendfilename "redis_6379.aof"
    appendonly yes          #是否打开aof日志功能
    appendfsync always      #每1个命令,都立即同步到aof
    appendfsync everysec    #每秒写1次
    appendfsync no          #写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof
    以上的几种写入方式根据需求选择一种
    

    1.3 redis持久化方式有哪些?有什么区别?

    rdb:基于快照的持久化,速度更快,一般用作备份,主从复制也是依赖于rdb持久化功能
    aof:以追加的方式记录redis操作日志的文件。可以最大程度的保证redis数据安全,类似于mysql的binlog
    

    1.4 特别注意

    1. 2种持久化方式是可以共存的
    2. redis关闭时,会先执行bgsave,然后在关闭,所以,当我们即使执行的操作即使不满足持久化条件,也会把操作记录到磁盘上
    3. 当2种持久共都共存的时候,redis启动时会读取AOF文件
    

    第12章 redis安全配置

    redis默认开启了保护模式,只允许本地回环地址登录并访问数据库。
    禁止protected-mode
    protected-mode yes/no (保护模式,是否只允许本地访问)
    

    (1)Bind :指定IP进行监听

    vim /data/6379/redis.conf
    bind 10.0.0.51  127.0.0.1
    

    (2)增加requirepass {password}

    vim /data/6379/redis.conf
    requirepass 123456
    

    (3)验证

    ----------验证-----
    方法一:
    [root@db03 ~]# redis-cli -a 123456
    127.0.0.1:6379> set name zhangsan 
    OK
    127.0.0.1:6379> exit
    方法二:
    [root@db03 ~]# redis-cli
    127.0.0.1:6379> auth 123456
    OK
    127.0.0.1:6379> set a b
    [root@db01 src]# redis-cli -a 123 -h 10.0.0.51 -p 6379
    10.0.0.51:6379> set b 2
    OK
    

    第13章 Redis主从复制

    1.1 主从介绍

    主从复制介绍
    在分布式系统中为了解决单点问题,通常会把数据复制多个副本到其他机器,满足故障恢复和负载均衡等求.
    Redis也是如此,提供了复制功能.
    复制功能是高可用Redis的基础,后面的哨兵和集群都是在复制的基础上实现高可用的
    

    1.2 Redis主从复制原理

    1. 副本库通过slaveof 10.0.1.51 6379命令,连接主库,并发送SYNC给主库 
    2. 主库收到SYNC,会立即触发BGSAVE,后台保存RDB,发送给副本库
    3. 副本库接收后会应用RDB快照
    4. 主库会陆续将中间产生的新的操作,保存并发送给副本库
    5. 到此,我们主复制集就正常工作了
    6. 再此以后,主库只要发生新的操作,都会以命令传播的形式自动发送给副本库.
    7. 所有复制相关信息,从info信息中都可以查到.即使重启任何节点,它的主从关系依然都在.
    8. 如果发生主从关系断开时,从库数据没有任何损坏,在下次重连之后,从库发送PSYNC给主库
    9. 主库只会将从库缺失部分的数据同步给从库应用,达到快速恢复主从的目的
    

    1.3 主从数据一致性保证

    min-slaves-to-write 1    #至少保证一个从库和主库的数据时一致的
    min-slaves-max-lag  3   #第一个参数会造成主库的阻塞,这个参数就是用来告诉前端应用,后面从库跟不上不要做操作了
    

    1.4 主库是否要开启持久化

    如果不开有可能,主库重启操作,造成所有主从数据丢失!
    说明:如果主库不开持久化,当主库宕机以后,所有数据消失,当再次启动主库时,从库会发送同步的请求,此时主库是没有数据的,由于从库要同步,会把自己所有的数据都删除掉
    如果不开持久化,解决办法:
    不要开启主库,直接让重库替代主库的工作
    

    第14章 主从复制搭建

    1.1 环境准备

    3台机器  一主2从
    Redis01  10.0.1.51   主节点  
    Redis02  10.0.1.52   从节点 
    Redis03  10.0.1.53   从节点
    

    1.2 Redis01配置文件

    [root@redis01 ~]# cat /data/6379/conf/redis.conf 
    ### 以守护进程模式启动
    daemonize yes
    ### 绑定的主机地址
    bind 10.0.1.51 127.0.0.1
    ### 监听端口
    port 6379
    ### pid文件和log文件的保存地址
    pidfile /data/6379/pid/redis_6379.pid
    logfile /data/6379/log/redis_6379.log
    ### 设置数据库的数量,默认数据库为0
    databases 16
    ### 指定本地持久化文件的文件名,默认是dump.rdb
    dbfilename redis_6379.rdb
    ### 本地数据库的目录
    dir /data/redis_6379
    requirepass 123
    masterauth 123
    appendonly yes
    appendfsync always
    

    1.3 Redis02配置文件

    [root@redis02 ~]# cat /data/6379/conf/redis.conf 
    ### 以守护进程模式启动
    daemonize yes
    ### 绑定的主机地址
    bind 10.0.1.52 127.0.0.1
    ### 监听端口
    port 6379
    ### pid文件和log文件的保存地址
    pidfile /data/6379/pid/redis_6379.pid
    logfile /data/6379/log/redis_6379.log
    ### 设置数据库的数量,默认数据库为0
    databases 16
    ### 指定本地持久化文件的文件名,默认是dump.rdb
    dbfilename redis_6379.rdb
    ### 本地数据库的目录
    dir /data/redis_6379
    requirepass 123
    masterauth 123
    appendonly yes
    appendfsync always
    

    1.3 Redis03配置文件

    [root@redis03 ~]# cat /data/6379/conf/redis.conf 
    ### 以守护进程模式启动
    daemonize yes
    ### 绑定的主机地址
    bind 10.0.1.53 127.0.0.1
    ### 监听端口
    port 6379
    ### pid文件和log文件的保存地址
    pidfile /data/6379/pid/redis_6379.pid
    logfile /data/6379/log/redis_6379.log
    ### 设置数据库的数量,默认数据库为0
    databases 16
    ### 指定本地持久化文件的文件名,默认是dump.rdb
    dbfilename redis_6379.rdb
    ### 本地数据库的目录
    dir /data/redis_6379
    requirepass 123
    masterauth 123
    appendonly yes
    appendfsync always
    

    1.4 构建主从

    在从库执行命令
    [root@redis02 ~]# redis-cli -p 6379 -a 123 SLAVEOF 10.0.1.51 6379
    [root@redis03 ~]# redis-cli -p 6379 -a 123 SLAVEOF 10.0.1.51 6379
    这种只是在命令行构建了,如果从库重启,主库的数据还是不能同步过来,所以要写入配置文件
    

    1.5 测试主从否搭建成功

    主库执行
    10.0.1.51:6379> set k1 v1
    OK
    从库Redis01查看
    10.0.1.52:6379> get k1
    "v1"
    从库Redis02查看
    10.0.1.53:6379> get k1
    "v1"
    查询主从状态
     redis-cli -h 10.0.1.51 -a 123 info replication
     redis-cli -h 10.0.1.52 -a 123 info replication
     redis-cli -h 10.0.1.53 -a 123 info replication
    

    1.6 断开复制

    Slaveof 命令不但可以建立复制,还可以在从节点执行 slaveof no one 来断开与主节点复制关系
    

    断开复制主要流程:

    1.断开与主节点复制关系
    2.从节点晋升为主节点
    从节点断开复制后不会抛弃原有数据,只是无法再获取主节点上的数据变化.
    通过 slaveof 命令还可以实现切主操作,所谓切主是指把当前从节点对主节点的复制切换到另一个主节点.
    执行 slaveof {newMasterIp} {newMasterPort}命令即可.
    

    切主操作流程如下:

    1.断开与旧主节点的复制关系
    2.与新主节点建立复制关系
    3.删除从节点当前所有数据
    4.对新主节点进行复制操作
    提示: 线上操作一定要小心,因为切主后会清空之前所有的数据.
    

    1.7 主从的缺点

    a)主从复制,若主节点出现问题,则不能提供服务,需要人工修改配置将从变主
    b)主从复制主节点的写能力单机,能力有限
    c)单机节点的存储能力也有限
    

    1.8 主从故障如何故障转移

    a)主节点(master)故障,从节点slave-1端执行 slaveof no one后变成新主节点;
    b)其它的节点成为新主节点的从节点,并从新节点复制数据;
    c)需要人工干预,无法实现高可用。
    

    第15章 Redis哨兵机制(Sentinel)

    1.1 为什么需要哨兵机制

    哨兵机制的出现是为了解决主从复制的缺点的
    

    1.2 哨兵机制的原理

    当主节点出现故障时,由Redis Sentinel自动完成故障发现和转移,并通知应用方,实现高可用性。
    哨兵之间的信息是共享的
    

    1.3 哨兵机制部署

    1.3.1 Redis01创建目录

    mkdir /data/26379/{conf,log,pid} -p
    

    1.3.2 Redis01 哨兵配置文件

    vim /data/26379/conf/redis_26379.conf
    bind 10.0.1.51
    port 26379
    daemonize yes
    logfile /data/26379/log/redis_26379.log
    dir /data/26379
    sentinel monitor mymaster 10.0.1.51 6379 2 
    sentinel down-after-milliseconds mymaster 3000
    sentinel parallel-syncs mymaster 1
    sentinel failover-timeout mymaster 18000
    sentinel auth-pass mymaster 123 
    

    1.3.3 Redis02创建目录

    mkdir /data/26379/{conf,log,pid} -p
    

    1.3.4 Redis02 哨兵配置文件

    vim /data/26379/conf/redis_26379.conf
    bind 10.0.1.52
    port 26379
    daemonize yes
    logfile /data/26379/log/redis_26379.log
    dir /data/26379
    sentinel monitor mymaster 10.0.1.51 6379 2 
    sentinel down-after-milliseconds mymaster 3000
    sentinel parallel-syncs mymaster 1
    sentinel failover-timeout mymaster 18000
    sentinel auth-pass mymaster 123 
    

    1.3.5 Redis03创建目录

    mkdir /data/26379/{conf,log,pid} -p
    

    1.3.6 Redis03哨兵配置文件

    vim /data/26379/conf/redis_26379.conf
    bind 10.0.1.53
    port 26379
    daemonize yes
    logfile /data/26379/log/redis_26379.log
    dir /data/26379
    sentinel monitor mymaster 10.0.1.51 6379 2 
    sentinel down-after-milliseconds mymaster 3000
    sentinel parallel-syncs mymaster 1
    sentinel failover-timeout mymaster 18000
    sentinel auth-pass mymaster 123 
    

    1.4 启动所有的单节点

    redis-server /data/6379/conf/redis.conf
    

    1.5 配置主从复制

    redis-cli -h 10.0.1.52 -a 123 slaveof 10.0.1.51 6379   #Redis02上执行
    redis-cli -h 10.0.1.53 -a 123 slaveof 10.0.1.51 6379   #Redis03上执行
    

    1.6 启动哨兵(每台机器都要执行)

    redis-sentinel /data/26379/conf/redis_26379.conf
    

    1.7 配置哨兵的机制的时候注意的坑

    如果主从的时候设置了密码,在配置哨兵机制的配置文件的时候一定要把密码这一行写进去,如果不写,检查进程的时候虽然显示哨兵模式是成功了,但是去哨兵的配置文件里面查看发现,哨兵模式并没有起到作用
    sentinel auth-pass mymaster 123 
    

    1.8 Sentinel管理命令

    redis-cli -p 26380
    PING :返回 PONG 。
    SENTINEL masters :列出所有被监视的主服务器
    SENTINEL slaves <master name> 
    SENTINEL get-master-addr-by-name <master name> : 返回给定名字的主服务器的 IP 地址和端口号。 
    SENTINEL reset <pattern> : 重置所有名字和给定模式 pattern 相匹配的主服务器。 
    SENTINEL failover <master name> : 当主服务器失效时, 在不询问其他 Sentinel 意见的情况下, 强制开始一次自动故障迁移。
    

    1.9 哨兵配置文件说明

    sentinel monitor mymaster 10.0.0.51 6379 2
    #mymaster 主节点别名 主节点 ip 和端口,判断主节点失败,两个 sentinel 节点同意
    sentinel down-after-milliseconds mymaster 30000
    #选项指定了 Sentinel 认为服务器已经断线所需的毫秒数。
    sentinel parallel-syncs mymaster 1
    #向新的主节点发起复制操作的从节点个数,1 轮询发起复制
    sentinel failover-timeout mymaster 180000
    #故障转移超时时间
    

    第16章 Redis 事务

    1.1 Redis事务和MySQL事务的区别

    redis的事务是基于队列实现的。
    mysql的事务是基于事务日志和锁机制实现的。
    redis是乐观锁机制。
    

    1.2 开启事务功能(multi)

    multi 
    command1      
    command2
    command3
    command4
    exec 
    discard
    4条语句作为一个组,并没有真正执行,而是被放入同一队列中。
    如果,这是执行discard,会直接丢弃队列中所有的命令,而不是做回滚。
    exec
    当执行exec时,对列中所有操作,要么全成功要么全失败
    MySQL开启事务时,是已经在内存中执行了,当我们提交时只是做了一个持久化的过程,而Redis开启事务时,是放在队列中并没有执行,所以就没有所谓的回滚动作,只要把这个队列干掉就可以了discard
    127.0.0.1:6379> set a b
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set a b
    QUEUED
    127.0.0.1:6379> set c d
    QUEUED
    127.0.0.1:6379> exec
    1) OK
    2) OK
    

    1.3 防止多个并发修改键值对

    因为Redis是没有锁的,为了防止多个并把修改同一个键值对时,开启事务的时候,我们可以先执行watch来防止多个并发修改同一个键值对的现象
    

    第17章 redis cluster(集群)

    1.1 高性能

    1、在多分片节点中,将16384个槽位,均匀分布到多个分片节点中
    2、存数据时,将key做crc16(key),然后和16384进行取模,得出槽位值(0-16383之间)
    3、根据计算得出的槽位值,找到相对应的分片节点的主节点,存储到相应槽位上
    4、如果客户端当时连接的节点不是将来要存储的分片节点,分片集群会将客户端连接切换至真正存储节点进行数据存储
    

    1.2 高可用

    在搭建集群时,会为每一个分片的主节点,对应一个从节点,实现slaveof的功能,同时当主节点down,实现类似于sentinel的自动failover的功能。
    1、redis会有多组分片构成
    2、redis cluster 使用固定个数的slot存储数据(一共16384slot)
    3、每组分片分得1/3 slot个数(0-5500  5501-11000  11001-16383)
    4、基于CRC16(key) % 16384 ====》值 (槽位号)。
    

    1.3 集群拓扑

    不太合理的集群拓扑

    合理的集群拓扑

    第18章 手动搭建部署集群

    1.1 搭建规划

    Redis01
    IP:10.0.1.51 Port:6380 主节点
    IP:10.0.1.51 Port:6381 从节点
    Redis02
    IP:10.0.1.52 Port:6380 主节点
    IP:10.0.1.52 Port:6381 从节点
    Redis03
    IP:10.0.1.53 Port:6380 主节点
    IP:10.0.1.53 Port:6381 从节点
    

    1.2 Redis01操作

    创建相应的目录

    mkdir /data01/{6380,6381}/{conf,log,pid} -p
    mkdir /data01/redis_{6380,6381} -p
    

    编写配置文件

    ===redis01 6380节点配置文件===
    vim /data01/6380/conf/redis_6380.conf
    bind 10.0.1.51
    port 6380
    daemonize yes
    pidfile "/data01/6380/pid/redis_6380.pid"
    logfile "/data01/6380/log/redis_6380.log"
    dbfilename "redis_6380.rdb"
    dir "/data01/redis_6380/"
    cluster-enabled yes
    cluster-config-file nodes_6380.conf
    cluster-node-timeout 15000
    ===Redis01 6381节点配置文件===
    vim /data01/6381/conf/redis_6381.conf
    bind 10.0.1.51
    port 6381
    daemonize yes
    pidfile "/data01/6381/pid/redis_6381.pid"
    logfile "/data01/6381/log/redis_6381.log"
    dbfilename "redis_6381.rdb"
    dir "/data01/redis_6381/"
    cluster-enabled yes
    cluster-config-file nodes_6381.conf
    cluster-node-timeout 15000
    

    1.3 Redis02操作

    创建相应的目录

    mkdir /data01/{6380,6381}/{conf,log,pid} -p
    mkdir /data01/redis_{6380,6381} -p
    

    编写配置文件

    ====redis02 6380节点配置文件===
    vim /data01/6380/conf/redis_6380.conf
    bind 10.0.1.52
    port 6380
    daemonize yes
    pidfile "/data01/6380/pid/redis_6380.pid"
    logfile "/data01/6380/log/redis_6380.log"
    dbfilename "redis_6380.rdb"
    dir "/data01/redis_6380/"
    cluster-enabled yes
    cluster-config-file nodes_6380.conf
    cluster-node-timeout 15000
    ===Redis02 6381节点配置文件===
    vim /data01/6381/conf/redis_6381.conf
    bind 10.0.1.52
    port 6381
    daemonize yes
    pidfile "/data01/6381/pid/redis_6381.pid"
    logfile "/data01/6381/log/redis_6381.log"
    dbfilename "redis_6381.rdb"
    dir "/data01/redis_6381/"
    cluster-enabled yes
    cluster-config-file nodes_6381.conf
    cluster-node-timeout 15000
    

    1.3 Redis03操作

    创建相应的目录

    mkdir /data01/{6380,6381}/{conf,log,pid} -p
    mkdir /data01/redis_{6380,6381} -p
    

    编写配置文件

    ====redis03 6380节点配置文件===
    vim /data01/6380/conf/redis_6380.conf
    bind 10.0.1.53
    port 6380
    daemonize yes
    pidfile "/data01/6380/pid/redis_6380.pid"
    logfile "/data01/6380/log/redis_6380.log"
    dbfilename "redis_6380.rdb"
    dir "/data01/redis_6380/"
    cluster-enabled yes
    cluster-config-file nodes_6380.conf
    cluster-node-timeout 15000
    ===Redis03 6381节点配置文件===
    vim /data01/6381/conf/redis_6381.conf
    bind 10.0.1.53
    port 6381
    daemonize yes
    pidfile "/data01/6381/pid/redis_6381.pid"
    logfile "/data01/6381/log/redis_6381.log"
    dbfilename "redis_6381.rdb"
    dir "/data01/redis_6381/"
    cluster-enabled yes
    cluster-config-file nodes_6381.conf
    cluster-node-timeout 15000
    

    1.4 启动节点

    Redis01 节点启动

    redis-server /data01/6380/conf/redis_6380.conf
    redis-server /data01/6381/conf/redis_6381.conf
    

    Redis02 节点启动

    redis-server /data01/6380/conf/redis_6380.conf
    redis-server /data01/6381/conf/redis_6381.conf
    

    Redis03 节点启动

    redis-server /data01/6380/conf/redis_6380.conf
    redis-server /data01/6381/conf/redis_6381.conf
    

    第19章 手动配置节点发现

    当把所有节点都启动后查看进程会有cluster的字样

    [root@redis01 ~]# ps -ef |grep redis
    root       1820      1  0 18:13 ?        00:00:00 redis-server 10.0.1.51:6380 [cluster]
    root       1824      1  0 18:13 ?        00:00:00 redis-server 10.0.1.51:6381 [cluster]
    root       1830   1515  0 18:14 pts/0    00:00:00 grep --color=auto redis
    

    但是登录后执行CLUSTER NODES命令会发现只有每个节点自己的ID,目前集群内的节点
    还没有互相发现,所以搭建redis集群我们第一步要做的就是让集群内的节点互相发现.

    [root@redis01 ~]# redis-cli -h 10.0.1.51 -p 6380
    10.0.1.51:6380> CLUSTER NODES
    eccbaf676277feecc3e75a7ca29090f8e5e461c8 :6380 myself,master - 0 0 0 connected
    

    在执行节点发现命令之前我们先查看一下集群的数据目录会发现有生成集群的配置文件

    [root@redis01 ~]# tree /data01/redis_638*
    /data01/redis_6380
    └── nodes_6380.conf
    /data01/redis_6381
    └── nodes_6381.conf
    0 directories, 2 files
    

    查看后发现只有自己的节点内容,等节点全部发现后会把所发现的节点ID写入这个文件

    [root@redis01 ~]# redis-cli -h 10.0.1.51 -p 6380
    10.0.1.51:6380> CLUSTER NODES
    eccbaf676277feecc3e75a7ca29090f8e5e461c8 :6380 myself,master - 0 0 0 connected
    

    集群模式的Redis除了原有的配置文件之外又加了一份集群配置文件.当集群内节点
    信息发生变化,如添加节点,节点下线,故障转移等.节点会自动保存集群状态到配置文件.
    需要注意的是,Redis自动维护集群配置文件,不需要手动修改,防止节点重启时产生错乱.
    节点发现使用命令: CLUSTER MEET {IP} {PORT}
    提示:在集群内任意一台机器执行此命令就可以

    [root@redis01 ~]# redis-cli -h 10.0.1.51 -p 6380
    10.0.1.51:6380> CLUSTER MEET 10.0.1.51 6381
    OK
    10.0.1.51:6380> CLUSTER MEET 10.0.1.52 6380
    OK
    10.0.1.51:6380> CLUSTER MEET 10.0.1.52 6381
    OK
    10.0.1.51:6380> CLUSTER MEET 10.0.1.53 6380
    OK
    10.0.1.51:6380> CLUSTER MEET 10.0.1.53 6381
    OK
    10.0.1.51:6380> CLUSTER NODES
    7b4122be963abeaecddc48f01543050595a18327 10.0.1.52:6380 master - 0 1573468326901 2 connected
    eccbaf676277feecc3e75a7ca29090f8e5e461c8 10.0.1.51:6380 myself,master - 0 0 1 connected
    598961fc65e2f8709c2cc6096e7b798c00b184e9 10.0.1.52:6381 master - 0 1573468328926 3 connected
    58855c95540fe1e85635f726a64d05d240740ef4 10.0.1.53:6381 master - 0 1573468325792 5 connected
    1d3c375341990acef7a58ed53e42a3ef612323ce 10.0.1.53:6380 master - 0 1573468327912 4 connected
    fac810474c90c0f533ab4bbcbf64af80a1383980 10.0.1.51:6381 master - 0 1573468324877 0 connected
    

    节点都发现完毕后我们再次查看集群配置文件
    可以看到,发现到的节点的 ID 也被写入到了集群的配置文件里

    [root@redis01 ~]# cat /data01/redis_6380/nodes_6380.conf 
    7b4122be963abeaecddc48f01543050595a18327 10.0.1.52:6380 master - 0 1573468326901 2 connected
    eccbaf676277feecc3e75a7ca29090f8e5e461c8 10.0.1.51:6380 myself,master - 0 0 1 connected
    598961fc65e2f8709c2cc6096e7b798c00b184e9 10.0.1.52:6381 master - 0 1573468325890 3 connected
    58855c95540fe1e85635f726a64d05d240740ef4 10.0.1.53:6381 master - 0 1573468325792 5 connected
    1d3c375341990acef7a58ed53e42a3ef612323ce 10.0.1.53:6380 master - 0 1573468327912 4 connected
    fac810474c90c0f533ab4bbcbf64af80a1383980 10.0.1.51:6381 master - 0 1573468324877 0 connected
    vars currentEpoch 5 lastVoteEpoch 0
    

    第20章 Redis Cluster 通讯流程

    在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责哪些数据,是否出现故障灯状态信息,redis 集群采用 Gossip(流言)协议,Gossip 协议工作原理就是节点彼此不断交换信息,一段时间后所有的节点都会知道集群完整信息,这种方式类似流言传播。

    1.1 通信过程

    1)集群中的每一个节点都会单独开辟一个 Tcp 通道,用于节点之间彼此通信,通信端口在基础端口上加10000.
    2)每个节点在固定周期内通过特定规则选择结构节点发送 ping 消息
    3)接收到 ping 消息的节点用 pong 消息作为响应。集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终他们会打成一致的状态,当节点出现故障,新节点加入,主从角色变化等,它能够给不断的ping/pong消息,从而达到同步目的
    

    1.2 通讯消息类型

    Gossip

    Gossip 协议职责就是信息交换,信息交换的载体就是节点间彼此发送Gossip 消息。
    常见 Gossip 消息分为:ping、 pong、 meet、 fail 等
    

    meet

    meet 消息:用于通知新节点加入,消息发送者通知接受者加入到当前集群,meet 消息通信正常完成后,接收节点会加入到集群中并进行ping、 pong 消息交换
    

    ping

    ping 消息:集群内交换最频繁的消息,集群内每个节点每秒想多个其他节点发送 ping 消息,用于检测节点是否在线和交换彼此信息。
    

    pong

    Pong 消息:当接收到 ping,meet 消息时,作为相应消息回复给发送方确认消息正常通信,节点也可以向集群内广播自身的 pong 消息来通知整个集群对自身状态进行更新。
    

    fail

    fail 消息:当节点判定集群内另一个节点下线时,回向集群内广播一个fail 消息,其他节点收到 fail 消息之后把对应节点更新为下线状态。
    

    1.3 通讯示意图

    第21章 Redis Cluster手动分配槽位

    虽然节点之间已经互相发现了,但是此时集群还是不可用的状态,因为并没有给节点分配槽位,而且必须是所有的槽位都分配完毕后整个集群才是可用的状态.
    反之,也就是说只要有一个槽位没有分配,那么整个集群就是不可用的
    测试命令

    10.0.1.51:6380> set k1 1
    (error) CLUSTERDOWN Hash slot not served
    10.0.1.51:6380> CLUSTER info
    cluster_state:fail                    #这里是fail表示集群有问题
    cluster_slots_assigned:0
    cluster_slots_ok:0
    cluster_slots_pfail:0
    cluster_slots_fail:0
    cluster_known_nodes:6
    cluster_size:0
    cluster_current_epoch:5
    cluster_my_epoch:1
    cluster_stats_messages_sent:2030
    cluster_stats_messages_received:2030
    

    我们虽然有6个节点,但是真正负责数据写入的只有3个节点,其它3个节点只是作为主节点的从节点,也就是说,只需要分配其中三个节点的槽位就可以了

    1.1 分配槽位的方法

    redis的槽位总共是16384个即0~16383===官方指定

    分配槽位需要在每个主节点上来配置,此时有2种方法执行:
    1.分别登录到每个主节点的客户端来执行命令
    2.在其中一台机器上用redis客户端远程登录到其他机器的主节点上执行命令
    

    在redis-01执行命令(redis可以远程登录到其它机器,这里就是在一台机器上做的操作)

    [root@db01 ~]# redis-cli -h 10.0.1.51 -p 6380 cluster addslots {0..5461}
    OK
    [root@db01 ~]# redis-cli -h 10.0.1.52 -p 6380 cluster addslots {5462..10922}
    OK
    [root@db01 ~]# redis-cli -h 10.0.1.53 -p 6380 cluster addslots {10923..16383}
    OK
    

    第22章 手动配置集群高可用

    虽然这时候集群是可用的了,但是整个集群只要有一台机器坏掉了,那么整个集群都是不可用的.
    所以这时候需要用到其他三个节点分别作为现在三个主节点的从节点,以应对集群主节点故障时可以进行自动切换以保证集群持续可用.
    注意

    1.不要让复制节点复制本机器的主节点, 因为如果那样的话机器挂了集群还是不可用状态, 所以复制节点要复制其他服务器的主节点.
    2.使用redis-trid工具自动分配的时候会出现复制节点和主节点在同一台机器上的情况,需要注意
    

    1.1 构建主从关系

    登录查看节点

    [root@redis02 ~]# redis-cli -h 10.0.1.51 -p 6380
    10.0.1.51:6380> CLUSTER nodes
    eccbaf676277feecc3e75a7ca29090f8e5e461c8 10.0.1.51:6380
    7b4122be963abeaecddc48f01543050595a18327 10.0.1.52:6380 
    1d3c375341990acef7a58ed53e42a3ef612323ce 10.0.1.53:6380 
    

    创建复制关系

    redis-cli -h 10.0.1.51 -p 6381 CLUSTER REPLICATE 7b4122be963abeaecddc48f01543050595a18327
    redis-cli -h 10.0.1.52 -p 6381 CLUSTER REPLICATE 1d3c375341990acef7a58ed53e42a3ef612323ce
    redis-cli -h 10.0.1.53 -p 6381 CLUSTER REPLICATE eccbaf676277feecc3e75a7ca29090f8e5e461c8
    

    注意ID不要搞混了,对应关系为
    51 的从节点对应 52的主节点
    52的从节点对应53的主节点
    53的从节点对应51的主节点

    1.2 Redis Cluster测试集群

    使用常规插入redis数据的方式往集群里写入数据看看会发生什么

    10.0.1.51:6380> set k1 1
    (error) MOVED 12706 10.0.1.53:6380
    

    结果提示error, 但是给出了集群另一个节点的地址
    那么这条数据到底有没有写入呢? 我们登录这两个节点分别查看

    [root@redis03 ~]# redis-cli -h 10.0.1.53 -p 6380 get k1
    (nil)
    

    结果没有,这是因为使用集群后由于数据被分片了,所以并不是说在那台机器上写入数据就会在哪台机器的节点上写入,集群的数据写入和读取就涉及到了另外一个概念,ASK路由

    第23章 Redis Cluster ASK路由介绍

    在集群模式下,Redis接受任何键相关命令时首先会计算键对应的槽,再根据槽找出所对应的节点
    如果节点是自身,则处理键命令;
    否则回复MOVED重定向错误,通知客户端请求正确的节点,这个过程称为Mover重定向
    示意图如下:

    知道了ask路由后,我们使用-c选项批量插入一些数据

    [root@redis01 ~]# cat input_key.sh 
    #!/bin/bash
    for i in $(seq 1 1000)
    do
        redis-cli -c -h 10.0.1.51 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok"
    done
    

    写入后我们同样使用-c选项来读取刚才插入的键值,然后查看下redis会不会帮我们路由到正确的节点上

    0.0.1.51:6380> 
    [root@redis01 ~]# redis-cli -h 10.0.1.51 -p 6380 -c
    10.0.1.51:6380> get k_2
    -> Redirected to slot [8970] located at 10.0.1.52:6380
    "v_2"
    

    由此可以看出-c选项就会帮我们执行了要去跳转到另一台机器执行

    第24章 使用工具搭建部署Redis Cluster

    手动搭建集群便于理解集群创建的流程和细节,不过手动搭建集群需要很多步骤,当集群节点众多时,必然会加大搭建集群的复杂度和运维成本,因此官方提供了 redis-trib.rb的工具方便我们快速搭建集群。
    redis-trib.rb是采用 Ruby 实现的 redis 集群管理工具,内部通过 Cluster相关命令帮我们简化集群创建、检查、槽迁移和均衡等常见运维操作,使用前要安装 ruby 依赖环境

    1.1 安装ruby 依赖环境

    Redis01上操作

    yum makecache fast
    yum install rubygems -y
    gem sources --remove https://rubygems.org/           #移除国外的源
    gem sources -a http://mirrors.aliyun.com/rubygems/   #替换成国内的源 
    gem update - system
    gem install redis -v 3.3.5
    

    1.2 Redis01操作

    创建相应的目录

    mkdir /data02/{6380,6381}/{conf,log,pid} -p
    mkdir /data02/redis_{6380,6381} -p
    

    编写配置文件

    ===redis01 6380节点配置文件===
    vim /data02/6380/conf/redis_6380.conf
    bind 10.0.1.51
    port 6380
    daemonize yes
    pidfile "/data02/6380/pid/redis_6380.pid"
    logfile "/data02/6380/log/redis_6380.log"
    dbfilename "redis_6380.rdb"
    dir "/data02/redis_6380/"
    cluster-enabled yes
    cluster-config-file nodes_6380.conf
    cluster-node-timeout 5000
    
    ===Redis01 6381节点配置文件===
    vim /data02/6381/conf/redis_6381.conf
    bind 10.0.1.51
    port 6381
    daemonize yes
    pidfile "/data02/6381/pid/redis_6381.pid"
    logfile "/data02/6381/log/redis_6381.log"
    dbfilename "redis_6381.rdb"
    dir "/data02/redis_6381/"
    cluster-enabled yes
    cluster-config-file nodes_6381.conf
    cluster-node-timeout 5000
    

    1.3 Redis02操作

    创建相应的目录

    mkdir /data02/{6380,6381}/{conf,log,pid} -p
    mkdir /data02/redis_{6380,6381} -p
    

    编写配置文件

    ===redis02 6380节点配置文件===
    vim /data02/6380/conf/redis_6380.conf
    bind 10.0.1.52
    port 6380
    daemonize yes
    pidfile "/data02/6380/pid/redis_6380.pid"
    logfile "/data02/6380/log/redis_6380.log"
    dbfilename "redis_6380.rdb"
    dir "/data02/redis_6380/"
    cluster-enabled yes
    cluster-config-file nodes_6380.conf
    cluster-node-timeout 5000
    
    ===Redis02 6381节点配置文件===
    vim /data02/6381/conf/redis_6381.conf
    bind 10.0.1.52
    port 6381
    daemonize yes
    pidfile "/data02/6381/pid/redis_6381.pid"
    logfile "/data02/6381/log/redis_6381.log"
    dbfilename "redis_6381.rdb"
    dir "/data02/redis_6381/"
    cluster-enabled yes
    cluster-config-file nodes_6381.conf
    cluster-node-timeout 5000
    

    1.4 Redis03操作

    创建相应的目录

    mkdir /data02/{6380,6381}/{conf,log,pid} -p
    mkdir /data02/redis_{6380,6381} -p
    

    编写配置文件

    ===redis03 6380节点配置文件===
    vim /data02/6380/conf/redis_6380.conf
    bind 10.0.1.53
    port 6380
    daemonize yes
    pidfile "/data02/6380/pid/redis_6380.pid"
    logfile "/data02/6380/log/redis_6380.log"
    dbfilename "redis_6380.rdb"
    dir "/data02/redis_6380/"
    cluster-enabled yes
    cluster-config-file nodes_6380.conf
    cluster-node-timeout 5000
    ===Redis03 6381节点配置文件===
    vim /data02/6381/conf/redis_6381.conf
    bind 10.0.1.53
    port 6381
    daemonize yes
    pidfile "/data02/6381/pid/redis_6381.pid"
    logfile "/data02/6381/log/redis_6381.log"
    dbfilename "redis_6381.rdb"
    dir "/data02/redis_6381/"
    cluster-enabled yes
    cluster-config-file nodes_6381.conf
    cluster-node-timeout 5000
    

    1.5 启动节点

    Redis01节点启动

    redis-server /data02/6380/conf/redis_6380.conf
    redis-server /data02/6381/conf/redis_6381.conf
    

    Redis02节点启动

    redis-server /data02/6380/conf/redis_6380.conf
    redis-server /data02/6381/conf/redis_6381.conf
    

    Redis03节点启动

    redis-server /data02/6380/conf/redis_6380.conf
    redis-server /data02/6381/conf/redis_6381.conf
    

    1.6redis-01执行创建集群命令(用工具部署集群,一定要在安装Ruby的节点执行)

    [root@redis01 ~]# cd /data/redis/src
    [root@redis01 /data/redis/src]#./redis-trib.rb create --replicas 1 10.0.1.51:6380 10.0.1.52:6380 10.0.1.53:6380 10.0.1.51:6381 10.0.1.52:6381 10.0.1.53:6381
    此命令解释
    1:表示每个主节点只有一个从节点
    节点排放顺序:主节点放在前面,从节点放在后面,工具会自动识别后面的为从节点
    

    1.7工具部署集群注意事项

    当工具执行完创建集群的命令,会出现如下的
    >>> Creating cluster
    >>> Performing hash slots allocation on 6 nodes...
    Using 3 masters:
    10.0.1.51:6380
    10.0.1.52:6380
    10.0.1.53:6380
    Adding replica 10.0.1.52:6381 to 10.0.1.51:6380
    Adding replica 10.0.1.51:6381 to 10.0.1.52:6380
    Adding replica 10.0.1.53:6381 to 10.0.1.53:6380
    M: 11b084fec199c4a518acb2cfb148c0435d6fa051 10.0.1.51:6380
       slots:0-5460 (5461 slots) master
    M: 4b0dab8162081dcc251560a86901c31441ff1327 10.0.1.52:6380
       slots:5461-10922 (5462 slots) master
    M: f7948fdd025db5646553b81bb83cbf873c2d7f25 10.0.1.53:6380
       slots:10923-16383 (5461 slots) master
    S: 8c055a244d395c5b475a2c5c842f6b5c8ff2aaa9 10.0.1.51:6381
       replicates 4b0dab8162081dcc251560a86901c31441ff1327
    S: cc866db9404f454acb43973f776b296df549c6de 10.0.1.52:6381
       replicates 11b084fec199c4a518acb2cfb148c0435d6fa051
    S: b7e1159f4ba9d485d3a93838b0d01e3987ae51b1 10.0.1.53:6381
       replicates f7948fdd025db5646553b81bb83cbf873c2d7f25
    Can I set the above configuration? (type 'yes' to accept): yes
    ======此时的对应关系为=====
    51从节点====52主节点
    52从节点====51主节点
    53是相互复制
    这种关系不是我们想要的,我们需要手动调整(可以理解这个是此工具的BUG一定要注意)
    

    1.8手动调整节点的复制关系

    redis-02 从节点节点执行

    10.0.1.52:6381> CLUSTER REPLICATE f7948fdd025db5646553b81bb83cbf873c2d7f25
    OK
    把Redis02的从节点改为复制Redis01的主节点
    

    redis-03 从节点节点执行

    10.0.1.53:6381> CLUSTER REPLICATE 11b084fec199c4a518acb2cfb148c0435d6fa051
    OK
    

    1.9 检查集群完整性

    [root@redis01 /data/redis/src]#  ./redis-trib.rb check 10.0.1.51:6380
    >>> Performing Cluster Check (using node 10.0.1.51:6380)
    M: 11b084fec199c4a518acb2cfb148c0435d6fa051 10.0.1.51:6380
       slots:0-5460 (5461 slots) master
       1 additional replica(s)
    S: 8c055a244d395c5b475a2c5c842f6b5c8ff2aaa9 10.0.1.51:6381
       slots: (0 slots) slave
       replicates 4b0dab8162081dcc251560a86901c31441ff1327
    M: f7948fdd025db5646553b81bb83cbf873c2d7f25 10.0.1.53:6380
       slots:10923-16383 (5461 slots) master
       1 additional replica(s)
    S: b7e1159f4ba9d485d3a93838b0d01e3987ae51b1 10.0.1.53:6381
       slots: (0 slots) slave
       replicates 11b084fec199c4a518acb2cfb148c0435d6fa051
    S: cc866db9404f454acb43973f776b296df549c6de 10.0.1.52:6381
       slots: (0 slots) slave
       replicates f7948fdd025db5646553b81bb83cbf873c2d7f25
    M: 4b0dab8162081dcc251560a86901c31441ff1327 10.0.1.52:6380
       slots:5461-10922 (5462 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.
    =======此时的对应关系为========
    51从节点====》52主节点
    52从节点====》53主节点
    53从节点====》51主节点
    这种对应关系正是我们想要的
    

    1.10 集群状态查看

    集群主节点状态
    redis-cli -h 10.0.1.51 -p 6380 cluster nodes | grep master
    集群从节点状态
    redis-cli -h 10.0.1.51 -p 6380 cluster nodes | grep slave
    

    第25章 工具扩容节点

    1.1 Redis集群的扩容操作可分为以下几个步骤

    1.准备新节点
    2.加入集群
    3.迁移槽和数据
    

    1.2 第一个里程:准备新节点

    Redis01上增加2个节点 :6390 主节点,6391从节点
    创建相应的目录

    mkdir /data02/{6390,6391}/{conf,log,pid} -p
    mkdir /data02/redis_{6390,6391} -p
    

    编写配置文件

    ===redis01 6390节点配置文件===
    vim /data02/6390/conf/redis_6390.conf
    bind 10.0.1.51
    port 6390
    daemonize yes
    pidfile "/data02/6390/pid/redis_6390.pid"
    logfile "/data02/6390/log/redis_6390.log"
    dbfilename "redis_6390.rdb"
    dir "/data02/redis_6390/"
    cluster-enabled yes
    cluster-config-file nodes_6390.conf
    cluster-node-timeout 5000
    ===Redis01 6391节点配置文件===
    vim /data02/6391/conf/redis_6391.conf
    bind 10.0.1.51
    port 6391
    daemonize yes
    pidfile "/data02/6391/pid/redis_6391.pid"
    logfile "/data02/6391/log/redis_6391.log"
    dbfilename "redis_6391.rdb"
    dir "/data02/redis_6391/"
    cluster-enabled yes
    cluster-config-file nodes_6391.conf
    cluster-node-timeout 5000
    

    1.3 第二个里程:启动节点

    redis-server /data02/6390/conf/redis_6390.conf
    redis-server /data02/6391/conf/redis_6391.conf
    

    1.4第三个里程:使用工具发现节点

    cd /data/redis/src/
    ./redis-trib.rb add-node 10.0.1.51:6390 10.0.1.51:6380
    说明:把节点加入到集群的地址,后面的这个地址可以是任意一个节点,因为redis集群是共享的
    

    1.5 第四个里程:在redis-01上使用工具扩容

    cd /data/redis/src/
    ./redis-trib.rb reshard 10.0.1.51:6380
    

    打印出进群每个节点信息后,reshard命令需要确认迁移的槽数量,这里我们输入4096个

    How many slots do you want to move (from 1 to 16384)? 4096
    

    输入6390的节点ID作为目标节点,也就是要扩容的节点,目标节点只能指定一个

    What is the receiving node ID? fb66ecc680fc419eefcfdf6393e44e655534d86f
    

    之后输入源节点的ID,这里分别输入每个主节点的6380的ID最后输入done,或者直接输入all

    Source node #1:all	
    迁移完成后命令会自动退出,这时候我们查看一下集群的状态
    ./redis-trib.rb rebalance 10.0.1.51:6380
    

    1.6添加一个从节点

    redis-trib.rb add-node --slave --master-id fb66ecc680fc419eefcfdf6393e44e655534d86f 10.0.1.51:6391
    10.0.1.51:6380
    

    致此,新的节点加入集群成功,只需重新构建复制关系即可

    第26章 工具收缩节点

    1.1 流程说明

    1).首先需要确定下线节点是否有负责的槽,
    如果是,需要把槽迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性.
    2).当下线节点不再负责槽或者本身是从节点时,
    就可以通知集群内其他节点忘记下线节点,当所有的节点忘记该节点后可以正常关闭.
    这里我们准备将刚才新添加的节点下线,也就是6390和6391
    收缩和扩容迁移的方向相反,6390变为源节点,其他节点变为目标节点,源节点把自己负责的4096个槽均匀的迁移到其他节点上,
    由于redis-trib..rb reshard命令只能有一个目标节点,因此需要执行3次reshard命令,分别迁移1365,1365,1366个槽.
    

    1.2 将需要删除节点slot移动走

    cd /data/redis/src/
    ./redis-trib.rb reshard 10.0.1.51:6380
    How many slots do you want to move (from 1 to 16384)? 1365
    输入6380的id
    输入6390的id
    done
    注意:最后的槽位数量要看一下要抛出的节点还有多少个槽位
    

    1.3 忘记节点

    由于我们的集群是做了高可用的,所以当主节点下线的时候从节点也会顶上,所以最好我们先下线从节点,然后在下线主节点
    cd /data/redis/src/
    ./redis-trib.rb del-node 10.0.1.51:6391 ID
    ./redis-trib.rb del-node 10.0.1.51:6390 ID
    

    第27章 redis的多API支持

    以python为例子

    yum install -y python36 
    python3 -V
    yum install -y python36-pip
    pip3 install redis 
    pip3 install redis-py-cluster
    

    1.1 对redis的单实例进行连接操作

    启动节点

    redis-server /data/6379/conf/redis.conf
    

    python连接

    [root@redis01 ~]# python
    Python 2.7.5 (default, Aug  4 2017, 00:39:18) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> inport redis    #把redis的包导入进去(刚才下载的安装包)
    >>> r = redis.StrictRedis(host='10.0.1.51', port=6379, db=0,password='123') #定义一个变量给r
    >>> r.set('oldgirl', 'oldguo')                            #直接调用变量
    True
    >>> r.get('oldgirl')
    b'oldguo'
    

    1.2 sentinel(哨兵)集群连接并操作

    启动Redis-sentinel集群

    redis-sentinel /data/26379/redis_26379.conf
    

    python连接操作

    [root@redis01 ~]# python3
    Python 3.6.8 (default, Aug  7 2019, 17:28:10) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from redis.sentinel import Sentinel  # 导入redis sentinel包
    >>> sentinel = Sentinel([('10.0.1.51', 26379)], socket_timeout=0.1)  # 指定sentinel的地址和端口号
    >>> sentinel.discover_master('mymaster')     ##测试,获取主库信息
    >>> sentinel.discover_slaves('mymaster')     ##测试,获取从库信息
    

    配置读写分离(主库用来承担写的职责,从库用来承担读的职责)

    ##定义写节点 (相当于定义一个变量给master,用的时候直接调用即可)
    >>> master = sentinel.master_for('mymaster', socket_timeout=0.1,password="123")
    ##定义读节点 (相当于定义一个变量给slave,用的时候直接调用即可)
    >>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1,password="123") 
    ####读写测试### 
    >>> master.set('oldboy', '123')  
    >>> slave.get('oldboy')  
    

    1.3 python连接rediscluster集群测试

    使用
    python3
    >>> from rediscluster import StrictRedisCluster  
    >>> startup_nodes = [{"host":"10.0.1.51", "port": "6380"},{"host":"10.0.1.52", "port": "6380"},{"host":"10.0.1.53", "port": "6380"}]  #把IP地址和端口放入一个地址池里面,由驱动自己去转发 从节点往后加即可 
    ### Note: decode_responses must be set to True when used with python3  
    >>> rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)  
    >>> rc.set("foo", "bar")  
    True  
    >>> print(rc.get("foo"))  
    'bar'
    

    第28章 数据导入导出工具

    需求背景
    刚切换到redis集群的时候肯定会面临数据导入的问题,所以这里推荐使用redis-migrate-tool工具来导入单节点数据到集群里
    官方地址

    https://www.oschina.net/p/redis-migrate-tool
    

    1.1 第一个里程:安装工具 Redis-Migrate-Tool

    mkdir /app  #软件安装目录    
    cd /app
    git clone https://github.com/vipshop/redis-migrate-tool.git
    cd redis-migrate-tool/
    autoreconf -fvi
    ./configure
    make && make install 
    

    1.2 第二个里程:创建配置文件

    [root@redis01 ~]# cat /app/redis_6379_to_6380.conf    
    [source]
    type: single
    servers:
    - 10.0.1.51:6379
    [target]
    type: redis cluster
    servers:
    - 10.0.1.51:6380 
    [common]
    listen: 0.0.0.0:8888
    source_safe: true
    

    1.3 第三个里程:生成测试数据

    [root@redis01 ~]# cat input_key1.sh 
    #!/bin/bash
    for i in $(seq 1 1000)
    do
        redis-cli -c -h 10.0.1.51 -a 123 -p 6379 set k_${i} v_${i} && echo "set k_${i} is ok"
    done
    

    1.4 第四个里程:导入数据

    [root@redis01 ~]# redis-migrate-tool -c redis_6379_to_6380.conf 
    

    1.5 第五个里程:数据校验

    [root@redis01 ~]# redis-migrate-tool -c /app/redis_6379_to_6380.conf -C redis_check
    

    第29章 分析键值大小

    需求背景
    redis的内存使用太大键值太多,不知道哪些键值占用的容量比较大,而且在线分析会影响性能.

    1.1 第一个里程:安装工具

    yum install python-pip gcc python-devel 
    cd /app
    git clone https://github.com/sripathikrishnan/redis-rdb-tools
    cd redis-rdb-tools
    python setup.py install
    

    1.2 第二个里程:使用该工具的方法

    cd /data/redis_6379/
    rdb -c memory redis_6380.rdb -f redis_6380.rdb.csv
    把rdb文件导出为csv格式   #csv格式和excel是差不多的
    

    1.3 第三个里程:分析rdb文件

    awk -F ',' '{print $4,$2,$3,$1}' redis_6380.rdb.csv |sort  > 6380.txt
    

    第30章 Redis运维脚本

    [root@db01 ~]# cat redis_shell.sh 
    #!/bin/bash
    USAG(){
        echo "sh $0 {start|stop|restart|login|ps|tail} PORT"
    }
    if [ "$#" = 1 ]
    then
        REDIS_PORT='6379'
    elif 
        [ "$#" = 2 -a -z "$(echo "$2"|sed 's#[0-9]##g')" ]
    then
        REDIS_PORT="$2"
    else
        USAG
        exit 0
    fi
    
    REDIS_IP=$(hostname -I|awk '{print $1}')
    PATH_DIR=/opt/redis_cluster/redis_${REDIS_PORT}/
    PATH_CONF=/opt/redis_cluster/redis_${REDIS_PORT}/conf/redis_${REDIS_PORT}.conf
    PATH_LOG=/opt/redis_cluster/redis_${REDIS_PORT}/logs/redis_${REDIS_PORT}.log
    CMD_START(){
        redis-server ${PATH_CONF}
    }
    CMD_SHUTDOWN(){
        redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT} shutdown
    }
    CMD_LOGIN(){
        redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT}
    }
    CMD_PS(){
        ps -ef|grep redis
    }
    CMD_TAIL(){
        tail -f ${PATH_LOG}
    }
    case $1 in
        start)
            CMD_START
            CMD_PS
            ;;
        stop)
            CMD_SHUTDOWN
            CMD_PS
            ;;
        restart)
            CMD_START
            CMD_SHUTDOWN
            CMD_PS
            ;;
        login)
            CMD_LOGIN
            ;;
        ps)
            CMD_PS
            ;;
        tail)
            CMD_TAIL
            ;;
        *)
            USAG
    esac
    
    学习的进阶之路
  • 相关阅读:
    彻底清除Linux centos minerd木马 实战  跟redis的设置有关
    linux 弹出光驱失败
    teamviewer "TeamViewer Daemon is not running
    linux 如何查找io的进程
    网站开启https后加密协议始终是TLS1.0如何配置成TLS1.2?
    查看openssl的版本
    https单向认证和双向认证
    pem转换成der
    locate: can not open `/var/lib/mlocate/mlocate.db': No such file or directory
    mysql 有报错  ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists
  • 原文地址:https://www.cnblogs.com/yufenchi/p/12820745.html
Copyright © 2011-2022 走看看