Redis学习笔记

1 服务端和客户端的使用

1.1 服务端使用

1.1.1 启动

  1. 前台启动
    redis-server
  2. 后台启动
    • 需要修改 redis.conf 配置文件
      daemonize yes //表示开启后台守护
      bind 192.168.2.101 // 绑定IP
    • 启动命令
      redis-server /**/redis.conf
  3. docker方式启动
    docker run -d -p 6379:6379 redis(或redis的image id)

1.1.2 使用客户端进行关闭的方式

  1. 客户端连接时关闭
    redis-cli shutdown
  2. 客户端连接后关闭
    shutdown

1.2 客户端使用

1.2.1 连接redis服务

  1. redis-cli
    redis-cli -h 192.168.2.101 -p 6379
    -h:即redis.conf中bind的值,默认127.0.0.1
    -p:指定端口,默认就是6379
  2. docker
    docker exec -it redis的ContainerId redis-cli
  3. 测试连接
    ping //若返回pone则表示连接无误

1.2.2 退出客户端

输入quit即可

2 数据类型

2.1 String:字符串

  • 应用场景很广泛,比如可以利用其自增属性,实现主键自增功能。

2.1.1 设置值

  1. 单个设置
    语法:set key value
  1. 批量设置
    语法:mset key1 value1 key2 value2

2.1.2. 获取值

  1. 单个获取
    语法:get key
  1. 批量获取
    语法:mget key1 key2

2.1.3 获取并设置值(先获取旧值再设置新值)

语法:getset key newValue

2.1.4 删除key

语法:del key1 key2 ...
返回:成功删除的个数

2.1.5 自增

语法1:incr key //默认增长量为1
语法2:incrby key increment //自定义每次增长量
注意:如果key不存在则自动创建,且初始值为1

2.1.6 自减

语法1:decr key //默认减少量为1
语法2:decrby key decrement //自定义减少量

2.1.7 追加拼接

语法:append key value
返回:拼接后value的长度

2.1.8 获取字符串长度

语法:strlen key

2.2 Hash:哈希

  • 哈希类型,为字段(key)设置属性(field)
  • 可以用来存储一个对象,解决了使用String类型保存对象不便的问题。

2.2.1 设置字段属性

语法1:hset key field fieldValue //单个设置
语法2:hmset key field1 field1Value field2 field2Value ...

2.2.2 获取字段属性

语法1:hget key field //单个获取
语法2:hmget key field1 field2 ... //批量获取

2.2.3 删除字段属性

语法:hdel key field1 field2 ...

2.2.4 字段属性增加

语法:hincrby key field fieldIncrement
注意:没有默认自增1;也没有减少计算,但是可以用增加一个负数来实现

2.2.5 获取所有字段属性

语法:hkeys key

2.2.6 获取所有字段属性值

语法:hvals key

2.2.7 判断某个属性是否存在

语法:hexists key field
返回:存在1,不存在0

2.2.8 获取某个字段(key)的属性(field)的个数

语法:hlen key

2.3 List:列表

  • 列表类型采用的是可以双向操作的链表来存储数据
  • 它是有序的,有序的实现方式是通过索引下标
  • 应用场景有评论、消息队列、时间轴等

2.3.1 添加数据

语法1:lpush key value1 value2 ... //从左侧添加
语法2:rpush key value1 value2 ... //从右侧添加

语法3:linsert key before/after pivot(中心点) value
解释:在从左往右第一个值为pivot的数据的before/after插入数据value

2.3.2 获取数据

语法1:lrange key start stop
解释:start和stop为列表的索引,从0开始,-1表示最后一个

语法2:lindex key index
解释:获取指定索引的数据

2.3.3 删除数据

语法1:lpop key //移除最左边数据
语法2:rpop key //移除最右边数据
返回:被移除的数据

语法3:lrem key count value
返回:成功删除的个数
解释:指要删除count个值等于value的数据,count大于0,从左往右删;count小于0则从右往左删

2.3.4 获取长度

语法:llen key

2.3.5 削减列表

语法:ltrim key start stop
解释:start和stop为索引,表示该列表只保留start-stop的数据

2.3.6 数据转移

语法:rpoplpush sourceList destinationList
解释:将source列表右边弹出一个数据,以lpush的方式移入到destination列表

2.4 Set:集合

  • 特点是唯一、无序
  • 应用场景有标签、社交等

