天天看点

分布式|玩转redis看这一篇就够了,轻轻松松应对各种面试难题

数据存储类型介绍

业务数据的特殊性

作为缓存使用

  • 原始业务功能设计
    • 秒杀
    • 618活动
    • 双11活动
    • 12306

附加功能

  • 系统功能优化升级
    • 单服务器升级集群
    • session管理
    • Token管理

Redis数据类型(5种常用)

  • string      string
  • hash      HashMap
  • list      LinkedList
  • set      HashSet
  • sorted_set      TreeSet

string

  • get key
  • set key
  • del [key]
  • mset key1 value1 key2 value2
  • mget key1 key2
  • strlen key
  • append key value

单数据操作与多数据操作的选择之或?

  • 比较发送与执行时间消耗时间对比

string数据类型的扩展操作

  • 设置数值数据新增加指定范围的值,可以使用负号作为递减操作
  • incr key
      incrby key increment
      incrbyfloat key increment
               
  • 设置数值数据新减去指定范围的值
  • decr key
      decrby key increment
               
  • 设置数值有效期 解决时效性控制的操作
  • setex key second value   秒
      psetex key milliseconds value 毫秒
               

string类型数据操作时的注意事项

  • 设置数值有效期 解决时效性控制的操作
    1. 数据未获取到
  • (nil)等于 null
               
    1. 数据最大存储量

      512m

    2. 数据计算最大范围 (java中的long的最大值)

      9223372036854775807

string类型应用场景

  • 在redis中存储用户信息
    1. user🆔333:fans -> 11111 数值
    2. user🆔333 -> {id:333,fans:333} json
  • redis应用于各种结构性和非结构性高热度数据访问的加速
  • key的设置约定 表名:主键名:主键值:字段名

hash

底层使用哈希表结构存储

hash存储结构优化

  • 如果field字段数量少,使用数据数组进行存储
  • 如果field字段数量多,存储结构使用hashmap

hash类型数据的基本操作

  • 添加/修改数据
  • hset key field value
               
  • 获取数据
  • hget key field
      hgetall key
               
  • 删除数据
  • hdel key field [field2]
               
  • 添加/修改多个数据
  • hmset key field1 value1 field2 value2
               
  • 获取多个数据
  • hmget key filed1 field2
               
  • 获取hash表中字段的数量
  • hlen key
               
  • 获取hash表中是否存在指定字段
  • hexists key field
               

hash数据类型的扩展操作

  • 获取hash表中所有的字段名和值
  • hkeys key
    hvalues key
               
  • 设置值自增
  • hincrby key increment
    hincrbyfloat key increment
               
  • 设置值字符,存在则设置失败,不存在则设置成功
  • setnx key field value
               

hash数据类型注意事项

  • hash类型value只能存字符串
  • 每个hash可以存储2^32-1个键值对
  • hash可以灵活操作属性,虽然可以作为对象使用,但是不能滥用
  • hgetall key 获取hash内的键值对

hash数据类型应用场景

  • 购物车

list

list类型数据的基本操作 链表

  • 添加/修改数据
  • lpush key value [value]
    rpush key value [value]
               
  • 获取数据
  • lrange key start stop (0,-1获取全部)
    lindex key index
    llen key
               
  • 获取并移除数据
  • lpop key
    rpop key
               
  • 规定时间内获取并移除数据
  • blpop key [key] timeout (单位为秒)
    brpop key [key] timeout (单位为秒)
               

业务场景

  • 删除指定元素
  • lrem key count value
               

list数据类型注意事项

  • list数据保存的数据都是string类型,最多2^32-1个元素
  • list常被用作队列
  • list结束索引为-1
  • list可以进行数据分页操作 第一页来自list,第二页及更多来自数据库

业务场景

  • 信息管理
  • 多路信息汇总
  • 最新消息

set 无序

set类型数据的基本操作

  • 添加数据
  • sadd key memeber1 [member]
               
  • 获取全部数据
  • smembers key
               
  • 删除数据
  • srem key member1 [member]
               

