redis 学习笔记

  1. 结构图

  2. redis通用命令

    1. keys             #时间复杂度o(n) 查询所有的key

    2.  Exists key   #时间复杂度o(1)判断key是否存在

    3. DBsize          #时间复杂度o(1)  判断redis的大小

    4. Expire           #设置过期时间  stt 查询过期时间,presite 去掉过期时间

  3. string 命令

    1. Get                               #获取key’对应的value
    2. Set  set  key  value     #设置key value的值, 不管key是否存在都设置
    3. setnx  key                   #不存在才设置
    4. Set key value xx        #存在才设置,相当于更新操作
    5. Del                              #删除key
    6. 整形操作的api

      1.incr    #key自增1,如果key不存在,自增后get(key)=1

      2.decr   #key自减1,如果key不存在,自减后get(key)=-1

      3.incrby  #key自增k,如果key不存在,自增后get(key)=k

      4.decrby  #key自减k,如果key不存在,自减后get(key)=-k

      3.批量操作命令

      1. mget  key1 key2 key3                                     #批量获取key 原子操作

      2.mset ket1 value1 key2 value2 key3 value3...... #批量设置key value

       

      Getset  key newvalue   #给key设置一个新的value 返回旧的值

      Append key value          #将vlaue值追加到旧的value后面

      Strlen key                       #返回字符串的长度(注意中文(中文占用字节不同,所以返回)) 时间复杂度为o(1) 在字符串内部维护一个长度,不需要计算

    7.  

       

      Incrbyfloat key 3.5               #浮点数的自增,自减的话传负值

       

      Getrange   key start end     #获取字符串指定下标的所有值

      Setrange  key index value   #设置指定下标所对应新的值

  4.  hash 命令

    1. Hget                  #获取hash key  对应的field的value值
    2. Hset                   #设置hash key  对应的field的value值
    3. Hdel                    #删除hash key  对应的field的value值
    4. Hexists  key field    #判断hash key是否存在field
    5. Hlen key             #获取 hash key field的数量
    6. Hmget key field1 field2 field3 field4.....    #获取hash key的 一批field的值   O(N)

      Hmset key field1 value1 field2 value2 field3 values3 field4 values4.。。#设置一批field的value值O(N)

      Hgetall  key          #返回所有的key  对应的field 和value值 O(N)

      Hvals key              #返回所有的key 对应的value值 O(N)

      Hkeys key            #返回key对应的field O(N)

      Hsetnx  key field   value  #不存在才设置

      Hincrby key field    #自增

      hincrbyFloat key  field floatcount   #自增浮点型数据

  5. 列表list 命令

    1. rpush key value1 value2 value3              #从列表右插入值o(1-n) rpush list c b a  c b a
    2. lpush key value1 value2 value3               #从列表左插入值o(1-n) lpush list c b a  a b c
    3. Linsert key  before | after value newValue  #在list指定的值前|后插入value  o(n)
    4. Lpop key                                                       #从左边弹出一个元素 o(1)
    5. Rpop key                                                      #从右边弹出一个元素 o(1)
    6. Lrem  key count value                                   #根据count的值删除所有value相等的值 o(n)
      1. 当count>0 从左到右删除最多count个value相等的项

        当count<0 从右到左删除最多count个value相等的项

        当count=0 删除所有value相等的项

    7. ltrim key start end                                   #按照索引范围修剪列表
    8. Lrange key start  end                             #(包含end) 获取列表指定范围的所有项
    9. Lindex  key index                                     #获取列表指定索引的项
    10. Llen key                                                  #获取列表长度(列表内部维护长度,不用遍历去算)
    11. Lset key index newvalue                        #设置列表指定索引的值
    12. Blpop key timeout                                   #左边弹出阻塞版本 timeout为超时时间,timeout=0为永不阻塞
    13. Brpop key timeout                                   #右边弹出阻塞版本 timeout为超时时间,timeout=0为永不阻塞
    14. Lpush + lpop                                              #=stack栈(相当于栈) 先进后出
    15. Lpush+ rpop                                               #=queue 队列(相当于队列)
    16. Lpush+ltrim                                               #=固定大小的列表
    17. Lpush+brpop                                            #=消息队列
  6.  集合set 命令

    1. 集合内的操作命令(时间复杂度o(1))

      1.sadd key element                            #向集合内添加元素(如果元素存在则添加失败)

      2.srem key element                              #删除集合中的元素

      3.scard  key                                          #计算集合的大小

      4.sismember key element                    #判断element  是否在元素中存在

      5.srandmember key count                  #从集合中随机挑选count个元素(元素没消失)

      6.smember                                             #获取结婚中的所有元素(元素无序的)

      7.spop                                                    #从集合中随机弹出一个元素(元素已经消失)

       

    2. 集合间的操作命令(时间复杂度o(1))
      1. sdiff  key1 key2                                 #差集
      2. Sinter  key1 key2                               #交集
      3. Sunion key1 key2                              #并集
      4. Sdiff|Sinter|Sunion +store key           #将集合结果保存到key中,方便后面使用
  7. 有序集合zset 命令

    1. 集合内的操作命令(时间复杂度o(1))

      1.zadd key score element       #(可以是多对) 向集合中添加score和element  score可以重复   o(log n)

      2.zrem key element                 #删除一个元素(可以是多个)

      3.zscore  key element             #获取元素分数

      4.zincrby key score element    #增加或减少元素的分数

      5.zcard key                                 #返回集合元素的总个数

      6.zrank key element                  #获取元素的排名

      7.zrange key start end  (withscores) # 根据一定范围遍历  升序排列(根据分值)

      9.zrangebyscore key mixscore maxscore withscores   # 返回指定分数范围内的升序元素(根据分值)

      10.zcount key  minscore maxscore                     #返回有序集合内在指定分数范围内的个数

      11.zremrangebyrank key  start end                       #删除指定排名内的升序元素

      12.zremrangescore key  minscore maxscore      # 删除指定分数内的升序元素

      13.zrevrank                   #获取集合元素 降序排名

      14.zrevrange                  #获取集合元素 降序

       

      2.集合操作

      1. Zunionstore            #取并集
      2. Zinterstore              #取交集
  8. Java通过jdes链接redis的2中方式

    1. jedis直连
      1. public class RedisTest {

         

            public static void main(String[] args) {

                Jedis jedis = null;

                try {

                    jedis = new Jedis("192.168.253.129", 6379);

                    System.out.println(jedis.ping());

                } catch (Exception e) {

                    e.printStackTrace();

                } finally {

                    if (jedis != null) {

                        jedis.close();

                    }

                }

            }

        }

    2. 连接池链接
      1. public class RedisTest {

         

            public static void main(String[] args) {

                GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

                poolConfig.setMaxTotal(50);

                poolConfig.setMaxIdle(50);

                poolConfig.setMaxWaitMillis(1000);

                JedisPool jedisPool = new JedisPool(poolConfig, "192.168.253.129", 6379);

                Jedis jedis = null;

                try {

                    jedis = jedisPool.getResource();

                    for (int i = 0; i < 10; i++) {

                        Pipeline pipeline = jedis.pipelined();

                        for (int j = i * 1000; j < (i + 1) * 1000; j++) {

                            pipeline.hset("hashkey" + j, "field" + j, "value" + j);

                        }

                        pipeline.syncAndReturnAll();

                    }

                } catch (Exception e) {

                    e.printStackTrace();

                } finally {

                    if (jedis != null) {

                        jedis.close();

                    }

                }

            }

        }

  9. 慢查询

    1. 生命周期
      1. 发送命令----排队等待(单线程)----执行命令------返回结果
      2. 说明:1.慢查询发生在生命周期第三阶段(执行命令阶段)

        2.客户端超时不一定是慢查询,慢查询是客户端超时的一 种可能

    2. 两个配置
      1. slowlog-max-len(队列长度  list)    
        1. 慢查询是一个先进先出的队列(第三步)

          是固定长度

          是保存在内存中的(断电重启会丢失,重置了)

      2. slowlog-max-slower-than慢查询阀值(单位:微秒)
        1. 当查询时间在什么时间内,将他定义为慢查询

          slowlog-max-slower-than=0 记录所有命令(通常没意义)

          查询确切的执行时间时用该命令

          slowlog-max-slower-than<0不记录任何命令

    3. 配置方法
      1. config get slowlog-max-len=128
      2. config get slowlog-max-slower-than=10000  10毫秒
        1. 在第一次配置时,修改配置文件,然后重启电脑

    4. 动态配置
      1. config get slowlog-max-len=128

        config get slowlog-max-slower-than=10000  10毫秒

    5. 慢查询命令
      1. slowlog get[n]: 获取慢查询队列  (有多少个队列)
      2. Slowlog len :获取慢查询队列长度  (有多少在排队)
      3. Slowlog reset: 清空慢查询队列  
    6. 使用经验
      1. config get slowlog-max-len=?  不要设置过小,默认128,通常设置为1000

        config get slowlog-max-slower-than=10000  不要设置过大,默认10ms,设置为1ms

        定期持久化慢查询到数据库

  10. pipeline流水线功能

    1. 解释:将批量操作打包,按顺序执行-返回

      1次pipeline(n条命令)=1次请求时间+n次命令时间

      注意:redis命令执行时间时微秒级别

      Pipeline每次条数要控制(网络时间比较长)

      Pipeline的操作是非原子性的,在service 是将多个拆分成小的命令执行的,返回的结果是顺序的。

      1.Jedis-对pipeline的支持

       JedisPool jedisPool = new JedisPool("192.168.1.9", 6379);

              /* 操作Redis */

              Jedis jedis = null;

              try {

                  jedis = jedisPool.getResource();

                  Pipeline p = jedis.pipelined();

                  /* 插入多条数据 */

                  for(Integer i = 0; i < 100000; i++) {

                      p.set(i.toString(), i.toString());

                  }

      }

    2. 建议
      1. 注意每次使用pipeline 携带的数量(不要太多)
      2. pipeline 每次只能作用在一个redis的节点上
      3. 批量操作和pipeline的区别(原子和非原子)
  11. 发布订阅

    1. api命令
      1. publish  channel(频道)  message     #发布-- 发布一个信息到频道,返回订阅者的个数
      2. subscride [channel ]                         #订阅  --一个或多个,收到订阅的消息  
      3. unsubscride [channel ]                    # 取消订阅--一个或多个
  12. Bitmap--位图

    1. Redis可以直接操作位

    2. Api
      1. setbit  key  offset(偏移量:下标:第几个数)  value(只能是0和1)         #给位图指定索引设置值
      2. Setbit  key  offset             #获取位图指定索引的值
      3. Bitcount  key [start end]     #获取位图指定范围(start end 单位为字节,如果不指定就是获取全部)位值为1的个数
  13. Hyperloglog 极小空间完成独立数量统计,本质还是字符串

    1. Api
      1. Pfadd key element [element......]         #向htperloglog添加元素,可以多个

        pfcount key[key......]                           #计算htperloglog的独立总数

        Pfmerge destkey sourcekey [sourcekey...]      #合并多个htperloglog

    2. 使用经验
      1. 是否能容忍错误(错误率0.81%),是否需要单条数据(不能取出单条数据)

  14. Geo,地理信息定位,存储经纬度,计算两地距离,范围计算等等

    1. Api
      1. Geoadd  key longitude(精度) latitude(纬度) member(可以是地名)  [longitude latitude member]    #增加地理位置

        Geopos  key member [member...]              #获取地理位置信息

        Geodist  key member 1 member 2            #获取两个地理位置的距离(unit) m米,km 千米,mi 英里,ft 英尺

    2. 使用
      1. Type geokey                 #=zset  geo是使用zset实现的

        Zrem  key member           #没有删除api,可以用zset的api删除

  15. redis持久化的取舍和选择

    1. 持久化:redis所有的数据保存在内存中,对数据的更新将异步的保存到磁盘上。
  16. redis持久化RDB

    1. RDB就是redis将内存的数据以快照的方式保存到硬盘上rdb(二进制文件),当断电重启时,读取rdb文件来恢复redis缓存。
    2. 同时我们的主从复制也可以用这种方式--是一种复制媒介
    3. 触发机制--三种方式:生成rdb文件的方式
      1. save命令:同步命令,需要排队吗,是阻塞的
        1. 文件策略:存在老的rdb文件,新的替换老文件

      2. Bgsave命令:异步命令,执行完返回ok,在后台单独启动线程执行。
      3. 自动:在某些条件达到的时候自动触发:可以自己设置
        1. Save 900  1   达成条件执行 900秒更新1条数据执行rdb

          Save 300  10达成条件执行 300秒更新10条数据执行rdb

          Save 60 10000达成条件执行60秒更新10000条数据执行rdb

      4. 常用配置以及默认值,名称

        1. Dbfinename dump.rdb         #rdb文件名称,执行时生成的默认文件名称

          Dir ./文件地址

        2. Stop-writes-on-bgsave-error   yes   #这个参数设置为yes,保存rdb出现错误是否停止写入

        3. Rdbcompression  yes     #是否采用压缩格式保存,默认也是压缩

        4. Rdbchecksum  yes         #对文件检验

          1. 最佳配置:

            通常用 dump-${prot}.rdb         #dump加端口号来命名 ,文件的命名格式

            Dir /自定义地址

            Stop-writes-on-bgsave-error yes

            Rdbcompression  yes

            Rdbchecksum  yes

    4. 触发方式
      1. 全量复制--没设置也生成rdb文件 主从复制生成

      2. debug  reload 这种方式会生成rdb文件

      3. shutdown 会生成rdb

  17. redis持久化AOF

    1. 什么是aop:日志文件,执行一条命令就在aof中记录这条命令,格式是按照aof的格式保存,基本上是实时的。

    2. 三种策略:aof 配置的三种属性
      1. always          #redis--写入缓存---(每条命令都写入)再写入磁盘(aof文件中) 确定io开销大
      2. Everyset       #redis--写入缓存---(每秒写入)再写入磁盘(aof文件中)有可能丢失一秒的数据,默认1秒,可配置
      3. No                #redis--写入缓存---(根据操作系统决定(我们不管))再写入磁盘(aof文件中)    不可控
    3. Aop重写:就是把过期的,重复的,可优化的命令重写
      1. 好处:减少硬盘占用量,加快恢复速度

      2. 实现的两种方式:

        1. Bgrewriteaof        #开子线程重写,将内存的数据重写
        2. Aof重写配置:提供两个配置实现aof自动重写
          1. 配置名:

            auto-aof-rewrite-min-size  aof文件重写需要的尺寸(当文件多大时才需要重写文件)

            Auto-aof-rewrite-percentage  aof文件增长率(比如aof100兆,下一次重写100%,就是200兆时重写)

          2. 统计名:

            aof-current-size  aof当前尺寸(单位字节)

            Aof-base-size  aof上次启动和重写的尺寸(单位字节)

          3. 自动触发机制:

            aof-current-size >auto-aof-rewrite-min-size

            aof-current-size ---减去--Aof-base-size/Aof-base-size >Auto-aof-rewrite-percentage

        3. 配置
          1. appendonly  yes    #表示使用aof功能(默认no)
          2. Appendfilename  appendonly-${prot}.aof  #文件名称
          3. Appendfsync  everyset   #每秒写入一次aof
          4. Dir /文件地址
          5. No-Appendfsync-on-rewrite  yes  #重写时 是否要做,不做
          6. Aof-load-truncated      #aof文件有错误,是否忽略错误
          7. Auto-aof-rewrite-percentage  100  #增长率
          8. auto-aof-rewrite-min-size   64mb   #大小
        4. rdb最佳策略

          1.“关”  关掉rdb(全量复制需要用到,关不掉)

          2.集中管理,  大量数据的操作有用

        5. aof最佳策略

          1. “开”:主要是缓存和存储

          2. aof重写集中管理.

          3. 选择everysed 策略

  18. 常规操作的问题

    1. fork 操作
      1. 同步操作

        与内存量息息相关;内存越大,耗时越久

        Info:latest_fork_usec  查询上次fork的时间

    2. 改善:

      1. 使用高效支持fork的物理机或者虚拟技术
      2. 控制redis实例最大可用内存:maxmmory
      3. 合理分配linux内存分配策略:vm.overcommit_memory=1  默认为0
      4. 降低fork的频率
    3. 子进程开销和优化
      1. cpu开销,Rdb和aof文件的生成,属于cpu密集型开销
      2. 优化:不做cpu绑定,不要把进程和一个cpu绑定,不和cpu密集型(多业务)部署在一起
    4. 内存:Fork内存开销 copy_on_werite
    5. 硬盘:Rdb和aof 写入硬盘的开销,
      1. 优化:不和高负载程序部署到一起
    6. aof阻塞定位
      1. 命令的方式:Info persistence
      2. 结果:aof_delayed_fsync:100   (100)是每次的结果累加,不能知道具体的是哪一次

  19. Redis复制的原理和优化

    1. 作用:将数据备份,主节点怠机,从节点继续提供服务,扩展读的性能(读写分离)

    2. 主从复制:一主一从,一主多从

      1. 一个master可以有多个slave

      2.  

        一个slave只有一个master

        数据流向是单向的,从master流向slave

         

    3. 主从复制的配置:两种方式

      1. Slave  ip地址 端口号 如:slave192.160.0.1 6379      该命令:清空以前的所有数据,复制命令是异步的。

        Slave no one  断开复制,注意:不会清空以前的数据

      2. 配置:在启动之前配置  slave ip port    Slave-read-only  yes  只做读的操作
      3. redis的runid:每次启动都会随机生成一个id,作为redis的标识,关闭就没了。
      4. 复制偏移量:
      5. 全量复制:用bgsave,生成可rdb文件,生成rdb文件形成期间的写命令的文件---清空从节点数据然后复制rdb文件,和写命令文件,同步成从节点的数据。

      6. 部分复制:从节点将runid和偏移量传给主节点,然后主节点在buffer判断偏移量是否在buffer期间,在的话,就将偏移量之后的数据同步到从节点。
      7. 故障处理: master 怠机,和slave怠机
    4. 开发运维遇见的问题:

      1. 读写分离:将流量分摊到从节点
        1. 读到过期数据(3.2已解决)
        2. 从节点故障
        3. 问题:
          1. 复制数据的延迟
          2. 读到过期数据(3.2版本已解决)
          3. 从节点故障
      2. 配置不一致:
        1. maxmemory 不一致:丢失数据

        2. 数据结构优化参数()导致内存不一致

      3. 规避全量复制:

        1. 第一次全量复制(无可避免) 避免方法:memory 设置小一点

        2. 配置复制时间-在夜间,低峰期的时候做复制

      4. 节点runid不匹配:

        1. 主节点重启(runid发生变化)

        2. 故障转移如:哨兵或者集群

      5. 复制积压缓存区不足:

        1. 缓冲区太小,无法满足部分复制

        2. 增大缓冲区配置:rel_backlog_size

      6. 规避复制风暴:

        1. 主节点重启,从节点复制-----解决:更改拓扑结构

        2. 单机器复制风暴:解决:将master部署在多个机器
  20. Redis sentienl

    1. 架构:

      1.  

        客户端 从sentienl 获取master和slave 而不关心真正的master和slave。

         

    2. 故障转移:

      1. 首先多个sentienl选出一个sentienl老大,让他来执行,然后将其中一个slave变成master,其他的slave来连接,如果原来的master好了,就将它变成slave。同时sentienl也会告知客户端该链接谁,每套sentienl可以监控多套 master-slave 可通过 master-name配置。

    3. Sentienl的主要配置:

      1. port ${port}    端口

      2. dir /opt/soft/redis/data   工作目录

      3. logfile ”${port}.log”   日志文件

      4. sentienl monitor  mymaster 192.168.0.1 7000 2   设置sentienl,2表示几个sentienl发现故障了才处理

      5. sentienl down-after-milliseconds  mymaster 30000    确认master故障时间

      6. sentienl parallel-syncs-mymaster 1  复制是并行的,1表示一次只有一个

      7. sentienl failover-timeout mymaster 180000  故障转移时间

    4. 客户端实现高可用:

      1. 流程:获取所有的Sentienl 节点集合,找到一个可以链接的节点,获取master的端口和地址(Sentienl 内部是通过发布订阅的模式实现的),然后重新链接。

      2. Jedis实现:

        jSentinelPool=new JedisSentinelPool(masterName,set(节点list),gPoolConfig);

    5. 三个定时任务:

      1. 每10秒Sentienl 对master和slave做info操作,发现slave节点,并确认主从信息。

      2. 每2秒Sentienl 通过master节点的channel交换信息(pub/sub发布订阅),通过_Sentienl_:hello交换频道信息
        1. 对节点的看法和自身的信息,来达到一个共识。

      3. 每隔1秒 Sentienl 对其他Sentienl 和redis执行ping的操作对后面的故障检测做基础。
      4. 主观下线: 每个Sentienl节点对redis节点失败的偏见:规定时间内Sentienl 单个节点的失败

        客观下线:所有Sentienl 对redis节点的失败打成共识(超过设置的个数)

    6. 领导者选举:
      1. 通过Sentienl  is-master-down-by-addr命令都希望成为领导者。

      2. 每个做主观下线的Sentienl向其他Sentienl 发送命令,希望自己成为领导者
      3. 收到命令得Sentienl ,如果没有同意其他Sentienl 的命令,则同意否则拒绝。

      4. 如果Sentienl 节点发现自己的票数已经超过节点集合的半数且超过quorum(设置((节点数/2)+1)) ,那么他就成为领导者
      5. 如果多个Sentienl 成为领导者,则重新选举。
    7. 故障转移:
      1. 从slave节点选择一个合适的slave节点成为新的master节点

      2. 对上面选出的slave节点执行slaveof no one 命令使其成为新的额master节点
      3. 向剩余的slave节点发送命令,让他们成为新的master节点的slave节点,并复制规则和parallel-syncs参数设置
      4. 将原master设置成slave,并保持对他的关注,当该节点恢复后,让他去复制新的master的数据
    8. 选择合适的slave节点:
      1. 选择slave-priority(优先级高)最高的节点,有就返回,没有就继续。

      2. 选择偏移量更大的节点(偏移量大,数据越完整),存在返回,不存在继续。

      3. 选择runid最小的slave节点(启动最早的节点)

  21. Redis cluster

    1. Redis cluster 集群:

      1. Cluster特性:主从复制,高可用的,分片的

      2. 数据分区:顺序分区和哈希分区

    2. 哈希分区主要有:

      1. 节点取余法(hash(key)%nodes)
        1. 优点:数据分布均匀,支持批量操作
        2. 缺点:节点伸缩(增加减少节点),80%的数据发生偏移

          优化:多倍扩容(双倍扩容迁移率50%左右)依次递减

      2. 一致性哈希算法:
        1. 有一个圆的闭环是token(0-2)32次方,每个key顺时针去找离他最近的节点存储。客服端分片
        2. 优点:数据伸缩(添加节点) 数据偏移少,只影响邻近节点,是取余算法的优化

          缺点:不能将数据迁移到新节点

          优化:翻倍扩容(负载均衡)

      3. 虚拟槽算法:
        1. 优点:

          缺点:

          优化:

          节点:cluster-enabled  yes   是否以集群来操作

          Meet:  meet操作让所有节点共享消息

    3. 两种安装方式:原生命令得安装(理解架构),官方工具安装rudy

      1. 原生命令安装:

        1. 配置开启节点
          1. Port ${port}   设置端口

            Daemonize yes   是否以守护进程的方式启动

            Dir /路径

            Dbfinename dump-${[port}.rdb  设置rdb文件的名称

            Logfine ${port}.log  设置日志文件的名称

            cluster-enabled  yes  是cluster节点(和普通的节点区分)

            Cluster-config-file  nodes-${port}.conf  添加cluster的配置文件

            Redis-server  nodes-${port}.conf   启动

        2. 节点的主要配置:

          1. cluster-enabled  yes  是cluster节点(和普通的节点区分)

            Cluster-node-timeout 15000(毫秒)故障转移,节点超时

            Cluster-config-file  nodes-${port}.conf  集群节点的配置

            Cluster-require-full-coverage  yes(要配置为no) 集群内所有的节点都是正确的才提供服务。

        3. Meet:
          1. Cluster meet ip port

            Redis-cli -h  ${ip} -p ${port}  Cluster meet  ${ip} ${port}

            Redis-cli -h  33.1 -p 8001  Cluster meet  71.1 3009

            Redis-cli -h  33.1 -p 8001  Cluster meet  91.1 4002

            之后通过关系,所有的节点都互相通信

        4. 指派槽:
          1. Cluster addslots slot[slot1,slot2....]  分配槽

            Redis-cli -h  33.1 -p 8001  Cluster addslots  {0..5461}

        5. 主从复制:命令
          1. Cluster-replicate node-id    node-id表示节点id

            Redis-cli -h  33.1 -p 8001  Cluster-replicate  ${node-id  port(端口)}  33.1去复制后面的数据

  22. 集群伸缩

    1. 集群伸缩:槽和数据在节点之间移动
    2. Moved重定向:槽已经迁移
      1. 发送命令(set hello)到任意节点---计算槽和节点---判断是否指向本身----指向本身则返回---不指向本身则返回槽和节点---然后----需要二次写逻辑--重定向槽返回。

    3. ask重定向:不确定槽位置
      1. 解决的问题,在做转移的槽之间发生,如访问源节点但是数据已经迁移到了目标节点,就会返回一个ask,然后ask重定向到目标节点,然后返回。

    4. 故障转移:
      1. 主关下线:节点1向节点2发送ping节点2返回pang,节点1记录返回时间,若没反回,则触发定时任务,当超过时间之后就认为节点2主关下线
      2. 客观下线:当半数持有槽的主节点都标记某节点主关下线。
      3. 流程:计算有效下线报告数量---是否大于持有槽的节点的一半,小于--退出,大于-更新为客观下线---向集群广播下线节点的消息

    5. 故障恢复:

      1. 检查资格:
        1. 每个从节点和故障主节点断开链接的资格

          超过cluster-node-timeout(15秒)*cluster-slave-validily-factor(默认10) (150秒)取消资格

      2. 准备选举时间:
        1. 偏移量较大(复制数据完整的)的 给与少的时间,增大几率成为主节点

      3. 选举投票:

        1. 主节点投票--主节点个数/(2+1)

      4. 替换主节点

        1. 当前送节点取消复制变成主节点(slave no one)

          执行clusterdelslot撤销故障主节点的槽,并执行clusteraddslot把这些槽分配给自己

          向集群pong自己的消息,表明已经替换主节点

      5. 集群的完整性:

        1. Cluster-require-full-coverage  yes
        2. 问题:

          1. 集群中16384个槽必须全部在线;保证集群完整性

          2. 节点故障或者故障正在转移:会返回down(不可用)

            优化:大多数业务无法容忍,所以该设置设置为no

        3. 带宽消耗:Redis cluseter 节点之间会做一些通信,或心跳反应,会带来带宽消耗。

          1. redis官方建议设置1000个节点
          2. Ping/pong消息
          3. 不容忽视的带宽消耗

          4. 消息发送频率: 节点发现与其他节点最后通信时间超过cluster-node-timeout/2会直接发送ping消息--会消耗带宽
          5. 消息数据量:slots槽数组(2kb空间)和整个集群1/10的状态数据(10个节点数据约为1kb)

          6. 节点部署的机器规模:集群分布的机器越多且每台机器划分的节点数越均匀,则集群内可用带宽越高
        4. 优化:

          1. 避免大集群:避免多个业务使用一个集群,大业务可以多集群
          2. Cluster-node-timeout  带宽和故障转移的均衡
          3. 尽量部署多的机器上,保证高可用和带宽
      6. Pub/sub广播:

        1. 问题:1.publish在集群每个节点广播,加重带宽

        2. 优化:单独 走一个 redis sentitenl

      7. 集群倾斜:

        1. 数据倾斜:内存不均

          1. 节点和槽分配不均(一般不常见)
            1. redis-trib.rb info ip:port 查看节点,槽,键值分布

            2. redis-trib.rb rebalance ip:port  进行均衡(谨慎使用--会涉及数据迁移--客户端的问题)
          2. 不同槽对应键值数量差异大
            1. 可能存在hash_tag问题(主要原因)

            2. Cluster countkeysinslot{slot}  获取槽对应键值个数

          3. 包含bigkey:

            1. 比如大的字符串,几百万元素的hash,set

            2. 查找bigkey:从节点:redis-cli --bigkeys

            3. 优化:数据结构(二次hash,拆分成小的字符串)

          4. 内存相关配置不一致(不常见)
            1. 优化:配置的一致性

      8. 请求倾斜;热点问题

        1. 热点key:重要的key或者bigkeys
          1. 优化:避免bigkey

          2. 避免使用hash_tag
          3. 当一致性性不高时,可以使用本地缓存+mq
      9. 数据迁移:

        1. 官方工具:redis-trib.rb import

          1. 只能单机迁移到集群

          2. 不支持在线迁移:source需要停写
          3. 不支持断点续传
          4. 单线程迁移,影响数度
        2. 在线迁移:常用工具

          1. redis-migrate-tool  工具

          2. redis-port

      10. 集群和单机的对比:

        1. 集群限制:

          1. key批量操作有限,mget,mset必须在一个slot里面

          2. Key事务和lua支持有限,操作的key必须在一个节点

          3. Key是数据分区的最小粒度:不支持bigkey分区
          4. 不支持多个数据库,集群模式下只有一个数据库
          5. 复制只支持一层,不支持树形结构

      11. 思考:

        1. redis cluster:满足容量和性能的扩展性,----很多系统不需要
          1. 大多数时间客户端性能会降低
          2. 很多命令无法跨节点使用:mget,mset,flush
          3. Lua和事务无法跨节点使用
          4. 客服端服务端维护复杂

          5. 很多场景redis sentienl 已经满足

      12. 集群总结:

        1. redis cluster数据分区采用虚拟槽方式(16384个槽),每一个节点负责一部分槽和相关数据,实现数据和请求的负载均衡。

        2. 搭建集群分4个步骤:准备节点,节点握手,分配槽,复制
          1. Redis-trib.rb工具用于快速搭建集群(还有扩容,节点检测等功能)

        3. 集群伸缩通过在节点之间移动槽和相关数据来实现
          1. 扩容时通过槽迁移计划将槽从源节点迁移到新节点

            收缩时要将下线节点的槽前移到其他节点,在通过 cluster forget命令让集群内所有节点忘记下线的节点

        4. 使用smart客户端操作集群达到通信效率的最大化,客户端内部负责计算维护键--槽--节点的映射,用于快速定位到目标节点
        5. 集群自动故障转移过程分为故障发现和节点恢复,节点下线分为主关下线和客观下线,当半数主节点认为故障节点主关下线时标记他为客观下线状态,送节点负责对客观下线的主节点触发故障恢复流程,保障集群的可用性。
  23. 缓存使用和优化

    1. 缓存的收益:

      1. 加速读写

      2. 降低后端负载

    2. 缓存的成本:
      1. 数据不一致:缓存层和数据层时间窗口不一致,和更新策略有关
      2. 代码维护成本,多了一层缓存逻辑
      3. 运维成本

    3. 缓存的使用场景
      1. 降低后端负载:高消耗的sql:join结果集/分组结果统计
      2. 加速请求响应:利用redis。。。优化io响应时间

      3. 大量写合并为批量写:计数器先累加在写db
    4. 缓存更新策略:
      1. lru/lfu/fifo算法剔除,列如maxmemory-policy(内存的最大值)   -----优势:设置简单
      2. 超时剔除:过期时间expire(问题--缓存时数据更新了)

      3. 主动更新:开发-控制生命周期
        1. 建议:低一致性,最大内存和淘汰策略

      4. 高一致性:超时剔除和主动更新结合,最大内存和淘汰策略兜底。(建议使用)

    5. 缓存粒度问题:
      1. 通用性:全量属性最好。
      2. 占用空间:部分属性
      3. 代码维护:表面上全面属性好,实际生产中,不适用
    6. 缓存穿透问题:
      1. 缓存穿透就是:大量请求不命中,比如一个不存在的key去访问,先访问缓存,再访问数据库,大量的请求,就会一直重复这个过程。最后都会2次。

      2. 产生原因:

        1. 业务代码原因
        2. 恶意攻击,爬虫等
      3. 怎么发现:

        1. 响应时间
        2. 业务本身问题
        3. 相关指数,总调用数,缓存层命中数,存储层命中数

      4. 怎么解决:

        1. 缓存空对象,如果查出来为空就存在缓存中,设置过期时间什么的,问题:1.需要更多的键(占用空间)2.缓存层和存储层短期数据不一致。
        2. 布隆过滤器拦截:再访问缓存前,再过滤一层,实现复杂
      5. 无底洞问题优化:
        1. 就是加机器,性能没有提升,反而下降了

        2. 问题:

          1. 更多的机器!=更多的性能

          2. 批量需求mget,mset
          3. 数据增长和水平扩展矛盾
        3. 优化:
          1. 命令本身优化:如慢查询等
          2. 减少网络通信
          3. 降低接入层本:如:客户端长链接/连接池,nio等

      6. 热点key重建问题:

        1. 问题:

          1. 热点key+较长的重建时间:就是大量的请求会导致大量的去查询数据库,重建缓存

        2. 三个目标:

          1. 减少缓存重建的时间

          2. 数据尽可能一致

          3. 减少潜在风险

        3. 解决办法:

          1. 互斥锁:就是把查询数据库和重建的过程锁起来。
            1. 问题:代码复杂,可能出现死锁

              有点:保证一致性,思路简单

          2. 永远不过期:

            1. 缓存层面:没有为key设置过期时间

              功能层面:为每个value设置逻辑过期时间,发现超过过期时间,会使用单独的线程构建缓存

            2. 优化:基本杜绝热点key重建问题

              问题:数据不一致,逻辑过期时间增加维护成本和内存成本。

  24. Redis云平台cachecloud

    1. 1.redis规模化困扰:

      1.发布构建繁琐,私搭乱建

      2.节点和机器等运维成本

      3.监控报警比较初级

      Cachecloud简介:

    2. 一键开启redis(standalone,sentienl,cluster)
    3. 机器,应用,实例监控,报警
    4. 客户端:透明使用,性能上报
    5. 可视化运维:配置,扩容,failover,机器应用,实例上下线
    6. 已存在的redis直接接入和数据迁移
    7. https://github.com/sohutv/cachecloud  开源地址

 

redis过期策略

在使用redis做缓存的时候,我们常常会设置过期时间。那么redis是如何清理这些过期的数据呢?

        定期删除: redis每100ms就会随机抽查删除过期的数据。但是这种方法有时候会留下大量过期但没有被抽查到的过期数据,白白浪费内存。

  • 惰性删除: 惰性删除此时就派上用场了,当用户获取数据时,redis会先检查该数据有没有过期,如果过期就删除。

听上去定期删除+惰性删除好像很完美的样子,but过期的数据用户又没有及时访问,那么内存中还是会存在大量的过期数据。此时应该采用redis内存淘汰机制。

  • noeviction:内存不足以写入新数据的时候会直接报错。
  • allKeys-lru:内存不足以写入新数据时候,移除最近最少使用的key。
  • allKeys-random: 内存不足以写入新数据时,随机移除key。
  • volatile-lru: 内存不足以写入新数据时,在设置了过期时间的key当中移除最近最少使用的key。
  • volatile-random: 内存不足以写入新数据时,在设置了过期时间的key中,随即移除key。
  • volatile-ttl: 内存不足以写入新数据时,在设置了过期时间的key当中移除最先过期的key。

上面六种你可以这么记:

  • 不移除直接报错: noeviction。
  • 在所有key中移除: 1.allKeys-lru 2. allKeys-random
  • 在设置了过期时间的key中移除: 1. volatile-lru 2. volatile-random 3.volatile-ttl

一般常用allKeys-lru

 

 

 

 

 

 

尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.youkuaiyun.com/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.youkuaiyun.com/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值