2.4.1 添加成员

语法:sadd key member1 member2 ...

2.4.2 删除成员

语法1:srem key member1 member2 ... //删除指定成员

语法2:spop key [count] //随机弹出count个,count默认为1

2.4.3 获取集合成员

语法:smembers key

2.4.4 判断成员是否在集合中

语法:sismember key member
返回:存在则返回1;不存在则返回0

2.4.5 集合运算

  1. 并集运算
    语法:sunion key1 key2 ...
  2. 交集运算
    语法:sinter key1 key2 ...
  3. 差集运算
    语法:sdiff key1 key2 ...

2.4.6 集合长度(成员个数)

语法:scard key

2.5 SortedSet:有序集合

  • 特点是唯一、有序
  • 又叫 zset
  • 有序的实现方式是通过分值,即为每个元素设置分数,根据分数大小实现排序
  • 应用场景有社交、排行榜系统、商品筛选等

2.5.1 添加成员

语法1:zadd key score1 member1 score2 member2 ...
注意:如果成员重复则后面的覆盖前面的,且之后的返回成功数为0,即不计入成功数,因为第一次添加时已经计入了

2.5.2 查看成员

语法1:zrange key start stop [WITHSCORES]
语法2:zrevrange key start stop [WITHSCORES]
解释:zrange表示按分数从低到高输出指定范围的成员,WITHSCORES表示同时输出分数,zrevrange表示倒序,即分数从高到低输出

语法3:zrangebyscore key minScore maxScore [withscores] [limit offset count]
例如:zrangebyscore math 72 90 limit 0 2
解释:输出 [72, 90] 分之间的两名成员

2.5.3 查看成员分数

语法:zscore key member
注意:一次只能查看一个成员

2.5.4 查看成员排名(即成员位置)

语法1:zrank key member
语法2:zrevrank key member //降序排名

2.5.5 删除成员

语法1:zrem key member1 member2 ...

语法2:zremrangebyscore key min max
例如:zremrangebyscore math 70 80
解释:删除math中 [70, 90] 分之间的成员

2.5.5 给成员添加分数

语法:zincrby key increment member

2.5.6 查看成员个数

语法:zcard key

3 通用命令

3.1 key的匹配查找

语法:keys pattern

  • keys *:获取所有的key
  • keys n*:获取以n开始的key
  • keys *n*:获取包含n的key

3.2 判断某个key是否存在

语法:exists key
返回:存在1,不存在0

3.3 查看key的数据类型

语法:type key

3.4 对key进行重命名

语法:rename key

3.5 设置key的生存时间

  1. 设置生存时间
    语法:expire key second
  2. 查看生存时间
    语法:ttl key
    返回:-1表示永久;-2表示已清除
  3. 清除生存时间的设置
    语法:persist key

3.6 清空缓存

语法:flushall

4 redis的持久化方式和持久化策略

4.1 概述

redis是一个内存数据库,所有的数据都保存在内存中,这样就存在一个风险,那就是一旦redis异常退出,数据将不复存在。对此redis有两种数据持久化方式(RDB和AOF),用于将内存中的数据保存到磁盘文件中。

  • 根据两种持久化方式的组合,redis有4种持久化策略
  1. RDB(数据快照模式)
    定期存储,保存的是数据本身
  2. AOF(追加模式)
    每次修改数据时,同步到硬盘,保存的是数据变更记录
  3. 同时关闭RDB和AOF
    当希望将数据只保存在内存中时,可以将这两个策略都关闭
  4. 同时开启RDB和AOF【推荐】
    当redis重启的时候,AOF文件会用于重建原始数据(AOF优先级高)

4.2 RDB:redis database

  • 默认的持久化方式
  • RDB定时备份内存中的数据,服务启动的时候可以从RDB中恢复数据集

4.2.1 优点

  1. 适用于备份,方便恢复不同版本的数据
  2. 适用于容灾恢复,备份文件可以在其他服务器恢复
  3. 数据保存比AOF快
  4. 最大化Redis的性能,备份的时候是启动子进程进行备份,父进程不需要执行IO操作

4.2.2 缺点

存在数据丢失的风险,因为如果Redis异常关闭,由于到上个保存点的数据未来得及备份,故而造成这部分数据丢失

4.2.3 触发RDB备份

4.2.3.1 手动触发