set类型数据的扩展操作

  • 随机获取几个元素
  • srandmember key count
               
  • 随机获取几个元素 并删除
  • spop key count
               
  • 获取元素个数
  • scard key
               
  • 求两个集合的交并差
  • sinter key key2
      sunion key1 key2
      sdiff key1 key2
               
  • 求两个集合的交并差 并存到指定集合
  • sinterstore desc key key2
      sunionstore desc key1 key2
      sdiffstore desc key1 key2
               
  • 将指定数据从原始集合移动到目标集合中
  • smove source desc member
               
  • 查看数据是否存在
  • sismember key memeber
               

业务场景

  • 随机推荐和抽奖等

zset 有序

zset类型数据的基本操作

  • 添加数据
  • zadd key score memeber1
               
  • 查询
  • zrange key start stop [withscores]
               
  • 查询 反序
  • zrevrange key start stop [withscores]
               
  • 删除
  • zrem key memeber [member]
               

数据类型实战

  • 限流 如果限流为100 则把最大值-100,利用异常做限制,不需要每次进行判断

通用命令

  • 删除key del key
  • key的类型 type key
  • key是否存在 exists key
  • 为key设置有效期
  • expire key  seconds
     pexpire key millseconds
      expireeat key timestamp
      pexpireeat key mill-timestamp
               
  • 获取key有效时间
  • ttl key
      pttl key
               
  • 切换key从临时转为永久
  • persist key
               
  • 查询模式
  • keys *  匹配所有
      keys ?lezai 匹配单个字符
      keys a[abc]  匹配aa ab ac
               
  • key重命名
  • rename key new key
      renamenx key newkey 新key不存在则成功
               
  • 对所有key 里面的内容排序
  • sort key 
               
  • 切换数据库
  • select dbindex
      ping pong
               
  • 数据库移动
  • mv key  dbindex
      flushdb 删除当前库数据
      flushall 清除所有数据
               

Jedis

  • 客户端连接redis
  • 连接 Jedis jedis =new Jedis("127.0.0.1",6379)
      设置 jedis.set("name",123)
      获取 jedis.get("name")
               

Linux安装redis

  • 下载 wget http://download.redis.io/releases/redis-4.0.10.tar.gz
  • 解压 tar-xvzf redis-4.0.10.tar.gz
  • 编译 make
  • 安装make install
  • 指定端口启动 redis-server --port 9999
  • 指定端口连接 redis-cli -p 9999
  • 指定配置文件启动 redis-server conf/redis.conf
redis服务端基本配置
  • daemonize yes 以守护进程方式启动
  • port 6379 设置启动端口
  • dir “/redis/data” 设置当前服务文件保存位置
  • logfile “744.log” 设置日志文件名
持久化

RDB

  • save 手动执行保存一次快照信息
  • 相关配置
  • dbfilename dump.rdb 设置本地数据库文件 默认为dump.rdb 一般设置为 dump-端口号.rdb
      rdbcompression yes 是否启动压缩
      rdbchecksum yes 是否对库文件进行校验
               
  • bgsave 使用fork函数生成一个子进程,在子进程中执行
  • rdb自动启动定时保存
  • 配置信息 save second changenum
      save 900 1  900 秒内有一个key变化
      save 60 3 60秒内有3个key变化
      save 10 6
               

AOF

写数据的三种策略

  • always 每次操作都同步写入到aof中,数据零误差 性能低
  • everysec 每秒 将缓冲区的指令同步到aof中,系统宕机只会丢失一秒的数据
  • no 系统控制 不可控

AOF功能开启

  • appendonly yes | no 开启持久化 默认不开启
  • appendfsync always | everysec | no AOF策略
  • appendfilename fielname

AOF重写 重写规则

  • 进程内已超时的数据不再重写
  • 忽略无效指令
  • 对同一数据的多条写合并为一条
  • bgrewriteaof 重写aof指令

AOF 与RDB 选择

  • 数据很敏感 使用aof
  • 数据间断性呈现 RDB
  • 综合方案 同时开启rdb+aof

Redis高级操作

Redis事务

事务的基本操作
  • 开启事务
  • multi 设定事务的开启 执行指令后,全都加入到事务中
               
  • 执行事务
  • exec 设定事务的结束,同时执行事务,与multi成对出现
               
  • 取消事务
  • discard 取消事务
               
  • 注意
  • 事务出错不能回滚,产生的数据不会回滚
               

  • watch key1 key2 …
  • 监控某个key,需要在事务外面使用,如果key被外部修改了,则终止事务的执行
               
  • unwatch
  • 取消对事务的监控
               

