redis基本使用
Redis简介
Redis 是一种基于键值对的NoSQL数据库,它提供了对多种数据类型(字符串、哈希、列表、集合、有序集合、位图等)的支持,能够满足很多应用场景的需求。Redis将数据放在内存中,因此读写性能是非常惊人的。与此同时,Redis也提供了持久化机制,能够将内存中的数据保存到硬盘上,在发生意外状况时数据也不会丢掉。
Redis 的作用:
- 内存存储、持久化(RDB 和 AOF)
- 效率高,可以用于高速缓存
- 发布订阅系统,队列
- 地图信息分析
- 计数器、计时器(比如浏览量)
Redis 的特征:
- 多样化的数据类型
- 持久化
- 集群
- 事务
Redis 官网: https://redis.io/
Redis 中文网: http://www.redis.cn/
Redis 优点
-
Redis的读写性能极高,并且有丰富的特性(发布/订阅、事务、通知等)。
-
Redis支持数据的持久化(RDB和AOF两种方式),可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
-
Redis支持多种数据类型,包括:string、hash、list、set,zset、bitmap、hyperloglog等。
-
Redis支持主从复制(实现读写分离)以及哨兵模式(监控master是否宕机并自动调整配置)
-
Redis支持分布式集群,可以很容易的通过水平扩展来提升系统的整体性能
-
Redis基于TCP提供的可靠传输服务进行通信,很多编程语言都提供了Redis客户端支持。
Redis的安装和配置
下载安装最新版的gcc编译器
#安装C 语言的编译环境
yum install gcc-c++
# 测试 gcc版本
gcc --version
下载安装包
wget https://download.redis.io/releases/redis-6.0.10.tar.gz
tar xzvf redis-6.0.10.tar.gz
解压Redis的安装包! 程序/opt
cd /opt
tar -zxvf redis-6.0.6.tar.gz
cd redis-6.0.6
make
make install
redis的默认安装路径 /usr/local/bin
查看默认安装目录:
redis-benchmark:性能测试工具,可以在自己本子运行,看看自己本子性能如何
redis-check-aof:修复有问题的AOF文件,rdb和aof后面讲
redis-check-dump:修复有问题的dump.rdb文件
redis-sentinel:Redis集群使用
redis-server:Redis服务器启动命令
redis-cli:客户端,操作入口
mkdir myredisconfig
将redis配置文件。复制到我们当前目录下
cp /opt/redis-6.0.6/redis.conf /usr/local/bin/myredisconfig/
后台启动设置daemonize no改成yes
Redis 的配置
在 redis 源代码目录下有一个名为redis.conf的配置文件,我们可以先查看一下该文件: vim redis.conf
配置将 Redis 服务绑定到指定的IP地址和端口
bind 127.0.0.1 #只允许本机登录
port 6379 #端口号
设置后台运行 (以守护进程方式运行)
daemonize yes
设置日志级别, 可选值: (debug: 调试, verbose: 详细, notice: 通知, warning: 警告)
loglevel warning
配置数据库的数量, 默认为 16 个
databases 16
配置数据写入规则
save 900 1 # 900 秒 (15 分钟) 内修改过 1 个 key, , 写入一次数据库
save 300 10 # 300 秒 (5 分钟) 内修改过 10 个 key, 写入一次数据库
save 60 10000 # 60 秒 (1 分钟) 内修改过 10000 个 key, 写入一次数据库
配置慢查询
slowlog-log-slower-than 10000 # 一次操作超过 10000 毫秒被视作一次慢查询
slowlog-max-len 128 # 最多纪录 128 次满查询
Redis持久化
Redis在运行时,所有的数据都保存在内存里,进程结束以后,会将数据写入到硬盘中。启动时,会读取硬盘里的内容,并将内容全部加载到内存中(会大量的占用内存)。
Redis的持久化有两种形式:RDB和AOF
RDB
默认的持久化方式,是对内存中的数据进行镜像,并以二进制的形式保存到dump.rdb文件中。会根据配置文件的时间节点对文件进行持久化。
save 900 1
save 300 10
save 60 10000
优点:速度快,直接镜像内存里的数据,文件小。
缺点:数据有可能会丢失,在两次保存间隔内的数据,有可能会丢失。
AOF
AOF(Append only file)持久化,将修改的每一条指令记录进appendonly.aof中,需要修改配置文件,来打开aof功能。
-
appendfsync always:每次有新命令追加到aof文件时就执行一个持久化,非常慢但是安全
-
appendfsync everysec:每秒执行一次持久化,足够快(和使用rdb持久化差不多)并且在故障时只会丢失1秒钟的数据
-
appendfsync no:从不持久化,将数据交给操作系统来处理。redis处理命令速度加快但是不安全。
优点:适合保存增量数据,数据不丢失。
缺点:文件体积大,恢复时间长
Redis的服务器和客户端
接下来启动 Redis 服务器,下面的方式将以指定的配置文件启动 Redis 服务。
redis-server myredisconfig/redis.conf
接下来用 Redis 客户端去连接服务器。
redis-cli -h localhost -p 6379
注意如果是6.0的版本开启客户端的时候要 先输入密码,否则会报错,
(error) NOAUTH Authentication required.
输入密码
auth 密码
关闭服务
或者:杀掉进程号
ps -ef|grep redis
kill -9 进程号
基础的知识
redis默认有16个数据库(0-15)
默认使用的是第0个
可以使用 select 进行切换数据库
127.0.0.1:6379> select 3 # 切换数据库
OK
127.0.0.1:6379[3]> DBSIZE # 查看DB大小!
(integer) 0
127.0.0.1:6379[3]> keys * # 查看数据库所有的key
1) "name"
清除当前数据库
flushdb
清除全部数据库的内容
FLUSHALL
redis键(key)
127.0.0.1:6379> set k1 dyk
OK
127.0.0.1:6379> set k2 cb
OK
查看当前库所有key
keys *
- KEYS * 匹配数据库中所有key 。
- KEYS h?llo 匹配hello ,hallo 和hxllo 等。
- KEYS h*llo 匹配hllo 和heeeeello 等。
- KEYS h[ae]llo 匹配hello 和hallo ,但不匹配hillo 。特殊符号用 “” 隔开
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
判断某个key是否存在
若key 存在,返回1 ,否则返回0。
exists key
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> exists k3
(integer) 0
查看你的key是什么类型
type key
127.0.0.1:6379> type k1
string
删除指定的key数据
del key
127.0.0.1:6379> del k1
(integer) 1
unlink key 根据value选择非阻塞删除
仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。
expire key 10 10秒钟:为给定的key设置过期时间
ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期
127.0.0.1:6379> expire k2 10
(integer) 1
127.0.0.1:6379> ttl k2
(integer) 6
127.0.0.1:6379> ttl k2
(integer) -2
- 当key 不存在时,返回-2 。
- 当key 存在但没有设置剩余生存时间时,返回-1 。
- 否则,以秒为单位,返回key 的剩余生存时间。
redis基本命令
字符串String
数据结构
String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配.,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M
SET
SET key value [EX seconds] [PX milliseconds] [NX|XX]
将字符串值 value 关联到 key 。
如果 key 已经持有其他值, SET 就覆写旧值, 无视类型。
当 SET 命令对一个带有生存时间(TTL)的键进行设置之后, 该键原有的 TTL 将被清除。
EX代表秒 PX代表毫秒
EX seconds : 将键的过期时间设置为 seconds 秒
PX milliseconds : 将键的过期时间设置为 milliseconds 毫秒
对不存在的键进行设置:
redis> SET name dyk
OK
redis> GET name
"dyk"
使用 EX 选项:
redis> SET name cb ex 10
OK
redis> ttl name
(integer) 8 #还剩8秒
redis> GET name
"cb"
redis> GET name
(nil) #到期
GET
返回与键 key 相关联的字符串值
GET key
如果键 key 不存在, 那么返回特殊值 nil ; 否则, 返回键 key 的值。
如果键 key 的值并非字符串类型, 那么返回一个错误, 因为 GET 命令只能用于字符串值。
对不存在的键 key 或是字符串类型的键 key 执行 GET 命令:
redis> GET db
(nil)
redis> SET db redis
OK
redis> GET db
"redis"
SETNX
SETNX key value
只在键 key 不存在的情况下, 将键 key 的值设置为 value 。
若键 key 已经存在, 则 SETNX 命令不做任何动作。
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写
返回值
命令在设置成功时返回 1 , 设置失败时返回 0
redis> EXISTS job # job 不存在
(integer) 0
redis> SETNX job "programmer" # job 设置成功
(integer) 1
redis> SETNX job "code-farmer" # 尝试覆盖 job ,失败
(integer) 0
redis> GET job # 没有被覆盖
"programmer"
SETEX
SETEX key seconds value
将键 key 的值设置为 value , 并将键 key 的生存时间设置为 seconds 秒钟。
如果键 key 已经存在, 那么 SETEX 命令将覆盖已有的值。
SETEX 命令的效果和以下两个命令的效果类似:
SET key value
EXPIRE key seconds # 设置生存时间
SETEX 和这两个命令的不同之处在于 SETEX 是一个原子(atomic)操作, 它可以在同一时间内完成设置值和设置过
期时间这两个操作
如果不设置剩余时间默认是(integer) -1,表示永远不会过期
返回值
命令在设置成功时返回 OK 。
当 seconds 参数不合法时, 命令将返回一个错误
在键 key 不存在的情况下执行 SETEX :
redis> SETEX cache_user_id 60 10086 # 设置值为10086,60秒过期
OK
redis> GET cache_user_id # 值
"10086"
redis> TTL cache_user_id # 剩余生存时间
(integer) 49
键 key 已经存在, 使用 SETEX 覆盖旧值:
redis> SET cd "timeless"
OK
redis> SETEX cd 3000 "goodbye my love"
OK
redis> GET cd
"goodbye my love"
redis> TTL cd
(integer) 2997
MSET
同时为多个键设置值
MSET key value [key value …]
如果某个给定键已经存在, 那么 MSET 将使用新值去覆盖旧值, 这个命令只会在所有给定键都不存在的情况
下进行设置
MSET 是一个原子性(atomic)操作, 所有给定键都会在同一时间内被设置, 不会出现某些键被设置了但是另一些键
没、有被设置的情况。简单理解就是要么设置的所有都成功,要么全都失败
返回值
MSET 命令总是返回 OK
同时对多个键进行设置:
redis> MSET name "dyk" age 18
OK
redis> MGET name age
1) "dyk"
2) "18"
覆盖已有的值:
redis> MGET name age
1) "dyk"
2) "18"
redis> mset name cb age 20
OK
redis> mget name age
1) "cb"
2) "20"
MGET
返回给定的一个或多个字符串键的值。
MGET key [key …]
如果给定的字符串键里面, 有某个键不存在, 那么这个键的值将以特殊值 nil 表示
返回值
MGET 命令将返回一个列表, 列表中包含了所有给定键的值
GETSET
GETSET key value
将键 key 的值设为 value , 并返回键 key 在被设置之前的旧值。
返回值
返回给定键 key 的旧值。
如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil 。
当键 key 存在但不是字符串类型时, 命令返回一个错误
redis> GETSET db mongodb # 没有旧值,返回 nil
(nil)
redis> GET db
"mongodb"
redis> GETSET db redis # 返回旧值 mongodb
"mongodb"
redis> GET db
"redis"
STRLEN
返回键 key 储存的字符串值的长度
返回值
STRLEN 命令返回字符串值的长度。
当键 key 不存在时, 命令返回 0 。
当 key 储存的不是字符串值时, 返回一个错误
获取字符串值的长度:
redis> SET name dyk
OK
redis> GET name
"dyk"
redis> STRLEN name
(integer) 3
不存在的键的长度为 0
redis> STRLEN height #height 不存在
(integer) 0
APPEND
APPEND key value
如果键 key 已经存在并且它的值是一个字符串, APPEND 命令将把 value 追加到键 key 现有值的末尾。
如果 key 不存在, APPEND 就简单地将键 key 的值设为 value , 就像执行 SET key value 一样。
返回值
追加 value 之后, 键 key 的值的长度
对不存在的 key 执行 APPEND
redis> EXISTS myphone # 确保 myphone 不存在
(integer) 0
redis> APPEND myphone "nokia" # 对不存在的 key 进行 APPEND ,等同于 SET myphone "nokia"
(integer) 5 # 字符长度
对已存在的字符串进行 APPEND :
127.0.0.1:6379> set name dyk # 长度从 3 个字符增加到 6 个字符
OK
127.0.0.1:6379> append name 123
(integer) 6
127.0.0.1:6379> get name
"dyk123"
SETRANGE
SETRANGE key offset value
从偏移量 offset 开始, 用 value 参数覆写(overwrite)键 key 储存的字符串值。
不存在的键 key 当作空白字符串处理。
SETRANGE 命令会确保字符串足够长以便将 value 设置到指定的偏移量上, 如果键 key 原来储存的字符串长度比偏
移量小(比如字符串只有 5 个字符长,但你设置的offset 是 10 ), 那么原字符和偏移量之间的空白将用零字节
(zerobytes, "\x00" )进行填充
对非空字符串执行 SETRANGE 命令:
redis> SET greeting "hello world"
OK
redis> SETRANGE greeting 6 "Redis"
(integer) 11
redis> GET greeting
"hello Redis"
对空字符串/不存在的键执行 SETRANGE 命令:
redis> EXISTS empty_string
(integer) 0
redis> SETRANGE empty_string 5 "Redis!" # 对不存在的 key 使用 SETRANGE
(integer) 11
redis> GET empty_string # 空白处被"\x00"填充
"\x00\x00\x00\x00\x00Redis!"
GETRANGE
相当于java里的截取字符串 GETRANGE key start end 闭区间
返回键 key 储存的字符串值的指定部分, 字符串的截取范围由 start 和 end 两个偏移量决定 (包括 start 和
end 在内)。[start,end]闭区间
负数偏移量表示从字符串的末尾开始计数, -1 表示最后一个字符, -2 表示倒数第二个字符, 以此类推。
返回值
GETRANGE 命令会返回字符串值的指定部分
redis> SET greeting "hello, my friend"
OK
redis> GETRANGE greeting 0 4 # 返回索引0-4的字符,包括4。
"hello"
redis> GETRANGE greeting -1 -5 # 不支持回绕操作
""
redis> GETRANGE greeting -3 -1 # 负数索引
"end"
redis> GETRANGE greeting 0 -1 # 从第一个到最后一个,全部字符串
"hello, my friend"
redis> GETRANGE greeting 0 1008611 # 值域范围不超过实际字符串,超过部分自动被符略
"hello, my friend"
INCR
为键 key 储存的数字值加上一
INCR key
如果键 key 不存在, 那么它的值会先被初始化为 0 , 然后再执行 INCR 命令。
如果键 key 储存的值不能被解释为数字, 那么 INCR 命令将返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
返回值
INCR 命令会返回键 key 在执行加一操作之后的值
redis> SET a 10
OK
redis> INCR a
(integer) 11
redis> GET a # 数字值在 Redis 中以字符串的形式保存
"11"
INCRBY
INCRBY key increment
为键 key 储存的数字值加上增量 increment 。
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 INCRBY 命令。
如果键 key 储存的值不能被解释为数字, 那么 INCRBY 命令将返回一个错误。
返回值
在加上增量 increment 之后, 键 key 当前的值。
键存在,并且值为数字:
redis> SET rank 50
OK
redis> INCRBY rank 20
(integer) 70
redis> GET rank
"70"
键不存在:
redis> EXISTS counter
(integer) 0
redis> INCRBY counter 30
(integer) 30
redis> GET counter
"30"
键存在,但值无法被解释为数字:
redis> SET book "long long ago..."
OK
redis> INCRBY book 200
(error) ERR value is not an integer or out of range
DECR
为键 key 储存的数字值减去一
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECR 操作。
如果键 key 储存的值不能被解释为数字, 那么 DECR 命令将返回一个错误
返回值
DECR 命令会返回键 key 在执行减一操作之后的值。
对储存数字值的键 key 执行 DECR 命令
redis> SET a 10
OK
redis> DECR a
(integer) 9
对不存在的键执行 DECR 命令:
redis> EXISTS count
(integer) 0
redis> DECR count
(integer) -1
DECRBY
将键 key 储存的整数值减去减量 decrement
DECRBY key decrement
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECRBY 命令。
如果键 key 储存的值不能被解释为数字, 那么 DECRBY 命令将返回一个错误
返回值
DECRBY 命令会返回键在执行减法操作之后的值
对已经存在的键执行 DECRBY 命令
redis> SET count 100
OK
redis> DECRBY count 20
(integer) 80
对不存在的键执行 DECRBY 命令
redis> EXISTS pages
(integer) 0
redis> DECRBY pages 10
(integer) -10
哈希表
HSET
HSET hash field value
将哈希表 hash 中域 field 的值设置为 value 。
如果给定的哈希表并不存在, 那么一个新的哈希表将被创建并执行 HSET 操作。
如果域 field 已经存在于哈希表中, 那么它的旧值将被新值 value 覆盖。
返回值
当 HSET 命令在哈希表中新创建 field 域并成功为它设置值时, 命令返回 1 ;
如果域 field 已经存在于哈希表, 并且 HSET 命令成功使用新值覆盖了它的旧值,
那么命令返回 0
设置一个新域
redis> hset student name dyk
(integer) 1
redis> hget student name
"dyk"
对一个已存在的域进行更新:
redis> hset student name cb
(integer) 0
redis> hget student name
"cb"
HGET
返回哈希表中给定域的值。
HGET 命令在默认情况下返回给定域的值。
如果给定域不存在于哈希表中, 又或者给定的哈希表并不存在, 那么命令返回 nil
域存在的情况:
redis> HSET homepage redis redis.com
(integer) 1
redis> HGET homepage redis
"redis.com"
域不存在的情况:
redis> HGET site mysql
(nil)
HMSET
同时将多个 field-value (域-值)对设置到哈希表 key 中
HMSET key field value [field value …]
此命令会覆盖哈希表中已存在的域。
如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
返回值:
如果命令执行成功,返回 OK 。
当 key 不是哈希表(hash)类型时,返回一个错误
redis> hmset student name "dyk" age 18 id 1
OK
redis> hmget student name age id
1) "dyk"
2) "18"
3) "1"
HMGET
HMGET key field [field …]
返回哈希表 key 中,一个或多个给定域的值。
如果给定的域不存在于哈希表,那么返回一个 nil 值。
因为不存在的 key 被当作一个空哈希表来处理,所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。
返回值:
一个包含多个给定域的关联值的表,表值的排列顺序和给定域参数的请求顺序一样。
```python
redis> hmset student name "dyk" age 18 id 1
OK
redis> hmget student name age id
1) "dyk"
2) "18"
3) "1"
HKEYS
返回哈希表 key 中的所有域。
HKEYS key
返回值:
一个包含哈希表中所有域的表。
当 key 不存在时,返回一个空表。
哈希表非空
redis> hkeys student
1) "name"
2) "age"
3) "id"
空哈希表/key不存在
redis> EXISTS fake_key
(integer) 0
redis> HKEYS fake_key
(empty list or set)
HVALS
返回哈希表 key 中所有域的值
返回值:
一个包含哈希表中所有值的表。
当 key 不存在时,返回一个空表。
非空哈希表
redis> hvals student
1) "dyk"
2) "18"
3) "1"
空哈希表/不存在的key
redis> EXISTS not_exists
(integer) 0
redis> HVALS not_exists
(empty list or set)
HGETALL
HGETALL key
返回哈希表 key 中,所有的域和值。
在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度
是哈希表大小的两倍。
返回值:
以列表形式返回哈希表的域和域的值。
若 key 不存在,返回空列表
redis> hgetall student
1) "name" # 域
2) "dyk" # 值
3) "age"
4) "18"
5) "id"
6) "1"
HDEL
删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
HDEL key field [field …]
返回值:
被成功移除的域的数量,不包括被忽略的域
redis> hgetall student
1) "name" # 域
2) "dyk" # 值
3) "age"
4) "18"
5) "id"
6) "1"
删除单个域
redis> hdel student id
(integer) 1
删除不存在的域
redis> HDEL abbr not-exists-field
(integer) 0
删除多个域
redis> hdel student name age
(integer) 2
redis> hgetall student
(empty array)
列表List
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差
LPUSH
将一个或多个值 value 插入到列表 key 的表头
LPUSH key value [value …]
如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头: 比如说,对空列表 mylist 执行命
令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b
和 LPUSH mylist c 三个命令。
如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。
当 key 存在但不是列表类型时,返回一个错误。
返回值
执行 LPUSH 命令后,列表的长度
加入单个元素
redis> lpush stu dyk
(integer) 1
加入重复元素
redis> lpush stu dyk # 列表允许重复元素
(integer) 2
加入多个元素
redis> lpush stu dyk lfw cb
(integer) 5
redis> lrange stu 0 -1
1) "cb"
2) "lfw"
3) "dyk"
4) "dyk"
5) "dyk"
RPUSH
将一个或多个值 value 插入到列表 key 的表尾(最右边)。
如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行
RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、
RPUSH mylist c 。
如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。
当 key 存在但不是列表类型时,返回一个错误。
LPUSHX
将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。
当 key 不存在时, LPUSHX 命令什么也不做
返回值
LPUSHX 命令执行之后,表的长度
# 对空列表执行 LPUSHX
redis> LLEN greet # greet 是一个空列表
(integer) 0
redis> LPUSHX greet "hello" # 尝试 LPUSHX,失败,因为列表为空
(integer) 0
# 对非空列表执行 LPUSHX
redis> LPUSH greet "hello" # 先用 LPUSH 创建一个有一个元素的列表
(integer) 1
redis> LPUSHX greet "good morning" # 这次 LPUSHX 执行成功
(integer) 2
redis> LRANGE greet 0 -1
1) "good morning"
2) "hello"
LPOP
移除并返回列表 key 的头元素。
返回值
列表的头元素。 当 key 不存在时,返回 nil
redis> lrange stu 0 -1
1) "cb"
2) "lfw"
3) "dyk"
4) "dyk"
5) "dyk"
redis> lpop stu # 移除头元素
"cb"
RPOP
RPOP key
移除并返回列表 key 的尾元素。
返回值
列表的尾元素。 当 key 不存在时,返回 nil 。
LRANGE
LRANGE key start stop
返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个
元素,以此类推。
你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
超出范围的下标
超出范围的下标值不会引起错误。
如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大,那么 LRANGE 返回一个空列表。
如果 stop 下标比 end 下标还要大,Redis将 stop 的值设置为 end 。
返回值
一个列表,包含指定区间内的元素。
redis> RPUSH fp-language lisp
(integer) 1
redis> LRANGE fp-language 0 0
1) "lisp"
redis> RPUSH fp-language scheme
(integer) 2
redis> LRANGE fp-language 0 1
1) "lisp"
2) "scheme"
LINDEX
LINDEX key index
返回列表 key 中,下标为 index 的元素。
下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个
元素,以此类推。
你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
如果 key 不是列表类型,返回一个错误。
返回值
列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range),返回 nil 。
redis> LPUSH mylist "World"
(integer) 1
redis> LPUSH mylist "Hello"
(integer) 2
redis> LINDEX mylist 0
"Hello"
redis> LINDEX mylist -1
"World"
redis> LINDEX mylist 3 # index不在 mylist 的区间范围内
(nil)
LLEN
LLEN key
返回列表 key 的长度。
如果 key 不存在,则 key 被解释为一个空列表,返回 0 .
如果 key 不是列表类型,返回一个错误。
返回值
列表 key 的长度。
# 空列表
redis> LLEN job
(integer) 0
# 非空列表
redis> LPUSH job "cook food"
(integer) 1
redis> LPUSH job "have lunch"
(integer) 2
redis> LLEN job
(integer) 2
LREM
LREM key count value
根据参数 count 的值,移除列表中与参数 value 相等的元素。
count 的值可以是以下几种:
count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
count = 0 : 移除表中所有与 value 相等的值
返回值
被移除元素的数量。 因为不存在的 key 被视作空表(empty list),所以当 key 不存在时, LREM 命令总是返回 0
# 先创建一个表,内容排列是
# morning hello morning helllo morning
redis> LPUSH greet "morning"
(integer) 1
redis> LPUSH greet "hello"
(integer) 2
redis> LPUSH greet "morning"
(integer) 3
redis> LPUSH greet "hello"
(integer) 4
redis> LPUSH greet "morning"
(integer) 5
redis> LRANGE greet 0 4 # 查看所有元素
1) "morning"
2) "hello"
3) "morning"
4) "hello"
5) "morning"
redis> LREM greet 2 morning # 移除从表头到表尾,最先发现的两个 morning
(integer) 2 # 两个元素被移除
redis> LLEN greet # 还剩 3 个元素
(integer) 3
redis> LRANGE greet 0 2
1) "hello"
2) "hello"
3) "morning"
redis> LREM greet -1 morning # 移除从表尾到表头,第一个 morning
(integer) 1
redis> LLEN greet # 剩下两个元素
(integer) 2
redis> LRANGE greet 0 1
1) "hello"
2) "hello"
redis> LREM greet 0 hello # 移除表中所有 hello
(integer) 2 # 两个 hello 被移除
redis> LLEN greet
(integer) 0
LSET
LSET key index value
将列表 key 下标为 index 的元素的值设置为 value 。
当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。
关于列表下标的更多信息,请参考 LINDEX key index 命令
返回值
操作成功返回 ok ,否则返回错误信息
# 对空列表(key 不存在)进行 LSET
redis> EXISTS list
(integer) 0
redis> LSET list 0 item
(error) ERR no such key
# 对非空列表进行 LSET
redis> LPUSH job "cook food"
(integer) 1
redis> LRANGE job 0 0
1) "cook food"
redis> LSET job 0 "play game"
OK
redis> LRANGE job 0 0
1) "play game"
# index 超出范围
redis> LLEN list # 列表长度为 1
(integer) 1
redis> LSET list 3 'out of range'
(error) ERR index out of range
集合Set
Redis的Set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。
数据结构
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表,它将所有的元素紧挨着一起存储,分配的是一块连续的内存,当数据量比较多的时候才会改成quicklist,因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next,Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余
SADD
SADD key member [member …]
将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
当 key 不是集合类型时,返回一个错误。
返回值
被添加到集合中的新元素的数量,不包括被忽略的元素。
# 添加单个元素
redis> SADD bbs "discuz.net"
(integer) 1
# 添加重复元素
redis> SADD bbs "discuz.net"
(integer) 0
# 添加多个元素
redis> SADD bbs "tianya.cn" "groups.google.com"
(integer) 2
redis> SMEMBERS bbs
1) "discuz.net"
2) "groups.google.com"
3) "tianya.cn"
SCARD
返回集合 key 的基数(集合中元素的数量)
返回值
集合的基数。 当 key 不存在时,返回 0 。
redis> SADD tool pc printer phone
(integer) 3
redis> SCARD tool # 非空集合
(integer) 3
redis> DEL tool
(integer) 1
redis> SCARD tool # 空集合
(integer) 0
SISMEMBER
判断 member 元素是否集合 key 的成员
返回值
如果 member 元素是集合的成员,返回 1 。 如果 member 元素不是集合的成员,或 key 不存在,返回 0
redis> SMEMBERS joe's_movies
1) "hi, lady"
2) "Fast Five"
3) "2012"
redis> SISMEMBER joe's_movies "bet man"
(integer) 0
redis> SISMEMBER joe's_movies "Fast Five"
(integer) 1
SREM
移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
当 key 不是集合类型,返回一个错误
返回值
被成功移除的元素的数量,不包括被忽略的元素
# 测试数据
redis> SMEMBERS languages
1) "c"
2) "lisp"
3) "python"
4) "ruby"
# 移除单个元素
redis> SREM languages ruby
(integer) 1
# 移除不存在元素
redis> SREM languages non-exists-language
(integer) 0
# 移除多个元素
redis> SREM languages lisp python c
(integer) 3
redis> SMEMBERS languages
(empty list or set)
SPOP
移除并返回集合中的一个随机元素。
返回值
被移除的随机元素。 当 key 不存在或 key 是空集时,返回 nil
SRANDMEMBER
SRANDMEMBER key [count]
如果命令执行时,只提供了 key 参数,那么返回集合中的一个随机元素
如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。
如果 count 大于等于集合基数,那么返回整个集合
如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值
返回值
只提供 key 参数时,返回一个元素;如果集合为空,返回 nil 。 如果提供了 count 参数,那么返回一个数组;如
果集合为空,返回空数组
# 添加元素
redis> SADD fruit apple banana cherry
(integer) 3
# 只给定 key 参数,返回一个随机元素
redis> SRANDMEMBER fruit
"cherry"
redis> SRANDMEMBER fruit
"apple"
# 给定 3 为 count 参数,返回 3 个随机元素
# 每个随机元素都不相同
redis> SRANDMEMBER fruit 3
1) "apple"
2) "banana"
3) "cherry"
# 给定 -3 为 count 参数,返回 3 个随机元素
# 元素可能会重复出现多次
redis> SRANDMEMBER fruit -3
1) "banana"
2) "cherry"
3) "apple"
redis> SRANDMEMBER fruit -3
1) "apple"
2) "apple"
3) "cherry"
# 如果 count 是整数,且大于等于集合基数,那么返回整个集合
redis> SRANDMEMBER fruit 10
1) "apple"
2) "banana"
3) "cherry"
SMEMBERS
SMEMBERS key
返回集合 key 中的所有成员。
不存在的 key 被视为空集合
返回值
集合中的所有成员
# key 不存在或集合为空
redis> EXISTS not_exists_key
(integer) 0
redis> SMEMBERS not_exists_key
(empty list or set)
# 非空集合
redis> SADD language Ruby Python Clojure
(integer) 3
redis> SMEMBERS language
1) "Python"
2) "Ruby"
3) "Clojure"
SUNION
sunion 返回两个集合的并集元素
SUNION key
返回一个集合的全部成员,该集合是所有给定集合的并集。
不存在的 key 被视为空集。
返回值
并集成员的列表
redis> SMEMBERS songs
1) "Billie Jean"
redis> SMEMBERS my_songs
1) "Believe Me"
redis> SUNION songs my_songs
1) "Billie Jean"
2) "Believe Me"
SDIFF
sdiff 返回两个集合的差集元素(key1中的,不包含key2中的)
SDIFF key [key …]
返回一个集合的全部成员,该集合是所有给定集合之间的差集。
不存在的 key 被视为空集。
返回值
一个包含差集成员的列表
redis> SMEMBERS peter's_movies
1) "bet man"
2) "start war"
3) "2012"
redis> SMEMBERS joe's_movies
1) "hi, lady"
2) "Fast Five"
3) "2012"
redis> SDIFF peter's_movies joe's_movies
1) "bet man"
2) "start war
SINTER
sinter 返回两个集合的交集元素
返回一个集合的全部成员,该集合是所有给定集合的交集。
不存在的 key 被视为空集。
当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。
返回值
交集成员的列表。
redis> SMEMBERS group_1
1) "LI LEI"
2) "TOM"
3) "JACK"
redis> SMEMBERS group_2
1) "HAN MEIMEI"
2) "JACK"
redis> SINTER group_1 group_2
1) "JACK"
SMOVE
将 member 元素从 source 集合移动到 destination 集合
如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 0 。否则,
member 元素从 source 集合中被移除,并添加到 destination 集合中去。
当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。
当 source 或 destination 不是集合类型时,返回一个错误
redis> SMEMBERS songs
1) "Billie Jean"
2) "Believe Me"
redis> SMEMBERS my_songs
(empty list or set)
redis> SMOVE songs my_songs "Believe Me"
(integer) 1
redis> SMEMBERS songs
1) "Billie Jean"
redis> SMEMBERS my_songs
1) "Believe Me"
有序集合zset
ZADD
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,
来保证该 member 在正确的位置上。
score 值可以是整数值或双精度浮点数。
如果 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
当 key 存在但不是有序集类型时,返回一个错误。
返回值
被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
# 添加单个元素
redis> ZADD page_rank 10 google.com
(integer) 1
# 添加多个元素
redis> ZADD page_rank 9 baidu.com 8 bing.com
(integer) 2
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"
# 添加已存在元素,且 score 值不变
redis> ZADD page_rank 10 google.com
(integer) 0
redis> ZRANGE page_rank 0 -1 WITHSCORES # 没有改变
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"
# 添加已存在元素,但是改变 score 值
redis> ZADD page_rank 6 bing.com
(integer) 0
redis> ZRANGE page_rank 0 -1 WITHSCORES # bing.com 元素的 score 值被改变
1) "bing.com"
2) "6"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"
zcard
ZCARD key
返回有序集 key 的基数。
返回值
当 key 存在且是有序集类型时,返回有序集的基数。 当 key 不存在时,返回 0
redis > ZADD salary 2000 tom # 添加一个成员
(integer) 1
redis > ZCARD salary
(integer) 1
redis > ZADD salary 5000 jack # 再添加一个成员
(integer) 1
redis > ZCARD salary
(integer) 2
redis > EXISTS non_exists_key # 对不存在的 key 进行 ZCARD 操作
(integer) 0
redis > ZCARD non_exists_key
(integer) 0
ZRANGE
返回有序集 key 中,指定区间内的成员。
其中成员的位置按 score 值递增(从小到大)来排序。
具有相同 score 值的成员按字典序(lexicographical order )来排列。
返回值
指定区间内,带有 score 值(可选)的有序集成员的列表
redis > ZRANGE salary 0 -1 WITHSCORES # 显示整个有序集成员
1) "jack"
2) "3500"
3) "tom"
4) "5000"
5) "boss"
6) "10086"
redis > ZRANGE salary 1 2 WITHSCORES # 显示有序集下标区间 1 至 2 的成员
1) "tom"
2) "5000"
3) "boss"
4) "10086"
redis > ZRANGE salary 0 200000 WITHSCORES # 测试 end 下标超出最大下标时的情况
1) "jack"
2) "3500"
3) "tom"
4) "5000"
5) "boss"
6) "10086"
redis > ZRANGE salary 200000 3000000 WITHSCORES # 测试当给定区间不存在于有序集时的情况
(empty list or set)
ZREVRANGE
返回有序集 key 中,指定区间内的成员。
其中成员的位置按 score 值递减(从大到小)来排列。 具有相同 score 值的成员按字典序的逆序(reverse lexicographical order)排列。
返回值
指定区间内,带有 score 值(可选)的有序集成员的列表。
ZRANGEBYSCORE
按照分数查找一个范围内的元素
返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
返回值
指定区间内,带有 score 值(可选)的有序集成员的列表。
redis> ZADD salary 2500 jack # 测试数据
(integer) 0
redis> ZADD salary 5000 tom
(integer) 0
redis> ZADD salary 12000 peter
(integer) 0
redis> ZRANGEBYSCORE salary -inf +inf # 显示整个有序集
1) "jack"
2) "tom"
3) "peter"
redis> ZRANGEBYSCORE salary -inf +inf WITHSCORES # 显示整个有序集及成员的 score 值
1) "jack"
2) "2500"
3) "tom"
4) "5000"
5) "peter"
6) "12000"
redis> ZRANGEBYSCORE salary -inf 5000 WITHSCORES # 显示工资 <=5000 的所有成员
1) "jack"
2) "2500"
3) "tom"
4) "5000"
redis> ZRANGEBYSCORE salary (5000 400000 # 显示工资大于 5000 小于等于 400000 的成员
1) "peter"
ZRANK
返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。
排名以 0 为底,也就是说, score 值最小的成员排名为 0
返回值
如果 member 是有序集 key 的成员,返回 member 的排名。 如果 member 不是有序集 key 的成员,返回 nil
redis> ZRANGE salary 0 -1 WITHSCORES # 显示所有成员及其 score 值
1) "peter"
2) "3500"
3) "tom"
4) "4000"
5) "jack"
6) "5000"
redis> ZRANK salary tom # 显示 tom 的薪水排名,第二
(integer) 1
ZREVRANK
返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。
排名以 0 为底,也就是说, score 值最大的成员排名为 0
返回值
如果 member 是有序集 key 的成员,返回 member 的排名。 如果 member 不是有序集 key 的成员,返回 nil
redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES # 测试数据
1) "jack"
2) "2000"
3) "peter"
4) "3500"
5) "tom"
6) "5000"
redis> ZREVRANK salary peter # peter 的工资排第二
(integer) 1
redis> ZREVRANK salary tom # tom 的工资最高
(integer) 0
ZSCORE
返回有序集 key 中,成员 member 的 score 值。
如果 member 元素不是有序集 key 的成员,或 key 不存在,返回 nil 。
返回值
member 成员的 score 值,以字符串形式表示。
redis> ZRANGE salary 0 -1 WITHSCORES # 测试数据
1) "tom"
2) "2000"
3) "peter"
4) "3500"
5) "jack"
6) "5000"
redis> ZSCORE salary peter # 注意返回值是字符串
"3500"
ZREM
移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。
当 key 存在但不是有序集类型时,返回一个错误
返回值
被成功移除的成员的数量,不包括被忽略的成员
# 测试数据
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"
# 移除单个元素
redis> ZREM page_rank google.com
(integer) 1
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
# 移除多个元素
redis> ZREM page_rank baidu.com bing.com
(integer) 2
redis> ZRANGE page_rank 0 -1 WITHSCORES
(empty list or set)
# 移除不存在元素
redis> ZREM page_rank non-exists-element
(integer) 0
ZINCRBY
为有序集 key 的成员 member 的 score 值加上增量 increment 。
可以通过传递一个负数值 increment ,让 score 减去相应的值,比如 ZINCRBY key -5 member ,就是让 member
的 score 值减去 5 。
当 key 不存在,或 member 不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment
member 。
当 key 不是有序集类型时,返回一个错误。
score 值可以是整数值或双精度浮点数。
返回值
member 成员的新 score 值,以字符串形式表示。
redis> ZSCORE salary tom
"2000"
redis> ZINCRBY salary 2000 tom # tom 加薪啦!
"4000"
持久化机制
client redis[内存] -----> 内存数据- 数据持久化–>磁盘
Redis官方提供了两种不同的持久化方法来将数据存储到硬盘里面分别是:
- 快照(Snapshot)
- AOF (Append Only File) 只追加日志文件
快照(Snapshot)
这种方式可以将某一时刻的所有数据都写入硬盘中,当然这也是redis的默认开启持久化方式,保存的文件是以.rdb形式结尾的文件因此这种方式也称之为RDB方式
1.客户端方式之BGSAVE
-
客户端可以使用BGSAVE命令来创建一个快照,当接收到客户端的BGSAVE命令时,redis会调用fork¹来创建一个子进程,然后子进程负责将快照写入磁盘中,而父进程则继续处理命令请求。
名词解释: fork当一个进程创建子进程的时候,底层的操作系统会创建该进程的一个副本,在类unix系统中创建子进程的操作会进行优化:在刚开始的时候,父子进程共享相同内存,直到父进程或子进程对内存进行了写之后,对被写入的内存的共享才会结束服务
2.客户端方式之SAVE
- b.客户端还可以使用SAVE命令来创建一个快照,接收到SAVE命令的redis服务器在快照创建完毕之前将不再响应任何其他的命令
注意: SAVE命令并不常用,使用SAVE命令在快照创建完毕之前,redis处于阻塞状态,无法对外服务
3.服务器配置方式之满足配置自动触发
- 如果用户在redis.conf中设置了save配置选项,redis会在save选项条件满足之后自动触发一次BGSAVE命令,如果设置多个save配置选项,当任意一个save配置选项条件满足,redis也会触发一次BGSAVE命令
4.服务器接收客户端shutdown指令
- 当redis通过shutdown指令接收到关闭服务器的请求时,会执行一个save命令,阻塞所有的客户端,不再执行客户端执行发送的任何命令,并且在save命令执行完毕之后关闭服务器
配置生成快照名称和位置
#1.修改生成快照名称
- dbfilename dump.rdb
# 2.修改生成位置
- dir ./
AOF 只追加日志文件
这种方式可以将所有客户端执行的写命令记录到日志文件中,AOF持久化会将被执行的写命令写到AOF的文件末尾,以此来记录数据发生的变化,因此只要redis从头到尾执行一次AOF文件所包含的所有写命令,就可以恢复AOF文件的记录的数据集
开启AOF持久化
在redis的默认配置中AOF持久化机制是没有开启的,需要在配置中开启
- a.修改 appendonly yes 开启持久化
- b.修改 appendfilename “appendonly.aof” 指定生成文件名称
日志追加频率
1.always 【谨慎使用】
- 说明: 每个redis写命令都要同步写入硬盘,严重降低redis速度
- 解释: 如果用户使用了always选项,那么每个redis写命令都会被写入硬盘,从而将发生系统崩溃时出现的数据丢失减到最少;遗憾的是,因为这种同步策略需要对硬盘进行大量的写入操作,所以redis处理命令的速度会受到硬盘性能的限制;
- 注意: 转盘式硬盘在这种频率下200左右个命令/s ; 固态硬盘(SSD) 几百万个命令/s;
- 警告: 使用SSD用户请谨慎使用always选项,这种模式不断写入少量数据的做法有可能会引发严重的写入放大问题,导致将固态硬盘的寿命从原来的几年降低为几个月。
2.everysec 【推荐】
- 说明: 每秒执行一次同步显式的将多个写命令同步到磁盘
- 解释: 为了兼顾数据安全和写入性能,用户可以考虑使用everysec选项,让redis每秒一次的频率对AOF文件进行同步;redis每秒同步一次AOF文件时性能和不使用任何持久化特性时的性能相差无几,而通过每秒同步一次AOF文件,redis可以保证,即使系统崩溃,用户最多丢失一秒之内产生的数据。
3.no 【不推荐】
- 说明: 由操作系统决定何时同步
- 解释:最后使用no选项,将完全有操作系统决定什么时候同步AOF日志文件,这个选项不会对redis性能带来影响但是系统崩溃时,会丢失不定数量的数据,另外如果用户硬盘处理写入操作不够快的话,当缓冲区被等待写入硬盘数据填满时,redis会处于阻塞状态,并导致redis的处理命令请求的速度变慢。
1.修改日志同步频率
- 修改appendfsync everysec|always|no 指定
AOF文件的重写
AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件Redis提供了AOF重写(ReWriter)机制。
AOF重写
用来在一定程度上减小AOF文件的体积
触发重写方式
# 1.客户端方式触发重写
- 执行BGREWRITEAOF命令 不会阻塞redis的服务
# 2.服务器配置方式自动触发
- 配置redis.conf中的auto-aof-rewrite-percentage选项 参加下图↓↓↓
- 如果设置auto-aof-rewrite-percentage值为100和auto-aof-rewrite-min-size 64mb,并且启用的AOF持久化时,那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发,如果重写过于频繁,用户可以考虑将auto-aof-rewrite-percentage设置为更大
注意:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件这点和快照有点类似。
重写原理
# 重写流程
- 1. redis调用fork ,现在有父子两个进程 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
- 2. 父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。
- 3. 当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
- 4. 现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。
主从复制
主从复制架构仅仅用来解决数据的冗余备份,从节点仅仅用来同步数据
主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主
无法解决: 1.master节点出现故障的自动故障转移
搭建主从复制
只配置从库,不用配置主库
查看当前redsi信息
info replication
修改端口、pid名字、log文件名字、dump.rdb
# 1.准备3台机器并修改配置
- master
port 6379
bind 0.0.0.0
- slave1
port 7000
bind 0.0.0.0
pidfile /var/run/redis_7000.pid
logfile "/usr/local/bin/redis_7000.log"
dbfilename dump_7000.rdb
slaveof masterip masterport
- slave2
port 7001
bind 0.0.0.0
pidfile /var/run/redis_7001.pid
logfile "/usr/local/bin/redis_7001.log"
dbfilename dump_7001.rdb
slaveof masterip masterport
修改端口
修改pid名字
修改log文件名字
修改dump.rdb
启动并查看redis
这里我以6379位主服务器,7000和7001为从服务器
从服务器执行命令
# slaveof host port
127.0.0.1:7000> slaveof 123.57.252.81 6379
主服务器查看
info replication
到此主从复制已完成,注意这里是命令配置的,redis重启后会主从复制会消失。真实的主从配置应该在配置文件配置,这样的话就是永久的
永久配置
设置配置文件
# replicaof <masterip> <masterport>
replicaof 123.57.252.81 6379
除了拷贝完整的配置文件外也可以建立空的文件使用include引入
include /myredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb
主从特点
1,主机可以写,从机不能写只能读,主机中所有信息和数据都会自动保存到从机汇总。
向主机中存入数据,主机能存也能取
2.主机断开连接,从机依旧连接到主机,但是没有写操作,这个时候主机如果重启了,从机依旧可以获取到主机写的信息
注意如果是用命令方式来配置从机,如果重启了此时该从机就会变成主机
薪火相传
上一个Slave可以是下一个slave的Master,Slave同样可以接收其他 slaves的连接和同步请求,那么该slave作为了链条中下一个的master, 可以有效减轻master的写压力,去中心化降低风险。
用 slaveof
中途变更转向:会清除之前的数据,重新建立拷贝最新的
风险是一旦某个slave宕机,后面的slave都没法备份
主机挂了,从机还是从机,无法写数据了
反客为主
当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改。
用 slaveof no one 将从机变为主机
slaveof no one
这个是手动变得后面的哨兵模式可以实现自动
复制原理
slave启动成功连接到master后会发送一个sync同步命令。
master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台程序执行完毕之后,matser将传送整个数据文件到slave,并完成一次完全同步。
全量复制: 而slave服务在接收到数据库文件数据后,将其存盘,并加载到内存汇总
增量复制:master继续将新的 所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将会被自动执行,我们的数据移一定可以在从机中看到