指通过在客户端中发送一条命令的方式,让服务端执行RDB备份,生成备份文件,备份命令有两种:

  1. 同步命令
    save命令,这种方式会阻塞服务端当前的服务,使服务端暂时去执行备份命令,期间服务端不再接受客户端的请求,故而一般不会去使用
  2. 异步命令
    bgsave命令,通过fork一个子进程去执行备份命令,服务端主进程依旧可以正常工作

4.2.3.2 自动触发

指的是通过在redis.conf中配置相应的备份触发策略,使达到策略中的条件时,服务端自动调用bgsave命令实现备份。
相关配置项有:

  1. save
    save 900 1
    save 300 10
    save 60 10000
    表示如果900秒内至少有1个key发生改变时,触发bgsave的调用
  2. dbfilename
    dbfilename dump.rdb
    指定备份文件的文件名,默认为dump.rdb
  3. rdbcompression
    rdbcompression yes
    是否启用压缩,默认启用,此时在rdb备份文件生成时,如果遇到字符串对象且该字符串对象占用字节数超过20,则对该字符串采用LZF算法进行压缩
  4. stop-writes-on-bgsave-error
    stop-writes-on-bgsave-error yes
    默认开启,表示调用gbsave过程中遇到错误时,将停止备份
  5. dir
    dir ./
    配置备份文件的存放路径
  6. rdbchecknum
    rdbchecksum yes
    是否使用CRC64校验算法检验RDB文件是否有损坏,默认开启,关闭可提高性能

4.3 AOF:appendonly file

基于命令操作日志,指的是当有命令更新命令,如set key value,del key等,就会将该命令保存到AOF缓存区,然后在配置的时间节点写入到磁盘文件中

4.3.1 优点

  1. 数据可靠性比RDB的更好,适用于做完整的数据备份
  2. 一些误操作可以直接在AOF备份文件中进行回退

4.3.2 缺点

备份文件较RDB的要大,恢复效率不及RDB,不适用于快速可用的容灾恢复

4.3.3 AOF启用


serverCore函数
在redis中,常规操作由serverCore函数实现,而它的每一次调用,都会尝试进行 AOF 或 RDB 持久化操作
延迟写 和 fsync 函数
当数据写入文件时,系统内核(UNIX)通常先将该数据复制到一个缓冲区中,并且如果该缓冲区尚未写满,则先不将其放到输出队列,只有等到该缓冲区写满,或者内核需要重用该缓存区以便存放其他磁盘块数据时,再将其放到输出队列,然后再等到该数据到达队首时,才进行真正的I/O操作,这就是写延迟 -- delayed write。
fsync函数的特点是,可以等待数据真正写入到文件中。


以下为启用AOF策略的相关配置项(均在redis.conf中):

  1. appendonly
    appendonly no
    表示是否开启AOF策略,默认不开启
  2. appendfliename
    appendfilename "appendonly.aof"
    生成的aof备份文件的文件名,默认是appendonly.aof
  3. hz
    hz 10
    hz参数可以用来指定每秒中执行serverCore的次数,默认每秒执行10次
  4. appendfsync
    appendfsync everysec
    当有一个key更新命令时,首先将该命令日志写入到AOF缓存区,再将缓存区中的内容写入到AOF备份文件中,appendfsync指定的是写入备份文件的频率以及写入的方式,它有三个选项:
    • everysec
      指的是每隔1秒,就将AOF缓存区的操作命令日志写入到AOF文件中,写入时会调用fsync函数,即完成磁盘同步
    • always
      指每次serverCore执行时,就刷新AOF缓存区一次,并且每次写入AOF时都调用fsync,完成磁盘同步,不建议,因为它十分消耗性能
    • no
      不做控制,由操作系统决定什么时候刷新缓冲区,并且每次写入AOF时不调用fsync,由系统自动进行磁盘同步

4.3.4 AOF重写

4.3.4.1 重写的作用

可以对AOF备份文件进行优化和压缩,比如有以下更新key的操作命令:
set key1 value1
set key 2 value2
del key1
经过重写,只会保留:
set key 2 value2

4.3.4.2 重写的说明

  • 重写的执行也是通过fork一个子进程进行的

4.3.4.3 重写的触发

4.3.4.3.1 手动触发

通过在客户端中发送bgrewriteaof命令,就可以触发重写

4.3.4.3.2 自动触发