分布式锁

  • setnx key value

解决死锁 添加时效性

Redis删除策略

定时删除

  • 创建一个定时器,当key设置有过期时间,且过期时间到达,由定时器执行对键的删除操作
  • 牺牲CPU保证内存空间 CPU空闲 内存紧张

惰性删除

  • 在获取数据的时候,如果未过期,返回数据,过期了,删除,返回不存在
  • 牺牲存储保证CPU 存储空间足 CPU紧张

定期删除

定期删除策略是怎么实现的?通过activeExpireCycle函数,serverCron函数执行时,activeExpireCycle函数就会被调用,规定的时间里面分多次遍历服务器的expires字典随机检查一部分key的过期时间,并删除其中的过期key

例如Redis每秒处理:

  1. 测试随机的20个keys进行相关过期检测。
  2. 删除所有已经过期的keys。
  3. 如果有多于25%的keys过期,重复步奏1.

Redis逐出算法

  • 在执行每一个命令前,都调用freememoryifneed,内存不足,需要临时删除一些数据清理空间
  • maxmemory 最大内存
  • maxmemory-samples 随机选择
  • maxmemory-policy
  • 有效期的数据
  • volatile-lru 最近最少使用
               
  • volatile-lfu 最近使用次数最少
               
  • volatile-ttl 挑选将要过期的数据
               
  • volatile-random 任意选择数据淘汰
               
  • 所有数据
  • allkeys-lru 最近最少使用
               
  • allkeys-lfu 最近使用次数最少
               
  • allkeys-random 任意选择数据淘汰
               
  • no-enviction

高级数据类型

bitmaps
  • setbits key offset value
  • getbits key offset
  • bitop [and or not xor] destkey key1 key2 对多个key组合操作,保存到destkey中
  • bitcount key [start end] 统计为1的数量
HyperLogLog
  • pfadd key element …
  • pfcount key
  • pfmerge destkey sourcekey1 sourcekey2
  • 相关说明
  • 用于基数统计,不是集合,不保存数据,只记录数量而不是具体数据
               
  • 核心是基数估算,最终数值存在一定误差
               
  • 误差范围:0.81%
               
  • 占用12k
               
  • pfadd 不是一次性分配12看,而是随基数增大而增加空间
               
Geo 距离计算
  • geoadd key longitude latitude member … 添加坐标
  • geopos key member … 获取坐标
  • geodist key member1 member2 unit 获取坐标点距离
  • georadius key longitude latitude radius unit 根据坐标求范围内的数据
  • georadiusbymember key memeber radius unit 根据点求范围内的数据

Redis集群

主从复制简介

互联网“三高”

  • 高性能
  • 高并发
  • 高可用 5个9 99.999%

工作流程

  • 建立连接
  • 数据同步(复制数据)
  • 反复同步(命令传播)
  • 建立连接阶段工作流程
  • 1. 发送指令 slaveof ip port
               
  • 2. 接收到指令,响应对方
               
  • 3.保存master的ip与端口 masterip masterport
               
  • 4.根据连接保存的信息创建与master的socket
               
  • 5.向master周期发送ping,master相应pong
               
  • 6.slave 发送author password
               
  • 7.验证授权
               
  • 8.发送指令replyconfiglistening-port port-num
               
  • 9.保存slave端口号
               
  • 连接的三种方式
  • 1.slaveof if ip port
               
  • 2.slave启动时 带参数 --slaveof masterip masterport
               
  • 3.服务器配置 slaveof if ip port
               
  • 数据同步阶段
  • 全量复制开始
               
  • ①发送指令 psync2 请求同步数据
               
  • ②master执行bgsave
               
  • ③第一个slave建立连接,创建命令缓冲区
               
  • ④生成rdb,通过socket发给slave
               
  • ⑤vslave接受rdb,清空数据,执行rdb文件恢复
               
  • ⑥发送命令,告知已经恢复完成
               
  • 全量复制结束
               
  • 部分复制开始
               
  • ⑦发送复制缓冲区指令信息
               
  • ⑧接受指令,执行bgrewriteeaof,恢复数据
               
  • 部分复制结束
               
  • 命令传播阶段
  • 复制缓冲区 偏移量 字节值
               
  • 工作原理: 通过offset区分不同的slave当前数据传播的差异,maste记录已发送的信息对应的offset,slave记录已经接受的offset
               