指在redis.conf中进行触发重写条件的相关配置,当达到重写触发的条件时,服务端将进行重写。
以下是触发重写的相关配置项:

  1. no-appendfsync-on-rewrite
    no-appendfsync-on-rewrite no
    有一种情况,主进程在执行将AOF缓冲区操作命令刷到AOF文件的过程时,同时还有一个AOF重写命令被调用了,而二者均需要对AOF文件进行写操作,且如果重写命令先进行,这样主进程就出现了阻塞的情况。
    no-appendfsync-on-rewrite参数的作用就是为了解决这种情况,他的默认取值是no,表示当进行重写时依旧要进行appendfsync,即主进程形成阻塞;当取值yes时,则相当于appendfsync的取值时no,即主进程写入AOF文件时,不调用fsync函数,只是将数据放入到缓冲区,这样就不存在阻塞的情况了。
    设置为yes时,如果redis宕机,则尚未真正执行I/O写入到AOF文件的那些缓冲区的数据都将丢失,在linux系统的默认设置下,最多会丢失30秒的数据。
  2. auto-aof-rewrite-percentage
    auto-aof-rewrite-percentage 100
    表示当AOF文件相较于上一版本AOF文件大小的百分比达到多少时将触发AOF重写,如auto-aof-rewrite-percentage 选项配置为 100,上一版本的 aof 文件大小为 100M,那么当AOF文件达到 200M 的时候,触发 AOF 重写
  3. auto-aof-rewrite-min-size
    auto-aof-rewrite-min-size 64mb
    当AOF文件超过64M(默认)时,将进行重写

5 主从模式

指一个主数据库Master,设置多个从数据库Slave的主从组合方式 [注:Slave还可以继续拥有自己的Slave],以此可以实现读写分离、哨兵模式[当Master宕机,Slave可以成为新的Master]等功能

5.1 主从搭建

可以使用不同的机器,通过ip区分主从;也可以使用同一个机器,通过port区分主从,比如使用后者方式进行搭建,只需要对后者配置上slaveof配置项,指明他的Master机器的ip和port即可,其中slaveof的设置可以直接在slave的redis-cli中直接指定,但是这种方式是临时性的,重启slave时失效,另外一种就是在slave的redis.conf中进行配置,永久有效。

5.2 读写分离

指在Redis的主从节点中,Master可读可写,而Slave只读不可写,所有的写只能在Master中进行,适用于少量写,大量读的场景。

图中左边6380端口为slave节点,进行写操作时直接抛出只读警告

过期key的处理
slave不会对key进行过期处理,master才会,当master对某个key进行过期清除时,将发送一条del命令给slave,以模拟key过期

5.3 主从复制

指的是为了保证数据库的数据的一致性,需要将Master的数据复制到Slave中,其中复制数据的方式又分为全量同步和增量同步两种

5.3.1 全量同步

全量同步一般发生在Slave初始化阶段,具体步骤如下

  1. slave连接上master后,会发送一条psync (旧版本为sync)指令给master
  2. master接收到psync指令后,会执行bgsave命令生成rdb文件,同时将从[master]客户端中接收到的所有的命令,缓存在内存中。
  3. 待bgsave命令执行完成,master向所有的slave发送rdb快照
  4. 在接收到快照之前,slave一直使用旧数据提供服务,此时将丢弃所有的旧数据,开始载入收到的快照
  5. master将快照发送完毕之后,开始将缓存的写命令发送给slave
  6. slave完成快照的载入后,开始接收命令请求,并执行来自master缓冲区的写命令

5.3.2 增量同步

  • 增量同步指的是Slave初始化完成后,开始正常工作时将Master的写操作进行同步的过程。
  • 同步过程主要就是当Master每执行一条写操作命令,就会将该写命令发送给Slave,Slave接收并执行该写命令。

5.3.3 断点续传

  • 从redis2.8版本开始支持,指的是在主从复制过程中,如果slave和master发生异常断开连接,再次连接时将从上次复制的断点开始继续复制,而不是从头开始复制。
  • 原理
    在主从复制中,Master会在内存中维护一个backlog,同时Master和Slave的内存中都维护着一个复制偏移量 replication offset 和 master run id。当连接断开重连时,Master会检测PSYNC中的master run id和replication offset,如果二者的id相同,且offset在有效范围内,则开始断点续传。
    由于id和offset都保存在内存中,所以无论Master还是Slave,如果是直接宕机,而非单纯的网络中断,则将无法断点续传,只能进行全量同步。