数据同步(全)

  • slave 发送指令 psync ?-1
  • master收到发现没有偏移量,则使用bgsave生成rdb文件,记录当前的复制偏移量offset
  • 发送fullresync runid offset,通过socket发送给slave,期间收到客户端命令,offset发生变化
  • 收到 + fullresync 保存master的runid和offset,清空当前数据,接受rdb文件,执行恢复
  • 发送命令 psync2 runid offset
  • master接受到命令,判定runid是否匹配,判定offset是否在缓冲中
  • 如果runid和offset不匹配,则执行全量复制
  • 如果runid和master校验通过,offset和offset相同,忽略
  • 如果runid和master校验通过,offset和offset不相同, 发送continue offset,通过socket发送缓冲区中offset到offset的数据
  • slave接收到continue,保存master的offset,接受信息后,执行bgrewriteaof,恢复数据
  • 主从复制参数注意
  • ① slave-server-stable-data yes|no 同步过程,开启或关闭对外写操作
               
  • ②repl-backlog-size 1mb 设置master指令缓冲区大小,
               
  • 主从复制常见问题

    频繁全量复制

  • ①缓冲区太小 导致offset不匹配 解决:缓冲区设置大点
               
  • ②maset宕机重启,导致runid和offset丢失,全量复制 master执行shutdown 时,将runid和offset进行保存,重启时进行读取
               
    频繁网络中断
    ① 执行命令一直阻塞耗时  设置超时时间
               
    数据不一致

哨兵简介

哨兵是一个分布式系统,用于对主从结构中的每台服务器做监控,当出现故障通过投票随机选择新的master并将所有的slave连接到信息master

作用

  • 监控
  • 通知
  • 自动故障转移

启用哨兵模式

  • 启动哨兵
  • redis-sentinel redis-sentinel.conf
               
  • 配置文件中配置 主redis节点
               

哨兵工作原理

监控阶段

  • 用于同步各个节点的状态信息
    • 获取sentinel的状态(是否在线)
    • 获取master状态
    • 获取所有slave状态
    • master保存sentinel信息,作用是让其他sentinel来发现其他的sentinel,建立订阅通道

通知阶段

  • 每个sentinel进行互通

故障转移阶段

  • sentinel发现master关挂了,标记master为主观下线,然后发送命令给奇特哨兵,其他哨兵也会去看看状态,如果一半以上的哨兵认为master挂了,那就直接标记为客观下线,执行故障转移操作
  • sentinel通过竞选,然后获得此次处理master的权利,成为领头sentinel
    • 去除不在线的
    • 去除响应慢的
    • 与原master断开时间久的
    • 优先原则
      • 优先级
      • offset
      • runid
  • 发送指令
    • 向新的master发送slave no one指令
    • 向其他slave发送slaveof新的ip端口

集群简介

数据存储设计

  • 通过算法设计,计算出key应该保存的位置
  • 将所有的存储空间分割成16384份,每台主机保存一部分代表的是一个存储空间,不是一个key的保存空间
  • 将key按照计算的结果放到对应的存储空间

集群内部通讯设计

  • 各个节点相互通信,保存各个库中槽的编号数据
  • 一次命中,直接返回
  • 一次未命中,告知具体位置

环境搭建

  • cluster-enabled yes
  • cluster-config-file node-6379.conf
  • cluster-node-timeout 10000
  • 在src下执行
  • ./redis-trib.rb create --replicas 1(一个master,一个slave,2 一个master两个slave)  主[...] 从[...]
               
  • 连接集群客户端
  • redis-cli -c
               

企业级解决方案

缓存预热

系统启动前,提前将相关的缓存数据直接加载到缓存系统,避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题,用户直接查询事先被预热的数据

缓存雪崩

缓存击穿

缓存穿透

解决方案

  • 缓存null
  • key加密
  • 实时监控
  • 白名单策略 bitmaps(效率低)

继续阅读