5.3.4 无磁盘化复制

指的是在全量复制过程中,对于rdb的创建,直接在磁盘中进行,然后发送给slave,而无需落地磁盘后在发送给slave,相关配置项如下:

  1. repl-diskless-sync
    repl-diskless-sync no
    是否开启,默认不开启
  2. repl-diskless-sync-delay
    repl-diskless-sync-delay 5
    默认等待5秒后才开始复制,为了确保slave完成连接,即slave端能够进行到待传送的目标队列中

6 集群架构

指多个主从模式结合起来,组成的彼此能够互相通信的集群,各节点分布式部署,可以解决单点故障、实现负载均衡

6.1 集群搭建

有三台机器bigdata1、bigdata2、bigdata3,每台机器上有6379和6380两个redis

6.1.1 配置redis.conf

  1. cluster-enabled yes
    表示开启集群
  2. cluster-node-timeout 15000
    网络抖动配置项,生产环境中,网络可能会常出现问题,该配置项表示这段时间一直无法访问,则该节点fail,进行主从切换,如果未设置此配置项,可能会造成频繁的主从切换
  3. cluster-config-file bigdata1-6379
    集群中每个结点都会生成一个自己的集群配置文件,这个文件最好每个redis都不一样
  4. slaveof
    将该配置项注释,由redis自动分配master和slave节点

6.1.2 环境准备

  1. redis-tri.rb
    在src目录下,是redis的集群管理器工具,可以使用它启停、管理集群
  2. ruby 和 rubygems
    redis-tri.rb是由ruby语言编写,使用它需要先要安装ruby和rubygems(ruby通信接口):
    sudo yum -y install ruby
    sudo yum -y install rubygems
    可使用ruby -v检查是否安装成功
  3. redis.gem
    让集群管理器和redis进行通信,还需要安装redis驱动 redis-3.2.1.gem:
    gem install redis-3.2.1.gem
    这种方式需要提前准备好驱动,也可以直接在线安装:gem install redis,但它要求ruby在2.2.2版本以上。
可以单独创建cluster目录方便管理,并将src/redis-trib.rb复制过来

6.1.3 清空数据

  1. 启动所有的redis
  2. 进入redis-cli,执行命令:
    flushall
    全新安装的redis可以跳过,如果是复制于其他已经使用过的redis,可能存在rdb文件,如果未删除该rdb直接启动,则启动的redis中有缓存数据存在,而cluster的创建要求所有节点都是空的不能有数据,所以必须先进行上面的清除操作

6.1.4 启动集群

./redis-trib.rb create --replicas 1 192.168.2.101:6379 192.168.2.101:6380 192.168.2.102:6379 192.168.2.102:6380 192.168.2.103:6379 192.168.2.103:6380

  1. --replicas 1 表示每个master中slave的个数,后面有6个cluster节点,将会自动生成3个master和3个slave
  2. cluster node必须要使用ip的形式,不能直接使用域名,否则可能会报错
启动成功截图

6.1.5 验证

  1. 连接集群
    redis-cli -h (任一cluster node的ip) -p port -c
    -c:表示连接到集群
  2. 查看集群信息
    cluster info
  3. 查看集群节点
    cluster nodes

6.2 负载均衡:插槽机制

redis cluster的负载均衡是通过插槽机制实现的

6.2.1 插槽计算

对key的有效部分进行CRC16算法计算出对应的哈希值,再将哈希值对16834进行取余,最终的结果就是这个key的插槽值

有效部分

  • 指的是key中如果有{},则{}中的内容就是有效部分,否则整个key就是有效部分
  • 比如:key = {hello}world,有效部分就是hello
  • 比如:key = helloworld,有效部分就是helloworld

6.2.2 插槽分配

  • 由插槽值计算可知,集群的插槽数有 16384(0 ~ 16383) 个,每个redis负责处理一部分的插槽。
  • 可以使用redis-trib.rb将未分配的插槽分给节点,或者将已经分配的插槽转移到指定节点(插槽中的数据同时也会被转移到该指定节点)。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,423评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,147评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,019评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,443评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,535评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,798评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,941评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,704评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,152评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,494评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,629评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,295评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,901评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,978评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,333评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,499评论 2 348